diff --git a/.gitignore b/.gitignore
index 5a65ef2..2091f63 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1 @@
-SOURCES/cert9.db
-SOURCES/key4.db
-SOURCES/sssd-1.16.0.tar.gz
+SOURCES/sssd-1.16.2.tar.gz
diff --git a/.sssd.metadata b/.sssd.metadata
index d8d858c..7f29762 100644
--- a/.sssd.metadata
+++ b/.sssd.metadata
@@ -1,3 +1 @@
-52bc755199e2c92ae81a8f93a7c6f2e46715b771 SOURCES/cert9.db
-52770a7b7564ef8e0508ae60f5dc238b78e70b99 SOURCES/key4.db
-fff74b3798e163a0fe311bdfc4588524afe6dd87 SOURCES/sssd-1.16.0.tar.gz
+46c59f189e5ae3286ef7878faf4801068d7bf2a7 SOURCES/sssd-1.16.2.tar.gz
diff --git a/SOURCES/0001-NSS-Move-memcache-setup-to-separate-function.patch b/SOURCES/0001-NSS-Move-memcache-setup-to-separate-function.patch
deleted file mode 100644
index 0d2e9f4..0000000
--- a/SOURCES/0001-NSS-Move-memcache-setup-to-separate-function.patch
+++ /dev/null
@@ -1,143 +0,0 @@
-From 82d52dbfd51330cd1fda4734b9e901431e137211 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
-Date: Thu, 19 Oct 2017 16:39:27 +0200
-Subject: [PATCH 01/21] NSS: Move memcache setup to separate function
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3496
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 878b0d42aca5839fdc1d97a68ce181e280f1ed7b)
----
- src/responder/nss/nsssrv.c | 91 ++++++++++++++++++++++++++--------------------
- 1 file changed, 51 insertions(+), 40 deletions(-)
-
-diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
-index d67b9fac8d770d113560e41b259e2d5edd219343..21dd198226da6cf14d7db4941806048662970fed 100644
---- a/src/responder/nss/nsssrv.c
-+++ b/src/responder/nss/nsssrv.c
-@@ -252,6 +252,56 @@ static void nss_dp_reconnect_init(struct sbus_connection *conn,
-     /* nss_shutdown(rctx); */
- }
- 
-+static int setup_memcaches(struct nss_ctx *nctx)
-+{
-+    int ret;
-+    int memcache_timeout;
-+
-+    /* Remove the CLEAR_MC_FLAG file if exists. */
-+    ret = unlink(SSS_NSS_MCACHE_DIR"/"CLEAR_MC_FLAG);
-+    if (ret != 0 && errno != ENOENT) {
-+        ret = errno;
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Failed to unlink file [%s]. This can cause memory cache to "
-+               "be purged when next log rotation is requested. %d: %s\n",
-+               SSS_NSS_MCACHE_DIR"/"CLEAR_MC_FLAG, ret, strerror(ret));
-+    }
-+
-+    ret = confdb_get_int(nctx->rctx->cdb,
-+                         CONFDB_NSS_CONF_ENTRY,
-+                         CONFDB_MEMCACHE_TIMEOUT,
-+                         300, &memcache_timeout);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_FATAL_FAILURE,
-+              "Failed to get 'memcache_timeout' option from confdb.\n");
-+        return ret;
-+    }
-+
-+    /* TODO: read cache sizes from configuration */
-+    ret = sss_mmap_cache_init(nctx, "passwd", SSS_MC_PASSWD,
-+                              SSS_MC_CACHE_ELEMENTS, (time_t)memcache_timeout,
-+                              &nctx->pwd_mc_ctx);
-+    if (ret) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "passwd mmap cache is DISABLED\n");
-+    }
-+
-+    ret = sss_mmap_cache_init(nctx, "group", SSS_MC_GROUP,
-+                              SSS_MC_CACHE_ELEMENTS, (time_t)memcache_timeout,
-+                              &nctx->grp_mc_ctx);
-+    if (ret) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "group mmap cache is DISABLED\n");
-+    }
-+
-+    ret = sss_mmap_cache_init(nctx, "initgroups", SSS_MC_INITGROUPS,
-+                              SSS_MC_CACHE_ELEMENTS, (time_t)memcache_timeout,
-+                              &nctx->initgr_mc_ctx);
-+    if (ret) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "initgroups mmap cache is DISABLED\n");
-+    }
-+
-+    return EOK;
-+}
-+
- int nss_process_init(TALLOC_CTX *mem_ctx,
-                      struct tevent_context *ev,
-                      struct confdb_ctx *cdb)
-@@ -260,7 +310,6 @@ int nss_process_init(TALLOC_CTX *mem_ctx,
-     struct sss_cmd_table *nss_cmds;
-     struct be_conn *iter;
-     struct nss_ctx *nctx;
--    int memcache_timeout;
-     int ret, max_retries;
-     enum idmap_error_code err;
-     int fd_limit;
-@@ -330,49 +379,11 @@ int nss_process_init(TALLOC_CTX *mem_ctx,
-         goto fail;
-     }
- 
--    /* create mmap caches */
--    /* Remove the CLEAR_MC_FLAG file if exists. */
--    ret = unlink(SSS_NSS_MCACHE_DIR"/"CLEAR_MC_FLAG);
--    if (ret != 0 && errno != ENOENT) {
--        ret = errno;
--        DEBUG(SSSDBG_CRIT_FAILURE,
--              "Failed to unlink file [%s]. This can cause memory cache to "
--               "be purged when next log rotation is requested. %d: %s\n",
--               SSS_NSS_MCACHE_DIR"/"CLEAR_MC_FLAG, ret, strerror(ret));
--    }
--
--    ret = confdb_get_int(nctx->rctx->cdb,
--                         CONFDB_NSS_CONF_ENTRY,
--                         CONFDB_MEMCACHE_TIMEOUT,
--                         300, &memcache_timeout);
-+    ret = setup_memcaches(nctx);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_FATAL_FAILURE,
--              "Failed to get 'memcache_timeout' option from confdb.\n");
-         goto fail;
-     }
- 
--    /* TODO: read cache sizes from configuration */
--    ret = sss_mmap_cache_init(nctx, "passwd", SSS_MC_PASSWD,
--                              SSS_MC_CACHE_ELEMENTS, (time_t)memcache_timeout,
--                              &nctx->pwd_mc_ctx);
--    if (ret) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "passwd mmap cache is DISABLED\n");
--    }
--
--    ret = sss_mmap_cache_init(nctx, "group", SSS_MC_GROUP,
--                              SSS_MC_CACHE_ELEMENTS, (time_t)memcache_timeout,
--                              &nctx->grp_mc_ctx);
--    if (ret) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "group mmap cache is DISABLED\n");
--    }
--
--    ret = sss_mmap_cache_init(nctx, "initgroups", SSS_MC_INITGROUPS,
--                              SSS_MC_CACHE_ELEMENTS, (time_t)memcache_timeout,
--                              &nctx->initgr_mc_ctx);
--    if (ret) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "initgroups mmap cache is DISABLED\n");
--    }
--
-     /* Set up file descriptor limits */
-     ret = confdb_get_int(nctx->rctx->cdb,
-                          CONFDB_NSS_CONF_ENTRY,
--- 
-2.13.5
-
diff --git a/SOURCES/0001-krb5-locator-add-support-for-multiple-addresses.patch b/SOURCES/0001-krb5-locator-add-support-for-multiple-addresses.patch
new file mode 100644
index 0000000..747c2f2
--- /dev/null
+++ b/SOURCES/0001-krb5-locator-add-support-for-multiple-addresses.patch
@@ -0,0 +1,468 @@
+From 4b1137562c3446e85a6383010702850f9532a4f2 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 24 Feb 2017 13:55:47 +0100
+Subject: [PATCH] krb5 locator: add support for multiple addresses
+
+Read multiple addresses from the kdcinfo files add call the provided
+callback with each of them.
+
+Related to https://pagure.io/SSSD/sssd/issue/941
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+
+(cherry picked from commit efae9509cb05648357e9b4c10a93c0d38558bed4)
+
+DOWNSTREAM:
+Resolves: rhbz#1494690 - kdcinfo files are not created for subdomains of a directly joined AD client
+---
+ src/krb5_plugin/sssd_krb5_locator_plugin.c | 344 +++++++++++++++------
+ 1 file changed, 246 insertions(+), 98 deletions(-)
+
+diff --git a/src/krb5_plugin/sssd_krb5_locator_plugin.c b/src/krb5_plugin/sssd_krb5_locator_plugin.c
+index 7c17fcb33373293fbbbe2be967dca57b31ef13de..82fb5c7b2ffa319ed250e54cdf9a0b6798d4ff51 100644
+--- a/src/krb5_plugin/sssd_krb5_locator_plugin.c
++++ b/src/krb5_plugin/sssd_krb5_locator_plugin.c
+@@ -42,7 +42,7 @@
+ #define DEFAULT_KADMIN_PORT 749
+ #define DEFAULT_KPASSWD_PORT 464
+ 
+-#define BUFSIZE 512
++#define BUFSIZE 4096
+ #define PORT_STR_SIZE 7
+ #define SSSD_KRB5_LOCATOR_DEBUG "SSSD_KRB5_LOCATOR_DEBUG"
+ #define SSSD_KRB5_LOCATOR_DISABLE "SSSD_KRB5_LOCATOR_DISABLE"
+@@ -53,12 +53,15 @@
+     } \
+ } while(0)
+ 
++struct addr_port {
++    char *addr;
++    uint16_t port;
++};
++
+ struct sssd_ctx {
+     char *sssd_realm;
+-    char *kdc_addr;
+-    uint16_t kdc_port;
+-    char *kpasswd_addr;
+-    uint16_t kpasswd_port;
++    struct addr_port *kdc_addr;
++    struct addr_port *kpasswd_addr;
+     bool debug;
+     bool disabled;
+ };
+@@ -82,6 +85,186 @@ void plugin_debug_fn(const char *format, ...)
+     free(s);
+ }
+ 
++
++static void free_addr_port_list(struct addr_port **list)
++{
++    size_t c;
++
++    if (list == NULL || *list == NULL) {
++        return;
++    }
++
++    for (c = 0; (*list)[c].addr != NULL; c++) {
++        free((*list)[c].addr);
++    }
++    free(*list);
++    *list = NULL;
++}
++
++static int copy_addr_port_list(struct addr_port *src, bool clear_port,
++                               struct addr_port **dst)
++{
++    size_t c;
++    struct addr_port *d = NULL;
++    int ret;
++
++    /* only copy if dst is initialized to NULL */
++    if (dst == NULL || *dst != NULL) {
++        return EINVAL;
++    }
++
++    if (src == NULL) {
++        return 0;
++    }
++
++    for (c = 0; src[c].addr != NULL; c++);
++
++    d = calloc((c + 1), sizeof(struct addr_port));
++    if (d == NULL) {
++        return ENOMEM;
++    }
++
++    for (c = 0; src[c].addr != NULL; c++) {
++        d[c].addr = strdup(src[c].addr);
++        if (d[c].addr == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
++        if (clear_port) {
++            d[c].port = 0;
++        } else {
++            d[c].port = src[c].port;
++        }
++    }
++
++    ret = EOK;
++
++done:
++    if (ret != EOK) {
++        free_addr_port_list(&d);
++    } else {
++        *dst = d;
++    }
++
++    return ret;
++}
++
++static int buf_to_addr_port_list(struct sssd_ctx *ctx,
++                                 uint8_t *buf, size_t buf_size,
++                                 struct addr_port **list)
++{
++    struct addr_port *l = NULL;
++    int ret;
++    uint8_t *p;
++    uint8_t *pn;
++    size_t c;
++    size_t len;
++    char *tmp = NULL;
++    char *port_str;
++    long port;
++    char *endptr;
++
++    /* only create if list is initialized to NULL */
++    if (buf == NULL || buf_size == 0 || list == NULL || *list != NULL) {
++        return EINVAL;
++    }
++
++    c = 1; /* to account for a missing \n at the very end */
++    p = buf;
++    while ((p - buf) < buf_size
++                && (p = memchr(p, '\n', buf_size - (p - buf))) != NULL) {
++        p++;
++        c++;
++    }
++
++    l = calloc((c + 1), sizeof(struct addr_port));
++    if (l == NULL) {
++        return ENOMEM;
++    }
++
++    c = 0;
++    p = buf;
++    do {
++        pn = memchr(p, '\n', buf_size - (p - buf));
++        if (pn != NULL) {
++            len = pn - p;
++        } else {
++            len = buf_size - (p - buf);
++        }
++        if (len == 0) {
++            /* empty line no more processing */
++            break;
++        }
++
++        free(tmp);
++        tmp = strndup((char *) p, len);
++        if (tmp == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
++
++        port_str = strrchr(tmp, ':');
++        if (port_str == NULL) {
++            port = 0;
++        } else {
++            *port_str = '\0';
++            ++port_str;
++
++            if (isdigit(*port_str)) {
++                errno = 0;
++                port = strtol(port_str, &endptr, 10);
++                if (errno != 0) {
++                    ret = errno;
++                    PLUGIN_DEBUG(("strtol failed on [%s]: [%d][%s], "
++                                "assuming default.\n", port_str, ret,
++                                                       strerror(ret)));
++                    port = 0;
++                }
++                if (*endptr != '\0') {
++                    PLUGIN_DEBUG(("Found additional characters [%s] in port "
++                                "number [%s], assuming default.\n", endptr,
++                                                                    port_str));
++                    port = 0;
++                }
++
++                if (port < 0 || port > 65535) {
++                    PLUGIN_DEBUG(("Illegal port number [%ld], assuming "
++                                  "default.\n", port));
++                    port = 0;
++                }
++            } else {
++                PLUGIN_DEBUG(("Illegal port number [%s], assuming default.\n",
++                            port_str));
++                port = 0;
++            }
++        }
++
++        PLUGIN_DEBUG(("Found [%s][%d].\n", tmp, port));
++
++        l[c].addr = strdup(tmp);
++        if (l[c].addr == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
++        l[c].port = port;
++
++        c++;
++        p = pn == NULL ? NULL : (pn + 1);
++    } while (p != NULL);
++
++    ret = EOK;
++
++done:
++    free(tmp);
++    if (ret != EOK) {
++        free_addr_port_list(&l);
++    } else {
++        *list = l;
++    }
++
++    return ret;
++}
++
+ static int get_krb5info(const char *realm, struct sssd_ctx *ctx,
+                         enum locate_service_type svc)
+ {
+@@ -91,9 +274,6 @@ static int get_krb5info(const char *realm, struct sssd_ctx *ctx,
+     uint8_t buf[BUFSIZE + 1];
+     int fd = -1;
+     const char *name_tmpl = NULL;
+-    char *port_str;
+-    long port;
+-    char *endptr;
+ 
+     switch (svc) {
+         case locate_service_kdc:
+@@ -148,62 +328,21 @@ static int get_krb5info(const char *realm, struct sssd_ctx *ctx,
+         PLUGIN_DEBUG(("Content of krb5info file [%s] is [%d] or larger.\n",
+                       krb5info_name, BUFSIZE));
+     }
+-    PLUGIN_DEBUG(("Found [%s] in [%s].\n", buf, krb5info_name));
+-
+-    port_str = strrchr((char *) buf, ':');
+-    if (port_str == NULL) {
+-        port = 0;
+-    } else {
+-        *port_str = '\0';
+-        ++port_str;
+-
+-        if (isdigit(*port_str)) {
+-            errno = 0;
+-            port = strtol(port_str, &endptr, 10);
+-            if (errno != 0) {
+-                ret = errno;
+-                PLUGIN_DEBUG(("strtol failed on [%s]: [%d][%s], "
+-                            "assuming default.\n", port_str, ret, strerror(ret)));
+-                port = 0;
+-            }
+-            if (*endptr != '\0') {
+-                PLUGIN_DEBUG(("Found additional characters [%s] in port number "
+-                            "[%s], assuming default.\n", endptr, port_str));
+-                port = 0;
+-            }
+-
+-            if (port < 0 || port > 65535) {
+-                PLUGIN_DEBUG(("Illegal port number [%ld], assuming default.\n",
+-                            port));
+-                port = 0;
+-            }
+-        } else {
+-            PLUGIN_DEBUG(("Illegal port number [%s], assuming default.\n",
+-                        port_str));
+-            port = 0;
+-        }
+-    }
+ 
+     switch (svc) {
+         case locate_service_kdc:
+-            free(ctx->kdc_addr);
+-            ctx->kdc_addr = strdup((char *) buf);
+-            if (ctx->kdc_addr == NULL) {
+-                PLUGIN_DEBUG(("strdup failed.\n"));
+-                ret = ENOMEM;
++            free_addr_port_list(&(ctx->kdc_addr));
++            ret = buf_to_addr_port_list(ctx, buf, len, &(ctx->kdc_addr));
++            if (ret != EOK) {
+                 goto done;
+             }
+-            ctx->kdc_port = (uint16_t) port;
+             break;
+         case locate_service_kpasswd:
+-            free(ctx->kpasswd_addr);
+-            ctx->kpasswd_addr = strdup((char *) buf);
+-            if (ctx->kpasswd_addr == NULL) {
+-                PLUGIN_DEBUG(("strdup failed.\n"));
+-                ret = ENOMEM;
++            free_addr_port_list(&(ctx->kpasswd_addr));
++            ret = buf_to_addr_port_list(ctx, buf, len, &(ctx->kpasswd_addr));
++            if (ret != EOK) {
+                 goto done;
+             }
+-            ctx->kpasswd_port = (uint16_t) port;
+             break;
+         default:
+             PLUGIN_DEBUG(("Unsupported service [%d].\n", svc));
+@@ -256,8 +395,8 @@ void sssd_krb5_locator_close(void *private_data)
+     ctx = (struct sssd_ctx *) private_data;
+     PLUGIN_DEBUG(("sssd_krb5_locator_close called\n"));
+ 
+-    free(ctx->kdc_addr);
+-    free(ctx->kpasswd_addr);
++    free_addr_port_list(&(ctx->kdc_addr));
++    free_addr_port_list(&(ctx->kpasswd_addr));
+     free(ctx->sssd_realm);
+     free(ctx);
+ 
+@@ -277,8 +416,10 @@ krb5_error_code sssd_krb5_locator_lookup(void *private_data,
+     struct sssd_ctx *ctx;
+     struct addrinfo ai_hints;
+     uint16_t port = 0;
+-    const char *addr = NULL;
++    uint16_t default_port = 0;
++    struct addr_port *addr = NULL;
+     char port_str[PORT_STR_SIZE];
++    size_t c;
+ 
+     if (private_data == NULL) return KRB5_PLUGIN_NO_HANDLE;
+     ctx = (struct sssd_ctx *) private_data;
+@@ -308,9 +449,13 @@ krb5_error_code sssd_krb5_locator_lookup(void *private_data,
+             if (ret != EOK) {
+                 PLUGIN_DEBUG(("reading kpasswd address failed, "
+                               "using kdc address.\n"));
+-                free(ctx->kpasswd_addr);
+-                ctx->kpasswd_addr = strdup(ctx->kdc_addr);
+-                ctx->kpasswd_port = 0;
++                free_addr_port_list(&(ctx->kpasswd_addr));
++                ret = copy_addr_port_list(ctx->kdc_addr, true,
++                                          &(ctx->kpasswd_addr));
++                if (ret != EOK) {
++                    PLUGIN_DEBUG(("copying address list failed.\n"));
++                    return KRB5_PLUGIN_NO_HANDLE;
++                }
+             }
+         }
+     }
+@@ -322,19 +467,19 @@ krb5_error_code sssd_krb5_locator_lookup(void *private_data,
+     switch (svc) {
+         case locate_service_kdc:
+             addr = ctx->kdc_addr;
+-            port = ctx->kdc_port ? ctx->kdc_port : DEFAULT_KERBEROS_PORT;
++            default_port = DEFAULT_KERBEROS_PORT;
+             break;
+         case locate_service_master_kdc:
+             addr = ctx->kpasswd_addr;
+-            port = DEFAULT_KERBEROS_PORT;
++            default_port = DEFAULT_KERBEROS_PORT;
+             break;
+         case locate_service_kadmin:
+             addr = ctx->kpasswd_addr;
+-            port = DEFAULT_KADMIN_PORT;
++            default_port = DEFAULT_KADMIN_PORT;
+             break;
+         case locate_service_kpasswd:
+             addr = ctx->kpasswd_addr;
+-            port = ctx->kpasswd_port ? ctx->kpasswd_port : DEFAULT_KPASSWD_PORT;
++            default_port = DEFAULT_KPASSWD_PORT;
+             break;
+         case locate_service_krb524:
+             return KRB5_PLUGIN_NO_HANDLE;
+@@ -362,46 +507,49 @@ krb5_error_code sssd_krb5_locator_lookup(void *private_data,
+     if (strcmp(realm, ctx->sssd_realm) != 0)
+         return KRB5_PLUGIN_NO_HANDLE;
+ 
+-    memset(port_str, 0, PORT_STR_SIZE);
+-    ret = snprintf(port_str, PORT_STR_SIZE-1, "%u", port);
+-    if (ret < 0 || ret >= (PORT_STR_SIZE-1)) {
+-        PLUGIN_DEBUG(("snprintf failed.\n"));
+-        return KRB5_PLUGIN_NO_HANDLE;
+-    }
+-
+-    memset(&ai_hints, 0, sizeof(struct addrinfo));
+-    ai_hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV;
+-    ai_hints.ai_socktype = socktype;
+-
+-    ret = getaddrinfo(addr, port_str, &ai_hints, &ai);
+-    if (ret != 0) {
+-        PLUGIN_DEBUG(("getaddrinfo failed [%d][%s].\n", ret,
+-                                                        gai_strerror(ret)));
+-        if (ret == EAI_SYSTEM) {
+-            PLUGIN_DEBUG(("getaddrinfo failed [%d][%s].\n", errno,
+-                                                            strerror(errno)));
++    for (c = 0; addr[c].addr != NULL; c++) {
++        port = (addr[c].port == 0 ? default_port : addr[c].port);
++        memset(port_str, 0, PORT_STR_SIZE);
++        ret = snprintf(port_str, PORT_STR_SIZE-1, "%u", port);
++        if (ret < 0 || ret >= (PORT_STR_SIZE-1)) {
++            PLUGIN_DEBUG(("snprintf failed.\n"));
++            return KRB5_PLUGIN_NO_HANDLE;
+         }
+-        return KRB5_PLUGIN_NO_HANDLE;
+-    }
+ 
+-    PLUGIN_DEBUG(("addr[%s:%s] family[%d] socktype[%d]\n", addr, port_str,
+-                 ai->ai_family, ai->ai_socktype));
++        memset(&ai_hints, 0, sizeof(struct addrinfo));
++        ai_hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV;
++        ai_hints.ai_socktype = socktype;
+ 
+-    if ((family == AF_UNSPEC || ai->ai_family == family) &&
+-        ai->ai_socktype == socktype) {
+-
+-        ret = cbfunc(cbdata, socktype, ai->ai_addr);
++        ret = getaddrinfo(addr[c].addr, port_str, &ai_hints, &ai);
+         if (ret != 0) {
+-            PLUGIN_DEBUG(("cbfunc failed\n"));
+-            freeaddrinfo(ai);
+-            return ret;
++            PLUGIN_DEBUG(("getaddrinfo failed [%d][%s].\n", ret,
++                                                            gai_strerror(ret)));
++            if (ret == EAI_SYSTEM) {
++                PLUGIN_DEBUG(("getaddrinfo failed [%d][%s].\n",
++                              errno, strerror(errno)));
++            }
++            return KRB5_PLUGIN_NO_HANDLE;
++        }
++
++        PLUGIN_DEBUG(("addr[%s:%s] family[%d] socktype[%d]\n", addr[c].addr,
++                     port_str, ai->ai_family, ai->ai_socktype));
++
++        if ((family == AF_UNSPEC || ai->ai_family == family) &&
++            ai->ai_socktype == socktype) {
++
++            ret = cbfunc(cbdata, socktype, ai->ai_addr);
++            if (ret != 0) {
++                PLUGIN_DEBUG(("cbfunc failed\n"));
++                freeaddrinfo(ai);
++                return ret;
++            } else {
++                PLUGIN_DEBUG(("[%s] used\n", addr[c].addr));
++            }
+         } else {
+-            PLUGIN_DEBUG(("[%s] used\n", addr));
++            PLUGIN_DEBUG(("[%s] NOT used\n", addr[c].addr));
+         }
+-    } else {
+-        PLUGIN_DEBUG(("[%s] NOT used\n", addr));
++        freeaddrinfo(ai);
+     }
+-    freeaddrinfo(ai);
+ 
+     return 0;
+ }
+-- 
+2.17.1
+
diff --git a/SOURCES/0002-NSS-Specify-memcache_timeout-0-semantics.patch b/SOURCES/0002-NSS-Specify-memcache_timeout-0-semantics.patch
deleted file mode 100644
index 6fb4dca..0000000
--- a/SOURCES/0002-NSS-Specify-memcache_timeout-0-semantics.patch
+++ /dev/null
@@ -1,118 +0,0 @@
-From f23a358915cfa27669c019fe0df21cce8851459e Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
-Date: Thu, 19 Oct 2017 16:42:19 +0200
-Subject: [PATCH 02/21] NSS: Specify memcache_timeout=0 semantics
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-With this patch the memcache files will not be created when
-memcache_timeout is set to zero.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3496
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit ffe29e570a9e885c2f0061c34bb6be2bbd6ab9e4)
----
- src/responder/nss/nsssrv.c          |  6 ++++
- src/tests/intg/test_memory_cache.py | 59 +++++++++++++++++++++++++++++++++++++
- 2 files changed, 65 insertions(+)
-
-diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
-index 21dd198226da6cf14d7db4941806048662970fed..32bfcd69bbb9b35e9932b70a826c4f99ab6a07f3 100644
---- a/src/responder/nss/nsssrv.c
-+++ b/src/responder/nss/nsssrv.c
-@@ -277,6 +277,12 @@ static int setup_memcaches(struct nss_ctx *nctx)
-         return ret;
-     }
- 
-+    if (memcache_timeout == 0) {
-+        DEBUG(SSSDBG_CONF_SETTINGS,
-+              "Fast in-memory cache will not be initialized.");
-+        return EOK;
-+    }
-+
-     /* TODO: read cache sizes from configuration */
-     ret = sss_mmap_cache_init(nctx, "passwd", SSS_MC_PASSWD,
-                               SSS_MC_CACHE_ELEMENTS, (time_t)memcache_timeout,
-diff --git a/src/tests/intg/test_memory_cache.py b/src/tests/intg/test_memory_cache.py
-index c7ba72490174a6ec2257f9d317ac96b35c674779..cac9feb00459957650c5e455db1b2712e17ccd68 100644
---- a/src/tests/intg/test_memory_cache.py
-+++ b/src/tests/intg/test_memory_cache.py
-@@ -207,6 +207,32 @@ def fqname_case_insensitive_rfc2307(request, ldap_conn):
-     return None
- 
- 
-+@pytest.fixture
-+def zero_timeout_rfc2307(request, ldap_conn):
-+    load_data_to_ldap(request, ldap_conn)
-+
-+    conf = unindent("""\
-+        [sssd]
-+        domains             = LDAP
-+        services            = nss
-+
-+        [nss]
-+        memcache_timeout = 0
-+
-+        [domain/LDAP]
-+        ldap_auth_disable_tls_never_use_in_production = true
-+        ldap_schema         = rfc2307
-+        id_provider         = ldap
-+        auth_provider       = ldap
-+        sudo_provider       = ldap
-+        ldap_uri            = {ldap_conn.ds_inst.ldap_url}
-+        ldap_search_base    = {ldap_conn.ds_inst.base_dn}
-+    """).format(**locals())
-+    create_conf_fixture(request, conf)
-+    create_sssd_fixture(request)
-+    return None
-+
-+
- def test_getpwnam(ldap_conn, sanity_rfc2307):
-     ent.assert_passwd_by_name(
-         'user1',
-@@ -778,3 +804,36 @@ def test_removed_mc(ldap_conn, sanity_rfc2307):
-         grp.getgrnam('group1')
-     with pytest.raises(KeyError):
-         grp.getgrgid(2001)
-+
-+
-+def test_mc_zero_timeout(ldap_conn, zero_timeout_rfc2307):
-+    """
-+    Test that the memory cache is not created at all with memcache_timeout=0
-+    """
-+    # No memory cache files must be created
-+    assert len(os.listdir(config.MCACHE_PATH)) == 0
-+
-+    ent.assert_passwd_by_name(
-+        'user1',
-+        dict(name='user1', passwd='*', uid=1001, gid=2001,
-+             gecos='1001', shell='/bin/bash'))
-+    ent.assert_passwd_by_uid(
-+        1001,
-+        dict(name='user1', passwd='*', uid=1001, gid=2001,
-+             gecos='1001', shell='/bin/bash'))
-+
-+    ent.assert_group_by_name("group1", dict(name="group1", gid=2001))
-+    ent.assert_group_by_gid(2001, dict(name="group1", gid=2001))
-+    stop_sssd()
-+
-+    # sssd is stopped; so the memory cache should not be used
-+    # in long living clients (py.test in this case)
-+    with pytest.raises(KeyError):
-+        pwd.getpwnam('user1')
-+    with pytest.raises(KeyError):
-+        pwd.getpwuid(1001)
-+
-+    with pytest.raises(KeyError):
-+        grp.getgrnam('group1')
-+    with pytest.raises(KeyError):
-+        grp.getgrgid(2001)
--- 
-2.13.5
-
diff --git a/SOURCES/0002-krb5-locator-fix-IPv6-support.patch b/SOURCES/0002-krb5-locator-fix-IPv6-support.patch
new file mode 100644
index 0000000..f602116
--- /dev/null
+++ b/SOURCES/0002-krb5-locator-fix-IPv6-support.patch
@@ -0,0 +1,65 @@
+From 45a48b9a73f39e9ef9e622dbcf87cc05a2a54e40 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 22 May 2018 17:59:52 +0200
+Subject: [PATCH] krb5 locator: fix IPv6 support
+
+IPv6 addresses are added with surrounding '[' and ']' to the kdcinfo
+file to be able to specify a port number properly. The Kerberos location
+plugin didn't handle those entries properly.
+
+Related to https://pagure.io/SSSD/sssd/issue/941
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+
+(cherry picked from commit 9f683246228848173c57ad02bde241bd761481ea)
+---
+ src/krb5_plugin/sssd_krb5_locator_plugin.c | 19 +++++++++++++++++--
+ 1 file changed, 17 insertions(+), 2 deletions(-)
+
+diff --git a/src/krb5_plugin/sssd_krb5_locator_plugin.c b/src/krb5_plugin/sssd_krb5_locator_plugin.c
+index 82fb5c7b2ffa319ed250e54cdf9a0b6798d4ff51..58cac7f4b244903347e6f1811cd8de2d61281c4f 100644
+--- a/src/krb5_plugin/sssd_krb5_locator_plugin.c
++++ b/src/krb5_plugin/sssd_krb5_locator_plugin.c
+@@ -159,6 +159,8 @@ static int buf_to_addr_port_list(struct sssd_ctx *ctx,
+     uint8_t *pn;
+     size_t c;
+     size_t len;
++    size_t addr_len;
++    char *addr_str = NULL;
+     char *tmp = NULL;
+     char *port_str;
+     long port;
+@@ -206,6 +208,9 @@ static int buf_to_addr_port_list(struct sssd_ctx *ctx,
+         port_str = strrchr(tmp, ':');
+         if (port_str == NULL) {
+             port = 0;
++        } else if (tmp[0] == '[' && *(port_str - 1) != ']') {
++            /* IPv6 address without port number */
++            port = 0;
+         } else {
+             *port_str = '\0';
+             ++port_str;
+@@ -239,9 +244,19 @@ static int buf_to_addr_port_list(struct sssd_ctx *ctx,
+             }
+         }
+ 
+-        PLUGIN_DEBUG(("Found [%s][%d].\n", tmp, port));
++        /* make sure tmp is not modified so that it can be freed later */
++        addr_str = tmp;
++        /* strip leading '[' and trailing ']' from IPv6 addresses */
++        if (addr_str[0] == '['
++                && (addr_len = strlen(addr_str))
++                && addr_str[addr_len - 1] == ']') {
++            addr_str[addr_len -1] = '\0';
++            addr_str++;
++        }
+ 
+-        l[c].addr = strdup(tmp);
++        PLUGIN_DEBUG(("Found [%s][%d].\n", addr_str, port));
++
++        l[c].addr = strdup(addr_str);
+         if (l[c].addr == NULL) {
+             ret = ENOMEM;
+             goto done;
+-- 
+2.17.1
+
diff --git a/SOURCES/0003-MAN-Document-memcache_timeout-0-meaning.patch b/SOURCES/0003-MAN-Document-memcache_timeout-0-meaning.patch
deleted file mode 100644
index a64b5a5..0000000
--- a/SOURCES/0003-MAN-Document-memcache_timeout-0-meaning.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-From 22bd144b48e83d812dd823298b723983c4e3288a Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
-Date: Thu, 19 Oct 2017 16:46:43 +0200
-Subject: [PATCH 03/21] MAN: Document memcache_timeout=0 meaning
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Document that by setting memcache_timeout to 0 the in-memoory cache
-will be disabled.
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3496
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 1becbb7bec29a3d418d8f19fc52433cf86bcf395)
----
- src/man/sssd.conf.5.xml | 9 ++++++++-
- 1 file changed, 8 insertions(+), 1 deletion(-)
-
-diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
-index 7752e450835b5beba50ddc4c635ff985d38ca421..7443f718319e292842c670aaf47cfc537545d021 100644
---- a/src/man/sssd.conf.5.xml
-+++ b/src/man/sssd.conf.5.xml
-@@ -974,12 +974,19 @@ fallback_homedir = /home/%u
-                     <listitem>
-                         <para>
-                             Specifies time in seconds for which records
--                            in the in-memory cache will be valid.
-+                            in the in-memory cache will be valid. Setting this
-+                            option to zero will disable the in-memory cache.
-                         </para>
-                         <para>
-                             Default: 300
-                         </para>
-                         <para>
-+                            WARNING: Disabling the in-memory cache will
-+                            have significant negative impact on SSSD's
-+                            performance and should only be used for
-+                            testing.
-+                        </para>
-+                        <para>
-                             NOTE: If the environment variable
-                             SSS_NSS_USE_MEMCACHE is set to "NO", client
-                             applications will not use the fast in-memory
--- 
-2.13.5
-
diff --git a/SOURCES/0003-krb5-locator-make-plugin-more-robust.patch b/SOURCES/0003-krb5-locator-make-plugin-more-robust.patch
new file mode 100644
index 0000000..fb596fb
--- /dev/null
+++ b/SOURCES/0003-krb5-locator-make-plugin-more-robust.patch
@@ -0,0 +1,35 @@
+From 4e851d1391f56c632c271fd21dd96f29565cadfe Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 22 May 2018 18:03:05 +0200
+Subject: [PATCH] krb5 locator: make plugin more robust
+
+Although currently libkrb5 sets all parameters of the locator plugin
+calls to suitable values we should make sure that provided pointers are
+not NULL before trying to dereference them.
+
+Related to https://pagure.io/SSSD/sssd/issue/941
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+
+(cherry picked from commit c1fbc6b64ecaf51efc4379c4c8a4960de095abf0)
+---
+ src/krb5_plugin/sssd_krb5_locator_plugin.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/src/krb5_plugin/sssd_krb5_locator_plugin.c b/src/krb5_plugin/sssd_krb5_locator_plugin.c
+index 58cac7f4b244903347e6f1811cd8de2d61281c4f..9874fd2d1ce63b69099f057dd05f6e353a12ce75 100644
+--- a/src/krb5_plugin/sssd_krb5_locator_plugin.c
++++ b/src/krb5_plugin/sssd_krb5_locator_plugin.c
+@@ -439,6 +439,10 @@ krb5_error_code sssd_krb5_locator_lookup(void *private_data,
+     if (private_data == NULL) return KRB5_PLUGIN_NO_HANDLE;
+     ctx = (struct sssd_ctx *) private_data;
+ 
++    if (realm == NULL || cbfunc == NULL || cbdata == NULL) {
++        return KRB5_PLUGIN_NO_HANDLE;
++    }
++
+     if (ctx->disabled) {
+         PLUGIN_DEBUG(("Plugin disabled, nothing to do.\n"));
+         return KRB5_PLUGIN_NO_HANDLE;
+-- 
+2.17.1
+
diff --git a/SOURCES/0004-CONFIG-Add-a-new-option-auto_private_groups.patch b/SOURCES/0004-CONFIG-Add-a-new-option-auto_private_groups.patch
deleted file mode 100644
index 9f2a67d..0000000
--- a/SOURCES/0004-CONFIG-Add-a-new-option-auto_private_groups.patch
+++ /dev/null
@@ -1,159 +0,0 @@
-From 1deab05ac0820d9be261b55027a90078a758febd Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 3 Oct 2017 12:34:33 +0200
-Subject: [PATCH 04/21] CONFIG: Add a new option auto_private_groups
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The auto_private_groups option is used to configure the domain->mpg flag
-which was already set automatically for subdomains, but for some time was
-not settable by the admin via the configuration file.
-
-The new option name, instead of the old magic_private_groups, was chosen
-purely because this name would hopefully be better understood by admins.
-
-The option doesn't do anything yet, it is just added to all the places a
-new option should be added to.
-
-Related:
-    https://pagure.io/SSSD/sssd/issue/1872
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit d72ac2c58360cd272277b5ddde67bbff53106a74)
----
- src/confdb/confdb.c                  |  8 ++++++++
- src/confdb/confdb.h                  |  1 +
- src/config/SSSDConfig/__init__.py.in |  1 +
- src/config/SSSDConfigTest.py         |  6 ++++--
- src/config/cfg_rules.ini             |  1 +
- src/config/etc/sssd.api.conf         |  1 +
- src/man/sssd.conf.5.xml              | 20 ++++++++++++++++++++
- 7 files changed, 36 insertions(+), 2 deletions(-)
-
-diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c
-index fefecc03d554f6eca12efe07990bfae17033bd02..a028224817f12ace2a0c4165d7b9cb0bb80ce5a1 100644
---- a/src/confdb/confdb.c
-+++ b/src/confdb/confdb.c
-@@ -936,6 +936,14 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb,
-         goto done;
-     }
- 
-+    ret = get_entry_as_bool(res->msgs[0], &domain->mpg,
-+                            CONFDB_DOMAIN_AUTO_UPG, 0);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_FATAL_FAILURE,
-+              "Invalid value for %s\n", CONFDB_DOMAIN_AUTO_UPG);
-+        goto done;
-+    }
-+
-     if (strcasecmp(domain->provider, "local") == 0) {
-         /* If this is the local provider, we need to ensure that
-          * no other provider was specified for other types, since
-diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
-index bcea99ae49a3fa5f0393ce6b2c215b5b2d4bc3fc..2539b906993edbceb38aac9265e04deed69cf2e4 100644
---- a/src/confdb/confdb.h
-+++ b/src/confdb/confdb.h
-@@ -198,6 +198,7 @@
- #define CONFDB_DEFAULT_CACHE_CREDS_MIN_FF_LENGTH 8
- #define CONFDB_DOMAIN_LEGACY_PASS "store_legacy_passwords"
- #define CONFDB_DOMAIN_MPG "magic_private_groups"
-+#define CONFDB_DOMAIN_AUTO_UPG "auto_private_groups"
- #define CONFDB_DOMAIN_FQ "use_fully_qualified_names"
- #define CONFDB_DOMAIN_ENTRY_CACHE_TIMEOUT "entry_cache_timeout"
- #define CONFDB_DOMAIN_ACCOUNT_CACHE_EXPIRATION "account_cache_expiration"
-diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
-index d99b718e09283d113f73639e0f94e7f1cec55f68..d2bb709d69c8790558b5c06a7e405463b508c189 100644
---- a/src/config/SSSDConfig/__init__.py.in
-+++ b/src/config/SSSDConfig/__init__.py.in
-@@ -195,6 +195,7 @@ option_strings = {
-     'cached_auth_timeout' : _('How long can cached credentials be used for cached authentication'),
-     'full_name_format' : _('Printf-compatible format for displaying fully-qualified names'),
-     're_expression' : _('Regex to parse username and domain'),
-+    'auto_private_groups' : _('Whether to automatically create private groups for users'),
- 
-     # [provider/ipa]
-     'ipa_domain' : _('IPA domain'),
-diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
-index 4a583bdd3124dc05a116d2e6bd48afb92aa0b54d..87d1f6e6410dfeafc77d578cf0b950dc71a1f0a2 100755
---- a/src/config/SSSDConfigTest.py
-+++ b/src/config/SSSDConfigTest.py
-@@ -624,7 +624,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
-             'subdomain_homedir',
-             'full_name_format',
-             're_expression',
--            'cached_auth_timeout']
-+            'cached_auth_timeout',
-+            'auto_private_groups']
- 
-         self.assertTrue(type(options) == dict,
-                         "Options should be a dictionary")
-@@ -994,7 +995,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
-             'subdomain_homedir',
-             'full_name_format',
-             're_expression',
--            'cached_auth_timeout']
-+            'cached_auth_timeout',
-+            'auto_private_groups']
- 
-         self.assertTrue(type(options) == dict,
-                         "Options should be a dictionary")
-diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
-index e49e8d43f4aead14d833866110784fd62382cc2b..4e70bf7b6f0fa7421a0c35bd4279830265bf3470 100644
---- a/src/config/cfg_rules.ini
-+++ b/src/config/cfg_rules.ini
-@@ -382,6 +382,7 @@ option = cached_auth_timeout
- option = wildcard_limit
- option = full_name_format
- option = re_expression
-+option = auto_private_groups
- 
- #Entry cache timeouts
- option = entry_cache_user_timeout
-diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
-index 7f2b8977b7e67fcfc20df49056cda8ebe6da0be8..2be2e3e685ba3abd9a4a419f93332a89ff774262 100644
---- a/src/config/etc/sssd.api.conf
-+++ b/src/config/etc/sssd.api.conf
-@@ -185,6 +185,7 @@ subdomain_homedir = str, None, false
- cached_auth_timeout = int, None, false
- full_name_format = str, None, false
- re_expression = str, None, false
-+auto_private_groups = str, None, false
- 
- #Entry cache timeouts
- entry_cache_user_timeout = int, None, false
-diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
-index 7443f718319e292842c670aaf47cfc537545d021..47da07c33bdcfbf2fa94ff932492e9ea4bbfe846 100644
---- a/src/man/sssd.conf.5.xml
-+++ b/src/man/sssd.conf.5.xml
-@@ -2823,6 +2823,26 @@ subdomain_inherit = ldap_purge_cache_timeout
-                         </para>
-                     </listitem>
-                 </varlistentry>
-+                <varlistentry>
-+                    <term>auto_private_groups (string)</term>
-+                    <listitem>
-+                        <para>
-+                            If this option is enabled, SSSD will automatically
-+                            create user private groups based on user's
-+                            UID number. The GID number is ignored in this case.
-+                        </para>
-+                        <para>
-+                            NOTE: Because the GID number and the user private group
-+                            are inferred frm the UID number, it is not supported
-+                            to have multiple entries with the same UID or GID number
-+                            with this option. In other words, enabling this option
-+                            enforces uniqueness across the ID space.
-+                        </para>
-+                        <para>
-+                            Default: False
-+                        </para>
-+                    </listitem>
-+                </varlistentry>
-             </variablelist>
-         </para>
- 
--- 
-2.13.5
-
diff --git a/SOURCES/0004-krb5-locator-add-unit-tests.patch b/SOURCES/0004-krb5-locator-add-unit-tests.patch
new file mode 100644
index 0000000..28fe091
--- /dev/null
+++ b/SOURCES/0004-krb5-locator-add-unit-tests.patch
@@ -0,0 +1,724 @@
+From 3d6b8b306cdbd4ec15b36a1e7936d219204e08dc Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 24 May 2018 17:14:42 +0200
+Subject: [PATCH] krb5 locator: add unit tests
+
+Unit test for existing and new functionality of the Kerberos locator
+plugin.
+
+Related to https://pagure.io/SSSD/sssd/issue/941
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+
+(cherry picked from commit 2124275fe494a0241a552538c70f40c2291f3795)
+---
+ Makefile.am                                   |  20 +
+ src/krb5_plugin/sssd_krb5_locator_plugin.c    |  16 +
+ .../cmocka/test_sssd_krb5_locator_plugin.c    | 631 ++++++++++++++++++
+ 3 files changed, 667 insertions(+)
+ create mode 100644 src/tests/cmocka/test_sssd_krb5_locator_plugin.c
+
+diff --git a/Makefile.am b/Makefile.am
+index 9539b3cff8544cf406e3e19ab23e76e9cc8234ee..9055130ed74057987795285c243ff47584cf8316 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -288,6 +288,7 @@ if HAVE_CMOCKA
+         krb5_common_test \
+         test_iobuf \
+         sss_certmap_test \
++        test_sssd_krb5_locator_plugin \
+         $(NULL)
+ 
+ 
+@@ -3518,6 +3519,25 @@ sss_certmap_test_LDADD = \
+     libsss_certmap.la \
+     $(NULL)
+ 
++test_sssd_krb5_locator_plugin_SOURCES = \
++    src/tests/cmocka/test_sssd_krb5_locator_plugin.c \
++    src/krb5_plugin/sssd_krb5_locator_plugin.c \
++    $(NULL)
++test_sssd_krb5_locator_plugin_CFLAGS = \
++    $(AM_CFLAGS) \
++    $(POPT_CFLAGS) \
++    $(TALLOC_CFLAGS) \
++    $(KRB5_CFLAGS) \
++    -DTEST_PUBCONF_PATH=\"$(abs_builddir)/src/tests/cmocka/pubconf\" \
++    $(NULL)
++test_sssd_krb5_locator_plugin_LDADD = \
++    $(CMOCKA_LIBS) \
++    $(POPT_LIBS) \
++    $(TALLOC_LIBS) \
++    $(KRB5_LIBS) \
++    libsss_test_common.la \
++    $(NULL)
++
+ if BUILD_KCM
+ test_kcm_json_SOURCES = \
+     src/tests/cmocka/test_kcm_json_marshalling.c \
+diff --git a/src/krb5_plugin/sssd_krb5_locator_plugin.c b/src/krb5_plugin/sssd_krb5_locator_plugin.c
+index 9874fd2d1ce63b69099f057dd05f6e353a12ce75..952d487c276ed51e0c3a018b0d0af59ca214525f 100644
+--- a/src/krb5_plugin/sssd_krb5_locator_plugin.c
++++ b/src/krb5_plugin/sssd_krb5_locator_plugin.c
+@@ -38,6 +38,22 @@
+ 
+ #include "providers/krb5/krb5_common.h"
+ 
++/* The following override of KDCINFO_TMPL and KPASSWDINFO_TMPL is not very
++ * elegant but since they are defined in krb5_common.h with the help of
++ * PUBCONF_PATH from config.h and PUBCONF_PATH can by set by a configure
++ * options I didn't found another way to change the path for a unit test. */
++#ifdef TEST_PUBCONF_PATH
++#ifdef KDCINFO_TMPL
++#undef KDCINFO_TMPL
++#endif
++#define KDCINFO_TMPL TEST_PUBCONF_PATH"/kdcinfo.%s"
++
++#ifdef KPASSWDINFO_TMPL
++#undef KPASSWDINFO_TMPL
++#endif
++#define KPASSWDINFO_TMPL TEST_PUBCONF_PATH"/kpasswdinfo.%s"
++#endif /* TEST_PUBCONF_PATH */
++
+ #define DEFAULT_KERBEROS_PORT 88
+ #define DEFAULT_KADMIN_PORT 749
+ #define DEFAULT_KPASSWD_PORT 464
+diff --git a/src/tests/cmocka/test_sssd_krb5_locator_plugin.c b/src/tests/cmocka/test_sssd_krb5_locator_plugin.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..3e7d00632ddb59da5474c0544eee6fc67edc5570
+--- /dev/null
++++ b/src/tests/cmocka/test_sssd_krb5_locator_plugin.c
+@@ -0,0 +1,631 @@
++/*
++    SSSD
++
++    Unit test for SSSD's MIT Kerberos locator plugin
++
++    Authors:
++        Sumit Bose <sbose@redhat.com>
++
++    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 "config.h"
++
++#include <popt.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <sys/stat.h>
++#include <string.h>
++#include <fcntl.h>
++#include <netdb.h>
++#include <krb5/krb5.h>
++#include <krb5/locate_plugin.h>
++
++#include "tests/cmocka/common_mock.h"
++
++#define TEST_REALM "TEST.REALM"
++#define TEST_IP_1 "123.231.132.213"
++#define TEST_IPV6_1_PURE "7025:4d2d:2b06:e321:d971:16c0:6eeb:cc41"
++#define TEST_IPV6_1 "["TEST_IPV6_1_PURE"]"
++#define TEST_SERVICE_1 "22334"
++#define TEST_SERVICE_2 "54321"
++#define TEST_IP_1_WITH_SERVICE TEST_IP_1":"TEST_SERVICE_1
++#define TEST_IPV6_1_WITH_SERVICE TEST_IPV6_1":"TEST_SERVICE_2
++
++struct test_state {
++    void *dummy;
++};
++
++static int setup(void **state)
++{
++    struct test_state *ts = NULL;
++
++    assert_true(leak_check_setup());
++
++    ts = talloc(global_talloc_context, struct test_state);
++    assert_non_null(ts);
++
++    check_leaks_push(ts);
++    *state = (void *)ts;
++
++    unlink(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM);
++    rmdir(TEST_PUBCONF_PATH);
++
++    return 0;
++}
++
++static int teardown(void **state)
++{
++    struct test_state *ts = talloc_get_type_abort(*state, struct test_state);
++
++    assert_non_null(ts);
++
++    assert_true(check_leaks_pop(ts));
++    talloc_free(ts);
++    assert_true(leak_check_teardown());
++    return 0;
++}
++
++/* Taken from MIT Kerberos src/lib/krb5/os/locate_kdc.c and
++ * lib/krb5/os/os-proto.h */
++
++typedef enum {
++    TCP_OR_UDP = 0,
++    TCP,
++    UDP,
++    HTTPS,
++} k5_transport;
++
++/* A single server hostname or address. */
++struct server_entry {
++    char *hostname;             /* NULL -> use addrlen/addr instead */
++    int port;                   /* Used only if hostname set */
++    k5_transport transport;     /* May be 0 for UDP/TCP if hostname set */
++    char *uri_path;             /* Used only if transport is HTTPS */
++    int family;                 /* May be 0 (aka AF_UNSPEC) if hostname set */
++    int master;                 /* True, false, or -1 for unknown. */
++    size_t addrlen;
++    struct sockaddr_storage addr;
++};
++
++/* A list of server hostnames/addresses. */
++struct serverlist {
++    struct server_entry *servers;
++    size_t nservers;
++};
++#define SERVERLIST_INIT { NULL, 0 }
++
++/* Free up everything pointed to by the serverlist structure, but don't
++ *  * free the structure itself. */
++void
++k5_free_serverlist (struct serverlist *list)
++{
++    size_t i;
++
++    for (i = 0; i < list->nservers; i++) {
++        free(list->servers[i].hostname);
++        free(list->servers[i].uri_path);
++    }
++    free(list->servers);
++    list->servers = NULL;
++    list->nservers = 0;
++}
++
++/* Make room for a new server entry in list and return a pointer to the new
++ * entry.  (Do not increment list->nservers.) */
++static struct server_entry *
++new_server_entry(struct serverlist *list)
++{
++    struct server_entry *newservers, *entry;
++    size_t newspace = (list->nservers + 1) * sizeof(struct server_entry);
++
++    newservers = realloc(list->servers, newspace);
++    if (newservers == NULL)
++        return NULL;
++    list->servers = newservers;
++    entry = &newservers[list->nservers];
++    memset(entry, 0, sizeof(*entry));
++    entry->master = -1;
++    return entry;
++}
++
++/* Add an address entry to list. */
++static int
++add_addr_to_list(struct serverlist *list, k5_transport transport, int family,
++                 size_t addrlen, struct sockaddr *addr)
++{
++    struct server_entry *entry;
++
++    entry = new_server_entry(list);
++    if (entry == NULL)
++        return ENOMEM;
++    entry->transport = transport;
++    entry->family = family;
++    entry->hostname = NULL;
++    entry->uri_path = NULL;
++    entry->addrlen = addrlen;
++    memcpy(&entry->addr, addr, addrlen);
++    list->nservers++;
++    return 0;
++}
++
++struct module_callback_data {
++    int out_of_mem;
++    struct serverlist *list;
++};
++
++static int
++module_callback(void *cbdata, int socktype, struct sockaddr *sa)
++{
++    struct module_callback_data *d = cbdata;
++    size_t addrlen;
++    k5_transport transport;
++
++    if (socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
++        return 0;
++    if (sa->sa_family == AF_INET)
++        addrlen = sizeof(struct sockaddr_in);
++    else if (sa->sa_family == AF_INET6)
++        addrlen = sizeof(struct sockaddr_in6);
++    else
++        return 0;
++    transport = (socktype == SOCK_STREAM) ? TCP : UDP;
++    if (add_addr_to_list(d->list, transport, sa->sa_family, addrlen,
++                         sa) != 0) {
++        /* Assumes only error is ENOMEM.  */
++        d->out_of_mem = 1;
++        return 1;
++    }
++    return 0;
++}
++
++krb5_error_code sssd_krb5_locator_init(krb5_context context,
++                                       void **private_data);
++void sssd_krb5_locator_close(void *private_data);
++
++krb5_error_code sssd_krb5_locator_lookup(void *private_data,
++                    enum locate_service_type svc,
++                    const char *realm,
++                    int socktype,
++                    int family,
++                    int (*cbfunc)(void *, int, struct sockaddr *),
++                    void *cbdata);
++
++void test_init(void **state)
++{
++    krb5_context ctx;
++    krb5_error_code kerr;
++    void *priv;
++
++    kerr = krb5_init_context (&ctx);
++    assert_int_equal(kerr, 0);
++
++    kerr = sssd_krb5_locator_init(ctx, &priv);
++    assert_int_equal(kerr, 0);
++
++    sssd_krb5_locator_close(priv);
++
++    krb5_free_context(ctx);
++}
++
++void test_failed_lookup(void **state)
++{
++    krb5_context ctx;
++    krb5_error_code kerr;
++    void *priv;
++    struct module_callback_data cbdata = { 0 };
++
++
++    kerr = krb5_init_context (&ctx);
++    assert_int_equal(kerr, 0);
++
++    kerr = sssd_krb5_locator_init(ctx, &priv);
++    assert_int_equal(kerr, 0);
++
++    kerr = sssd_krb5_locator_lookup(NULL, -1, NULL, -1, -1, NULL, NULL);
++    assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE);
++
++    kerr = sssd_krb5_locator_lookup(priv, -1, NULL, -1, -1, NULL, NULL);
++    assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE);
++
++    kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , NULL, -1, -1,
++                                    NULL, NULL);
++    assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE);
++
++    kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM, -1,
++                                    -1, NULL, NULL);
++    assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE);
++
++    kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM,
++                                    SOCK_DGRAM, -1, NULL, NULL);
++    assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE);
++
++    kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM,
++                                    SOCK_DGRAM, AF_INET6, NULL, NULL);
++    assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE);
++
++    kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM,
++                                    SOCK_DGRAM, AF_INET6, module_callback,
++                                    NULL);
++    assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE);
++
++    kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM,
++                                    SOCK_DGRAM, AF_INET6, module_callback,
++                                    &cbdata);
++    assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE);
++
++    sssd_krb5_locator_close(priv);
++
++    krb5_free_context(ctx);
++}
++
++void test_empty(void **state)
++{
++    krb5_context ctx;
++    krb5_error_code kerr;
++    void *priv;
++    int fd;
++    struct module_callback_data cbdata = { 0 };
++
++    kerr = krb5_init_context (&ctx);
++    assert_int_equal(kerr, 0);
++
++    kerr = sssd_krb5_locator_init(ctx, &priv);
++    assert_int_equal(kerr, 0);
++
++    mkdir(TEST_PUBCONF_PATH, 0777);
++    fd = open(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM, O_CREAT, 0777);
++    assert_int_not_equal(fd, -1);
++    close(fd);
++
++    kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM,
++                                    SOCK_DGRAM, AF_INET6, module_callback,
++                                    &cbdata);
++    assert_int_equal(kerr, KRB5_PLUGIN_NO_HANDLE);
++    unlink(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM);
++    rmdir(TEST_PUBCONF_PATH);
++
++    sssd_krb5_locator_close(priv);
++
++    krb5_free_context(ctx);
++}
++
++void test_single(void **state)
++{
++    krb5_context ctx;
++    krb5_error_code kerr;
++    void *priv;
++    int fd;
++    struct serverlist list = SERVERLIST_INIT;
++    struct module_callback_data cbdata = { 0 };
++    ssize_t s;
++    int ret;
++    char host[NI_MAXHOST];
++    char service[NI_MAXSERV];
++
++    cbdata.list = &list;
++
++    kerr = krb5_init_context (&ctx);
++    assert_int_equal(kerr, 0);
++
++    kerr = sssd_krb5_locator_init(ctx, &priv);
++    assert_int_equal(kerr, 0);
++
++    mkdir(TEST_PUBCONF_PATH, 0777);
++    fd = open(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM, O_CREAT|O_RDWR, 0777);
++    assert_int_not_equal(fd, -1);
++    s = write(fd, TEST_IP_1, sizeof(TEST_IP_1));
++    assert_int_equal(s, sizeof(TEST_IP_1));
++    close(fd);
++
++    kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM,
++                                    SOCK_DGRAM, AF_INET6, module_callback,
++                                    &cbdata);
++    assert_int_equal(kerr, 0);
++
++    /* We asked for AF_INET6, but TEST_IP_1 is IPv4 */
++    assert_int_equal(list.nservers, 0);
++    assert_null(list.servers);
++
++    kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM,
++                                    SOCK_DGRAM, AF_INET, module_callback,
++                                    &cbdata);
++    assert_int_equal(kerr, 0);
++    assert_int_equal(list.nservers, 1);
++    assert_non_null(list.servers);
++    assert_int_equal(list.servers[0].addrlen, 16);
++    ret = getnameinfo((struct sockaddr *) &list.servers[0].addr,
++                      list.servers[0].addrlen,
++                      host, sizeof(host), service, sizeof(service),
++                      NI_NUMERICHOST|NI_NUMERICSERV);
++    assert_int_equal(ret, 0);
++    assert_string_equal(TEST_IP_1, host);
++    assert_string_equal("88", service);
++
++    k5_free_serverlist(&list);
++
++    kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM,
++                                    SOCK_DGRAM, AF_UNSPEC, module_callback,
++                                    &cbdata);
++    assert_int_equal(kerr, 0);
++    assert_int_equal(list.nservers, 1);
++    assert_non_null(list.servers);
++    assert_int_equal(list.servers[0].addrlen, 16);
++    ret = getnameinfo((struct sockaddr *) &list.servers[0].addr,
++                      list.servers[0].addrlen,
++                      host, sizeof(host), service, sizeof(service),
++                      NI_NUMERICHOST|NI_NUMERICSERV);
++    assert_int_equal(ret, 0);
++    assert_string_equal(TEST_IP_1, host);
++    assert_string_equal("88", service);
++
++    k5_free_serverlist(&list);
++
++    unlink(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM);
++    rmdir(TEST_PUBCONF_PATH);
++    sssd_krb5_locator_close(priv);
++
++    krb5_free_context(ctx);
++}
++
++struct test_data {
++    const char *ip;
++    bool found;
++};
++
++void test_multi_check_results(struct test_data *test_data,
++                              struct serverlist *list,
++                              const char *exp_service)
++{
++    int ret;
++    char host[NI_MAXHOST];
++    char service[NI_MAXSERV];
++    size_t c;
++    size_t d;
++
++    /* To make sure each result from list has a matching entry in test_data we
++     * use a flag to mark found entries, this way we can properly detect is
++     * the same address is used multiple times. */
++    for (d = 0; test_data[d].ip != NULL; d++) {
++        test_data[d].found = false;
++    }
++
++    for (c = 0; c < list->nservers; c++) {
++        ret = getnameinfo((struct sockaddr *) &list->servers[c].addr,
++                          list->servers[c].addrlen,
++                          host, sizeof(host), service, sizeof(service),
++                          NI_NUMERICHOST|NI_NUMERICSERV);
++        assert_int_equal(ret, 0);
++        assert_string_equal(exp_service, service);
++        for (d = 0; test_data[d].ip != NULL; d++) {
++            /* Compare result with test_data, be aware that the test_data has
++             * '[]' around IPv& addresses */
++            if (strncmp(host,
++                        test_data[d].ip + (test_data[d].ip[0] == '[' ? 1 : 0),
++                        strlen(host)) == 0 && !test_data[d].found) {
++                test_data[d].found = true;
++                break;
++            }
++        }
++        /* Make sure we found the result in the list */
++        assert_non_null(test_data[d].ip);
++    }
++}
++
++void test_multi(void **state)
++{
++    krb5_context ctx;
++    krb5_error_code kerr;
++    void *priv;
++    int fd;
++    struct serverlist list = SERVERLIST_INIT;
++    struct module_callback_data cbdata = { 0 };
++    ssize_t s;
++    size_t c;
++    struct test_data test_data[] = {
++                           {TEST_IP_1, false},
++                           {TEST_IPV6_1, false},
++                           {"[c89a:565b:4510:5b9f:41fe:ea81:87a0:f21b]", false},
++                           {"155.42.66.53", false},
++                           {"[f812:5941:ba69:2bae:e806:3b68:770d:d75e]", false},
++                           {"[3ad3:9dda:50e4:3c82:548f:eaa1:e120:6dd]", false},
++                           {"55.116.79.183", false},
++                           {"[ce8a:ee99:98cd:d8cd:218d:393e:d5a9:dc52]", false},
++                           /* the following address is added twice to check if
++                            * an address can be added more than once. */
++                           {"37.230.88.162", false},
++                           {"37.230.88.162", false},
++                           {NULL, false} };
++
++    cbdata.list = &list;
++
++    kerr = krb5_init_context (&ctx);
++    assert_int_equal(kerr, 0);
++
++    kerr = sssd_krb5_locator_init(ctx, &priv);
++    assert_int_equal(kerr, 0);
++
++    mkdir(TEST_PUBCONF_PATH, 0777);
++    fd = open(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM, O_CREAT|O_RDWR, 0777);
++    assert_int_not_equal(fd, -1);
++    for (c = 0; test_data[c].ip != NULL; c++) {
++        s = write(fd, test_data[c].ip, strlen(test_data[c].ip));
++        assert_int_equal(s, strlen(test_data[c].ip));
++        s = write(fd, "\n", 1);
++        assert_int_equal(s, 1);
++    }
++    close(fd);
++
++    kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM,
++                                    SOCK_DGRAM, AF_INET6, module_callback,
++                                    &cbdata);
++    assert_int_equal(kerr, 0);
++
++    assert_int_equal(list.nservers, 5);
++    assert_non_null(list.servers);
++    test_multi_check_results(test_data, &list, "88");
++
++    k5_free_serverlist(&list);
++
++    kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM,
++                                    SOCK_DGRAM, AF_INET, module_callback,
++                                    &cbdata);
++    assert_int_equal(kerr, 0);
++
++    assert_int_equal(list.nservers, 5);
++    assert_non_null(list.servers);
++    test_multi_check_results(test_data, &list, "88");
++
++
++    k5_free_serverlist(&list);
++
++    kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM,
++                                    SOCK_DGRAM, AF_UNSPEC, module_callback,
++                                    &cbdata);
++    assert_int_equal(kerr, 0);
++
++    assert_int_equal(list.nservers, 10);
++    assert_non_null(list.servers);
++    test_multi_check_results(test_data, &list, "88");
++
++    k5_free_serverlist(&list);
++
++    unlink(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM);
++    rmdir(TEST_PUBCONF_PATH);
++    sssd_krb5_locator_close(priv);
++
++    krb5_free_context(ctx);
++}
++
++void test_service(void **state)
++{
++    krb5_context ctx;
++    krb5_error_code kerr;
++    void *priv;
++    int fd;
++    struct serverlist list = SERVERLIST_INIT;
++    struct module_callback_data cbdata = { 0 };
++    ssize_t s;
++    int ret;
++    char host[NI_MAXHOST];
++    char service[NI_MAXSERV];
++
++    cbdata.list = &list;
++
++    kerr = krb5_init_context (&ctx);
++    assert_int_equal(kerr, 0);
++
++    kerr = sssd_krb5_locator_init(ctx, &priv);
++    assert_int_equal(kerr, 0);
++
++    mkdir(TEST_PUBCONF_PATH, 0777);
++    fd = open(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM, O_CREAT|O_RDWR, 0777);
++    assert_int_not_equal(fd, -1);
++    s = write(fd, TEST_IP_1_WITH_SERVICE, sizeof(TEST_IP_1_WITH_SERVICE));
++    assert_int_equal(s, sizeof(TEST_IP_1_WITH_SERVICE));
++    s = write(fd, "\n", 1);
++    assert_int_equal(s, 1);
++    s = write(fd, TEST_IPV6_1_WITH_SERVICE, sizeof(TEST_IPV6_1_WITH_SERVICE));
++    assert_int_equal(s, sizeof(TEST_IPV6_1_WITH_SERVICE));
++    close(fd);
++
++    kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM,
++                                    SOCK_DGRAM, AF_INET6, module_callback,
++                                    &cbdata);
++    assert_int_equal(kerr, 0);
++
++    assert_int_equal(list.nservers, 1);
++    assert_non_null(list.servers);
++    ret = getnameinfo((struct sockaddr *) &list.servers[0].addr,
++                      list.servers[0].addrlen,
++                      host, sizeof(host), service, sizeof(service),
++                      NI_NUMERICHOST|NI_NUMERICSERV);
++    assert_int_equal(ret, 0);
++    assert_string_equal(TEST_IPV6_1_PURE, host);
++    assert_string_equal(TEST_SERVICE_2, service);
++
++    k5_free_serverlist(&list);
++
++    kerr = sssd_krb5_locator_lookup(priv, locate_service_kdc , TEST_REALM,
++                                    SOCK_DGRAM, AF_INET, module_callback,
++                                    &cbdata);
++    assert_int_equal(kerr, 0);
++    assert_int_equal(list.nservers, 1);
++    assert_non_null(list.servers);
++    ret = getnameinfo((struct sockaddr *) &list.servers[0].addr,
++                      list.servers[0].addrlen,
++                      host, sizeof(host), service, sizeof(service),
++                      NI_NUMERICHOST|NI_NUMERICSERV);
++    assert_int_equal(ret, 0);
++    assert_string_equal(TEST_IP_1, host);
++    assert_string_equal(TEST_SERVICE_1, service);
++
++    k5_free_serverlist(&list);
++
++
++    unlink(TEST_PUBCONF_PATH"/kdcinfo."TEST_REALM);
++    rmdir(TEST_PUBCONF_PATH);
++    sssd_krb5_locator_close(priv);
++
++    krb5_free_context(ctx);
++}
++
++int main(int argc, const char *argv[])
++{
++    poptContext pc;
++    int opt;
++    int ret;
++    struct poptOption long_options[] = {
++        POPT_AUTOHELP
++        SSSD_DEBUG_OPTS
++        POPT_TABLEEND
++    };
++
++    const struct CMUnitTest tests[] = {
++        cmocka_unit_test_setup_teardown(test_init,
++                                        setup, teardown),
++        cmocka_unit_test_setup_teardown(test_failed_lookup,
++                                        setup, teardown),
++        cmocka_unit_test_setup_teardown(test_empty,
++                                        setup, teardown),
++        cmocka_unit_test_setup_teardown(test_single,
++                                        setup, teardown),
++        cmocka_unit_test_setup_teardown(test_multi,
++                                        setup, teardown),
++        cmocka_unit_test_setup_teardown(test_service,
++                                        setup, 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);
++
++    ret = cmocka_run_group_tests(tests, NULL, NULL);
++
++    return ret;
++}
+-- 
+2.17.1
+
diff --git a/SOURCES/0005-AD-IPA-Create-kdcinfo-file-for-sub-domains.patch b/SOURCES/0005-AD-IPA-Create-kdcinfo-file-for-sub-domains.patch
new file mode 100644
index 0000000..f6d7cd8
--- /dev/null
+++ b/SOURCES/0005-AD-IPA-Create-kdcinfo-file-for-sub-domains.patch
@@ -0,0 +1,148 @@
+From 660ef95e36ad73b4715656a4207aeb499ac96d16 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 24 May 2018 17:15:38 +0200
+Subject: [PATCH] AD/IPA: Create kdcinfo file for sub-domains
+
+With this patch kdcinfo files are created for sub-domains by the AD
+provider and by the IPA provider on the IPA servers
+(ipa_server_mode=True).
+
+Related to https://pagure.io/SSSD/sssd/issue/3652
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+
+(cherry picked from commit cc7922755dac53c69558ba060b309ac48ae82783)
+---
+ src/providers/ad/ad_common.c              |  9 +++++++++
+ src/providers/ad/ad_common.h              |  1 +
+ src/providers/ad/ad_init.c                |  1 +
+ src/providers/ad/ad_subdomains.c          | 17 ++++++++++++++---
+ src/providers/ipa/ipa_subdomains_server.c | 16 ++++++++++++++--
+ 5 files changed, 39 insertions(+), 5 deletions(-)
+
+diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
+index be7791e6cc2527d45d3e2ff50294f9b98106ffae..0aea985e00faa996643fd7e7630d4264fb6cf233 100644
+--- a/src/providers/ad/ad_common.c
++++ b/src/providers/ad/ad_common.c
+@@ -727,6 +727,7 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
+                  const char *ad_service,
+                  const char *ad_gc_service,
+                  const char *ad_domain,
++                 bool use_kdcinfo,
+                  struct ad_service **_service)
+ {
+     errno_t ret;
+@@ -762,6 +763,14 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
+         goto done;
+     }
+ 
++    /* Set flag that controls whether we want to write the
++     * kdcinfo files at all
++     */
++    service->krb5_service->write_kdcinfo = use_kdcinfo;
++    DEBUG(SSSDBG_CONF_SETTINGS, "write_kdcinfo for realm %s set to %s\n",
++                       krb5_realm,
++                       service->krb5_service->write_kdcinfo ? "true" : "false");
++
+     ret = be_fo_add_service(bectx, ad_service, ad_user_data_cmp);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create failover service!\n");
+diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
+index 6eb2ba7e9a7350d1924c45d33d8c332073767a34..dd440da33d48a5820c665f43908d1e1fb18171a6 100644
+--- a/src/providers/ad/ad_common.h
++++ b/src/providers/ad/ad_common.h
+@@ -144,6 +144,7 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *ctx,
+                  const char *ad_service,
+                  const char *ad_gc_service,
+                  const char *ad_domain,
++                 bool use_kdcinfo,
+                  struct ad_service **_service);
+ 
+ errno_t
+diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
+index b19624782000c5c7c65e766e3e01ff6ac3ab7adb..637efb761c1cf87b0a2c2b1c19b00ea0bbbe161f 100644
+--- a/src/providers/ad/ad_init.c
++++ b/src/providers/ad/ad_init.c
+@@ -159,6 +159,7 @@ static errno_t ad_init_options(TALLOC_CTX *mem_ctx,
+     ret = ad_failover_init(ad_options, be_ctx, ad_servers, ad_backup_servers,
+                            ad_realm, AD_SERVICE_NAME, AD_GC_SERVICE_NAME,
+                            dp_opt_get_string(ad_options->basic, AD_DOMAIN),
++                           false, /* will be set in ad_get_auth_options() */
+                            &ad_options->service);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to init AD failover service: "
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index 74b9f075174b1eaa6c5b5dcbaf609600ef197b52..84886e920b37f8803d85ce0903b74e6c809a8904 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -249,6 +249,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
+     const char *hostname;
+     const char *keytab;
+     char *subdom_conf_path;
++    bool use_kdcinfo = false;
+ 
+     realm = dp_opt_get_cstring(id_ctx->ad_options->basic, AD_KRB5_REALM);
+     hostname = dp_opt_get_cstring(id_ctx->ad_options->basic, AD_HOSTNAME);
+@@ -296,9 +297,19 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
+     servers = dp_opt_get_string(ad_options->basic, AD_SERVER);
+     backup_servers = dp_opt_get_string(ad_options->basic, AD_BACKUP_SERVER);
+ 
+-    ret = ad_failover_init(ad_options, be_ctx, servers, backup_servers, realm,
+-                           service_name, gc_service_name,
+-                           subdom->name, &ad_options->service);
++    if (id_ctx->ad_options->auth_ctx != NULL
++            && id_ctx->ad_options->auth_ctx->opts != NULL) {
++        use_kdcinfo = dp_opt_get_bool(id_ctx->ad_options->auth_ctx->opts,
++                                      KRB5_USE_KDCINFO);
++    }
++
++    DEBUG(SSSDBG_TRACE_ALL,
++          "Init failover for [%s][%s] with use_kdcinfo [%s].\n",
++          subdom->name, subdom->realm, use_kdcinfo ? "true" : "false");
++
++    ret = ad_failover_init(ad_options, be_ctx, servers, backup_servers,
++                           subdom->realm, service_name, gc_service_name,
++                           subdom->name, use_kdcinfo, &ad_options->service);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD failover\n");
+         talloc_free(ad_options);
+diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
+index 1e53e7a951189120fcf3f438362e902a5a8f6d97..02577c92159d099a04cbd5cee80064309466db93 100644
+--- a/src/providers/ipa/ipa_subdomains_server.c
++++ b/src/providers/ipa/ipa_subdomains_server.c
+@@ -228,6 +228,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
+     struct sdap_domain *sdom;
+     errno_t ret;
+     const char *extra_attrs;
++    bool use_kdcinfo = false;
+ 
+     ad_domain = subdom->name;
+     DEBUG(SSSDBG_TRACE_LIBS, "Setting up AD subdomain %s\n", subdom->name);
+@@ -284,12 +285,23 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
+     ad_servers = dp_opt_get_string(ad_options->basic, AD_SERVER);
+     ad_backup_servers = dp_opt_get_string(ad_options->basic, AD_BACKUP_SERVER);
+ 
++    if (id_ctx->ipa_options != NULL && id_ctx->ipa_options->auth != NULL) {
++        use_kdcinfo = dp_opt_get_bool(id_ctx->ipa_options->auth,
++                                      KRB5_USE_KDCINFO);
++    }
++
++    DEBUG(SSSDBG_TRACE_ALL,
++          "Init failover for [%s][%s] with use_kdcinfo [%s].\n",
++          subdom->name, subdom->realm, use_kdcinfo ? "true" : "false");
++
+     /* Set KRB5 realm to same as the one of IPA when IPA
+      * is able to attach PAC. For testing, use hardcoded. */
++    /* Why? */
+     ret = ad_failover_init(ad_options, be_ctx, ad_servers, ad_backup_servers,
+-                           id_ctx->server_mode->realm,
++                           subdom->realm,
+                            service_name, gc_service_name,
+-                           subdom->name, &ad_options->service);
++                           subdom->name, use_kdcinfo,
++                           &ad_options->service);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "Cannot initialize AD failover\n");
+         talloc_free(ad_options);
+-- 
+2.17.1
+
diff --git a/SOURCES/0005-CONFDB-Remove-the-obsolete-option-magic_private_grou.patch b/SOURCES/0005-CONFDB-Remove-the-obsolete-option-magic_private_grou.patch
deleted file mode 100644
index 017e97c..0000000
--- a/SOURCES/0005-CONFDB-Remove-the-obsolete-option-magic_private_grou.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 8e4858a044391cdfd7b6eae327daf043225c4536 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 3 Oct 2017 12:36:02 +0200
-Subject: [PATCH 05/21] CONFDB: Remove the obsolete option magic_private_groups
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Since this confdb definition was completely unused across the codebase,
-this patch just removes the definition.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 8fab9d6fa88824b20d3febe697147c407d31c160)
----
- src/confdb/confdb.h | 1 -
- 1 file changed, 1 deletion(-)
-
-diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
-index 2539b906993edbceb38aac9265e04deed69cf2e4..1471949623e9dd7a8536e3ac3048a10227a5d857 100644
---- a/src/confdb/confdb.h
-+++ b/src/confdb/confdb.h
-@@ -197,7 +197,6 @@
-                                  "cache_credentials_minimal_first_factor_length"
- #define CONFDB_DEFAULT_CACHE_CREDS_MIN_FF_LENGTH 8
- #define CONFDB_DOMAIN_LEGACY_PASS "store_legacy_passwords"
--#define CONFDB_DOMAIN_MPG "magic_private_groups"
- #define CONFDB_DOMAIN_AUTO_UPG "auto_private_groups"
- #define CONFDB_DOMAIN_FQ "use_fully_qualified_names"
- #define CONFDB_DOMAIN_ENTRY_CACHE_TIMEOUT "entry_cache_timeout"
--- 
-2.13.5
-
diff --git a/SOURCES/0006-SDAP-Allow-the-mpg-flag-for-the-main-domain.patch b/SOURCES/0006-SDAP-Allow-the-mpg-flag-for-the-main-domain.patch
deleted file mode 100644
index 29bb20b..0000000
--- a/SOURCES/0006-SDAP-Allow-the-mpg-flag-for-the-main-domain.patch
+++ /dev/null
@@ -1,167 +0,0 @@
-From c28d61203655dd41cd8eb69752e435d3241e63b2 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 3 Oct 2017 12:34:49 +0200
-Subject: [PATCH 06/21] SDAP: Allow the mpg flag for the main domain
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This commit allows saving the users in the MPG domain in the SDAP
-layer.
-
-The commit contains the following changes:
-    - abstracts the change where if the primary GID exists in the original
-      object, it is saved instead as the SYSDB_PRIMARY_GROUP_GIDNUM attribute,
-      which will allow the original primary GID to be exposed as a
-      secondary group
-
-    - if the primary GID does not exist, no SYSDB_PRIMARY_GROUP_GIDNUM
-      is added. This will allow to handle LDAP objects that only contain
-      the UID but no GID. Since this is a new use-case, a test is added
-      later
-
-    - a branch that handles the above is added to sdap_save_user() also
-      for joined domains that set the MPG flag. Previously, only
-      subdomains were handled.
-
-    - to allow passing GID=0 to the sysdb layer, the range check is
-      relaxed.
-
-Related:
-    https://pagure.io/SSSD/sssd/issue/1872
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit cdb74b2cc6cc3fe52969712907c9eb4026c7a44f)
----
- src/providers/ldap/sdap_async_users.c | 83 +++++++++++++++++++++++++++++++----
- 1 file changed, 75 insertions(+), 8 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
-index 09d096e84cac6c9d52bcde0e1587c47dbd88b504..7338b4a15694b1d0a16723990130a23a7280af5f 100644
---- a/src/providers/ldap/sdap_async_users.c
-+++ b/src/providers/ldap/sdap_async_users.c
-@@ -136,6 +136,38 @@ static errno_t sdap_set_non_posix_flag(struct sysdb_attrs *attrs,
-     return EOK;
- }
- 
-+static int sdap_user_set_mpg(struct sysdb_attrs *user_attrs,
-+                             gid_t *_gid)
-+{
-+    errno_t ret;
-+
-+    if (_gid == NULL) {
-+        return EINVAL;
-+    }
-+
-+    if (*_gid == 0) {
-+        /* The original entry had no GID number. This is OK, we just won't add
-+         * the SYSDB_PRIMARY_GROUP_GIDNUM attribute
-+         */
-+        return EOK;
-+    }
-+
-+    ret = sysdb_attrs_add_uint32(user_attrs,
-+                                 SYSDB_PRIMARY_GROUP_GIDNUM,
-+                                 (uint32_t) *_gid);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_uint32 failed.\n");
-+        return ret;
-+    }
-+
-+    /* We won't really store gidNumber=0, but the zero value tells
-+     * the sysdb layer that no GID is set, which sysdb requires for
-+     * MPG-enabled domains
-+     */
-+    *_gid = 0;
-+    return EOK;
-+}
-+
- /* FIXME: support storing additional attributes */
- int sdap_save_user(TALLOC_CTX *memctx,
-                    struct sdap_options *opts,
-@@ -357,7 +389,7 @@ int sdap_save_user(TALLOC_CTX *memctx,
-             goto done;
-         }
- 
--        if (IS_SUBDOMAIN(dom)) {
-+        if (IS_SUBDOMAIN(dom) || dom->mpg == true) {
-             /* For subdomain users, only create the private group as
-              * the subdomain is an MPG domain.
-              * But we have to save the GID of the original primary group
-@@ -365,14 +397,13 @@ int sdap_save_user(TALLOC_CTX *memctx,
-              * typically (Unix and AD) the user is not listed in his primary
-              * group as a member.
-              */
--            ret = sysdb_attrs_add_uint32(user_attrs, SYSDB_PRIMARY_GROUP_GIDNUM,
--                                         (uint32_t) gid);
-+            ret = sdap_user_set_mpg(user_attrs, &gid);
-             if (ret != EOK) {
--                DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_uint32 failed.\n");
-+                DEBUG(SSSDBG_OP_FAILURE,
-+                      "sdap_user_set_mpg failed [%d]: %s\n", ret,
-+                      sss_strerror(ret));
-                 goto done;
-             }
--
--            gid = 0;
-         }
- 
-         /* Store the GID in the ldap_attrs so it doesn't get
-@@ -380,6 +411,41 @@ int sdap_save_user(TALLOC_CTX *memctx,
-         */
-         ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, gid);
-         if (ret != EOK) goto done;
-+    } else if (dom->mpg) {
-+        /* Likewise, if a domain is set to contain 'magic private groups', do
-+         * not process the real GID, but save it in the cache as originalGID
-+         * (if available)
-+         */
-+        ret = sysdb_attrs_get_uint32_t(attrs,
-+                                       opts->user_map[SDAP_AT_USER_GID].sys_name,
-+                                       &gid);
-+        if (ret == ENOENT) {
-+            DEBUG(SSSDBG_TRACE_LIBS,
-+                  "Missing GID, won't save the %s attribute\n",
-+                  SYSDB_PRIMARY_GROUP_GIDNUM);
-+
-+            /* Store the UID as GID (since we're in a MPG domain so that it doesn't
-+             * get treated as a missing attribute and removed
-+             */
-+            ret = sdap_replace_id(attrs, SYSDB_GIDNUM, uid);
-+            if (ret) {
-+                DEBUG(SSSDBG_OP_FAILURE, "Cannot set the id-mapped UID\n");
-+                goto done;
-+            }
-+            gid = 0;
-+        } else if (ret != EOK) {
-+            DEBUG(SSSDBG_MINOR_FAILURE,
-+                  "Cannot retrieve GID, won't save the %s attribute\n",
-+                  SYSDB_PRIMARY_GROUP_GIDNUM);
-+            gid = 0;
-+        }
-+
-+        ret = sdap_user_set_mpg(user_attrs, &gid);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "sdap_user_set_mpg failed [%d]: %s\n", ret, sss_strerror(ret));
-+            goto done;
-+        }
-     } else {
-         ret = sysdb_attrs_get_uint32_t(attrs,
-                                        opts->user_map[SDAP_AT_USER_GID].sys_name,
-@@ -403,8 +469,9 @@ int sdap_save_user(TALLOC_CTX *memctx,
-     }
- 
-     /* check that the gid is valid for this domain */
--    if (is_posix == true && IS_SUBDOMAIN(dom) == false &&
--            OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) {
-+    if (is_posix == true && IS_SUBDOMAIN(dom) == false
-+            && dom->mpg == false
-+            && OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) {
-         DEBUG(SSSDBG_CRIT_FAILURE,
-               "User [%s] filtered out! (primary gid out of range)\n",
-                user_name);
--- 
-2.13.5
-
diff --git a/SOURCES/0006-krb5-refactor-removal-of-krb5info-files.patch b/SOURCES/0006-krb5-refactor-removal-of-krb5info-files.patch
new file mode 100644
index 0000000..9787c85
--- /dev/null
+++ b/SOURCES/0006-krb5-refactor-removal-of-krb5info-files.patch
@@ -0,0 +1,493 @@
+From 713bc782502163251ef22eb81b09eed61a8407f7 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 5 Jun 2018 17:44:59 +0200
+Subject: [PATCH] krb5: refactor removal of krb5info files
+
+Currently a persistent offline callback removes the krb5info files for
+the configured main domain and those files were removed by a SIGTERM
+signal handlers as well.
+
+This does not scale if krb5info files are created for sub-domains as
+well. To remove the files automatically the removal is moved into a
+talloc destructor of an offline callback which is added if the file is
+created and frees itself when the system goes offline. Due to the
+talloc memory hierarchy we get removal on shutdown for free.
+
+Related to https://pagure.io/SSSD/sssd/issue/3652
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+
+(cherry picked from commit d91661e295c8e878f1bbf34e6f65f61e8301bf0e)
+---
+ src/providers/ad/ad_common.c          |   7 +-
+ src/providers/ipa/ipa_common.c        |   5 +-
+ src/providers/krb5/krb5_common.c      | 176 +++++++++++++-------------
+ src/providers/krb5/krb5_common.h      |   7 +-
+ src/providers/krb5/krb5_init_shared.c |   6 -
+ src/providers/ldap/ldap_common.c      |  87 -------------
+ 6 files changed, 102 insertions(+), 186 deletions(-)
+
+diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
+index 0aea985e00faa996643fd7e7630d4264fb6cf233..8caaba6c0d06cfe83d9741536192d662fc936273 100644
+--- a/src/providers/ad/ad_common.c
++++ b/src/providers/ad/ad_common.c
+@@ -804,6 +804,8 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
+         goto done;
+     }
+ 
++    service->krb5_service->be_ctx = bectx;
++
+     if (!primary_servers) {
+         DEBUG(SSSDBG_CONF_SETTINGS,
+               "No primary servers defined, using service discovery\n");
+@@ -984,8 +986,9 @@ ad_resolve_callback(void *private_data, struct fo_server *server)
+             goto done;
+         }
+ 
+-        ret = write_krb5info_file(service->krb5_service->realm, safe_address,
+-                                SSS_KRB5KDC_FO_SRV);
++        ret = write_krb5info_file(service->krb5_service,
++                                  safe_address,
++                                  SSS_KRB5KDC_FO_SRV);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_MINOR_FAILURE,
+                 "write_krb5info_file failed, authentication might fail.\n");
+diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
+index 87ed967673358bf833dae13c29b1f6a17b0fc19c..dcbb54a744358718e444972b9827ee64887e5e33 100644
+--- a/src/providers/ipa/ipa_common.c
++++ b/src/providers/ipa/ipa_common.c
+@@ -838,7 +838,8 @@ static void ipa_resolve_callback(void *private_data, struct fo_server *server)
+             return;
+         }
+ 
+-        ret = write_krb5info_file(service->krb5_service->realm, safe_address,
++        ret = write_krb5info_file(service->krb5_service,
++                                  safe_address,
+                                   SSS_KRB5KDC_FO_SRV);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE,
+@@ -1012,6 +1013,8 @@ int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+         goto done;
+     }
+ 
++    service->krb5_service->be_ctx = ctx;
++
+     if (!primary_servers) {
+         DEBUG(SSSDBG_CONF_SETTINGS,
+               "No primary servers defined, using service discovery\n");
+diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
+index 520e7591ce1b37b4a8dea357b6dd0ec7afd76f58..c6896a6cd663da896075e72aa0a0602c198b45e8 100644
+--- a/src/providers/krb5/krb5_common.c
++++ b/src/providers/krb5/krb5_common.c
+@@ -389,7 +389,76 @@ done:
+     return ret;
+ }
+ 
+-errno_t write_krb5info_file(const char *realm, const char *server,
++static int remove_info_files_destructor(void *p)
++{
++    int ret;
++    struct remove_info_files_ctx *ctx = talloc_get_type(p,
++                                                  struct remove_info_files_ctx);
++
++    ret = remove_krb5_info_files(ctx, ctx->realm);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "remove_krb5_info_files failed.\n");
++    }
++
++    return 0;
++}
++
++static errno_t
++krb5_add_krb5info_offline_callback(struct krb5_service *krb5_service)
++{
++    int ret;
++    struct remove_info_files_ctx *ctx;
++
++    if (krb5_service == NULL || krb5_service->name == NULL
++                             || krb5_service->realm == NULL
++                             || krb5_service->be_ctx == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Missing KDC service name or realm!\n");
++        return EINVAL;
++    }
++
++    ctx = talloc_zero(krb5_service->be_ctx, struct remove_info_files_ctx);
++    if (ctx == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zfree failed.\n");
++        return ENOMEM;
++    }
++
++    ctx->realm = talloc_strdup(ctx, krb5_service->realm);
++    if (ctx->realm == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed!\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ctx->be_ctx = krb5_service->be_ctx;
++    ctx->kdc_service_name = talloc_strdup(ctx, krb5_service->name);
++    if (ctx->kdc_service_name == NULL) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed!\n");
++        ret = ENOMEM;
++        goto done;
++    }
++
++    ret = be_add_offline_cb(ctx, krb5_service->be_ctx,
++                            remove_krb5_info_files_callback, ctx, NULL);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "be_add_offline_cb failed.\n");
++        goto done;
++    }
++
++    talloc_set_destructor((TALLOC_CTX *) ctx, remove_info_files_destructor);
++
++    ret = EOK;
++
++done:
++    if (ret != EOK) {
++        talloc_zfree(ctx);
++    }
++
++    return ret;
++}
++
++
++errno_t write_krb5info_file(struct krb5_service *krb5_service,
++                            const char *server,
+                             const char *service)
+ {
+     int ret;
+@@ -401,17 +470,19 @@ errno_t write_krb5info_file(const char *realm, const char *server,
+     size_t server_len;
+     ssize_t written;
+ 
+-    if (realm == NULL || *realm == '\0' || server == NULL || *server == '\0' ||
+-        service == NULL || *service == '\0') {
++    if (krb5_service == NULL || krb5_service->realm == NULL
++                             || *krb5_service->realm == '\0'
++                             || server == NULL || *server == '\0'
++                             || service == NULL || *service == '\0') {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+               "Missing or empty realm, server or service.\n");
+         return EINVAL;
+     }
+ 
+-    if (sss_krb5_realm_has_proxy(realm)) {
++    if (sss_krb5_realm_has_proxy(krb5_service->realm)) {
+         DEBUG(SSSDBG_CONF_SETTINGS,
+               "KDC Proxy available for realm [%s], no kdcinfo file created.\n",
+-              realm);
++              krb5_service->realm);
+         return EOK;
+     }
+ 
+@@ -439,7 +510,7 @@ errno_t write_krb5info_file(const char *realm, const char *server,
+         goto done;
+     }
+ 
+-    krb5info_name = talloc_asprintf(tmp_ctx, name_tmpl, realm);
++    krb5info_name = talloc_asprintf(tmp_ctx, name_tmpl, krb5_service->realm);
+     if (krb5info_name == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
+         ret = ENOMEM;
+@@ -495,6 +566,12 @@ errno_t write_krb5info_file(const char *realm, const char *server,
+         goto done;
+     }
+ 
++    ret = krb5_add_krb5info_offline_callback(krb5_service);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "Failed to add offline callback, krb5info "
++                                 "file might not be removed properly.\n");
++    }
++
+     ret = EOK;
+ done:
+     if (fd != -1) {
+@@ -561,7 +638,8 @@ static void krb5_resolve_callback(void *private_data, struct fo_server *server)
+             return;
+         }
+ 
+-        ret = write_krb5info_file(krb5_service->realm, safe_address,
++        ret = write_krb5info_file(krb5_service,
++                                  safe_address,
+                                   krb5_service->name);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE,
+@@ -761,6 +839,7 @@ int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+     }
+ 
+     service->write_kdcinfo = use_kdcinfo;
++    service->be_ctx = ctx;
+ 
+     if (!primary_servers) {
+         DEBUG(SSSDBG_CONF_SETTINGS,
+@@ -839,7 +918,6 @@ errno_t remove_krb5_info_files(TALLOC_CTX *mem_ctx, const char *realm)
+ void remove_krb5_info_files_callback(void *pvt)
+ {
+     int ret;
+-    TALLOC_CTX *tmp_ctx = NULL;
+     struct remove_info_files_ctx *ctx = talloc_get_type(pvt,
+                                                   struct remove_info_files_ctx);
+ 
+@@ -864,19 +942,10 @@ void remove_krb5_info_files_callback(void *pvt)
+         }
+     }
+ 
+-    tmp_ctx = talloc_new(NULL);
+-    if (tmp_ctx == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "talloc_new failed, cannot remove krb5 info files.\n");
+-        return;
+-    }
+-
+-    ret = remove_krb5_info_files(tmp_ctx, ctx->realm);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "remove_krb5_info_files failed.\n");
+-    }
+-
+-    talloc_zfree(tmp_ctx);
++    /* Freeing the remove_info_files_ctx will remove the related krb5info
++     * file. Additionally the callback from the list of callbacks is removed,
++     * it will be added again when a new krb5info file is created. */
++    talloc_free(ctx);
+ }
+ 
+ void krb5_finalize(struct tevent_context *ev,
+@@ -886,74 +955,9 @@ void krb5_finalize(struct tevent_context *ev,
+                    void *siginfo,
+                    void *private_data)
+ {
+-    char *realm = (char *)private_data;
+-    int ret;
+-
+-    ret = remove_krb5_info_files(se, realm);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "remove_krb5_info_files failed.\n");
+-    }
+-
+     orderly_shutdown(0);
+ }
+ 
+-errno_t krb5_install_offline_callback(struct be_ctx *be_ctx,
+-                                      struct krb5_ctx *krb5_ctx)
+-{
+-    int ret;
+-    struct remove_info_files_ctx *ctx;
+-    const char *krb5_realm;
+-
+-    if (krb5_ctx->service == NULL || krb5_ctx->service->name == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Missing KDC service name!\n");
+-        return EINVAL;
+-    }
+-
+-    ctx = talloc_zero(krb5_ctx, struct remove_info_files_ctx);
+-    if (ctx == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zfree failed.\n");
+-        return ENOMEM;
+-    }
+-
+-    krb5_realm = dp_opt_get_cstring(krb5_ctx->opts, KRB5_REALM);
+-    if (krb5_realm == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "Missing krb5_realm option!\n");
+-        ret = EINVAL;
+-        goto done;
+-    }
+-
+-    ctx->realm = talloc_strdup(ctx, krb5_realm);
+-    if (ctx->realm == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed!\n");
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    ctx->be_ctx = be_ctx;
+-    ctx->kdc_service_name = krb5_ctx->service->name;
+-    if (krb5_ctx->kpasswd_service == NULL) {
+-        ctx->kpasswd_service_name =NULL;
+-    } else {
+-        ctx->kpasswd_service_name = krb5_ctx->kpasswd_service->name;
+-    }
+-
+-    ret = be_add_offline_cb(ctx, be_ctx, remove_krb5_info_files_callback, ctx,
+-                            NULL);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "be_add_offline_cb failed.\n");
+-        goto done;
+-    }
+-
+-    ret = EOK;
+-
+-done:
+-    if (ret != EOK) {
+-        talloc_zfree(ctx);
+-    }
+-
+-    return ret;
+-}
+-
+ errno_t krb5_install_sigterm_handler(struct tevent_context *ev,
+                                      struct krb5_ctx *krb5_ctx)
+ {
+diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h
+index 48368a528e75947102c74cb75bf7a74ec0dd258f..a2e47b0605debdffa28305dab4f7674707f713ac 100644
+--- a/src/providers/krb5/krb5_common.h
++++ b/src/providers/krb5/krb5_common.h
+@@ -67,6 +67,7 @@ enum krb5_opts {
+ typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type;
+ 
+ struct krb5_service {
++    struct be_ctx *be_ctx;
+     char *name;
+     char *realm;
+     bool write_kdcinfo;
+@@ -157,7 +158,8 @@ errno_t krb5_try_kdcip(struct confdb_ctx *cdb, const char *conf_path,
+ errno_t sss_krb5_get_options(TALLOC_CTX *memctx, struct confdb_ctx *cdb,
+                              const char *conf_path, struct dp_option **_opts);
+ 
+-errno_t write_krb5info_file(const char *realm, const char *kdc,
++errno_t write_krb5info_file(struct krb5_service *krb5_service,
++                            const char *server,
+                             const char *service);
+ 
+ int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+@@ -177,9 +179,6 @@ void krb5_finalize(struct tevent_context *ev,
+                    void *siginfo,
+                    void *private_data);
+ 
+-errno_t krb5_install_offline_callback(struct be_ctx *be_ctx,
+-                                      struct krb5_ctx *krb_ctx);
+-
+ errno_t krb5_install_sigterm_handler(struct tevent_context *ev,
+                                      struct krb5_ctx *krb5_ctx);
+ 
+diff --git a/src/providers/krb5/krb5_init_shared.c b/src/providers/krb5/krb5_init_shared.c
+index 3901b7272119c32930c2b6b47279a2c685bf3cfb..368d6f7b0f2bc038e4cc4aa8f0970cd0e81d7b6b 100644
+--- a/src/providers/krb5/krb5_init_shared.c
++++ b/src/providers/krb5/krb5_init_shared.c
+@@ -71,12 +71,6 @@ errno_t krb5_child_init(struct krb5_ctx *krb5_auth_ctx,
+         goto done;
+     }
+ 
+-    ret = krb5_install_offline_callback(bectx, krb5_auth_ctx);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "krb5_install_offline_callback failed.\n");
+-        goto done;
+-    }
+-
+     ret = krb5_install_sigterm_handler(bectx->ev, krb5_auth_ctx);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "krb5_install_sigterm_handler failed.\n");
+diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
+index 91e229243b9a1b43e7a57704824f5db0341f4ee9..15377ee1f062c0167aabee30ef0757ebe7271682 100644
+--- a/src/providers/ldap/ldap_common.c
++++ b/src/providers/ldap/ldap_common.c
+@@ -158,14 +158,6 @@ static void sdap_finalize(struct tevent_context *ev,
+                           void *siginfo,
+                           void *private_data)
+ {
+-    char *realm = (char *) private_data;
+-    int ret;
+-
+-    ret = remove_krb5_info_files(se, realm);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "remove_krb5_info_files failed.\n");
+-    }
+-
+     orderly_shutdown(0);
+ }
+ 
+@@ -196,78 +188,6 @@ errno_t sdap_install_sigterm_handler(TALLOC_CTX *mem_ctx,
+     return EOK;
+ }
+ 
+-void sdap_remove_kdcinfo_files_callback(void *pvt)
+-{
+-    int ret;
+-    TALLOC_CTX *tmp_ctx = NULL;
+-    struct remove_info_files_ctx *ctx = talloc_get_type(pvt,
+-                                                  struct remove_info_files_ctx);
+-
+-    ret = be_fo_run_callbacks_at_next_request(ctx->be_ctx,
+-                                              ctx->kdc_service_name);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "be_fo_run_callbacks_at_next_request failed, "
+-                  "krb5 info files will not be removed, because "
+-                  "it is unclear if they will be recreated properly.\n");
+-        return;
+-    }
+-
+-    tmp_ctx = talloc_new(NULL);
+-    if (tmp_ctx == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE,
+-              "talloc_new failed, cannot remove krb5 info files.\n");
+-        return;
+-    }
+-
+-    ret = remove_krb5_info_files(tmp_ctx, ctx->realm);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "remove_krb5_info_files failed.\n");
+-    }
+-
+-    talloc_zfree(tmp_ctx);
+-}
+-
+-
+-errno_t sdap_install_offline_callback(TALLOC_CTX *mem_ctx,
+-                                      struct be_ctx *be_ctx,
+-                                      const char *realm,
+-                                      const char *service_name)
+-{
+-    int ret;
+-    struct remove_info_files_ctx *ctx;
+-
+-    ctx = talloc_zero(mem_ctx, struct remove_info_files_ctx);
+-    if (ctx == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zfree failed.\n");
+-        return ENOMEM;
+-    }
+-
+-    ctx->be_ctx = be_ctx;
+-    ctx->realm = talloc_strdup(ctx, realm);
+-    ctx->kdc_service_name = talloc_strdup(ctx, service_name);
+-    if (ctx->realm == NULL || ctx->kdc_service_name == NULL) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed!\n");
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    ret = be_add_offline_cb(ctx, be_ctx,
+-                            sdap_remove_kdcinfo_files_callback,
+-                            ctx, NULL);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "be_add_offline_cb failed.\n");
+-        goto done;
+-    }
+-
+-    ret = EOK;
+-done:
+-    if (ret != EOK) {
+-        talloc_zfree(ctx);
+-    }
+-    return ret;
+-}
+-
+ errno_t
+ sdap_set_sasl_options(struct sdap_options *id_opts,
+                       char *default_primary,
+@@ -458,13 +378,6 @@ int sdap_gssapi_init(TALLOC_CTX *mem_ctx,
+         goto done;
+     }
+ 
+-    ret = sdap_install_offline_callback(mem_ctx, bectx,
+-                                        krb5_realm, SSS_KRB5KDC_FO_SRV);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to install sigterm handler\n");
+-        goto done;
+-    }
+-
+     sdap_service->kinit_service_name = talloc_strdup(sdap_service,
+                                                      service->name);
+     if (sdap_service->kinit_service_name == NULL) {
+-- 
+2.17.1
+
diff --git a/SOURCES/0007-LDAP-Turn-group-request-into-user-request-for-MPG-do.patch b/SOURCES/0007-LDAP-Turn-group-request-into-user-request-for-MPG-do.patch
deleted file mode 100644
index 12745ce..0000000
--- a/SOURCES/0007-LDAP-Turn-group-request-into-user-request-for-MPG-do.patch
+++ /dev/null
@@ -1,222 +0,0 @@
-From f048f210112a2ca6df52f10f9e47afac5996fc09 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 3 Oct 2017 14:31:18 +0200
-Subject: [PATCH 07/21] LDAP: Turn group request into user request for MPG
- domains if needed
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-If the primary group GID or the group name is requested before the user
-is, we need to also search the user space to save the user in the back
-end which then allows the responder to generate the group from the
-user entry.
-
-Related:
-    https://pagure.io/SSSD/sssd/issue/1872
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 057e8af379aa32f7d9ea48bfff22a3304c59444b)
----
- src/providers/ldap/ldap_id.c | 162 +++++++++++++++++++++++++++++++------------
- 1 file changed, 118 insertions(+), 44 deletions(-)
-
-diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
-index 93204d35ea3782c9aa5d622a962c295869472631..e89fc6133316f684810afe4c1a0731b8a04f2931 100644
---- a/src/providers/ldap/ldap_id.c
-+++ b/src/providers/ldap/ldap_id.c
-@@ -694,6 +694,8 @@ struct groups_get_state {
- static int groups_get_retry(struct tevent_req *req);
- static void groups_get_connect_done(struct tevent_req *subreq);
- static void groups_get_posix_check_done(struct tevent_req *subreq);
-+static void groups_get_mpg_done(struct tevent_req *subreq);
-+static errno_t groups_get_handle_no_group(struct tevent_req *req);
- static void groups_get_search(struct tevent_req *req);
- static void groups_get_done(struct tevent_req *subreq);
- 
-@@ -1051,8 +1053,6 @@ static void groups_get_done(struct tevent_req *subreq)
-                                                       struct tevent_req);
-     struct groups_get_state *state = tevent_req_data(req,
-                                                      struct groups_get_state);
--    char *endptr;
--    gid_t gid;
-     int dp_error = DP_ERR_FATAL;
-     int ret;
- 
-@@ -1078,49 +1078,33 @@ static void groups_get_done(struct tevent_req *subreq)
-         return;
-     }
- 
--    if (ret == ENOENT && state->noexist_delete == true) {
--        switch (state->filter_type) {
--        case BE_FILTER_ENUM:
--            tevent_req_error(req, ret);
-+    if (ret == ENOENT
-+            && state->domain->mpg == true) {
-+        /* The requested filter did not find a group. Before giving up, we must
-+         * also check if the GID can be resolved through a primary group of a
-+         * user
-+         */
-+        subreq = users_get_send(state,
-+                                state->ev,
-+                                state->ctx,
-+                                state->sdom,
-+                                state->conn,
-+                                state->filter_value,
-+                                state->filter_type,
-+                                NULL,
-+                                state->noexist_delete);
-+        if (subreq == NULL) {
-+            tevent_req_error(req, ENOMEM);
-             return;
--        case BE_FILTER_NAME:
--            ret = sysdb_delete_group(state->domain, state->filter_value, 0);
--            if (ret != EOK && ret != ENOENT) {
--                tevent_req_error(req, ret);
--                return;
--            }
--            break;
--
--        case BE_FILTER_IDNUM:
--            gid = (gid_t) strtouint32(state->filter_value, &endptr, 10);
--            if (errno || *endptr || (state->filter_value == endptr)) {
--                tevent_req_error(req, errno ? errno : EINVAL);
--                return;
--            }
--
--            ret = sysdb_delete_group(state->domain, NULL, gid);
--            if (ret != EOK && ret != ENOENT) {
--                tevent_req_error(req, ret);
--                return;
--            }
--            break;
--
--        case BE_FILTER_SECID:
--        case BE_FILTER_UUID:
--            /* Since it is not clear if the SID/UUID belongs to a user or a
--             * group we have nothing to do here. */
--            break;
--
--        case BE_FILTER_WILDCARD:
--            /* We can't know if all groups are up-to-date, especially in
--             * a large environment. Do not delete any records, let the
--             * responder fetch the entries they are requested in.
--             */
--            break;
--
--
--        default:
--            tevent_req_error(req, EINVAL);
-+        }
-+        tevent_req_set_callback(subreq, groups_get_mpg_done, req);
-+        return;
-+    } else if (ret == ENOENT && state->noexist_delete == true) {
-+        ret = groups_get_handle_no_group(req);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Could not delete group [%d]: %s\n", ret, sss_strerror(ret));
-+            tevent_req_error(req, ret);
-             return;
-         }
-     }
-@@ -1129,6 +1113,96 @@ static void groups_get_done(struct tevent_req *subreq)
-     tevent_req_done(req);
- }
- 
-+static void groups_get_mpg_done(struct tevent_req *subreq)
-+{
-+    errno_t ret;
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct groups_get_state *state = tevent_req_data(req,
-+                                                     struct groups_get_state);
-+
-+    ret = users_get_recv(subreq, &state->dp_error, &state->sdap_ret);
-+    talloc_zfree(subreq);
-+
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    if (state->sdap_ret == ENOENT && state->noexist_delete == true) {
-+        ret = groups_get_handle_no_group(req);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Could not delete group [%d]: %s\n", ret, sss_strerror(ret));
-+            tevent_req_error(req, ret);
-+            return;
-+        }
-+    }
-+
-+    /* GID resolved to a user private group, done */
-+    tevent_req_done(req);
-+    return;
-+}
-+
-+static errno_t groups_get_handle_no_group(struct tevent_req *req)
-+{
-+    struct groups_get_state *state = tevent_req_data(req,
-+                                                     struct groups_get_state);
-+    errno_t ret;
-+    char *endptr;
-+    gid_t gid;
-+
-+    switch (state->filter_type) {
-+    case BE_FILTER_ENUM:
-+        ret = ENOENT;
-+        break;
-+    case BE_FILTER_NAME:
-+        ret = sysdb_delete_group(state->domain, state->filter_value, 0);
-+        if (ret != EOK && ret != ENOENT) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Cannot delete group %s [%d]: %s\n",
-+                  state->filter_value, ret, sss_strerror(ret));
-+            return ret;
-+        }
-+        ret = EOK;
-+        break;
-+    case BE_FILTER_IDNUM:
-+        gid = (gid_t) strtouint32(state->filter_value, &endptr, 10);
-+        if (errno || *endptr || (state->filter_value == endptr)) {
-+            ret = errno ? errno : EINVAL;
-+            break;
-+        }
-+
-+        ret = sysdb_delete_group(state->domain, NULL, gid);
-+        if (ret != EOK && ret != ENOENT) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Cannot delete group %"SPRIgid" [%d]: %s\n",
-+                  gid, ret, sss_strerror(ret));
-+            return ret;
-+        }
-+        ret = EOK;
-+        break;
-+    case BE_FILTER_SECID:
-+    case BE_FILTER_UUID:
-+        /* Since it is not clear if the SID/UUID belongs to a user or a
-+         * group we have nothing to do here. */
-+        ret = EOK;
-+        break;
-+    case BE_FILTER_WILDCARD:
-+        /* We can't know if all groups are up-to-date, especially in
-+         * a large environment. Do not delete any records, let the
-+         * responder fetch the entries they are requested in.
-+         */
-+        ret = EOK;
-+        break;
-+    default:
-+        ret = EINVAL;
-+        break;
-+    }
-+
-+    return ret;
-+}
-+
- int groups_get_recv(struct tevent_req *req, int *dp_error_out, int *sdap_ret)
- {
-     struct groups_get_state *state = tevent_req_data(req,
--- 
-2.13.5
-
diff --git a/SOURCES/0007-krb5_common-add-callback-only-once.patch b/SOURCES/0007-krb5_common-add-callback-only-once.patch
new file mode 100644
index 0000000..2b36703
--- /dev/null
+++ b/SOURCES/0007-krb5_common-add-callback-only-once.patch
@@ -0,0 +1,86 @@
+From 54ea4576ba8cb8dfbefdd3ced29fc35f836afc61 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 8 Jun 2018 08:29:04 +0200
+Subject: [PATCH] krb5_common: add callback only once
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 4759a482781bcecdb0ad1119e74dcefa1fe94337)
+---
+ src/providers/krb5/krb5_common.c | 12 +++++++++++-
+ src/providers/krb5/krb5_common.h |  2 ++
+ 2 files changed, 13 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
+index c6896a6cd663da896075e72aa0a0602c198b45e8..d064a09ac3726c4185c2fa1eeac76ef6c261d33b 100644
+--- a/src/providers/krb5/krb5_common.c
++++ b/src/providers/krb5/krb5_common.c
+@@ -399,6 +399,7 @@ static int remove_info_files_destructor(void *p)
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "remove_krb5_info_files failed.\n");
+     }
++    ctx->krb5_service->removal_callback_available = false;
+ 
+     return 0;
+ }
+@@ -407,7 +408,7 @@ static errno_t
+ krb5_add_krb5info_offline_callback(struct krb5_service *krb5_service)
+ {
+     int ret;
+-    struct remove_info_files_ctx *ctx;
++    struct remove_info_files_ctx *ctx = NULL;
+ 
+     if (krb5_service == NULL || krb5_service->name == NULL
+                              || krb5_service->realm == NULL
+@@ -416,6 +417,13 @@ krb5_add_krb5info_offline_callback(struct krb5_service *krb5_service)
+         return EINVAL;
+     }
+ 
++    if (krb5_service->removal_callback_available) {
++        DEBUG(SSSDBG_TRACE_ALL,
++              "Removal callback already available for service [%s].\n",
++              krb5_service->name);
++        return EOK;
++    }
++
+     ctx = talloc_zero(krb5_service->be_ctx, struct remove_info_files_ctx);
+     if (ctx == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zfree failed.\n");
+@@ -430,6 +438,7 @@ krb5_add_krb5info_offline_callback(struct krb5_service *krb5_service)
+     }
+ 
+     ctx->be_ctx = krb5_service->be_ctx;
++    ctx->krb5_service = krb5_service;
+     ctx->kdc_service_name = talloc_strdup(ctx, krb5_service->name);
+     if (ctx->kdc_service_name == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup failed!\n");
+@@ -445,6 +454,7 @@ krb5_add_krb5info_offline_callback(struct krb5_service *krb5_service)
+     }
+ 
+     talloc_set_destructor((TALLOC_CTX *) ctx, remove_info_files_destructor);
++    krb5_service->removal_callback_available = true;
+ 
+     ret = EOK;
+ 
+diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h
+index a2e47b0605debdffa28305dab4f7674707f713ac..3529d740b89fee91281f936fdafd1bdb99e95bd7 100644
+--- a/src/providers/krb5/krb5_common.h
++++ b/src/providers/krb5/krb5_common.h
+@@ -71,6 +71,7 @@ struct krb5_service {
+     char *name;
+     char *realm;
+     bool write_kdcinfo;
++    bool removal_callback_available;
+ };
+ 
+ struct fo_service;
+@@ -146,6 +147,7 @@ struct remove_info_files_ctx {
+     struct be_ctx *be_ctx;
+     const char *kdc_service_name;
+     const char *kpasswd_service_name;
++    struct krb5_service *krb5_service;
+ };
+ 
+ errno_t sss_krb5_check_options(struct dp_option *opts,
+-- 
+2.17.1
+
diff --git a/SOURCES/0008-SYSDB-Prevent-users-and-groups-ID-collision-in-MPG-d.patch b/SOURCES/0008-SYSDB-Prevent-users-and-groups-ID-collision-in-MPG-d.patch
deleted file mode 100644
index b8d60e1..0000000
--- a/SOURCES/0008-SYSDB-Prevent-users-and-groups-ID-collision-in-MPG-d.patch
+++ /dev/null
@@ -1,97 +0,0 @@
-From d75b796151973a5d94a79f5577c15cda6eecb5ee Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Thu, 19 Oct 2017 17:18:15 +0200
-Subject: [PATCH 08/21] SYSDB: Prevent users and groups ID collision in MPG
- domains except for id_provider=local
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This commit makes the check when adding an object in a MPG domain
-stricter in the sense that not only same names are allowed in a MPG
-domain, but also the same groups are not allowed either.
-
-This commit is a backwards-incompatible change, but one that is needed,
-otherwise requesting the duplicate group first and then requesting the
-user entry would yield two object when searching by GID.
-
-In order to keep backwards-compatibility, this uniqueness is NOT
-enforced with id_provider=local. This constraint can be removed in
-the future (or the local provider can be dropped altogether)
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit ac962e2b286988d8666b3b81bf8b55b1705b9ac0)
----
- src/db/sysdb_ops.c | 41 ++++++++++++++++++++++++++++++++++++++---
- 1 file changed, 38 insertions(+), 3 deletions(-)
-
-diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
-index 0e39a629a5823ff49ed02ec4c08a21b66119f06f..2f8e36c6c9a2c2cefe4af5fb78957763304d989a 100644
---- a/src/db/sysdb_ops.c
-+++ b/src/db/sysdb_ops.c
-@@ -1960,16 +1960,34 @@ int sysdb_add_user(struct sss_domain_info *domain,
-     }
- 
-     if (domain->mpg) {
--        /* In MPG domains you can't have groups with the same name as users,
--         * search if a group with the same name exists.
-+        /* In MPG domains you can't have groups with the same name or GID
-+         * as users, search if a group with the same name exists.
-          * Don't worry about users, if we try to add a user with the same
-          * name the operation will fail */
- 
-         ret = sysdb_search_group_by_name(tmp_ctx, domain, name, NULL, &msg);
-         if (ret != ENOENT) {
--            if (ret == EOK) ret = EEXIST;
-+            if (ret == EOK) {
-+                DEBUG(SSSDBG_OP_FAILURE,
-+                      "Group named %s already exists in an MPG domain\n",
-+                      name);
-+                ret = EEXIST;
-+            }
-             goto done;
-         }
-+
-+        if (strcasecmp(domain->provider, "local") != 0) {
-+            ret = sysdb_search_group_by_gid(tmp_ctx, domain, uid, NULL, &msg);
-+            if (ret != ENOENT) {
-+                if (ret == EOK) {
-+                    DEBUG(SSSDBG_OP_FAILURE,
-+                        "Group with GID [%"SPRIgid"] already exists in an "
-+                        "MPG domain\n", gid);
-+                    ret = EEXIST;
-+                }
-+                goto done;
-+            }
-+        }
-     }
- 
-     /* check no other user with the same uid exist */
-@@ -2177,6 +2195,23 @@ int sysdb_add_group(struct sss_domain_info *domain,
-             }
-             goto done;
-         }
-+
-+        if (strcasecmp(domain->provider, "local") != 0) {
-+            ret = sysdb_search_user_by_uid(tmp_ctx, domain, gid, NULL, &msg);
-+            if (ret != ENOENT) {
-+                if (ret == EOK) {
-+                    DEBUG(SSSDBG_TRACE_LIBS,
-+                          "User with the same UID exists in MPG domain: "
-+                          "[%"SPRIgid"].\n", gid);
-+                    ret = EEXIST;
-+                } else {
-+                    DEBUG(SSSDBG_TRACE_LIBS,
-+                          "sysdb_search_user_by_uid failed for gid: "
-+                          "[%"SPRIgid"].\n", gid);
-+                }
-+                goto done;
-+            }
-+        }
-     }
- 
-     /* check no other groups with the same gid exist */
--- 
-2.13.5
-
diff --git a/SOURCES/0008-data-provider-run-offline-callbacks-only-once.patch b/SOURCES/0008-data-provider-run-offline-callbacks-only-once.patch
new file mode 100644
index 0000000..fd7a973
--- /dev/null
+++ b/SOURCES/0008-data-provider-run-offline-callbacks-only-once.patch
@@ -0,0 +1,95 @@
+From 2d350235bc960a91233d29b97c3a205bd2e04c08 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 8 Jun 2018 18:42:28 +0200
+Subject: [PATCH] data provider: run offline callbacks only once
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit f28d995719db632130e9e063cb1ab7cb4e0fc8d8)
+---
+ src/providers/backend.h                 |  1 +
+ src/providers/data_provider_be.c        |  1 +
+ src/providers/data_provider_callbacks.c | 36 +++++++++++++++++++------
+ 3 files changed, 30 insertions(+), 8 deletions(-)
+
+diff --git a/src/providers/backend.h b/src/providers/backend.h
+index 1914274037ce7f7ff4b6d8486b041789a865fd59..6a34b91a911fc12163fa9448ea82ff93f5bf3849 100644
+--- a/src/providers/backend.h
++++ b/src/providers/backend.h
+@@ -95,6 +95,7 @@ struct be_ctx {
+     struct be_cb *online_cb_list;
+     bool run_online_cb;
+     struct be_cb *offline_cb_list;
++    bool run_offline_cb;
+     struct be_cb *reconnect_cb_list;
+     /* In contrast to online_cb_list which are only run if the backend is
+      * offline the unconditional_online_cb_list should be run whenever the
+diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
+index e8cddd976bb164dc6d4655bf2ebe9a03c3d9d26a..fad6f280195b615d1de45afaf0c459bdf78c8c0a 100644
+--- a/src/providers/data_provider_be.c
++++ b/src/providers/data_provider_be.c
+@@ -219,6 +219,7 @@ static void be_reset_offline(struct be_ctx *ctx)
+ {
+     ctx->offstat.went_offline = 0;
+     ctx->offstat.offline = false;
++    ctx->run_offline_cb = true;
+ 
+     reactivate_subdoms(ctx->domain);
+ 
+diff --git a/src/providers/data_provider_callbacks.c b/src/providers/data_provider_callbacks.c
+index 436357e228c0e1a689aa18b8ef41a82f63774d3a..24e125ea5be70208d7cf2cb06a80c39207e29db4 100644
+--- a/src/providers/data_provider_callbacks.c
++++ b/src/providers/data_provider_callbacks.c
+@@ -265,22 +265,42 @@ void be_run_unconditional_online_cb(struct be_ctx *be)
+ int be_add_offline_cb(TALLOC_CTX *mem_ctx, struct be_ctx *ctx, be_callback_t cb,
+                       void *pvt, struct be_cb **offline_cb)
+ {
+-    return be_add_cb(mem_ctx, ctx, cb, pvt, &ctx->offline_cb_list, offline_cb);
++    int ret;
++
++    ret = be_add_cb(mem_ctx, ctx, cb, pvt, &ctx->offline_cb_list, offline_cb);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "be_add_cb failed.\n");
++        return ret;
++    }
++
++    /* Make sure we run the callback when SSSD goes offline */
++    ctx->run_offline_cb = true;
++
++    return EOK;
+ }
+ 
+ void be_run_offline_cb(struct be_ctx *be) {
+     int ret;
+ 
+-    if (be->offline_cb_list) {
+-        DEBUG(SSSDBG_MINOR_FAILURE, "Going offline. Running callbacks.\n");
++    if (be->run_offline_cb) {
++        /* Reset the flag, we only want to run these callbacks once when going
++         * offline */
++        be->run_offline_cb = false;
+ 
+-        ret = be_run_cb(be, be->offline_cb_list);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_CRIT_FAILURE, "be_run_cb failed.\n");
++        if (be->offline_cb_list) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Going offline. Running callbacks.\n");
++
++            ret = be_run_cb(be, be->offline_cb_list);
++            if (ret != EOK) {
++                DEBUG(SSSDBG_CRIT_FAILURE, "be_run_cb failed.\n");
++            }
++
++        } else {
++            DEBUG(SSSDBG_TRACE_ALL,
++                  "Offline call back list is empty, nothing to do.\n");
+         }
+-
+     } else {
+         DEBUG(SSSDBG_TRACE_ALL,
+-              "Offline call back list is empty, nothing to do.\n");
++              "Flag indicates that offline callback were already called.\n");
+     }
+ }
+-- 
+2.17.1
+
diff --git a/SOURCES/0009-TESTS-Add-integration-tests-for-the-auto_private_gro.patch b/SOURCES/0009-TESTS-Add-integration-tests-for-the-auto_private_gro.patch
deleted file mode 100644
index a9c1356..0000000
--- a/SOURCES/0009-TESTS-Add-integration-tests-for-the-auto_private_gro.patch
+++ /dev/null
@@ -1,346 +0,0 @@
-From 95053cd058a9045c45c59e002fd6078048fdca76 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 3 Oct 2017 16:55:40 +0200
-Subject: [PATCH 09/21] TESTS: Add integration tests for the
- auto_private_groups option
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-    https://pagure.io/SSSD/sssd/issue/1872
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit 6c802b2009c1b6dd0c3306ba97056e64acc0ec9e)
----
- src/tests/intg/test_enumeration.py |  79 +++++++++++++-
- src/tests/intg/test_ldap.py        | 214 +++++++++++++++++++++++++++++++++++++
- 2 files changed, 290 insertions(+), 3 deletions(-)
-
-diff --git a/src/tests/intg/test_enumeration.py b/src/tests/intg/test_enumeration.py
-index fdb8d376879f756957f8f25fd28b37d7178aeff5..c7d78155c64dc6c85cb4dc070b205bdcfceff6af 100644
---- a/src/tests/intg/test_enumeration.py
-+++ b/src/tests/intg/test_enumeration.py
-@@ -237,9 +237,7 @@ def sanity_rfc2307(request, ldap_conn):
-     create_sssd_fixture(request)
-     return None
- 
--
--@pytest.fixture
--def sanity_rfc2307_bis(request, ldap_conn):
-+def populate_rfc2307bis(request, ldap_conn):
-     ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn)
-     ent_list.add_user("user1", 1001, 2001)
-     ent_list.add_user("user2", 1002, 2002)
-@@ -266,6 +264,11 @@ def sanity_rfc2307_bis(request, ldap_conn):
-                            [], ["one_user_group1", "one_user_group2"])
- 
-     create_ldap_fixture(request, ldap_conn, ent_list)
-+
-+
-+@pytest.fixture
-+def sanity_rfc2307_bis(request, ldap_conn):
-+    populate_rfc2307bis(request, ldap_conn)
-     conf = format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS)
-     create_conf_fixture(request, conf)
-     create_sssd_fixture(request)
-@@ -695,3 +698,73 @@ def test_vetoed_shells(vetoed_shells):
-                  shell="/bin/default")
-         )
-     )
-+
-+
-+@pytest.fixture
-+def sanity_rfc2307_bis_mpg(request, ldap_conn):
-+    populate_rfc2307bis(request, ldap_conn)
-+
-+    ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn)
-+    ent_list.add_group_bis("conflict1", 1001)
-+    ent_list.add_group_bis("conflict2", 1002)
-+    create_ldap_fixture(request, ldap_conn, ent_list)
-+
-+    conf = \
-+        format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + \
-+        unindent("""
-+            [domain/LDAP]
-+            auto_private_groups = True
-+        """).format(**locals())
-+    create_conf_fixture(request, conf)
-+    create_sssd_fixture(request)
-+    return None
-+
-+
-+def test_ldap_auto_private_groups_enumerate(ldap_conn,
-+                                            sanity_rfc2307_bis_mpg):
-+    """
-+    Test the auto_private_groups together with enumeration
-+    """
-+    passwd_pattern = ent.contains_only(
-+        dict(name='user1', passwd='*', uid=1001, gid=1001, gecos='1001',
-+             dir='/home/user1', shell='/bin/bash'),
-+        dict(name='user2', passwd='*', uid=1002, gid=1002, gecos='1002',
-+             dir='/home/user2', shell='/bin/bash'),
-+        dict(name='user3', passwd='*', uid=1003, gid=1003, gecos='1003',
-+             dir='/home/user3', shell='/bin/bash')
-+    )
-+    ent.assert_passwd(passwd_pattern)
-+
-+    group_pattern = ent.contains_only(
-+        dict(name='user1', passwd='*', gid=1001, mem=ent.contains_only()),
-+        dict(name='user2', passwd='*', gid=1002, mem=ent.contains_only()),
-+        dict(name='user3', passwd='*', gid=1003, mem=ent.contains_only()),
-+        dict(name='group1', passwd='*', gid=2001, mem=ent.contains_only()),
-+        dict(name='group2', passwd='*', gid=2002, mem=ent.contains_only()),
-+        dict(name='group3', passwd='*', gid=2003, mem=ent.contains_only()),
-+        dict(name='empty_group1', passwd='*', gid=2010,
-+             mem=ent.contains_only()),
-+        dict(name='empty_group2', passwd='*', gid=2011,
-+             mem=ent.contains_only()),
-+        dict(name='two_user_group', passwd='*', gid=2012,
-+             mem=ent.contains_only("user1", "user2")),
-+        dict(name='group_empty_group', passwd='*', gid=2013,
-+             mem=ent.contains_only()),
-+        dict(name='group_two_empty_groups', passwd='*', gid=2014,
-+             mem=ent.contains_only()),
-+        dict(name='one_user_group1', passwd='*', gid=2015,
-+             mem=ent.contains_only("user1")),
-+        dict(name='one_user_group2', passwd='*', gid=2016,
-+             mem=ent.contains_only("user2")),
-+        dict(name='group_one_user_group', passwd='*', gid=2017,
-+             mem=ent.contains_only("user1")),
-+        dict(name='group_two_user_group', passwd='*', gid=2018,
-+             mem=ent.contains_only("user1", "user2")),
-+        dict(name='group_two_one_user_groups', passwd='*', gid=2019,
-+             mem=ent.contains_only("user1", "user2"))
-+    )
-+    ent.assert_group(group_pattern)
-+
-+    with pytest.raises(KeyError):
-+        grp.getgrnam("conflict1")
-+    ent.assert_group_by_gid(1002, dict(name="user2", mem=ent.contains_only()))
-diff --git a/src/tests/intg/test_ldap.py b/src/tests/intg/test_ldap.py
-index f2467f1ffe9890049ad73bba6432102d029510e8..a6659b1b78df4d72eb98c208d67ee5d10c9c88ea 100644
---- a/src/tests/intg/test_ldap.py
-+++ b/src/tests/intg/test_ldap.py
-@@ -1169,3 +1169,217 @@ def test_nss_filters_cached(ldap_conn, sanity_nss_filter_cached):
- 
-     res, _ = call_sssd_getgrgid(0)
-     assert res == NssReturnCode.NOTFOUND
-+
-+
-+@pytest.fixture
-+def mpg_setup(request, ldap_conn):
-+    ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn)
-+    ent_list.add_user("user1", 1001, 2001)
-+    ent_list.add_user("user2", 1002, 2002)
-+    ent_list.add_user("user3", 1003, 2003)
-+
-+    ent_list.add_group_bis("group1", 2001)
-+    ent_list.add_group_bis("group2", 2002)
-+    ent_list.add_group_bis("group3", 2003)
-+
-+    ent_list.add_group_bis("two_user_group", 2012, ["user1", "user2"])
-+    ent_list.add_group_bis("one_user_group1", 2015, ["user1"])
-+    ent_list.add_group_bis("one_user_group2", 2016, ["user2"])
-+
-+    create_ldap_entries(ldap_conn, ent_list)
-+    create_ldap_cleanup(request, ldap_conn, None)
-+
-+    conf = \
-+        format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + \
-+        unindent("""
-+            [domain/LDAP]
-+            auto_private_groups = True
-+        """).format(**locals())
-+    create_conf_fixture(request, conf)
-+    create_sssd_fixture(request)
-+    return None
-+
-+
-+def test_ldap_auto_private_groups_direct(ldap_conn, mpg_setup):
-+    """
-+    Integration test for auto_private_groups
-+
-+    See also ticket https://pagure.io/SSSD/sssd/issue/1872
-+    """
-+    # Make sure the user's GID is taken from their uidNumber
-+    ent.assert_passwd_by_name("user1", dict(name="user1", uid=1001, gid=1001))
-+    # Make sure the private group is resolvable by name and by GID
-+    ent.assert_group_by_name("user1", dict(gid=1001, mem=ent.contains_only()))
-+    ent.assert_group_by_gid(1001, dict(name="user1", mem=ent.contains_only()))
-+
-+    # The group referenced in user's gidNumber attribute should be still
-+    # visible, but it's fine that it doesn't contain the user as a member
-+    # as the group is currently added during the initgroups operation only
-+    ent.assert_group_by_name("group1", dict(gid=2001, mem=ent.contains_only()))
-+    ent.assert_group_by_gid(2001, dict(name="group1", mem=ent.contains_only()))
-+
-+    # The user's secondary groups list must be correct as well
-+    # Note that the original GID is listed as well -- this is correct and expected
-+    # because we save the original GID in the SYSDB_PRIMARY_GROUP_GIDNUM attribute
-+    user1_expected_gids = [1001, 2001, 2012, 2015]
-+    (res, errno, gids) = sssd_id.call_sssd_initgroups("user1", 1001)
-+    assert res == sssd_id.NssReturnCode.SUCCESS
-+
-+    assert sorted(gids) == sorted(user1_expected_gids), \
-+        "result: %s\n expected %s" % (
-+            ", ".join(["%s" % s for s in sorted(gids)]),
-+            ", ".join(["%s" % s for s in sorted(user1_expected_gids)])
-+        )
-+
-+    # Request user2's private group by GID without resolving the user first.
-+    # This must trigger user resolution through by-GID resolution, since the GID
-+    # doesn't exist on its own in LDAP
-+    ent.assert_group_by_gid(1002, dict(name="user2", mem=ent.contains_only()))
-+
-+    # Test supplementary groups for user2 as well
-+    user1_expected_gids = [1002, 2002, 2012, 2016]
-+    (res, errno, gids) = sssd_id.call_sssd_initgroups("user2", 1002)
-+    assert res == sssd_id.NssReturnCode.SUCCESS
-+
-+    assert sorted(gids) == sorted(user1_expected_gids), \
-+        "result: %s\n expected %s" % (
-+            ", ".join(["%s" % s for s in sorted(gids)]),
-+            ", ".join(["%s" % s for s in sorted(user1_expected_gids)])
-+        )
-+
-+    # Request user3's private group by name without resolving the user first
-+    # This must trigger user resolution through by-name resolution, since the
-+    # name doesn't exist on its own in LDAP
-+    ent.assert_group_by_name("user3", dict(gid=1003, mem=ent.contains_only()))
-+
-+    # Remove entries and request them again to make sure they are not
-+    # resolvable anymore
-+    cleanup_ldap_entries(ldap_conn, None)
-+
-+    if subprocess.call(["sss_cache", "-GU"]) != 0:
-+        raise Exception("sssd_cache failed")
-+
-+    with pytest.raises(KeyError):
-+        pwd.getpwnam("user1")
-+    with pytest.raises(KeyError):
-+        grp.getgrnam("user1")
-+    with pytest.raises(KeyError):
-+        grp.getgrgid(1002)
-+    with pytest.raises(KeyError):
-+        grp.getgrnam("user3")
-+
-+
-+@pytest.fixture
-+def mpg_setup_conflict(request, ldap_conn):
-+    ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn)
-+    ent_list.add_user("user1", 1001, 2001)
-+    ent_list.add_user("user2", 1002, 2002)
-+    ent_list.add_user("user3", 1003, 1003)
-+    ent_list.add_group_bis("group1", 1001)
-+    ent_list.add_group_bis("group2", 1002)
-+    ent_list.add_group_bis("group3", 1003)
-+    ent_list.add_group_bis("supp_group", 2015, ["user3"])
-+    create_ldap_fixture(request, ldap_conn, ent_list)
-+
-+    conf = \
-+        format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + \
-+        unindent("""
-+            [domain/LDAP]
-+            auto_private_groups = True
-+        """).format(**locals())
-+    create_conf_fixture(request, conf)
-+    create_sssd_fixture(request)
-+    return None
-+
-+
-+def test_ldap_auto_private_groups_conflict(ldap_conn, mpg_setup_conflict):
-+    """
-+    Make sure that conflicts between groups that are auto-created with the
-+    help of the auto_private_groups option and between 'real' LDAP groups
-+    are handled in a predictable manner.
-+    """
-+    # Make sure the user's GID is taken from their uidNumber
-+    ent.assert_passwd_by_name("user1", dict(name="user1", uid=1001, gid=1001))
-+    # Make sure the private group is resolvable by name and by GID
-+    ent.assert_group_by_name("user1", dict(gid=1001, mem=ent.contains_only()))
-+    ent.assert_group_by_gid(1001, dict(name="user1", mem=ent.contains_only()))
-+
-+    # Let's request the group with the same ID as user2's private group
-+    # The request should match the 'real' group
-+    ent.assert_group_by_gid(1002, dict(name="group2", mem=ent.contains_only()))
-+    # But because of the GID conflict, the user cannot be resolved
-+    with pytest.raises(KeyError):
-+        pwd.getpwnam("user2")
-+
-+    # This user's GID is the same as the UID in this entry. The most important
-+    # thing here is that the supplementary groups are correct and the GID
-+    # resolves to the private group (as long as the user was requested first)
-+    user3_expected_gids = [1003, 2015]
-+    ent.assert_passwd_by_name("user3", dict(name="user3", uid=1003, gid=1003))
-+    (res, errno, gids) = sssd_id.call_sssd_initgroups("user3", 1003)
-+    assert res == sssd_id.NssReturnCode.SUCCESS
-+
-+    assert sorted(gids) == sorted(user3_expected_gids), \
-+        "result: %s\n expected %s" % (
-+            ", ".join(["%s" % s for s in sorted(gids)]),
-+            ", ".join(["%s" % s for s in sorted(user3_expected_gids)])
-+        )
-+    # Make sure the private group is resolvable by name and by GID
-+    ent.assert_group_by_gid(1003, dict(name="user3", mem=ent.contains_only()))
-+    ent.assert_group_by_name("user3", dict(gid=1003, mem=ent.contains_only()))
-+
-+
-+@pytest.fixture
-+def mpg_setup_no_gid(request, ldap_conn):
-+    ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn)
-+    ent_list.add_user("user1", 1001, 2001)
-+
-+    ent_list.add_group_bis("group1", 2001)
-+    ent_list.add_group_bis("one_user_group1", 2015, ["user1"])
-+
-+    create_ldap_entries(ldap_conn, ent_list)
-+    create_ldap_cleanup(request, ldap_conn, None)
-+
-+    conf = \
-+        format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + \
-+        unindent("""
-+            [domain/LDAP]
-+            auto_private_groups = True
-+            ldap_user_gid_number = no_such_attribute
-+        """).format(**locals())
-+    create_conf_fixture(request, conf)
-+    create_sssd_fixture(request)
-+    return None
-+
-+
-+def test_ldap_auto_private_groups_direct_no_gid(ldap_conn, mpg_setup_no_gid):
-+    """
-+    Integration test for auto_private_groups - test that even a user with
-+    no GID assigned at all can be resolved including their autogenerated
-+    primary group.
-+
-+    See also ticket https://pagure.io/SSSD/sssd/issue/1872
-+    """
-+    # Make sure the user's GID is taken from their uidNumber
-+    ent.assert_passwd_by_name("user1", dict(name="user1", uid=1001, gid=1001))
-+    # Make sure the private group is resolvable by name and by GID
-+    ent.assert_group_by_name("user1", dict(gid=1001, mem=ent.contains_only()))
-+    ent.assert_group_by_gid(1001, dict(name="user1", mem=ent.contains_only()))
-+
-+    # The group referenced in user's gidNumber attribute should be still
-+    # visible, but shouldn't have any relation to the user
-+    ent.assert_group_by_name("group1", dict(gid=2001, mem=ent.contains_only()))
-+    ent.assert_group_by_gid(2001, dict(name="group1", mem=ent.contains_only()))
-+
-+    # The user's secondary groups list must be correct as well. This time only
-+    # the generated group and the explicit secondary group are added, since
-+    # there is no original GID
-+    user1_expected_gids = [1001, 2015]
-+    (res, errno, gids) = sssd_id.call_sssd_initgroups("user1", 1001)
-+    assert res == sssd_id.NssReturnCode.SUCCESS
-+
-+    assert sorted(gids) == sorted(user1_expected_gids), \
-+        "result: %s\n expected %s" % (
-+            ", ".join(["%s" % s for s in sorted(gids)]),
-+            ", ".join(["%s" % s for s in sorted(user1_expected_gids)])
-+        )
--- 
-2.13.5
-
diff --git a/SOURCES/0009-TESTS-Extend-the-schema-with-sshPublicKey-attribute.patch b/SOURCES/0009-TESTS-Extend-the-schema-with-sshPublicKey-attribute.patch
new file mode 100644
index 0000000..3cb7eda
--- /dev/null
+++ b/SOURCES/0009-TESTS-Extend-the-schema-with-sshPublicKey-attribute.patch
@@ -0,0 +1,62 @@
+From 2b210b10ce54f6f2595f6ab181a51bce367d43a9 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sun, 17 Jun 2018 21:48:36 +0200
+Subject: [PATCH] TESTS: Extend the schema with sshPublicKey attribute
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This will allow to store the users with a sshPublicKey attribute
+provided that they have the right objectclass as well.
+
+Related to:
+https://pagure.io/SSSD/sssd/issue/3747
+
+Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
+(cherry picked from commit 1575ec97e080656f69b3f93e641c76e74ffb8182)
+
+DOWNSTREAM:
+Resolves: rhbz#1583343 - Login with sshkeys stored in ipa not working after update to RHEL-7.5
+---
+ src/tests/intg/data/ssh_schema.ldif | 11 +++++++++++
+ src/tests/intg/ds_openldap.py       |  6 ++++++
+ 2 files changed, 17 insertions(+)
+ create mode 100644 src/tests/intg/data/ssh_schema.ldif
+
+diff --git a/src/tests/intg/data/ssh_schema.ldif b/src/tests/intg/data/ssh_schema.ldif
+new file mode 100644
+index 0000000000000000000000000000000000000000..efe05706b9ded5614a7f3f5e0bab28a7eb869daa
+--- /dev/null
++++ b/src/tests/intg/data/ssh_schema.ldif
+@@ -0,0 +1,11 @@
++dn: cn=openssh-lpk,cn=schema,cn=config
++objectClass: olcSchemaConfig
++cn: openssh-lpk
++olcAttributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey'
++  DESC 'MANDATORY: OpenSSH Public key'
++  EQUALITY octetStringMatch
++  SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
++olcObjectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
++  DESC 'MANDATORY: OpenSSH LPK objectclass'
++  MAY ( sshPublicKey $ uid )
++  )
+diff --git a/src/tests/intg/ds_openldap.py b/src/tests/intg/ds_openldap.py
+index 842ff910803658834841c8f9181f3c4af29b955a..c9a4b6de8c53c6644b3de9047d657ee35ce06512 100644
+--- a/src/tests/intg/ds_openldap.py
++++ b/src/tests/intg/ds_openldap.py
+@@ -186,6 +186,12 @@ class DSOpenLDAP(DS):
+         db_config_file.write(db_config)
+         db_config_file.close()
+ 
++        # Import ad schema
++        subprocess.check_call(
++            ["slapadd", "-F", self.conf_slapd_d_dir, "-b", "cn=config",
++             "-l", "data/ssh_schema.ldif"],
++        )
++
+     def _start_daemon(self):
+         """Start the instance."""
+         if subprocess.call(["slapd", "-F", self.conf_slapd_d_dir,
+-- 
+2.17.1
+
diff --git a/SOURCES/0010-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch b/SOURCES/0010-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch
deleted file mode 100644
index 39c79de..0000000
--- a/SOURCES/0010-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch
+++ /dev/null
@@ -1,142 +0,0 @@
-From ec3334b5a09328de492804c391654073553ff7e7 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
-Date: Fri, 20 Oct 2017 09:26:43 +0200
-Subject: [PATCH 10/21] CACHE_REQ: Copy the cr_domain list for each request
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Let's copy the cr_domain list for each request as this list may be
-free'd due to a refresh domains request.
-
-Resolves: https://pagure.io/SSSD/sssd/issue/3551
-
-Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit 0f44eefe2ce75a0814c8688495477f6c57f3d39a)
----
- src/responder/common/cache_req/cache_req.c        | 14 +++++++--
- src/responder/common/cache_req/cache_req_domain.c | 38 +++++++++++++++++++++++
- src/responder/common/cache_req/cache_req_domain.h |  5 +++
- 3 files changed, 55 insertions(+), 2 deletions(-)
-
-diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c
-index abcb9cba351b06e833bacde26a504e5ee3445528..5fed7a2ab8beded2fee91f679a12f9a0ff6013ec 100644
---- a/src/responder/common/cache_req/cache_req.c
-+++ b/src/responder/common/cache_req/cache_req.c
-@@ -699,6 +699,7 @@ struct cache_req_state {
-     const char *domain_name;
- 
-     /* work data */
-+    struct cache_req_domain *cr_domains;
-     struct cache_req_result **results;
-     size_t num_results;
-     bool first_iteration;
-@@ -953,6 +954,7 @@ static errno_t cache_req_select_domains(struct tevent_req *req,
-     bool bypass_cache;
-     bool bypass_dp;
-     bool search;
-+    errno_t ret;
- 
-     state = tevent_req_data(req, struct cache_req_state);
- 
-@@ -964,12 +966,20 @@ static errno_t cache_req_select_domains(struct tevent_req *req,
-         return EOK;
-     }
- 
-+    ret = cache_req_domain_copy_cr_domains(state,
-+                                           state->cr->rctx->cr_domains,
-+                                           &state->cr_domains);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_copy_cr_domains() failed\n");
-+        return EINVAL;
-+    }
-+
-     if (domain_name != NULL) {
-         CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
-                         "Performing a single domain search\n");
- 
-         cr_domain = cache_req_domain_get_domain_by_name(
--                                    state->cr->rctx->cr_domains, domain_name);
-+                                    state->cr_domains, domain_name);
-         if (cr_domain == NULL) {
-             return ERR_DOMAIN_NOT_FOUND;
-         }
-@@ -978,7 +988,7 @@ static errno_t cache_req_select_domains(struct tevent_req *req,
-         CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr,
-                         "Performing a multi-domain search\n");
- 
--        cr_domain = state->cr->rctx->cr_domains;
-+        cr_domain = state->cr_domains;
-         check_next = true;
-     }
- 
-diff --git a/src/responder/common/cache_req/cache_req_domain.c b/src/responder/common/cache_req/cache_req_domain.c
-index 7b58f7c94a77881429f870bc5162fb2fe0aa57c6..15893ba548f6d0e3979010d6d5bbf27441d5fa97 100644
---- a/src/responder/common/cache_req/cache_req_domain.c
-+++ b/src/responder/common/cache_req/cache_req_domain.c
-@@ -47,6 +47,44 @@ cache_req_domain_get_domain_by_name(struct cache_req_domain *domains,
-     return ret;
- }
- 
-+errno_t
-+cache_req_domain_copy_cr_domains(TALLOC_CTX *mem_ctx,
-+                                 struct cache_req_domain *src,
-+                                 struct cache_req_domain **_dest)
-+{
-+    struct cache_req_domain *cr_domains = NULL;
-+    struct cache_req_domain *cr_domain;
-+    struct cache_req_domain *iter;
-+    errno_t ret;
-+
-+    if (src == NULL) {
-+        return EINVAL;
-+    }
-+
-+    DLIST_FOR_EACH(iter, src) {
-+        cr_domain = talloc_zero(mem_ctx, struct cache_req_domain);
-+        if (cr_domain == NULL) {
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+
-+        cr_domain->domain = iter->domain;
-+        cr_domain->fqnames = iter->fqnames;
-+
-+        DLIST_ADD_END(cr_domains, cr_domain, struct cache_req_domain *);
-+    }
-+
-+    *_dest = cr_domains;
-+    ret = EOK;
-+
-+done:
-+    if (ret != EOK) {
-+        cache_req_domain_list_zfree(&cr_domains);
-+    }
-+
-+    return ret;
-+}
-+
- void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains)
- {
-     struct cache_req_domain *p, *q, *r;
-diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h
-index 3780a5d8d88d76e100738d28d1dd0e697edf5eae..ebdc71dd635d5d8a5d06e30e96c5d4101b6d98bf 100644
---- a/src/responder/common/cache_req/cache_req_domain.h
-+++ b/src/responder/common/cache_req/cache_req_domain.h
-@@ -50,6 +50,11 @@ cache_req_domain_new_list_from_domain_resolution_order(
-                                         const char *domain_resolution_order,
-                                         struct cache_req_domain **_cr_domains);
- 
-+errno_t
-+cache_req_domain_copy_cr_domains(TALLOC_CTX *mem_ctx,
-+                                 struct cache_req_domain *src,
-+                                 struct cache_req_domain **_dest);
-+
- void cache_req_domain_list_zfree(struct cache_req_domain **cr_domains);
- 
- 
--- 
-2.13.5
-
diff --git a/SOURCES/0010-TESTS-Allow-adding-sshPublicKey-for-users.patch b/SOURCES/0010-TESTS-Allow-adding-sshPublicKey-for-users.patch
new file mode 100644
index 0000000..ed461cd
--- /dev/null
+++ b/SOURCES/0010-TESTS-Allow-adding-sshPublicKey-for-users.patch
@@ -0,0 +1,78 @@
+From 4bff9d92a51bff2fabb6168f8ae69c8a8d17ba2a Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sun, 17 Jun 2018 22:06:22 +0200
+Subject: [PATCH] TESTS: Allow adding sshPublicKey for users
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Adds the objectclass and allows storing a list of sshPublicKey
+attributes for users. Since there is no harm in adding the extra
+objectclass, we can do it unconditionally.
+
+Related to:
+https://pagure.io/SSSD/sssd/issue/3747
+
+Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
+(cherry picked from commit 56cda832e9f61c52e9cfde1f0864507de718ffbb)
+---
+ src/tests/intg/ldap_ent.py | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+diff --git a/src/tests/intg/ldap_ent.py b/src/tests/intg/ldap_ent.py
+index 6b6d8f903cbcc277d892c3212ca382f4aaadc671..a4c987969d3dcefba2af69e095b220180e0fa54c 100644
+--- a/src/tests/intg/ldap_ent.py
++++ b/src/tests/intg/ldap_ent.py
+@@ -24,7 +24,8 @@ def user(base_dn, uid, uidNumber, gidNumber,
+          homeDirectory=None,
+          loginShell=None,
+          cn=None,
+-         sn=None):
++         sn=None,
++         sshPubKey=()):
+     """
+     Generate an RFC2307(bis) user add-modlist for passing to ldap.add*
+     """
+@@ -33,7 +34,8 @@ def user(base_dn, uid, uidNumber, gidNumber,
+     user = (
+         "uid=" + uid + ",ou=Users," + base_dn,
+         [
+-            ('objectClass', [b'top', b'inetOrgPerson', b'posixAccount']),
++            ('objectClass', [b'top', b'inetOrgPerson',
++                             b'posixAccount', b'ldapPublicKey']),
+             ('cn', [uidNumber if cn is None else cn.encode('utf-8')]),
+             ('sn', [b'User' if sn is None else sn.encode('utf-8')]),
+             ('uidNumber', [uidNumber]),
+@@ -51,6 +53,9 @@ def user(base_dn, uid, uidNumber, gidNumber,
+     )
+     if gecos is not None:
+         user[1].append(('gecos', [gecos.encode('utf-8')]))
++    if len(sshPubKey) > 0:
++        pubkeys = [key.encode('utf-8') for key in sshPubKey]
++        user[1].append(('sshPublicKey', pubkeys))
+     return user
+ 
+ 
+@@ -118,7 +123,8 @@ class List(list):
+                  homeDirectory=None,
+                  loginShell=None,
+                  cn=None,
+-                 sn=None):
++                 sn=None,
++                 sshPubKey=()):
+         """Add an RFC2307(bis) user add-modlist."""
+         self.append(user(base_dn or self.base_dn,
+                          uid, uidNumber, gidNumber,
+@@ -127,7 +133,8 @@ class List(list):
+                          homeDirectory=homeDirectory,
+                          loginShell=loginShell,
+                          cn=cn,
+-                         sn=sn))
++                         sn=sn,
++                         sshPubKey=sshPubKey))
+ 
+     def add_group(self, cn, gidNumber, member_uids=[],
+                   base_dn=None):
+-- 
+2.17.1
+
diff --git a/SOURCES/0011-MAN-GPO-Security-Filtering-limitation.patch b/SOURCES/0011-MAN-GPO-Security-Filtering-limitation.patch
deleted file mode 100644
index 880f661..0000000
--- a/SOURCES/0011-MAN-GPO-Security-Filtering-limitation.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 314c3a0efc276b74f7a2e39da4db29d8fbf43b12 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
-Date: Thu, 26 Oct 2017 17:12:17 +0200
-Subject: [PATCH 11/21] MAN: GPO Security Filtering limitation
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Note in the man pages that current version of SSSD does not support
-host entries in the 'Security filtering' list.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3444
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 6c1661d2f4e860d1b547d6188a4fe2bd564e87cf)
----
- src/man/sssd-ad.5.xml | 7 +++++++
- 1 file changed, 7 insertions(+)
-
-diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
-index 08c1dd09fb829c6cffb416250b9b518668ec5790..649042d587de3d3600fff59866681e302c721af8 100644
---- a/src/man/sssd-ad.5.xml
-+++ b/src/man/sssd-ad.5.xml
-@@ -346,6 +346,13 @@ DOM:dom1:(memberOf:1.2.840.113556.1.4.1941:=cn=nestedgroup,ou=groups,dc=example,
-                             host.
-                         </para>
-                         <para>
-+                            NOTE: The current version of SSSD does not support
-+                            host (computer) entries in the GPO 'Security
-+                            Filtering' list. Only user and group entries are
-+                            supported. Host entries in the list have no
-+                            effect.
-+                        </para>
-+                        <para>
-                             NOTE: If the operation mode is set to enforcing, it
-                             is possible that users that were previously allowed
-                             logon access will now be denied logon access (as
--- 
-2.13.5
-
diff --git a/SOURCES/0011-TESTS-Add-a-basic-SSH-responder-test.patch b/SOURCES/0011-TESTS-Add-a-basic-SSH-responder-test.patch
new file mode 100644
index 0000000..0760c43
--- /dev/null
+++ b/SOURCES/0011-TESTS-Add-a-basic-SSH-responder-test.patch
@@ -0,0 +1,276 @@
+From 079464a0fd417f09cfafa2bda9ff1a4e1afdbe8a Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 18 Jun 2018 09:12:13 +0200
+Subject: [PATCH] TESTS: Add a basic SSH responder test
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Adds a basic test that makes sure that a list of SSH public keys can be
+retrieved. This is to make sure we don't break the SSH integration later
+on.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3747
+
+Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
+(cherry picked from commit 804c5b538ad89a1a3897b93f39d716fa50530842)
+---
+ src/tests/intg/Makefile.am        |   1 +
+ src/tests/intg/test_ssh_pubkey.py | 232 ++++++++++++++++++++++++++++++
+ 2 files changed, 233 insertions(+)
+ create mode 100644 src/tests/intg/test_ssh_pubkey.py
+
+diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am
+index 9c5338261353f473d9051c0512c15a54ec38e1ec..a15022eb578394313155538898fe7cd7407eb9c0 100644
+--- a/src/tests/intg/Makefile.am
++++ b/src/tests/intg/Makefile.am
+@@ -36,6 +36,7 @@ dist_noinst_DATA = \
+     data/ad_schema.ldif \
+     test_pysss_nss_idmap.py \
+     test_infopipe.py \
++    test_ssh_pubkey.py \
+     $(NULL)
+ 
+ EXTRA_DIST = data/cwrap-dbus-system.conf.in
+diff --git a/src/tests/intg/test_ssh_pubkey.py b/src/tests/intg/test_ssh_pubkey.py
+new file mode 100644
+index 0000000000000000000000000000000000000000..fbf55566e341373873057ec4e3af1d7f83202aa7
+--- /dev/null
++++ b/src/tests/intg/test_ssh_pubkey.py
+@@ -0,0 +1,232 @@
++#
++# ssh public key integration test
++#
++# Copyright (c) 2018 Red Hat, Inc.
++#
++# This is free software; you can redistribute it and/or modify it
++# under the terms of the GNU General Public License as published by
++# the Free Software Foundation; version 2 only
++#
++# This program is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++# General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program.  If not, see <http://www.gnu.org/licenses/>.
++#
++
++import os
++import stat
++import signal
++import subprocess
++import time
++import ldap
++import ldap.modlist
++import pytest
++
++import config
++import ds_openldap
++import ent
++import ldap_ent
++from util import unindent, get_call_output
++
++LDAP_BASE_DN = "dc=example,dc=com"
++
++USER1_PUBKEY1 = "ssh-dss AAAAB3NzaC1kc3MAAACBAPMkvcU53RVhBtjwiC3IqeRIWR9Qwdv8\
++DmZzEsDD3Csd6jYxMsPZoXcPrHqwYcEj1s5MVqhdSFS0Cjz13e7gO6OMLInO3xMBSSFHjfp9RE1H\
++pgc4WisazzyJaW9EMkQo/DqvkFkKh31oqAmxcSbLAFJRg4TTIqm18qu8IRKS6m/RAAAAFQC97TA5\
++JSsMsaX1bRszC7y4PhMBvQAAAIEAt9Yo9v/h9W4nDbzUdkGwNRszlPEK+T12bJv0O9Fk6subD3Do\
++6A4Qru/Nr6voXoq8b018Wb7iFWvKOoz5uT/plWBKLXL2NN7ovTR+dUJIzvwurQZroukmU1EghNey\
++lkSHmDlxSoMK6Nh21uGu6l+b6x5pXNaZHMpsywG4kY8SoC0AAACAAWLHneEGvqkYA8La4Eob+Hjj\
++mAKilx8byxm3Kfb1XO+ZrR6XxadofZOaUYRMpPKgFjKAKPxJftPLiDjWM7lSe6h8df0dUMLVXt6m\
++eA83kE0uK5JOOGJfJDqmRed2YnfxUDNNFQGT4xFWGrNtYNbGyw9BWKbkooAsLqaO04zP3Rs= \
++user1@LDAP"
++
++USER1_PUBKEY2 = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAwHUUF3HPH+DkU6j8k7Q1wHG\
++RJY9NeLqSav3h95mTSCQYPSC7I9RTJ4OORgqCbEzrP/DYrrn4TtQ9dhRJar3ZY+F36SH5yFIXORb\
++lAIbFU+/anahBuFS9vHi1MqFPckGmwJ4QCpjQhdYxo1ro0e1RuGSaQNp/w9N6S/fDz4Cj4I99xDz\
++SeQeGHxYv0e60plQ8dUajmnaGmYRJHF9a6Ban7IWySActCja7eQP2zIRXEZMpuhl1E0U4y+gHTFI\
++gD3zQai3QrXm8RUrQURIJ0u6BlGS910OPbHqLpLTFWG08L8sNUcYzC+DY6yoCSO0n/Df3pVRS4C9\
++5Krf3FqppMTjdfQ== user1@LDAP"
++
++
++@pytest.fixture(scope="module")
++def ds_inst(request):
++    """LDAP server instance fixture"""
++    ds_inst = ds_openldap.DSOpenLDAP(
++        config.PREFIX, 10389, LDAP_BASE_DN,
++        "cn=admin", "Secret123"
++    )
++
++    try:
++        ds_inst.setup()
++    except:
++        ds_inst.teardown()
++        raise
++    request.addfinalizer(ds_inst.teardown)
++    return ds_inst
++
++
++@pytest.fixture(scope="module")
++def ldap_conn(request, ds_inst):
++    """LDAP server connection fixture"""
++    ldap_conn = ds_inst.bind()
++    ldap_conn.ds_inst = ds_inst
++    request.addfinalizer(ldap_conn.unbind_s)
++    return ldap_conn
++
++
++def create_ldap_entries(ldap_conn, ent_list=None):
++    """Add LDAP entries from ent_list"""
++    if ent_list is not None:
++        for entry in ent_list:
++            ldap_conn.add_s(entry[0], entry[1])
++
++
++def cleanup_ldap_entries(ldap_conn, ent_list=None):
++    """Remove LDAP entries added by create_ldap_entries"""
++    if ent_list is None:
++        for ou in ("Users", "Groups", "Netgroups", "Services", "Policies"):
++            for entry in ldap_conn.search_s("ou=" + ou + "," +
++                                            ldap_conn.ds_inst.base_dn,
++                                            ldap.SCOPE_ONELEVEL,
++                                            attrlist=[]):
++                ldap_conn.delete_s(entry[0])
++    else:
++        for entry in ent_list:
++            ldap_conn.delete_s(entry[0])
++
++
++def create_ldap_cleanup(request, ldap_conn, ent_list=None):
++    """Add teardown for removing all user/group LDAP entries"""
++    request.addfinalizer(lambda: cleanup_ldap_entries(ldap_conn, ent_list))
++
++
++def create_ldap_fixture(request, ldap_conn, ent_list=None):
++    """Add LDAP entries and add teardown for removing them"""
++    create_ldap_entries(ldap_conn, ent_list)
++    create_ldap_cleanup(request, ldap_conn, ent_list)
++
++
++SCHEMA_RFC2307_BIS = "rfc2307bis"
++
++
++def format_basic_conf(ldap_conn, schema):
++    """Format a basic SSSD configuration"""
++    schema_conf = "ldap_schema         = " + schema + "\n"
++    schema_conf += "ldap_group_object_class = groupOfNames\n"
++    return unindent("""\
++        [sssd]
++        domains             = LDAP
++        services            = nss, ssh
++
++        [nss]
++
++        [ssh]
++        debug_level=10
++
++        [domain/LDAP]
++        {schema_conf}
++        id_provider         = ldap
++        auth_provider       = ldap
++        ldap_uri            = {ldap_conn.ds_inst.ldap_url}
++        ldap_search_base    = {ldap_conn.ds_inst.base_dn}
++        ldap_sudo_use_host_filter = false
++        debug_level=10
++    """).format(**locals())
++
++
++def create_conf_file(contents):
++    """Create sssd.conf with specified contents"""
++    conf = open(config.CONF_PATH, "w")
++    conf.write(contents)
++    conf.close()
++    os.chmod(config.CONF_PATH, stat.S_IRUSR | stat.S_IWUSR)
++
++
++def cleanup_conf_file():
++    """Remove sssd.conf, if it exists"""
++    if os.path.lexists(config.CONF_PATH):
++        os.unlink(config.CONF_PATH)
++
++
++def create_conf_cleanup(request):
++    """Add teardown for removing sssd.conf"""
++    request.addfinalizer(cleanup_conf_file)
++
++
++def create_conf_fixture(request, contents):
++    """
++    Create sssd.conf with specified contents and add teardown for removing it
++    """
++    create_conf_file(contents)
++    create_conf_cleanup(request)
++
++
++def create_sssd_process():
++    """Start the SSSD process"""
++    if subprocess.call(["sssd", "-D", "-f"]) != 0:
++        raise Exception("sssd start failed")
++
++
++def get_sssd_pid():
++    pid_file = open(config.PIDFILE_PATH, "r")
++    pid = int(pid_file.read())
++    return pid
++
++
++def cleanup_sssd_process():
++    """Stop the SSSD process and remove its state"""
++    try:
++        pid = get_sssd_pid()
++        os.kill(pid, signal.SIGTERM)
++        while True:
++            try:
++                os.kill(pid, signal.SIGCONT)
++            except:
++                break
++            time.sleep(1)
++    except:
++        pass
++    for path in os.listdir(config.DB_PATH):
++        os.unlink(config.DB_PATH + "/" + path)
++    for path in os.listdir(config.MCACHE_PATH):
++        os.unlink(config.MCACHE_PATH + "/" + path)
++
++
++def create_sssd_fixture(request):
++    """Start SSSD and add teardown for stopping it and removing its state"""
++    create_sssd_process()
++    create_sssd_cleanup(request)
++
++
++def create_sssd_cleanup(request):
++    """Add teardown for stopping SSSD and removing its state"""
++    request.addfinalizer(cleanup_sssd_process)
++
++
++@pytest.fixture
++def add_user_with_ssh_key(request, ldap_conn):
++    ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn)
++    ent_list.add_user("user1", 1001, 2001,
++                      sshPubKey=(USER1_PUBKEY1, USER1_PUBKEY2))
++    ent_list.add_user("user2", 1002, 2001)
++    create_ldap_fixture(request, ldap_conn, ent_list)
++
++    conf = format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS)
++    create_conf_fixture(request, conf)
++    create_sssd_fixture(request)
++    return None
++
++
++def test_ssh_pubkey_retrieve(add_user_with_ssh_key):
++    """
++    Test that we can retrieve an SSH public key for a user who has one
++    and can't retrieve a key for a user who does not have one.
++    """
++    sshpubkey = get_call_output(["sss_ssh_authorizedkeys", "user1"])
++    assert sshpubkey == USER1_PUBKEY1 + '\n' + USER1_PUBKEY2 + '\n'
++
++    sshpubkey = get_call_output(["sss_ssh_authorizedkeys", "user2"])
++    assert len(sshpubkey) == 0
+-- 
+2.17.1
+
diff --git a/SOURCES/0012-SSH-Do-not-exit-abruptly-if-SSHD-closes-its-end-of-t.patch b/SOURCES/0012-SSH-Do-not-exit-abruptly-if-SSHD-closes-its-end-of-t.patch
new file mode 100644
index 0000000..b212cbc
--- /dev/null
+++ b/SOURCES/0012-SSH-Do-not-exit-abruptly-if-SSHD-closes-its-end-of-t.patch
@@ -0,0 +1,88 @@
+From 60f868ac16c4678d60f17d62fa3b47534d4d07cb Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 28 May 2018 21:41:49 +0200
+Subject: [PATCH] SSH: Do not exit abruptly if SSHD closes its end of the pipe
+ before reading all the SSH keys
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3747
+
+Before writing the keys to sshd, ignore SIGPIPE so that if the pipe
+towards the authorizedkeys helper is closed, the sss_ssh_authorizedkeys
+helper is not terminated with SIGPIPE, but instead proceeds and then the
+write(2) calls would non-terminally fail with EPIPE.
+
+Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
+(cherry picked from commit cb138d7d060611e891d341db08477e41f9a3d17d)
+---
+ src/sss_client/ssh/sss_ssh_authorizedkeys.c | 35 ++++++++++++++++++++-
+ 1 file changed, 34 insertions(+), 1 deletion(-)
+
+diff --git a/src/sss_client/ssh/sss_ssh_authorizedkeys.c b/src/sss_client/ssh/sss_ssh_authorizedkeys.c
+index 782a9f44379bff5346c896b3e03570720632c0be..b0280fbf8b0ed0501d792973241b826fc4a7a04d 100644
+--- a/src/sss_client/ssh/sss_ssh_authorizedkeys.c
++++ b/src/sss_client/ssh/sss_ssh_authorizedkeys.c
+@@ -21,6 +21,7 @@
+ #include <stdio.h>
+ #include <talloc.h>
+ #include <popt.h>
++#include <signal.h>
+ 
+ #include "util/util.h"
+ #include "util/crypto/sss_crypto.h"
+@@ -99,8 +100,16 @@ int main(int argc, const char **argv)
+         goto fini;
+     }
+ 
++    /* if sshd closes its end of the pipe, we don't want sss_ssh_authorizedkeys
++     * to exit abruptly, but to finish gracefully instead because the valid
++     * key can be present in the data already written
++     */
++    signal(SIGPIPE, SIG_IGN);
++
+     /* print results */
+     for (i = 0; i < ent->num_pubkeys; i++) {
++        char *repr_break = NULL;
++
+         ret = sss_ssh_format_pubkey(mem_ctx, &ent->pubkeys[i], &repr);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE,
+@@ -109,7 +118,31 @@ int main(int argc, const char **argv)
+             continue;
+         }
+ 
+-        printf("%s\n", repr);
++        /* OpenSSH expects a linebreak after each key */
++        repr_break = talloc_asprintf(mem_ctx, "%s\n", repr);
++        talloc_zfree(repr);
++        if (repr_break == NULL) {
++            ret = ENOMEM;
++            goto fini;
++        }
++
++        ret = sss_atomic_write_s(STDOUT_FILENO, repr_break, strlen(repr_break));
++        /* Avoid spiking memory with too many large keys */
++        talloc_zfree(repr_break);
++        if (ret < 0) {
++            ret = errno;
++            if (ret == EPIPE) {
++                DEBUG(SSSDBG_MINOR_FAILURE,
++                      "SSHD closed the pipe before all keys could be written\n");
++                /* Return 0 so that openssh doesn't abort pubkey auth */
++                ret = 0;
++                goto fini;
++            }
++            DEBUG(SSSDBG_CRIT_FAILURE,
++                  "sss_atomic_write_s() failed (%d): %s\n",
++                  ret, strerror(ret));
++            goto fini;
++        }
+     }
+ 
+     ret = EXIT_SUCCESS;
+-- 
+2.17.1
+
diff --git a/SOURCES/0012-sudo-always-use-srv_opts-from-id-context.patch b/SOURCES/0012-sudo-always-use-srv_opts-from-id-context.patch
deleted file mode 100644
index 8c782f9..0000000
--- a/SOURCES/0012-sudo-always-use-srv_opts-from-id-context.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From 7738a74e6878536e155d9d589e7ec727c135f5a0 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 19 Oct 2017 10:39:21 +0200
-Subject: [PATCH 12/21] sudo: always use srv_opts from id context
-
-Prior this patch, we remember id_ctx->srv_opts in sudo request to switch
-the latest usn values. This works fine most of the time but it may cause
-a crash.
-
-If we have two concurrent sudo refresh and one of these fails, it causes
-failover to try the next server and possibly replacing the old srv_opts
-with new one and it causes an access after free in the other refresh.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3562
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 2ee201dcf6bbe52abbbed3c2fc4c35ca2e0c8a43)
----
- src/providers/ldap/sdap_async_sudo.c | 7 +------
- 1 file changed, 1 insertion(+), 6 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_async_sudo.c b/src/providers/ldap/sdap_async_sudo.c
-index 3c69837fda313b2645c3a8497252670312f600ea..88a387422d5c9ae86cea583bb38dadf90cba37f3 100644
---- a/src/providers/ldap/sdap_async_sudo.c
-+++ b/src/providers/ldap/sdap_async_sudo.c
-@@ -279,7 +279,6 @@ done:
- struct sdap_sudo_refresh_state {
-     struct sdap_sudo_ctx *sudo_ctx;
-     struct tevent_context *ev;
--    struct sdap_server_opts *srv_opts;
-     struct sdap_options *opts;
-     struct sdap_id_op *sdap_op;
-     struct sysdb_ctx *sysdb;
-@@ -405,9 +404,6 @@ static void sdap_sudo_refresh_connect_done(struct tevent_req *subreq)
- 
-     DEBUG(SSSDBG_TRACE_FUNC, "SUDO LDAP connection successful\n");
- 
--    /* Obtain srv_opts here in case of first connection. */
--    state->srv_opts = state->sudo_ctx->id_ctx->srv_opts;
--
-     /* Renew host information if needed. */
-     if (state->sudo_ctx->run_hostinfo) {
-         subreq = sdap_sudo_get_hostinfo_send(state, state->opts,
-@@ -586,7 +582,6 @@ static void sdap_sudo_refresh_done(struct tevent_req *subreq)
-         goto done;
-     }
- 
--
-     /* start transaction */
-     ret = sysdb_transaction_start(state->sysdb);
-     if (ret != EOK) {
-@@ -621,7 +616,7 @@ static void sdap_sudo_refresh_done(struct tevent_req *subreq)
-     /* remember new usn */
-     ret = sysdb_get_highest_usn(state, rules, rules_count, &usn);
-     if (ret == EOK) {
--        sdap_sudo_set_usn(state->srv_opts, usn);
-+        sdap_sudo_set_usn(state->sudo_ctx->id_ctx->srv_opts, usn);
-     } else {
-         DEBUG(SSSDBG_MINOR_FAILURE, "Unable to get highest USN [%d]: %s\n",
-               ret, sss_strerror(ret));
--- 
-2.13.5
-
diff --git a/SOURCES/0013-AD-Remember-last-site-discovered.patch b/SOURCES/0013-AD-Remember-last-site-discovered.patch
deleted file mode 100644
index f1ad8c2..0000000
--- a/SOURCES/0013-AD-Remember-last-site-discovered.patch
+++ /dev/null
@@ -1,109 +0,0 @@
-From 020d7f12f7c57e3a5c8f844de2b2d0cad020e662 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 18 Oct 2017 15:20:34 +0200
-Subject: [PATCH 13/21] AD: Remember last site discovered
-
-To discover Active Directory site for a client we must first contact any
-directory controller for an LDAP ping. This is done by searching
-domain-wide DNS tree which may however contain servers that are not
-reachable from current site and than we face long timeouts or failure.
-
-This patch makes sssd remember the last successfuly discovered site
-and use this for DNS search to lookup a site and forest again similar
-to what we do when ad_site option is set.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3265
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit f54d202db528207d7794870aabef0656b20369f1)
----
- src/providers/ad/ad_srv.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 43 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c
-index ff01ee95c4d2c6875a989394489f1a0495cc3003..be1ba0f237add894566ae713ce5e29fd202d414c 100644
---- a/src/providers/ad/ad_srv.c
-+++ b/src/providers/ad/ad_srv.c
-@@ -481,6 +481,7 @@ struct ad_srv_plugin_ctx {
-     const char *hostname;
-     const char *ad_domain;
-     const char *ad_site_override;
-+    const char *current_site;
- };
- 
- struct ad_srv_plugin_ctx *
-@@ -518,6 +519,11 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
-         if (ctx->ad_site_override == NULL) {
-             goto fail;
-         }
-+
-+        ctx->current_site = talloc_strdup(ctx, ad_site_override);
-+        if (ctx->current_site == NULL) {
-+            goto fail;
-+        }
-     }
- 
-     return ctx;
-@@ -527,6 +533,32 @@ fail:
-     return NULL;
- }
- 
-+static errno_t
-+ad_srv_plugin_ctx_switch_site(struct ad_srv_plugin_ctx *ctx,
-+                              const char *new_site)
-+{
-+    const char *site;
-+    errno_t ret;
-+
-+    if (new_site == NULL) {
-+        return EOK;
-+    }
-+
-+    if (ctx->current_site != NULL && strcmp(ctx->current_site, new_site) == 0) {
-+        return EOK;
-+    }
-+
-+    site = talloc_strdup(ctx, new_site);
-+    if (site == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    talloc_zfree(ctx->current_site);
-+    ctx->current_site = site;
-+
-+    return EOK;
-+}
-+
- struct ad_srv_plugin_state {
-     struct tevent_context *ev;
-     struct ad_srv_plugin_ctx *ctx;
-@@ -613,7 +645,7 @@ struct tevent_req *ad_srv_plugin_send(TALLOC_CTX *mem_ctx,
- 
-     subreq = ad_get_dc_servers_send(state, ev, ctx->be_res->resolv,
-                                     state->discovery_domain,
--                                    state->ctx->ad_site_override);
-+                                    state->ctx->current_site);
-     if (subreq == NULL) {
-         ret = ENOMEM;
-         goto immediately;
-@@ -709,6 +741,16 @@ static void ad_srv_plugin_site_done(struct tevent_req *subreq)
-     backup_domain = NULL;
- 
-     if (ret == EOK) {
-+        /* Remember current site so it can be used during next lookup so
-+         * we can contact directory controllers within a known reachable
-+         * site first. */
-+        ret = ad_srv_plugin_ctx_switch_site(state->ctx, state->site);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set site [%d]: %s\n",
-+                  ret, sss_strerror(ret));
-+            goto done;
-+        }
-+
-         if (strcmp(state->service, "gc") == 0) {
-             if (state->forest != NULL) {
-                 if (state->site != NULL) {
--- 
-2.13.5
-
diff --git a/SOURCES/0013-TESTS-Add-a-helper-binary-that-can-trigger-the-SIGPI.patch b/SOURCES/0013-TESTS-Add-a-helper-binary-that-can-trigger-the-SIGPI.patch
new file mode 100644
index 0000000..a9da871
--- /dev/null
+++ b/SOURCES/0013-TESTS-Add-a-helper-binary-that-can-trigger-the-SIGPI.patch
@@ -0,0 +1,213 @@
+From ef28a3bdc50d0da6fab86b0d27e4c548ac61a749 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 28 May 2018 21:49:41 +0200
+Subject: [PATCH] TESTS: Add a helper binary that can trigger the SIGPIPE to
+ authorizedkeys
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Adds a test tool that simulates the behaviour of OpenSSH in the sense
+that it starts to read the output from the sss_ssh_authorizedkeys tool,
+but then closes the pipe before reading the whole output.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3747
+
+Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
+(cherry picked from commit 909c16edb26a3c48b10a49e7919a35d13d31c52e)
+---
+ Makefile.am                 |  15 +++-
+ src/tests/test_ssh_client.c | 133 ++++++++++++++++++++++++++++++++++++
+ 2 files changed, 147 insertions(+), 1 deletion(-)
+ create mode 100644 src/tests/test_ssh_client.c
+
+diff --git a/Makefile.am b/Makefile.am
+index 9055130ed74057987795285c243ff47584cf8316..99974cf0e94e1ec6086a53585042653ec5966c2c 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -331,6 +331,7 @@ endif   # HAVE_CMOCKA
+ check_PROGRAMS = \
+     stress-tests \
+     krb5-child-test \
++    test_ssh_client \
+     $(non_interactive_cmocka_based_tests) \
+     $(non_interactive_check_based_tests)
+ 
+@@ -2291,6 +2292,18 @@ krb5_child_test_LDADD = \
+     $(SSSD_INTERNAL_LTLIBS) \
+     libsss_test_common.la
+ 
++test_ssh_client_SOURCES = \
++    src/tests/test_ssh_client.c \
++    $(NULL)
++test_ssh_client_CFLAGS = \
++    $(AM_CFLAGS) \
++    -DSSH_CLIENT_DIR=\"$(abs_top_builddir)\" \
++    $(NULL)
++test_ssh_client_LDADD = \
++    $(SSSD_INTERNAL_LTLIBS) \
++    $(SSSD_LIBS) \
++    $(NULL)
++
+ if BUILD_DBUS_TESTS
+ 
+ sbus_tests_SOURCES = \
+@@ -3446,7 +3459,6 @@ test_iobuf_LDADD = \
+     $(SSSD_LIBS) \
+     $(NULL)
+ 
+-
+ EXTRA_simple_access_tests_DEPENDENCIES = \
+     $(ldblib_LTLIBRARIES)
+ simple_access_tests_SOURCES = \
+@@ -3655,6 +3667,7 @@ intgcheck-prepare:
+ 	    $(INTGCHECK_CONFIGURE_FLAGS) \
+ 	    CFLAGS="-O2 -g $$CFLAGS -DKCM_PEER_UID=$$(id -u)"; \
+ 	$(MAKE) $(AM_MAKEFLAGS) ; \
++	$(MAKE) $(AM_MAKEFLAGS) test_ssh_client; \
+ 	: Force single-thread install to workaround concurrency issues; \
+ 	$(MAKE) $(AM_MAKEFLAGS) -j1 install; \
+ 	: Remove .la files from LDB module directory to avoid loader warnings; \
+diff --git a/src/tests/test_ssh_client.c b/src/tests/test_ssh_client.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..8f963941f3249561178436d6f6dfc376780a4cda
+--- /dev/null
++++ b/src/tests/test_ssh_client.c
+@@ -0,0 +1,133 @@
++/*
++    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 <popt.h>
++#include <sys/wait.h>
++#include "util/util.h"
++
++#ifdef SSH_CLIENT_DIR
++#define SSH_AK_CLIENT_PATH SSH_CLIENT_DIR"/sss_ssh_authorizedkeys"
++#else
++#error "The path to the ssh authorizedkeys helper is not defined"
++#endif /* SSH_CLIENT_DIR */
++
++int main(int argc, const char *argv[])
++{
++    poptContext pc;
++    int opt;
++    struct poptOption long_options[] = {
++        POPT_AUTOHELP
++        SSSD_DEBUG_OPTS
++        POPT_TABLEEND
++    };
++    struct stat sb;
++    int ret;
++    int status;
++    int p[2];
++    pid_t pid;
++    const char *pc_user = NULL;
++    char *av[3];
++    char buf[5]; /* Ridiculously small buffer by design */
++
++    /* 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);
++    poptSetOtherOptionHelp(pc, "USER");
++    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 3;
++        }
++    }
++
++    pc_user = poptGetArg(pc);
++    if (pc_user == NULL) {
++        fprintf(stderr, "No user specified\n");
++        return 3;
++    }
++
++    poptFreeContext(pc);
++
++    DEBUG_CLI_INIT(debug_level);
++
++    ret = stat(SSH_AK_CLIENT_PATH, &sb);
++    if (ret != 0) {
++        ret = errno;
++        DEBUG(SSSDBG_CRIT_FAILURE,
++              "Could not stat %s [%d]: %s\n",
++              SSH_AK_CLIENT_PATH, ret, strerror(ret));
++        return 3;
++    }
++
++    ret = pipe(p);
++    if (ret != 0) {
++        perror("pipe");
++        return 3;
++    }
++
++    switch (pid = fork()) {
++    case -1:
++        ret = errno;
++        close(p[0]);
++        close(p[1]);
++        DEBUG(SSSDBG_CRIT_FAILURE, "fork failed: %d\n", ret);
++        return 3;
++    case 0:
++        /* child */
++        av[0] = discard_const(SSH_AK_CLIENT_PATH);
++        av[1] = discard_const(pc_user);
++        av[2] = NULL;
++
++        close(p[0]);
++        ret = dup2(p[1], STDOUT_FILENO);
++        if (ret == -1) {
++            perror("dup2");
++            return 3;
++        }
++
++        execv(av[0], av);
++        return 3;
++    default:
++        /* parent */
++        break;
++    }
++
++    close(p[1]);
++    read(p[0], buf, sizeof(buf));
++    close(p[0]);
++
++    pid = waitpid(pid, &status, 0);
++    if (pid == -1) {
++        perror("waitpid");
++        return 3;
++    }
++
++    if (WIFEXITED(status)) {
++        printf("sss_ssh_authorizedkeys exited with return code %d\n", WEXITSTATUS(status));
++        return 0;
++    } else if (WIFSIGNALED(status)) {
++        printf("sss_ssh_authorizedkeys exited with signal %d\n", WTERMSIG(status));
++        return 1;
++    }
++
++    printf("sss_ssh_authorizedkeys exited for another reason\n");
++    return 2;
++}
+-- 
+2.17.1
+
diff --git a/SOURCES/0014-TESTS-Add-a-regression-test-for-SIGHUP-handling-in-s.patch b/SOURCES/0014-TESTS-Add-a-regression-test-for-SIGHUP-handling-in-s.patch
new file mode 100644
index 0000000..ccb7133
--- /dev/null
+++ b/SOURCES/0014-TESTS-Add-a-regression-test-for-SIGHUP-handling-in-s.patch
@@ -0,0 +1,94 @@
+From 0adf4f50e9773afda2dc422b04163f19d946c150 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 19 Jun 2018 11:39:02 +0200
+Subject: [PATCH] TESTS: Add a regression test for SIGHUP handling in
+ sss_ssh_authorizedkeys
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+A regression test for:
+https://pagure.io/SSSD/sssd/issue/3747
+
+Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
+(cherry picked from commit 4cc3c1a1b1070c12bcc4351880d8207e47b37496)
+---
+ src/tests/intg/test_ssh_pubkey.py | 58 +++++++++++++++++++++++++++++++
+ 1 file changed, 58 insertions(+)
+
+diff --git a/src/tests/intg/test_ssh_pubkey.py b/src/tests/intg/test_ssh_pubkey.py
+index fbf55566e341373873057ec4e3af1d7f83202aa7..8fb41c62d87ec210c9aad8582023fe1cb00f2b4e 100644
+--- a/src/tests/intg/test_ssh_pubkey.py
++++ b/src/tests/intg/test_ssh_pubkey.py
+@@ -24,6 +24,8 @@ import time
+ import ldap
+ import ldap.modlist
+ import pytest
++import string
++import random
+ 
+ import config
+ import ds_openldap
+@@ -230,3 +232,59 @@ def test_ssh_pubkey_retrieve(add_user_with_ssh_key):
+ 
+     sshpubkey = get_call_output(["sss_ssh_authorizedkeys", "user2"])
+     assert len(sshpubkey) == 0
++
++
++@pytest.fixture()
++def sighup_client(request):
++    test_ssh_cli_path = os.path.join(config.ABS_BUILDDIR,
++                                     "..", "..", "..", "test_ssh_client")
++    assert os.access(test_ssh_cli_path, os.X_OK)
++    return test_ssh_cli_path
++
++
++@pytest.fixture
++def add_user_with_many_keys(request, ldap_conn):
++    # Generate a large list of unique ssh pubkeys
++    pubkey_list = []
++    while len(pubkey_list) < 50:
++        new_pubkey = list(USER1_PUBKEY1)
++        new_pubkey[10] = random.choice(string.ascii_uppercase)
++        new_pubkey[11] = random.choice(string.ascii_uppercase)
++        new_pubkey[12] = random.choice(string.ascii_uppercase)
++        str_new_pubkey = ''.join(c for c in new_pubkey)
++        if str_new_pubkey in pubkey_list:
++            continue
++        pubkey_list.append(str_new_pubkey)
++
++    ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn)
++    ent_list.add_user("user1", 1001, 2001, sshPubKey=pubkey_list)
++    create_ldap_fixture(request, ldap_conn, ent_list)
++
++    conf = format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS)
++    create_conf_fixture(request, conf)
++    create_sssd_fixture(request)
++    return None
++
++
++def test_ssh_sighup(add_user_with_many_keys, sighup_client):
++    """
++    A regression test for https://pagure.io/SSSD/sssd/issue/3747
++
++    OpenSSH can close its end of the pipe towards sss_ssh_authorizedkeys
++    before all of the output is read. In that case, older versions
++    of sss_ssh_authorizedkeys were receiving a SIGPIPE
++    """
++    cli_path = sighup_client
++
++    # python actually does the sensible, but unexpected (for a C programmer)
++    # thing and handles SIGPIPE. In order to reproduce the bug, we need
++    # to unset the SIGPIPE handler
++    signal.signal(signal.SIGPIPE, signal.SIG_DFL)
++
++    process = subprocess.Popen([cli_path, "user1"],
++                               stdout=subprocess.PIPE,
++                               stderr=subprocess.PIPE)
++    _, _ = process.communicate()
++    # If the test tool detects that sss_ssh_authorizedkeys was killed with a
++    # signal, it would have returned 1
++    assert process.returncode == 0
+-- 
+2.17.1
+
diff --git a/SOURCES/0014-sysdb-add-functions-to-get-set-client-site.patch b/SOURCES/0014-sysdb-add-functions-to-get-set-client-site.patch
deleted file mode 100644
index 7fc6ff1..0000000
--- a/SOURCES/0014-sysdb-add-functions-to-get-set-client-site.patch
+++ /dev/null
@@ -1,206 +0,0 @@
-From fafc90b8c225fd77e30e94d985c72f5f2980e59e Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Tue, 24 Oct 2017 12:09:39 +0200
-Subject: [PATCH 14/21] sysdb: add functions to get/set client site
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit e16539779668dacff868999bd59dbf33e3eab872)
----
- src/db/sysdb.h                           |  10 +++
- src/db/sysdb_subdomains.c                | 108 +++++++++++++++++++++++++++++++
- src/tests/cmocka/test_sysdb_subdomains.c |  28 ++++++++
- 3 files changed, 146 insertions(+)
-
-diff --git a/src/db/sysdb.h b/src/db/sysdb.h
-index fbbe321072385bd43353ef2f7d0e30667887d128..4192f9085d941814eccd2ac60ce8fb6d4e1bfa67 100644
---- a/src/db/sysdb.h
-+++ b/src/db/sysdb.h
-@@ -154,6 +154,7 @@
- #define SYSDB_SUBDOMAIN_FOREST "memberOfForest"
- #define SYSDB_SUBDOMAIN_TRUST_DIRECTION "trustDirection"
- #define SYSDB_UPN_SUFFIXES "upnSuffixes"
-+#define SYSDB_SITE "site"
- 
- #define SYSDB_BASE_ID "baseID"
- #define SYSDB_ID_RANGE_SIZE "idRangeSize"
-@@ -509,6 +510,15 @@ errno_t sysdb_domain_update_domain_resolution_order(
-                                         const char *domain_name,
-                                         const char *domain_resolution_order);
- 
-+errno_t
-+sysdb_get_site(TALLOC_CTX *mem_ctx,
-+               struct sss_domain_info *dom,
-+               const char **_site);
-+
-+errno_t
-+sysdb_set_site(struct sss_domain_info *dom,
-+               const char *site);
-+
- errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb,
-                               const char *name, const char *realm,
-                               const char *flat_name, const char *domain_id,
-diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
-index 2789cc4949fb7be9ad272d7613ed18a64fa8a20a..cb5de1afe3e8c9692789c5d2679eb3a4e6e1cdb2 100644
---- a/src/db/sysdb_subdomains.c
-+++ b/src/db/sysdb_subdomains.c
-@@ -1284,3 +1284,111 @@ done:
-     talloc_free(tmp_ctx);
-     return ret;
- }
-+
-+errno_t
-+sysdb_get_site(TALLOC_CTX *mem_ctx,
-+               struct sss_domain_info *dom,
-+               const char **_site)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    struct ldb_res *res;
-+    struct ldb_dn *dn;
-+    const char *attrs[] = { SYSDB_SITE, NULL };
-+    errno_t ret;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    dn = ldb_dn_new_fmt(tmp_ctx, dom->sysdb->ldb, SYSDB_DOM_BASE, dom->name);
-+    if (dn == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = ldb_search(dom->sysdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE,
-+                     attrs, NULL);
-+    if (ret != LDB_SUCCESS) {
-+        ret = sysdb_error_to_errno(ret);
-+        goto done;
-+    }
-+
-+    if (res->count == 0) {
-+        *_site = NULL;
-+        ret = EOK;
-+        goto done;
-+    } else if (res->count != 1) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Got more than one reply for base search!\n");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    *_site = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SITE, NULL);
-+    talloc_steal(mem_ctx, *_site);
-+
-+    ret = EOK;
-+
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
-+errno_t
-+sysdb_set_site(struct sss_domain_info *dom,
-+               const char *site)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    struct ldb_message *msg;
-+    struct ldb_dn *dn;
-+    errno_t ret;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    dn = ldb_dn_new_fmt(tmp_ctx, dom->sysdb->ldb, SYSDB_DOM_BASE, dom->name);
-+    if (dn == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    msg = ldb_msg_new(tmp_ctx);
-+    if (msg == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    msg->dn = dn;
-+
-+    ret = ldb_msg_add_empty(msg, SYSDB_SITE, LDB_FLAG_MOD_REPLACE, NULL);
-+    if (ret != LDB_SUCCESS) {
-+        ret = sysdb_error_to_errno(ret);
-+        goto done;
-+    }
-+
-+    if (site != NULL) {
-+        ret = ldb_msg_add_string(msg, SYSDB_SITE, site);
-+        if (ret != LDB_SUCCESS) {
-+            ret = sysdb_error_to_errno(ret);
-+            goto done;
-+        }
-+    }
-+
-+    ret = ldb_modify(dom->sysdb->ldb, msg);
-+    if (ret != LDB_SUCCESS) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "ldb_modify()_failed: [%s][%d][%s]\n",
-+              ldb_strerror(ret), ret, ldb_errstring(dom->sysdb->ldb));
-+        ret = sysdb_error_to_errno(ret);
-+        goto done;
-+    }
-+
-+    ret = EOK;
-+
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-diff --git a/src/tests/cmocka/test_sysdb_subdomains.c b/src/tests/cmocka/test_sysdb_subdomains.c
-index 84bcdc17b39dbc8822097c2006f157a09ea5e466..f8e3e1d915dba0f3a79adbf5af733980bf23a265 100644
---- a/src/tests/cmocka/test_sysdb_subdomains.c
-+++ b/src/tests/cmocka/test_sysdb_subdomains.c
-@@ -513,6 +513,31 @@ static void test_sysdb_link_ad_multidom(void **state)
- 
- }
- 
-+static void test_sysdb_set_and_get_site(void **state)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    struct subdom_test_ctx *test_ctx =
-+        talloc_get_type(*state, struct subdom_test_ctx);
-+    const char *site;
-+    errno_t ret;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    assert_non_null(test_ctx);
-+
-+    ret = sysdb_get_site(test_ctx, test_ctx->tctx->dom, &site);
-+    assert_int_equal(ret, EOK);
-+    assert_null(site);
-+
-+    ret = sysdb_set_site(test_ctx->tctx->dom, "TestSite");
-+    assert_int_equal(ret, EOK);
-+
-+    ret = sysdb_get_site(tmp_ctx, test_ctx->tctx->dom, &site);
-+    assert_int_equal(ret, EOK);
-+    assert_string_equal(site, "TestSite");
-+
-+    talloc_free(tmp_ctx);
-+}
-+
- int main(int argc, const char *argv[])
- {
-     int rv;
-@@ -546,6 +571,9 @@ int main(int argc, const char *argv[])
-         cmocka_unit_test_setup_teardown(test_sysdb_link_ad_multidom,
-                                         test_sysdb_subdom_setup,
-                                         test_sysdb_subdom_teardown),
-+        cmocka_unit_test_setup_teardown(test_sysdb_set_and_get_site,
-+                                        test_sysdb_subdom_setup,
-+                                        test_sysdb_subdom_teardown),
-     };
- 
-     /* Set debug level to invalid value so we can deside if -d 0 was used. */
--- 
-2.13.5
-
diff --git a/SOURCES/0015-AD-Remember-last-site-discovered-in-sysdb.patch b/SOURCES/0015-AD-Remember-last-site-discovered-in-sysdb.patch
deleted file mode 100644
index 9c14628..0000000
--- a/SOURCES/0015-AD-Remember-last-site-discovered-in-sysdb.patch
+++ /dev/null
@@ -1,161 +0,0 @@
-From 1be48c91f3d80b51dc2361217f5c840656e0b088 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Wed, 1 Nov 2017 14:57:17 +0100
-Subject: [PATCH 15/21] AD: Remember last site discovered in sysdb
-
-This can speed up sssd startup.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3265
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit fb0431b13a9fcd8ac31e622503acbd10d2b73ac9)
----
- src/db/sysdb_subdomains.c                 |  2 +-
- src/providers/ad/ad_init.c                |  2 +-
- src/providers/ad/ad_srv.c                 | 21 +++++++++++++++++++++
- src/providers/ad/ad_srv.h                 |  1 +
- src/providers/ad/ad_subdomains.c          |  2 +-
- src/providers/ipa/ipa_subdomains_server.c |  2 +-
- 6 files changed, 26 insertions(+), 4 deletions(-)
-
-diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
-index cb5de1afe3e8c9692789c5d2679eb3a4e6e1cdb2..353561765904efe4bd698c38949a1b290ecf0b80 100644
---- a/src/db/sysdb_subdomains.c
-+++ b/src/db/sysdb_subdomains.c
-@@ -1291,7 +1291,7 @@ sysdb_get_site(TALLOC_CTX *mem_ctx,
-                const char **_site)
- {
-     TALLOC_CTX *tmp_ctx;
--    struct ldb_res *res;
-+    struct ldb_result *res;
-     struct ldb_dn *dn;
-     const char *attrs[] = { SYSDB_SITE, NULL };
-     errno_t ret;
-diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
-index 131e960d4c623398506f834742400df9c786b86b..e62025d4acd24844a5c7082d00c597516f35de16 100644
---- a/src/providers/ad/ad_init.c
-+++ b/src/providers/ad/ad_init.c
-@@ -199,7 +199,7 @@ static errno_t ad_init_srv_plugin(struct be_ctx *be_ctx,
-         return EOK;
-     }
- 
--    srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res,
-+    srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx, be_ctx->be_res,
-                                      default_host_dbs, ad_options->id,
-                                      hostname, ad_domain,
-                                      ad_site_override);
-diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c
-index be1ba0f237add894566ae713ce5e29fd202d414c..4fa1668605e131b2e31802b1401f49fc6e00a23b 100644
---- a/src/providers/ad/ad_srv.c
-+++ b/src/providers/ad/ad_srv.c
-@@ -34,6 +34,7 @@
- #include "providers/fail_over_srv.h"
- #include "providers/ldap/sdap.h"
- #include "providers/ldap/sdap_async.h"
-+#include "db/sysdb.h"
- 
- #define AD_SITE_DOMAIN_FMT "%s._sites.%s"
- 
-@@ -475,6 +476,7 @@ int ad_get_client_site_recv(TALLOC_CTX *mem_ctx,
- }
- 
- struct ad_srv_plugin_ctx {
-+    struct be_ctx *be_ctx;
-     struct be_resolv_ctx *be_res;
-     enum host_database *host_dbs;
-     struct sdap_options *opts;
-@@ -486,6 +488,7 @@ struct ad_srv_plugin_ctx {
- 
- struct ad_srv_plugin_ctx *
- ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
-+                       struct be_ctx *be_ctx,
-                        struct be_resolv_ctx *be_res,
-                        enum host_database *host_dbs,
-                        struct sdap_options *opts,
-@@ -494,12 +497,14 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
-                        const char *ad_site_override)
- {
-     struct ad_srv_plugin_ctx *ctx = NULL;
-+    errno_t ret;
- 
-     ctx = talloc_zero(mem_ctx, struct ad_srv_plugin_ctx);
-     if (ctx == NULL) {
-         return NULL;
-     }
- 
-+    ctx->be_ctx = be_ctx;
-     ctx->be_res = be_res;
-     ctx->host_dbs = host_dbs;
-     ctx->opts = opts;
-@@ -524,6 +529,15 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
-         if (ctx->current_site == NULL) {
-             goto fail;
-         }
-+    } else {
-+        ret = sysdb_get_site(ctx, be_ctx->domain, &ctx->current_site);
-+        if (ret != EOK) {
-+            /* Not fatal. */
-+            DEBUG(SSSDBG_MINOR_FAILURE,
-+                  "Unable to get current site from cache [%d]: %s\n",
-+                  ret, sss_strerror(ret));
-+            ctx->current_site = NULL;
-+        }
-     }
- 
-     return ctx;
-@@ -556,6 +570,13 @@ ad_srv_plugin_ctx_switch_site(struct ad_srv_plugin_ctx *ctx,
-     talloc_zfree(ctx->current_site);
-     ctx->current_site = site;
- 
-+    ret = sysdb_set_site(ctx->be_ctx->domain, ctx->current_site);
-+    if (ret != EOK) {
-+        /* Not fatal. */
-+        DEBUG(SSSDBG_MINOR_FAILURE, "Unable to store site information "
-+              "[%d]: %s\n", ret, sss_strerror(ret));
-+    }
-+
-     return EOK;
- }
- 
-diff --git a/src/providers/ad/ad_srv.h b/src/providers/ad/ad_srv.h
-index ae5efe44755fa09f74064014cce749e35b1831da..fddef686762e57bb95d648247131d39a797aa516 100644
---- a/src/providers/ad/ad_srv.h
-+++ b/src/providers/ad/ad_srv.h
-@@ -25,6 +25,7 @@ struct ad_srv_plugin_ctx;
- 
- struct ad_srv_plugin_ctx *
- ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
-+                       struct be_ctx *be_ctx,
-                        struct be_resolv_ctx *be_res,
-                        enum host_database *host_dbs,
-                        struct sdap_options *opts,
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index 280aa54c23bf61e60d23ea91bd44a39f9f43d155..3fb9b950f171d85817cce35ac92ad7c4974ccb68 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -245,7 +245,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
-     ad_options->id_ctx = ad_id_ctx;
- 
-     /* use AD plugin */
--    srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res,
-+    srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx, be_ctx->be_res,
-                                      default_host_dbs,
-                                      ad_id_ctx->ad_options->id,
-                                      hostname,
-diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c
-index 10166d162f746fde176e6c7c2bfbe3906b1bfddc..d670a156b37608d20d49d79131138f02e4abf82b 100644
---- a/src/providers/ipa/ipa_subdomains_server.c
-+++ b/src/providers/ipa/ipa_subdomains_server.c
-@@ -305,7 +305,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx,
-     ad_site_override = dp_opt_get_string(ad_options->basic, AD_SITE);
- 
-     /* use AD plugin */
--    srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res,
-+    srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx, be_ctx->be_res,
-                                      default_host_dbs,
-                                      ad_id_ctx->ad_options->id,
-                                      id_ctx->server_mode->hostname,
--- 
-2.13.5
-
diff --git a/SOURCES/0015-Revert-LDAP-IPA-add-local-email-address-to-aliases.patch b/SOURCES/0015-Revert-LDAP-IPA-add-local-email-address-to-aliases.patch
new file mode 100644
index 0000000..fb6b1da
--- /dev/null
+++ b/SOURCES/0015-Revert-LDAP-IPA-add-local-email-address-to-aliases.patch
@@ -0,0 +1,141 @@
+From 9efaade255e59b4a2f5cff2ab78c1db61132a40a Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 21 Jun 2018 12:27:32 +0200
+Subject: [PATCH] Revert "LDAP/IPA: add local email address to aliases"
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This reverts commit 9a310913d696d190db14c625080678db853a33fd.
+
+Storing the e-mail address as a nameAlias was a performance optimization
+to avoid having to fall back to the UPN lookup, but had the disadvantage
+of returning multiple results for cases where an e-mail address is the
+same as a user's fully qualified name.
+
+Since the e-mail lookups would still work without this optimization,
+just after one more lookup, let's revert the patch.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3607
+
+Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
+(cherry picked from commit b0ec3875da281a9c29eda2cb19c1026510866d5b)
+
+DOWNSTREAM:
+Resolves: rhbz#1527662 - Handle conflicting e-mail addresses more gracefully
+---
+ src/providers/ipa/ipa_s2n_exop.c | 49 --------------------------------
+ src/providers/ldap/sdap_utils.c  | 22 --------------
+ 2 files changed, 71 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
+index 9cb735526293ff5a209d732366b86fdb95dc8679..6f3974637a08b9d70e32fb6d79724be4f6e8dbde 100644
+--- a/src/providers/ipa/ipa_s2n_exop.c
++++ b/src/providers/ipa/ipa_s2n_exop.c
+@@ -2118,49 +2118,6 @@ done:
+     return ret;
+ }
+ 
+-static errno_t add_emails_to_aliases(struct sysdb_attrs *attrs,
+-                                     struct sss_domain_info *dom)
+-{
+-    int ret;
+-    const char **emails;
+-    size_t c;
+-    TALLOC_CTX *tmp_ctx;
+-
+-    tmp_ctx = talloc_new(NULL);
+-    if (tmp_ctx == NULL) {
+-        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+-        return ENOMEM;
+-    }
+-
+-    ret = sysdb_attrs_get_string_array(attrs, SYSDB_USER_EMAIL, tmp_ctx,
+-                                       &emails);
+-    if (ret == EOK) {
+-        for (c = 0; emails[c] != NULL; c++) {
+-            if (is_email_from_domain(emails[c], dom)) {
+-                ret = sysdb_attrs_add_lc_name_alias_safe(attrs, emails[c]);
+-                if (ret != EOK) {
+-                    DEBUG(SSSDBG_OP_FAILURE,
+-                          "Failed to add lower-cased version of email [%s] "
+-                          "into the alias list\n", emails[c]);
+-                    goto done;
+-                }
+-            }
+-        }
+-    } else if (ret == ENOENT) {
+-        DEBUG(SSSDBG_TRACE_ALL, "No email addresses available.\n");
+-    } else {
+-        DEBUG(SSSDBG_OP_FAILURE,
+-              "sysdb_attrs_get_string_array failed, skipping ...\n");
+-    }
+-
+-    ret = EOK;
+-
+-done:
+-    talloc_free(tmp_ctx);
+-
+-    return ret;
+-}
+-
+ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+                                     struct req_input *req_input,
+                                     struct resp_attrs *attrs,
+@@ -2314,12 +2271,6 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
+                 goto done;
+             }
+ 
+-            ret = add_emails_to_aliases(attrs->sysdb_attrs, dom);
+-            if (ret != EOK) {
+-                DEBUG(SSSDBG_OP_FAILURE,
+-                      "add_emails_to_aliases failed, skipping ...\n");
+-            }
+-
+             if (upn == NULL) {
+                 /* We also have to store a fake UPN here, because otherwise the
+                  * krb5 child later won't be able to properly construct one as
+diff --git a/src/providers/ldap/sdap_utils.c b/src/providers/ldap/sdap_utils.c
+index 0ac3ab2e416d887d00480b5123859c611f514274..6d543101f06ce3cd3925a675af6cabdacb8ebcaa 100644
+--- a/src/providers/ldap/sdap_utils.c
++++ b/src/providers/ldap/sdap_utils.c
+@@ -87,7 +87,6 @@ sdap_save_all_names(const char *name,
+     int i;
+     bool lowercase = !dom->case_sensitive;
+     bool store_as_fqdn;
+-    const char **emails;
+ 
+     switch (entry_type) {
+     case SYSDB_MEMBER_USER:
+@@ -144,27 +143,6 @@ sdap_save_all_names(const char *name,
+ 
+     }
+ 
+-    ret = sysdb_attrs_get_string_array(ldap_attrs, SYSDB_USER_EMAIL, tmp_ctx,
+-                                       &emails);
+-    if (ret == EOK) {
+-        for (i = 0; emails[i] != NULL; i++) {
+-            if (is_email_from_domain(emails[i], dom)) {
+-                ret = sysdb_attrs_add_lc_name_alias_safe(attrs, emails[i]);
+-                if (ret) {
+-                    DEBUG(SSSDBG_OP_FAILURE,
+-                          "Failed to add lower-cased version of email [%s] "
+-                          "into the alias list\n", emails[i]);
+-                    goto done;
+-                }
+-            }
+-        }
+-    } else if (ret == ENOENT) {
+-        DEBUG(SSSDBG_TRACE_ALL, "No email addresses available.\n");
+-    } else {
+-        DEBUG(SSSDBG_OP_FAILURE,
+-              "sysdb_attrs_get_string_array failed, skipping ...\n");
+-    }
+-
+     ret = EOK;
+ done:
+     talloc_free(tmp_ctx);
+-- 
+2.17.1
+
diff --git a/SOURCES/0016-UTIL-Add-wrapper-function-to-configure-logger.patch b/SOURCES/0016-UTIL-Add-wrapper-function-to-configure-logger.patch
deleted file mode 100644
index a4dea5f..0000000
--- a/SOURCES/0016-UTIL-Add-wrapper-function-to-configure-logger.patch
+++ /dev/null
@@ -1,133 +0,0 @@
-From 34fa82bc07c4da14606d7a8a9b68a872fe210a9f Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Mon, 23 Oct 2017 14:58:14 +0200
-Subject: [PATCH 16/21] UTIL: Add wrapper function to configure logger
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Let's use one enum for logger type instead of many integers (debug_to_file,
-debug_to_stderr plus some weird combination for journald).
-Old variable were also transformed to enum for backward compatibility
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 09e3f0af96cecb94be69084c025f0355b3111993)
----
- src/util/debug.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/util/debug.h | 18 ++++++++++++++++++
- 2 files changed, 72 insertions(+)
-
-diff --git a/src/util/debug.c b/src/util/debug.c
-index ca4fa4c6f5b150700a0a136d8a7ca9df30c29d73..4e469447e5ab8aa89cd57bcd6d00269875a12bc6 100644
---- a/src/util/debug.c
-+++ b/src/util/debug.c
-@@ -43,9 +43,63 @@ int debug_timestamps = SSSDBG_TIMESTAMP_UNRESOLVED;
- int debug_microseconds = SSSDBG_MICROSECONDS_UNRESOLVED;
- int debug_to_file = 0;
- int debug_to_stderr = 0;
-+enum sss_logger_t sss_logger;
- const char *debug_log_file = "sssd";
- FILE *debug_file = NULL;
- 
-+const char *sss_logger_str[] = {
-+        [STDERR_LOGGER] = "stderr",
-+        [FILES_LOGGER] = "files",
-+#ifdef WITH_JOURNALD
-+        [JOURNALD_LOGGER] = "journald",
-+#endif
-+        NULL,
-+};
-+
-+#ifdef WITH_JOURNALD
-+#define JOURNALD_STR " journald,"
-+#else
-+#define JOURNALD_STR ""
-+#endif
-+
-+void sss_set_logger(const char *logger)
-+{
-+    /* use old flags */
-+    if (logger == NULL) {
-+        if (debug_to_stderr != 0) {
-+            sss_logger = STDERR_LOGGER;
-+        }
-+        /* It is never described what should be used in case of
-+         * debug_to_stderr == 1 && debug_to_file == 1. Because neither
-+         * of binaries provide both command line arguments.
-+         * Let files have higher priority.
-+         */
-+        if (debug_to_file != 0) {
-+            sss_logger = FILES_LOGGER;
-+        }
-+#ifdef WITH_JOURNALD
-+        if (debug_to_file == 0 && debug_to_stderr == 0) {
-+            sss_logger = JOURNALD_LOGGER;
-+        }
-+#endif
-+    } else {
-+        if (strcmp(logger, "stderr") == 0) {
-+            sss_logger = STDERR_LOGGER;
-+        } else if (strcmp(logger, "files") == 0) {
-+            sss_logger = FILES_LOGGER;
-+#ifdef WITH_JOURNALD
-+        } else if (strcmp(logger, "journald") == 0) {
-+            sss_logger = JOURNALD_LOGGER;
-+#endif
-+        } else {
-+            /* unexpected value */
-+            fprintf(stderr, "Unexpected logger: %s\nExpected:%s stderr, "
-+                            "files\n", logger, JOURNALD_STR);
-+            sss_logger = STDERR_LOGGER;
-+        }
-+    }
-+}
-+
- errno_t set_debug_file_from_fd(const int fd)
- {
-     FILE *dummy;
-diff --git a/src/util/debug.h b/src/util/debug.h
-index 2a1bd4ffd30817d7128805996c21105fe40982a2..4adafb7cfc03f7381c4d03071eb44edad04bee00 100644
---- a/src/util/debug.h
-+++ b/src/util/debug.h
-@@ -31,13 +31,26 @@
- 
- #define APPEND_LINE_FEED 0x1
- 
-+enum sss_logger_t {
-+    STDERR_LOGGER = 0,
-+    FILES_LOGGER,
-+#ifdef WITH_JOURNALD
-+    JOURNALD_LOGGER,
-+#endif
-+};
-+
-+extern const char *sss_logger_str[];
- extern const char *debug_prg_name;
- extern int debug_level;
- extern int debug_timestamps;
- extern int debug_microseconds;
- extern int debug_to_file;
- extern int debug_to_stderr;
-+extern enum sss_logger_t sss_logger;
- extern const char *debug_log_file;
-+
-+void sss_set_logger(const char *logger);
-+
- void sss_vdebug_fn(const char *file,
-                    long line,
-                    const char *function,
-@@ -80,6 +93,11 @@ int get_fd_from_debug_file(void);
- #define SSSDBG_MICROSECONDS_UNRESOLVED   -1
- #define SSSDBG_MICROSECONDS_DEFAULT       0
- 
-+#define SSSD_LOGGER_OPTS \
-+        {"logger", '\0', POPT_ARG_STRING, &opt_logger, 0, \
-+         _("Set logger"), "stderr|files|journald"},
-+
-+
- #define SSSD_DEBUG_OPTS \
-         {"debug-level", 'd', POPT_ARG_INT, &debug_level, 0, \
-          _("Debug level"), NULL}, \
--- 
-2.13.5
-
diff --git a/SOURCES/0016-util-Remove-the-unused-function-is_email_from_domain.patch b/SOURCES/0016-util-Remove-the-unused-function-is_email_from_domain.patch
new file mode 100644
index 0000000..ba26190
--- /dev/null
+++ b/SOURCES/0016-util-Remove-the-unused-function-is_email_from_domain.patch
@@ -0,0 +1,117 @@
+From 5651a893f7dddb13fa9edc94e96d7bc95ec13f8b Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 21 Jun 2018 12:40:44 +0200
+Subject: [PATCH] util: Remove the unused function is_email_from_domain
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This commit pretty much reverts commit
+04d4c4d45f3942a813b7f772737f801f877f4e64, it's just coded manually,
+because "git revert 04d4c4d45f3942a813b7f772737f801f877f4e64"
+resulted in conflicts. It's easier to just remove the single
+function.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3607
+
+Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
+(cherry picked from commit 58f60a0949f5d84b1fe5d15e52adfceb84053569)
+---
+ src/tests/cmocka/test_utils.c | 21 ---------------------
+ src/util/domain_info_utils.c  | 27 ---------------------------
+ src/util/util.h               |  1 -
+ 3 files changed, 49 deletions(-)
+
+diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
+index cf314abe2db4056fe92c167454a4ddc31be98a51..1a8699a2a87d57ab43c70ceebf9bc71da4def4d4 100644
+--- a/src/tests/cmocka/test_utils.c
++++ b/src/tests/cmocka/test_utils.c
+@@ -1849,25 +1849,6 @@ static void test_sss_get_domain_mappings_content(void **state)
+      * capaths might not be as expected. */
+ }
+ 
+-static void test_is_email_from_domain(void **state)
+-{
+-    struct dom_list_test_ctx *test_ctx = talloc_get_type(*state,
+-                                                      struct dom_list_test_ctx);
+-    struct sss_domain_info *d;
+-
+-    d = find_domain_by_name(test_ctx->dom_list, "name_0.dom", false);
+-    assert_non_null(d);
+-
+-    assert_false(is_email_from_domain(NULL, NULL));
+-    assert_false(is_email_from_domain("hello", NULL));
+-    assert_false(is_email_from_domain(NULL, d));
+-    assert_false(is_email_from_domain("hello", d));
+-    assert_false(is_email_from_domain("hello@hello", d));
+-
+-    assert_true(is_email_from_domain("hello@name_0.dom", d));
+-    assert_true(is_email_from_domain("hello@NaMe_0.DoM", d));
+-}
+-
+ int main(int argc, const char *argv[])
+ {
+     poptContext pc;
+@@ -1896,8 +1877,6 @@ int main(int argc, const char *argv[])
+                                         setup_dom_list, teardown_dom_list),
+         cmocka_unit_test_setup_teardown(test_find_domain_by_name_disabled,
+                                         setup_dom_list, teardown_dom_list),
+-        cmocka_unit_test_setup_teardown(test_is_email_from_domain,
+-                                        setup_dom_list, teardown_dom_list),
+ 
+         cmocka_unit_test_setup_teardown(test_sss_names_init,
+                                         confdb_test_setup,
+diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
+index 66077092a40111967a98b0937506d9e4472f50d5..9d608ef2079cadbf3c66187e3bb8c81d2d7b4604 100644
+--- a/src/util/domain_info_utils.c
++++ b/src/util/domain_info_utils.c
+@@ -889,33 +889,6 @@ bool sss_domain_is_forest_root(struct sss_domain_info *dom)
+     return (dom->forest_root == dom);
+ }
+ 
+-bool is_email_from_domain(const char *email, struct sss_domain_info *dom)
+-{
+-    const char *p;
+-
+-    if (email == NULL || dom == NULL) {
+-        return false;
+-    }
+-
+-    p = strchr(email, '@');
+-    if (p == NULL) {
+-        DEBUG(SSSDBG_TRACE_ALL,
+-              "Input [%s] does not look like an email address.\n", email);
+-        return false;
+-    }
+-
+-    if (strcasecmp(p+1, dom->name) == 0) {
+-        DEBUG(SSSDBG_TRACE_ALL, "Email [%s] is from domain [%s].\n", email,
+-                                                                     dom->name);
+-        return true;
+-    }
+-
+-    DEBUG(SSSDBG_TRACE_ALL, "Email [%s] is not from domain [%s].\n", email,
+-                                                                     dom->name);
+-
+-    return false;
+-}
+-
+ char *subdomain_create_conf_path(TALLOC_CTX *mem_ctx,
+                                  struct sss_domain_info *subdomain)
+ {
+diff --git a/src/util/util.h b/src/util/util.h
+index 4657ab0c691e3e0442f340b94ae149e9d6602bb5..2785ac2e285cfb4dd6a309fe5d73dd755e07b8ad 100644
+--- a/src/util/util.h
++++ b/src/util/util.h
+@@ -539,7 +539,6 @@ struct sss_domain_info *find_domain_by_sid(struct sss_domain_info *domain,
+ enum sss_domain_state sss_domain_get_state(struct sss_domain_info *dom);
+ void sss_domain_set_state(struct sss_domain_info *dom,
+                           enum sss_domain_state state);
+-bool is_email_from_domain(const char *email, struct sss_domain_info *dom);
+ bool sss_domain_is_forest_root(struct sss_domain_info *dom);
+ const char *sss_domain_type_str(struct sss_domain_info *dom);
+ 
+-- 
+2.17.1
+
diff --git a/SOURCES/0017-Add-parameter-logger-to-daemons.patch b/SOURCES/0017-Add-parameter-logger-to-daemons.patch
deleted file mode 100644
index 1a547c3..0000000
--- a/SOURCES/0017-Add-parameter-logger-to-daemons.patch
+++ /dev/null
@@ -1,830 +0,0 @@
-From de26ea6f603e87ef306f08fa1b458b8a180bdf2d Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Mon, 23 Oct 2017 15:18:47 +0200
-Subject: [PATCH 17/21] Add parameter --logger to daemons
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Different binary handled information about logging differently
- e,g, --debug-to-files --debug-to-stderr
-And logging to journald was a special case of previous options
-(!debug_file && !debug_to_stderr). It was also tied to the monitor option
-"--daemon" and therefore loggind to stderr was used in interactive mode
-+ systemd Type=notify.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3433
-
-Reviewed-by: Justin Stephenson <jstephen@redhat.com>
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit cb75b275d15beedd1fdecc1f8ced657fba282218)
----
- src/man/sssd.8.xml                | 31 +++++++++++++++++++++++++
- src/monitor/monitor.c             | 48 ++++++++++++---------------------------
- src/p11_child/p11_child_nss.c     |  3 +++
- src/providers/ad/ad_gpo_child.c   |  4 ++++
- src/providers/data_provider_be.c  |  4 ++++
- src/providers/ipa/selinux_child.c |  4 ++++
- src/providers/krb5/krb5_child.c   |  4 ++++
- src/providers/ldap/ldap_child.c   |  4 ++++
- src/providers/proxy/proxy_auth.c  |  4 ++--
- src/providers/proxy/proxy_child.c |  4 ++++
- src/responder/autofs/autofssrv.c  |  4 ++++
- src/responder/ifp/ifpsrv.c        |  4 ++++
- src/responder/kcm/kcm.c           |  4 ++++
- src/responder/nss/nsssrv.c        |  4 ++++
- src/responder/pac/pacsrv.c        |  4 ++++
- src/responder/pam/pamsrv.c        |  4 ++++
- src/responder/secrets/secsrv.c    |  4 ++++
- src/responder/ssh/sshsrv.c        |  4 ++++
- src/responder/sudo/sudosrv.c      |  4 ++++
- src/tests/cmocka/dummy_child.c    |  4 ++++
- src/tests/debug-tests.c           | 10 ++++++++
- src/util/child_common.c           |  2 +-
- src/util/debug.c                  |  4 ++--
- src/util/server.c                 | 12 ++++++----
- 24 files changed, 135 insertions(+), 43 deletions(-)
-
-diff --git a/src/man/sssd.8.xml b/src/man/sssd.8.xml
-index 923da6824907f0d2d140d9ca83f87338e7664f83..0b725628ff93f48f832140dd5dc15b040a8b179f 100644
---- a/src/man/sssd.8.xml
-+++ b/src/man/sssd.8.xml
-@@ -94,6 +94,37 @@
-             </varlistentry>
-             <varlistentry>
-                 <term>
-+                    <option>--logger=</option><replaceable>value</replaceable>
-+                </term>
-+                <listitem>
-+                    <para>
-+                        Location where SSSD will send log messages. This option
-+                        overrides the value of the deprecated option
-+                        <option>--debug-to-files</option>. The deprecated
-+                        option will still work if the <option>--logger</option>
-+                        is not used.
-+                    </para>
-+                    <para>
-+                        <emphasis>stderr</emphasis>: Redirect debug messages to
-+                        standard error output.
-+                    </para>
-+                    <para>
-+                        <emphasis>files</emphasis>: Redirect debug messages to
-+                        the log files. By default, the log files are stored in
-+                        <filename>/var/log/sssd</filename> and there are
-+                        separate log files for every SSSD service and domain.
-+                    </para>
-+                    <para>
-+                        <emphasis>journald</emphasis>: Redirect debug messages
-+                        to systemd-journald
-+                    </para>
-+                    <para>
-+                        Default: not set
-+                    </para>
-+                </listitem>
-+            </varlistentry>
-+            <varlistentry>
-+                <term>
-                     <option>-D</option>,<option>--daemon</option>
-                 </term>
-                 <listitem>
-diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
-index 7726548bbb666bb189667efc1de2295f8a001105..3c0b7ab2dac10fe15a8a5b807cb68ea4b7ab8461 100644
---- a/src/monitor/monitor.c
-+++ b/src/monitor/monitor.c
-@@ -1211,22 +1211,11 @@ static int get_service_config(struct mt_ctx *ctx, const char *name,
-             }
-         }
- 
--        if (debug_to_file) {
--            svc->command = talloc_strdup_append(
--                svc->command, " --debug-to-files"
--            );
--            if (!svc->command) {
--                talloc_free(svc);
--                return ENOMEM;
--            }
--        } else if (ctx->is_daemon == false) {
--            svc->command = talloc_strdup_append(
--                svc->command, " --debug-to-stderr"
--            );
--            if (!svc->command) {
--                talloc_free(svc);
--                return ENOMEM;
--            }
-+        svc->command = talloc_asprintf_append(
-+            svc->command, " --logger=%s", sss_logger_str[sss_logger]);
-+        if (!svc->command) {
-+            talloc_free(svc);
-+            return ENOMEM;
-         }
-     }
- 
-@@ -1374,22 +1363,11 @@ static int get_provider_config(struct mt_ctx *ctx, const char *name,
-             }
-         }
- 
--        if (debug_to_file) {
--            svc->command = talloc_strdup_append(
--                svc->command, " --debug-to-files"
--            );
--            if (!svc->command) {
--                talloc_free(svc);
--                return ENOMEM;
--            }
--        } else if (ctx->is_daemon == false) {
--            svc->command = talloc_strdup_append(
--                svc->command, " --debug-to-stderr"
--            );
--            if (!svc->command) {
--                talloc_free(svc);
--                return ENOMEM;
--            }
-+        svc->command = talloc_asprintf_append(
-+            svc->command, " --logger=%s", sss_logger_str[sss_logger]);
-+        if (!svc->command) {
-+            talloc_free(svc);
-+            return ENOMEM;
-         }
-     }
- 
-@@ -2454,6 +2432,7 @@ int main(int argc, const char *argv[])
-     int opt_version = 0;
-     int opt_netlinkoff = 0;
-     char *opt_config_file = NULL;
-+    char *opt_logger = NULL;
-     char *config_file = NULL;
-     int flags = 0;
-     struct main_context *main_ctx;
-@@ -2465,6 +2444,7 @@ int main(int argc, const char *argv[])
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-         SSSD_MAIN_OPTS
-+        SSSD_LOGGER_OPTS
-         {"daemon", 'D', POPT_ARG_NONE, &opt_daemon, 0, \
-          _("Become a daemon (default)"), NULL }, \
-         {"interactive", 'i', POPT_ARG_NONE, &opt_interactive, 0, \
-@@ -2551,6 +2531,8 @@ int main(int argc, const char *argv[])
-         debug_to_stderr = 1;
-     }
- 
-+    sss_set_logger(opt_logger);
-+
-     if (opt_config_file) {
-         config_file = talloc_strdup(tmp_ctx, opt_config_file);
-     } else {
-@@ -2575,7 +2557,7 @@ int main(int argc, const char *argv[])
- 
-     /* Open before server_setup() does to have logging
-      * during configuration checking */
--    if (debug_to_file) {
-+    if (sss_logger == FILES_LOGGER) {
-         ret = open_debug_file();
-         if (ret) {
-             return 7;
-diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
-index f165b58e63d2b8a6f26acf8bd89e7b41713e7359..e7dbcb689220d1cd2585fbde5f26e84f8fa15cc2 100644
---- a/src/p11_child/p11_child_nss.c
-+++ b/src/p11_child/p11_child_nss.c
-@@ -537,6 +537,7 @@ int main(int argc, const char *argv[])
-     int opt;
-     poptContext pc;
-     int debug_fd = -1;
-+    char *opt_logger = NULL;
-     errno_t ret;
-     TALLOC_CTX *main_ctx = NULL;
-     char *cert;
-@@ -564,6 +565,7 @@ int main(int argc, const char *argv[])
-         {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN,
-          &debug_to_stderr, 0,
-          _("Send the debug output to stderr directly."), NULL },
-+        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},
-         {"pin", 0, POPT_ARG_NONE, NULL, 'i', _("Expect PIN on stdin"), NULL},
-@@ -672,6 +674,7 @@ int main(int argc, const char *argv[])
-             DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n");
-         }
-     }
-+    sss_set_logger(opt_logger);
- 
-     DEBUG(SSSDBG_TRACE_FUNC, "p11_child started.\n");
- 
-diff --git a/src/providers/ad/ad_gpo_child.c b/src/providers/ad/ad_gpo_child.c
-index 8e5e062547721567cb450f9d0f72f1ec8cb99f96..5375cc691e8649c289672b74c4bfe5266c8222c9 100644
---- a/src/providers/ad/ad_gpo_child.c
-+++ b/src/providers/ad/ad_gpo_child.c
-@@ -687,6 +687,7 @@ main(int argc, const char *argv[])
-     int opt;
-     poptContext pc;
-     int debug_fd = -1;
-+    char *opt_logger = NULL;
-     errno_t ret;
-     int sysvol_gpt_version;
-     int result;
-@@ -710,6 +711,7 @@ main(int argc, const char *argv[])
-         {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN,
-          &debug_to_stderr, 0,
-          _("Send the debug output to stderr directly."), NULL },
-+        SSSD_LOGGER_OPTS
-         POPT_TABLEEND
-     };
- 
-@@ -744,6 +746,8 @@ main(int argc, const char *argv[])
-         }
-     }
- 
-+    sss_set_logger(opt_logger);
-+
-     DEBUG(SSSDBG_TRACE_FUNC, "gpo_child started.\n");
- 
-     main_ctx = talloc_new(NULL);
-diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
-index 2e55dc4e3fe9ba1aa8c1c51c426efee00b9ae91d..56ddac112a209b6937313d3d3c94a73d2067331f 100644
---- a/src/providers/data_provider_be.c
-+++ b/src/providers/data_provider_be.c
-@@ -537,6 +537,7 @@ int main(int argc, const char *argv[])
- {
-     int opt;
-     poptContext pc;
-+    char *opt_logger = NULL;
-     char *be_domain = NULL;
-     char *srv_name = NULL;
-     struct main_context *main_ctx;
-@@ -548,6 +549,7 @@ int main(int argc, const char *argv[])
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-         SSSD_MAIN_OPTS
-+        SSSD_LOGGER_OPTS
-         SSSD_SERVER_OPTS(uid, gid)
-         {"domain", 0, POPT_ARG_STRING, &be_domain, 0,
-          _("Domain of the information provider (mandatory)"), NULL },
-@@ -582,6 +584,8 @@ int main(int argc, const char *argv[])
-     debug_log_file = talloc_asprintf(NULL, "sssd_%s", be_domain);
-     if (!debug_log_file) return 2;
- 
-+    sss_set_logger(opt_logger);
-+
-     srv_name = talloc_asprintf(NULL, "sssd[be[%s]]", be_domain);
-     if (!srv_name) return 2;
- 
-diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c
-index 073475094ee491bd5453898c6ba65214fa14fe59..120492686963241b7e419413f489cc38953e32f2 100644
---- a/src/providers/ipa/selinux_child.c
-+++ b/src/providers/ipa/selinux_child.c
-@@ -206,6 +206,7 @@ int main(int argc, const char *argv[])
-     struct response *resp = NULL;
-     ssize_t written;
-     bool needs_update;
-+    char *opt_logger = NULL;
- 
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-@@ -220,6 +221,7 @@ int main(int argc, const char *argv[])
-         {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN,
-          &debug_to_stderr, 0,
-          _("Send the debug output to stderr directly."), NULL },
-+        SSSD_LOGGER_OPTS
-         POPT_TABLEEND
-     };
- 
-@@ -254,6 +256,8 @@ int main(int argc, const char *argv[])
-         }
-     }
- 
-+    sss_set_logger(opt_logger);
-+
-     DEBUG(SSSDBG_TRACE_FUNC, "selinux_child started.\n");
-     DEBUG(SSSDBG_TRACE_INTERNAL,
-           "Running with effective IDs: [%"SPRIuid"][%"SPRIgid"].\n",
-diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
-index 888cc5d6f5c554901cc46d4315844d7bbbe582b8..700338e47a3f9ac6fcf11b4c92364dbdb4f9bcf7 100644
---- a/src/providers/krb5/krb5_child.c
-+++ b/src/providers/krb5/krb5_child.c
-@@ -3020,6 +3020,7 @@ int main(int argc, const char *argv[])
-     int opt;
-     poptContext pc;
-     int debug_fd = -1;
-+    char *opt_logger = NULL;
-     errno_t ret;
-     krb5_error_code kerr;
-     uid_t fast_uid;
-@@ -3039,6 +3040,7 @@ int main(int argc, const char *argv[])
-         {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN,
-          &debug_to_stderr, 0,
-          _("Send the debug output to stderr directly."), NULL },
-+        SSSD_LOGGER_OPTS
-         {CHILD_OPT_FAST_CCACHE_UID, 0, POPT_ARG_INT, &fast_uid, 0,
-           _("The user to create FAST ccache as"), NULL},
-         {CHILD_OPT_FAST_CCACHE_GID, 0, POPT_ARG_INT, &fast_gid, 0,
-@@ -3097,6 +3099,8 @@ int main(int argc, const char *argv[])
-         }
-     }
- 
-+    sss_set_logger(opt_logger);
-+
-     DEBUG(SSSDBG_TRACE_FUNC, "krb5_child started.\n");
- 
-     kr = talloc_zero(NULL, struct krb5_req);
-diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c
-index b796e5cae01517c85c2fc1605b1e5877454691dc..baeed239db5dc7ffa482edcbc155f25f718c8249 100644
---- a/src/providers/ldap/ldap_child.c
-+++ b/src/providers/ldap/ldap_child.c
-@@ -599,6 +599,7 @@ int main(int argc, const char *argv[])
-     int kerr;
-     int opt;
-     int debug_fd = -1;
-+    char *opt_logger = NULL;
-     poptContext pc;
-     TALLOC_CTX *main_ctx = NULL;
-     uint8_t *buf = NULL;
-@@ -622,6 +623,7 @@ int main(int argc, const char *argv[])
-          _("An open file descriptor for the debug logs"), NULL},
-         {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_stderr, 0, \
-          _("Send the debug output to stderr directly."), NULL }, \
-+        SSSD_LOGGER_OPTS
-         POPT_TABLEEND
-     };
- 
-@@ -657,6 +659,8 @@ int main(int argc, const char *argv[])
-         }
-     }
- 
-+    sss_set_logger(opt_logger);
-+
-     BlockSignals(false, SIGTERM);
-     CatchSignal(SIGTERM, sig_term_handler);
- 
-diff --git a/src/providers/proxy/proxy_auth.c b/src/providers/proxy/proxy_auth.c
-index a05586e60b6ef894b0fcf1b8b3f30fdbf51a808d..665a29cf779290b8d35973245a36a1b5224bca78 100644
---- a/src/providers/proxy/proxy_auth.c
-+++ b/src/providers/proxy/proxy_auth.c
-@@ -178,9 +178,9 @@ static struct tevent_req *proxy_child_init_send(TALLOC_CTX *mem_ctx,
- 
-     state->command = talloc_asprintf(req,
-             "%s/proxy_child -d %#.4x --debug-timestamps=%d "
--            "--debug-microseconds=%d%s --domain %s --id %d",
-+            "--debug-microseconds=%d --logger=%s --domain %s --id %d",
-             SSSD_LIBEXEC_PATH, debug_level, debug_timestamps,
--            debug_microseconds, (debug_to_file ? " --debug-to-files" : ""),
-+            debug_microseconds, sss_logger_str[sss_logger],
-             auth_ctx->be->domain->name,
-             child_ctx->id);
-     if (state->command == NULL) {
-diff --git a/src/providers/proxy/proxy_child.c b/src/providers/proxy/proxy_child.c
-index be58622eb8b26231eeb6699976d51f57dc44de98..ae4855adeb5cc68f1a19003355a5d94f5b1bb378 100644
---- a/src/providers/proxy/proxy_child.c
-+++ b/src/providers/proxy/proxy_child.c
-@@ -504,6 +504,7 @@ int main(int argc, const char *argv[])
- {
-     int opt;
-     poptContext pc;
-+    char *opt_logger = NULL;
-     char *domain = NULL;
-     char *srv_name = NULL;
-     char *conf_entry = NULL;
-@@ -517,6 +518,7 @@ int main(int argc, const char *argv[])
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-         SSSD_MAIN_OPTS
-+        SSSD_LOGGER_OPTS
-         SSSD_SERVER_OPTS(uid, gid)
-         {"domain", 0, POPT_ARG_STRING, &domain, 0,
-          _("Domain of the information provider (mandatory)"), NULL },
-@@ -561,6 +563,8 @@ int main(int argc, const char *argv[])
-     debug_log_file = talloc_asprintf(NULL, "proxy_child_%s", domain);
-     if (!debug_log_file) return 2;
- 
-+    sss_set_logger(opt_logger);
-+
-     srv_name = talloc_asprintf(NULL, "sssd[proxy_child[%s]]", domain);
-     if (!srv_name) return 2;
- 
-diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c
-index cfb2233fdfc346bf27b128ee8c4261f4c73e3470..b0762a2b685a7c5ab3abfa281f0906ad8bfe1c88 100644
---- a/src/responder/autofs/autofssrv.c
-+++ b/src/responder/autofs/autofssrv.c
-@@ -185,6 +185,7 @@ int main(int argc, const char *argv[])
- {
-     int opt;
-     poptContext pc;
-+    char *opt_logger = NULL;
-     struct main_context *main_ctx;
-     int ret;
-     uid_t uid;
-@@ -193,6 +194,7 @@ int main(int argc, const char *argv[])
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-         SSSD_MAIN_OPTS
-+        SSSD_LOGGER_OPTS
-         SSSD_SERVER_OPTS(uid, gid)
-         SSSD_RESPONDER_OPTS
-         POPT_TABLEEND
-@@ -221,6 +223,8 @@ int main(int argc, const char *argv[])
-     /* set up things like debug, signals, daemonization, etc... */
-     debug_log_file = "sssd_autofs";
- 
-+    sss_set_logger(opt_logger);
-+
-     ret = server_setup("sssd[autofs]", 0, uid, gid,
-                        CONFDB_AUTOFS_CONF_ENTRY, &main_ctx);
-     if (ret != EOK) {
-diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c
-index 0dc61a42200cc79fc6f12515a8f581ad0201a043..85dfbacc217e2870dd7517e36a1d39e7f2054a8b 100644
---- a/src/responder/ifp/ifpsrv.c
-+++ b/src/responder/ifp/ifpsrv.c
-@@ -355,6 +355,7 @@ int main(int argc, const char *argv[])
- {
-     int opt;
-     poptContext pc;
-+    char *opt_logger = NULL;
-     struct main_context *main_ctx;
-     int ret;
-     uid_t uid;
-@@ -363,6 +364,7 @@ int main(int argc, const char *argv[])
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-         SSSD_MAIN_OPTS
-+        SSSD_LOGGER_OPTS
-         SSSD_SERVER_OPTS(uid, gid)
-         SSSD_RESPONDER_OPTS
-         POPT_TABLEEND
-@@ -391,6 +393,8 @@ int main(int argc, const char *argv[])
-     /* set up things like debug, signals, daemonization, etc... */
-     debug_log_file = "sssd_ifp";
- 
-+    sss_set_logger(opt_logger);
-+
-     ret = server_setup("sssd[ifp]", 0, 0, 0,
-                        CONFDB_IFP_CONF_ENTRY, &main_ctx);
-     if (ret != EOK) return 2;
-diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c
-index 2202f96381a2622a2c5433e281172287b325f960..358fcc18165dec7b41a7389a3ef22660ac04b4a8 100644
---- a/src/responder/kcm/kcm.c
-+++ b/src/responder/kcm/kcm.c
-@@ -258,6 +258,7 @@ int main(int argc, const char *argv[])
- {
-     int opt;
-     poptContext pc;
-+    char *opt_logger = NULL;
-     struct main_context *main_ctx;
-     int ret;
-     uid_t uid;
-@@ -266,6 +267,7 @@ int main(int argc, const char *argv[])
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-         SSSD_MAIN_OPTS
-+        SSSD_LOGGER_OPTS
-         SSSD_SERVER_OPTS(uid, gid)
-         POPT_TABLEEND
-     };
-@@ -293,6 +295,8 @@ int main(int argc, const char *argv[])
-     /* set up things like debug, signals, daemonization, etc... */
-     debug_log_file = "sssd_kcm";
- 
-+    sss_set_logger(opt_logger);
-+
-     ret = server_setup("sssd[kcm]", 0, uid, gid, CONFDB_KCM_CONF_ENTRY,
-                        &main_ctx);
-     if (ret != EOK) return 2;
-diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
-index 32bfcd69bbb9b35e9932b70a826c4f99ab6a07f3..11d19fd30c86283d537623db12e52caa6cc4dcd3 100644
---- a/src/responder/nss/nsssrv.c
-+++ b/src/responder/nss/nsssrv.c
-@@ -422,6 +422,7 @@ int main(int argc, const char *argv[])
- {
-     int opt;
-     poptContext pc;
-+    char *opt_logger = NULL;
-     struct main_context *main_ctx;
-     int ret;
-     uid_t uid;
-@@ -430,6 +431,7 @@ int main(int argc, const char *argv[])
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-         SSSD_MAIN_OPTS
-+        SSSD_LOGGER_OPTS
-         SSSD_SERVER_OPTS(uid, gid)
-         SSSD_RESPONDER_OPTS
-         POPT_TABLEEND
-@@ -458,6 +460,8 @@ int main(int argc, const char *argv[])
-     /* set up things like debug, signals, daemonization, etc... */
-     debug_log_file = "sssd_nss";
- 
-+    sss_set_logger(opt_logger);
-+
-     ret = server_setup("sssd[nss]", 0, uid, gid, CONFDB_NSS_CONF_ENTRY,
-                        &main_ctx);
-     if (ret != EOK) return 2;
-diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c
-index 1f820c07f5c55fe8df75cce05b403c41075d9f94..b72e5c8d2a42bc85f0974dcb81a1290d3f740986 100644
---- a/src/responder/pac/pacsrv.c
-+++ b/src/responder/pac/pacsrv.c
-@@ -209,6 +209,7 @@ int main(int argc, const char *argv[])
- {
-     int opt;
-     poptContext pc;
-+    char *opt_logger = NULL;
-     struct main_context *main_ctx;
-     int ret;
-     uid_t uid;
-@@ -217,6 +218,7 @@ int main(int argc, const char *argv[])
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-         SSSD_MAIN_OPTS
-+        SSSD_LOGGER_OPTS
-         SSSD_SERVER_OPTS(uid, gid)
-         SSSD_RESPONDER_OPTS
-         POPT_TABLEEND
-@@ -245,6 +247,8 @@ int main(int argc, const char *argv[])
-     /* set up things like debug, signals, daemonization, etc... */
-     debug_log_file = "sssd_pac";
- 
-+    sss_set_logger(opt_logger);
-+
-     ret = server_setup("sssd[pac]", 0, uid, gid,
-                        CONFDB_PAC_CONF_ENTRY, &main_ctx);
-     if (ret != EOK) return 2;
-diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c
-index 79470823d18138da6ef9235e6336a3220ead1797..cc0e4bddcdbecfadabea78a6d2815d0ac6d651b6 100644
---- a/src/responder/pam/pamsrv.c
-+++ b/src/responder/pam/pamsrv.c
-@@ -355,6 +355,7 @@ int main(int argc, const char *argv[])
- {
-     int opt;
-     poptContext pc;
-+    char *opt_logger = NULL;
-     struct main_context *main_ctx;
-     int ret;
-     uid_t uid;
-@@ -365,6 +366,7 @@ int main(int argc, const char *argv[])
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-         SSSD_MAIN_OPTS
-+        SSSD_LOGGER_OPTS
-         SSSD_SERVER_OPTS(uid, gid)
-         SSSD_RESPONDER_OPTS
-         POPT_TABLEEND
-@@ -393,6 +395,8 @@ int main(int argc, const char *argv[])
-     /* set up things like debug, signals, daemonization, etc... */
-     debug_log_file = "sssd_pam";
- 
-+    sss_set_logger(opt_logger);
-+
-     if (!is_socket_activated()) {
-         /* Crate pipe file descriptors here before privileges are dropped
-          * in server_setup() */
-diff --git a/src/responder/secrets/secsrv.c b/src/responder/secrets/secsrv.c
-index 2b661b165ef0c174557f53012b2dbaa236a6e359..59c0f3a56040a6fc0c092247fbd124a069f97153 100644
---- a/src/responder/secrets/secsrv.c
-+++ b/src/responder/secrets/secsrv.c
-@@ -324,6 +324,7 @@ int main(int argc, const char *argv[])
- {
-     int opt;
-     poptContext pc;
-+    char *opt_logger = NULL;
-     struct main_context *main_ctx;
-     int ret;
-     uid_t uid;
-@@ -332,6 +333,7 @@ int main(int argc, const char *argv[])
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-         SSSD_MAIN_OPTS
-+        SSSD_LOGGER_OPTS
-         SSSD_SERVER_OPTS(uid, gid)
-         POPT_TABLEEND
-     };
-@@ -359,6 +361,8 @@ int main(int argc, const char *argv[])
-     /* set up things like debug, signals, daemonization, etc... */
-     debug_log_file = "sssd_secrets";
- 
-+    sss_set_logger(opt_logger);
-+
-     ret = server_setup("sssd[secrets]", 0, uid, gid, CONFDB_SEC_CONF_ENTRY,
-                        &main_ctx);
-     if (ret != EOK) return 2;
-diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c
-index 440f0e2b9dc06e3dc52ff96d7207b8a3727865c0..8b0e7cc2d71044d7ab3bd2439041f678ddedb4cd 100644
---- a/src/responder/ssh/sshsrv.c
-+++ b/src/responder/ssh/sshsrv.c
-@@ -177,6 +177,7 @@ int main(int argc, const char *argv[])
- {
-     int opt;
-     poptContext pc;
-+    char *opt_logger = NULL;
-     struct main_context *main_ctx;
-     int ret;
-     uid_t uid;
-@@ -185,6 +186,7 @@ int main(int argc, const char *argv[])
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-         SSSD_MAIN_OPTS
-+        SSSD_LOGGER_OPTS
-         SSSD_SERVER_OPTS(uid, gid)
-         SSSD_RESPONDER_OPTS
-         POPT_TABLEEND
-@@ -213,6 +215,8 @@ int main(int argc, const char *argv[])
-     /* set up things like debug, signals, daemonization, etc... */
-     debug_log_file = "sssd_ssh";
- 
-+    sss_set_logger(opt_logger);
-+
-     ret = server_setup("sssd[ssh]", 0, uid, gid,
-                        CONFDB_SSH_CONF_ENTRY, &main_ctx);
-     if (ret != EOK) {
-diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c
-index dca70ea4afc0e6df6d1b1864338c7b1091a98fee..19058321a25022d7704556ec0ef79729db3ac1f2 100644
---- a/src/responder/sudo/sudosrv.c
-+++ b/src/responder/sudo/sudosrv.c
-@@ -178,6 +178,7 @@ int main(int argc, const char *argv[])
- {
-     int opt;
-     poptContext pc;
-+    char *opt_logger = NULL;
-     struct main_context *main_ctx;
-     int ret;
-     uid_t uid;
-@@ -186,6 +187,7 @@ int main(int argc, const char *argv[])
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-         SSSD_MAIN_OPTS
-+        SSSD_LOGGER_OPTS
-         SSSD_SERVER_OPTS(uid, gid)
-         SSSD_RESPONDER_OPTS
-         POPT_TABLEEND
-@@ -214,6 +216,8 @@ int main(int argc, const char *argv[])
-     /* set up things like debug, signals, daemonization, etc... */
-     debug_log_file = "sssd_sudo";
- 
-+    sss_set_logger(opt_logger);
-+
-     ret = server_setup("sssd[sudo]", 0, uid, gid, CONFDB_SUDO_CONF_ENTRY,
-                        &main_ctx);
-     if (ret != EOK) {
-diff --git a/src/tests/cmocka/dummy_child.c b/src/tests/cmocka/dummy_child.c
-index bcaa9455037a0604422750bf7cc719a25cef4a99..811cb40490c89c4250401e0d8d3e9d1c277f57af 100644
---- a/src/tests/cmocka/dummy_child.c
-+++ b/src/tests/cmocka/dummy_child.c
-@@ -34,6 +34,7 @@ int main(int argc, const char *argv[])
- {
-     int opt;
-     int debug_fd = -1;
-+    char *opt_logger = NULL;
-     poptContext pc;
-     ssize_t len;
-     ssize_t written;
-@@ -55,6 +56,7 @@ int main(int argc, const char *argv[])
-          _("An open file descriptor for the debug logs"), NULL},
-         {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_stderr, 0, \
-          _("Send the debug output to stderr directly."), NULL },
-+        SSSD_LOGGER_OPTS
-         {"guitar", 0, POPT_ARG_STRING, &guitar, 0, _("Who plays guitar"), NULL },
-         {"drums", 0, POPT_ARG_STRING, &drums, 0, _("Who plays drums"), NULL },
-         POPT_TABLEEND
-@@ -76,6 +78,8 @@ int main(int argc, const char *argv[])
-     }
-     poptFreeContext(pc);
- 
-+    sss_set_logger(opt_logger);
-+
-     action = getenv("TEST_CHILD_ACTION");
-     if (action) {
-         if (strcasecmp(action, "check_extra_args") == 0) {
-diff --git a/src/tests/debug-tests.c b/src/tests/debug-tests.c
-index d904d7eb8b5418608023faca0d62067f3106d23b..1446ec0474ab4bf72e66b58831fef59defd7be76 100644
---- a/src/tests/debug-tests.c
-+++ b/src/tests/debug-tests.c
-@@ -343,6 +343,7 @@ START_TEST(test_debug_is_set_single_no_timestamp)
-     debug_microseconds = 0;
-     debug_to_file = 1;
-     debug_prg_name = "sssd";
-+    sss_set_logger(sss_logger_str[FILES_LOGGER]);
- 
-     for (i = 0; i <= 9; i++) {
-         debug_level = levels[i];
-@@ -385,6 +386,8 @@ START_TEST(test_debug_is_set_single_timestamp)
-     debug_microseconds = 0;
-     debug_to_file = 1;
-     debug_prg_name = "sssd";
-+    sss_set_logger(sss_logger_str[FILES_LOGGER]);
-+
- 
-     for (i = 0; i <= 9; i++) {
-         debug_level = levels[i];
-@@ -432,6 +435,8 @@ START_TEST(test_debug_is_set_single_timestamp_microseconds)
-     debug_microseconds = 1;
-     debug_to_file = 1;
-     debug_prg_name = "sssd";
-+    sss_set_logger(sss_logger_str[FILES_LOGGER]);
-+
- 
-     for (i = 0; i <= 9; i++) {
-         debug_level = levels[i];
-@@ -480,6 +485,8 @@ START_TEST(test_debug_is_notset_no_timestamp)
-     debug_microseconds = 0;
-     debug_to_file = 1;
-     debug_prg_name = "sssd";
-+    sss_set_logger(sss_logger_str[FILES_LOGGER]);
-+
- 
-     for (i = 0; i <= 9; i++) {
-         debug_level = all_set & ~levels[i];
-@@ -525,6 +532,8 @@ START_TEST(test_debug_is_notset_timestamp)
-     debug_microseconds = 0;
-     debug_to_file = 1;
-     debug_prg_name = "sssd";
-+    sss_set_logger(sss_logger_str[FILES_LOGGER]);
-+
- 
-     for (i = 0; i <= 9; i++) {
-         debug_level = all_set & ~levels[i];
-@@ -570,6 +579,7 @@ START_TEST(test_debug_is_notset_timestamp_microseconds)
-     debug_microseconds = 1;
-     debug_to_file = 1;
-     debug_prg_name = "sssd";
-+    sss_set_logger(sss_logger_str[FILES_LOGGER]);
- 
-     for (i = 0; i <= 9; i++) {
-         debug_level = all_set & ~levels[i];
-diff --git a/src/util/child_common.c b/src/util/child_common.c
-index b300d84bf432608db96de36e04637b5fb115212e..dc070f26446305e07cbb34edd1e4d72db72aedc5 100644
---- a/src/util/child_common.c
-+++ b/src/util/child_common.c
-@@ -676,7 +676,7 @@ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx,
-         }
- 
-         if (child_debug_stderr) {
--            argv[--argc] = talloc_strdup(argv, "--debug-to-stderr");
-+            argv[--argc] = talloc_strdup(argv, "--logger=stderr");
-             if (argv[argc] == NULL) {
-                 ret = ENOMEM;
-                 goto fail;
-diff --git a/src/util/debug.c b/src/util/debug.c
-index 4e469447e5ab8aa89cd57bcd6d00269875a12bc6..30801fce7c27b115d1cafd4ed826a57c7d444a72 100644
---- a/src/util/debug.c
-+++ b/src/util/debug.c
-@@ -277,7 +277,7 @@ void sss_vdebug_fn(const char *file,
-     errno_t ret;
-     va_list ap_fallback;
- 
--    if (!debug_file && !debug_to_stderr) {
-+    if (sss_logger == JOURNALD_LOGGER) {
-         /* If we are not outputting logs to files, we should be sending them
-          * to journald.
-          * NOTE: on modern systems, this is where stdout/stderr will end up
-@@ -470,7 +470,7 @@ int rotate_debug_files(void)
-     int ret;
-     errno_t error;
- 
--    if (!debug_to_file) return EOK;
-+    if (sss_logger != FILES_LOGGER) return EOK;
- 
-     do {
-         error = 0;
-diff --git a/src/util/server.c b/src/util/server.c
-index 0046c9737bc0d9aea7be59b4fed5e0f8930ff66e..26b8b27f0e5c8524520a2d4774e90fd6cb32bf7a 100644
---- a/src/util/server.c
-+++ b/src/util/server.c
-@@ -455,7 +455,7 @@ int server_setup(const char *name, int flags,
-     char *conf_db;
-     int ret = EOK;
-     bool dt;
--    bool dl;
-+    bool dl = false;
-     bool dm;
-     struct tevent_signal *tes;
-     struct logrotate_ctx *lctx;
-@@ -637,16 +637,18 @@ int server_setup(const char *name, int flags,
-     }
- 
-     /* same for debug to file */
--    dl = (debug_to_file != 0);
-     ret = confdb_get_bool(ctx->confdb_ctx, conf_entry,
-                           CONFDB_SERVICE_DEBUG_TO_FILES,
--                          dl, &dl);
-+                          false, &dl);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_FATAL_FAILURE, "Error reading from confdb (%d) [%s]\n",
-                                      ret, strerror(ret));
-         return ret;
-     }
--    if (dl) debug_to_file = 1;
-+    if (dl) {
-+        debug_to_file = 1;
-+        sss_set_logger(sss_logger_str[FILES_LOGGER]);
-+    }
- 
-     /* before opening the log file set up log rotation */
-     lctx = talloc_zero(ctx, struct logrotate_ctx);
-@@ -662,7 +664,7 @@ int server_setup(const char *name, int flags,
-     }
- 
-     /* open log file if told so */
--    if (debug_to_file) {
-+    if (sss_logger == FILES_LOGGER) {
-         ret = open_debug_file();
-         if (ret != EOK) {
-             DEBUG(SSSDBG_FATAL_FAILURE, "Error setting up logging (%d) "
--- 
-2.13.5
-
diff --git a/SOURCES/0017-TESTS-Allow-storing-e-mail-address-for-users.patch b/SOURCES/0017-TESTS-Allow-storing-e-mail-address-for-users.patch
new file mode 100644
index 0000000..85bee19
--- /dev/null
+++ b/SOURCES/0017-TESTS-Allow-storing-e-mail-address-for-users.patch
@@ -0,0 +1,65 @@
+From 75710952e74ea6070a53baaf5ea4e80507cdc26c Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 21 Jun 2018 12:37:42 +0200
+Subject: [PATCH] TESTS: Allow storing e-mail address for users
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This would allow adding tests for by-e-mail lookups later
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3607
+
+Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
+(cherry picked from commit d057eb2e20a19ce975dc2202f7c0e9f204eb9510)
+---
+ src/tests/intg/ldap_ent.py | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/src/tests/intg/ldap_ent.py b/src/tests/intg/ldap_ent.py
+index a4c987969d3dcefba2af69e095b220180e0fa54c..1f23e3ab7a7ee62909babb8338379a5f2d4e37f2 100644
+--- a/src/tests/intg/ldap_ent.py
++++ b/src/tests/intg/ldap_ent.py
+@@ -25,7 +25,8 @@ def user(base_dn, uid, uidNumber, gidNumber,
+          loginShell=None,
+          cn=None,
+          sn=None,
+-         sshPubKey=()):
++         sshPubKey=(),
++         mail=None):
+     """
+     Generate an RFC2307(bis) user add-modlist for passing to ldap.add*
+     """
+@@ -56,6 +57,8 @@ def user(base_dn, uid, uidNumber, gidNumber,
+     if len(sshPubKey) > 0:
+         pubkeys = [key.encode('utf-8') for key in sshPubKey]
+         user[1].append(('sshPublicKey', pubkeys))
++    if mail is not None:
++        user[1].append(('mail', [mail.encode('utf-8')]))
+     return user
+ 
+ 
+@@ -124,7 +127,8 @@ class List(list):
+                  loginShell=None,
+                  cn=None,
+                  sn=None,
+-                 sshPubKey=()):
++                 sshPubKey=(),
++                 mail=None):
+         """Add an RFC2307(bis) user add-modlist."""
+         self.append(user(base_dn or self.base_dn,
+                          uid, uidNumber, gidNumber,
+@@ -134,7 +138,8 @@ class List(list):
+                          loginShell=loginShell,
+                          cn=cn,
+                          sn=sn,
+-                         sshPubKey=sshPubKey))
++                         sshPubKey=sshPubKey,
++                         mail=mail))
+ 
+     def add_group(self, cn, gidNumber, member_uids=[],
+                   base_dn=None):
+-- 
+2.17.1
+
diff --git a/SOURCES/0018-SYSTEMD-Replace-parameter-debug-to-files-with-DEBUG_.patch b/SOURCES/0018-SYSTEMD-Replace-parameter-debug-to-files-with-DEBUG_.patch
deleted file mode 100644
index a409fab..0000000
--- a/SOURCES/0018-SYSTEMD-Replace-parameter-debug-to-files-with-DEBUG_.patch
+++ /dev/null
@@ -1,259 +0,0 @@
-From 66cdb732268cc8dfd4f0800178d1cc186de83ef7 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Mon, 23 Oct 2017 18:03:46 +0200
-Subject: [PATCH 18/21] SYSTEMD: Replace parameter --debug-to-files with
- ${DEBUG_LOGGER}
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Users can set variable DEBUG_LOGGER in environment files
-(/etc/sysconfig/sssd or /etc/default/sssd; depending on the distribution)
-to override default logging to files.
-
-e.g.
-DEBUG_LOGGER=--logger=stderr
-DEBUG_LOGGER=--logger=journald
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3433
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit a7277fecf7a65ab6c83b36f009c558cdfbf997d2)
----
- Makefile.am                              | 12 +-----------
- contrib/sssd.spec.in                     |  4 ----
- src/sysv/systemd/journal.conf.in         |  7 -------
- src/sysv/systemd/sssd-autofs.service.in  |  3 ++-
- src/sysv/systemd/sssd-ifp.service.in     |  3 ++-
- src/sysv/systemd/sssd-kcm.service.in     |  3 ++-
- src/sysv/systemd/sssd-nss.service.in     |  3 ++-
- src/sysv/systemd/sssd-pac.service.in     |  3 ++-
- src/sysv/systemd/sssd-pam.service.in     |  3 ++-
- src/sysv/systemd/sssd-secrets.service.in |  3 ++-
- src/sysv/systemd/sssd-ssh.service.in     |  3 ++-
- src/sysv/systemd/sssd-sudo.service.in    |  3 ++-
- src/sysv/systemd/sssd.service.in         |  3 ++-
- 13 files changed, 21 insertions(+), 32 deletions(-)
- delete mode 100644 src/sysv/systemd/journal.conf.in
-
-diff --git a/Makefile.am b/Makefile.am
-index 41a8f32f4e76fdcbd09ad833161f0bdada19e389..5483375167d99568e8313c9a0488900419be6ec3 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -91,7 +91,7 @@ sssdkcmdatadir = $(datadir)/sssd-kcm
- deskprofilepath = $(sss_statedir)/deskprofile
- 
- if HAVE_SYSTEMD_UNIT
--ifp_exec_cmd = $(sssdlibexecdir)/sssd_ifp --uid 0 --gid 0 --debug-to-files --dbus-activated
-+ifp_exec_cmd = $(sssdlibexecdir)/sssd_ifp --uid 0 --gid 0 --dbus-activated
- ifp_systemdservice = SystemdService=sssd-ifp.service
- ifp_restart = Restart=on-failure
- else
-@@ -4483,10 +4483,6 @@ if BUILD_KCM
-         src/sysv/systemd/sssd-kcm.service \
-         $(NULL)
- endif
--if WITH_JOURNALD
--    systemdconf_DATA += \
--        src/sysv/systemd/journal.conf
--endif
- else
- if HAVE_SUSE
-     init_SCRIPTS += \
-@@ -4535,7 +4531,6 @@ replace_script = \
- 
- EXTRA_DIST += \
-     src/sysv/systemd/sssd.service.in \
--    src/sysv/systemd/journal.conf.in \
-     src/sysv/systemd/sssd-nss.socket.in \
-     src/sysv/systemd/sssd-nss.service.in \
-     src/sysv/systemd/sssd-pam.socket.in \
-@@ -4585,10 +4580,6 @@ src/sysv/systemd/sssd.service: src/sysv/systemd/sssd.service.in Makefile
- 	@$(MKDIR_P) src/sysv/systemd/
- 	$(replace_script)
- 
--src/sysv/systemd/journal.conf: src/sysv/systemd/journal.conf.in Makefile
--	@$(MKDIR_P) src/sysv/systemd/
--	$(replace_script)
--
- src/sysv/systemd/sssd-nss.socket: src/sysv/systemd/sssd-nss.socket.in Makefile
- 	@$(MKDIR_P) src/sysv/systemd/
- 	$(replace_script)
-@@ -4924,7 +4915,6 @@ endif
- 	rm -f $(builddir)/src/sysv/systemd/sssd-secrets.service
- 	rm -f $(builddir)/src/sysv/systemd/sssd-kcm.socket
- 	rm -f $(builddir)/src/sysv/systemd/sssd-kcm.service
--	rm -f $(builddir)/src/sysv/systemd/journal.conf
- 	rm -f $(builddir)/src/tools/wrappers/sss_debuglevel
- 
- CLEANFILES += *.X */*.X */*/*.X
-diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
-index e76b51833d5dfa3207d28add4af1016c00f25e1f..1ee64d5a2a64635984260fceced779f4804e8b31 100644
---- a/contrib/sssd.spec.in
-+++ b/contrib/sssd.spec.in
-@@ -971,10 +971,6 @@ done
- %attr(711,sssd,sssd) %dir %{_sysconfdir}/sssd
- %attr(711,sssd,sssd) %dir %{_sysconfdir}/sssd/conf.d
- %ghost %attr(0600,sssd,sssd) %config(noreplace) %{_sysconfdir}/sssd/sssd.conf
--%if (0%{?use_systemd} == 1)
--%attr(755,root,root) %dir %{_sysconfdir}/systemd/system/sssd.service.d
--%config(noreplace) %{_sysconfdir}/systemd/system/sssd.service.d/journal.conf
--%endif
- %dir %{_sysconfdir}/logrotate.d
- %config(noreplace) %{_sysconfdir}/logrotate.d/sssd
- %dir %{_sysconfdir}/rwtab.d
-diff --git a/src/sysv/systemd/journal.conf.in b/src/sysv/systemd/journal.conf.in
-deleted file mode 100644
-index 9ce170b4893629792516aab41573adea1fb741f0..0000000000000000000000000000000000000000
---- a/src/sysv/systemd/journal.conf.in
-+++ /dev/null
-@@ -1,7 +0,0 @@
--[Service]
--# Uncomment *both* of the following lines to enable debug logging
--# to go to journald instead of /var/log/sssd. You will need to
--# run 'systemctl daemon-reload' and then restart the SSSD service
--# for this to take effect
--#ExecStart=
--#ExecStart=@sbindir@/sssd -i
-diff --git a/src/sysv/systemd/sssd-autofs.service.in b/src/sysv/systemd/sssd-autofs.service.in
-index 32ea6e19ca7f9aa65599c0cf296a8c5e73362271..c2dc254c8f3f56cb6ae4dc481781688aa702b102 100644
---- a/src/sysv/systemd/sssd-autofs.service.in
-+++ b/src/sysv/systemd/sssd-autofs.service.in
-@@ -9,8 +9,9 @@ RefuseManualStart=true
- Also=sssd-autofs.socket
- 
- [Service]
-+Environment=DEBUG_LOGGER=--logger=files
- ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_autofs.log
--ExecStart=@libexecdir@/sssd/sssd_autofs --debug-to-files --socket-activated
-+ExecStart=@libexecdir@/sssd/sssd_autofs ${DEBUG_LOGGER} --socket-activated
- Restart=on-failure
- User=@SSSD_USER@
- Group=@SSSD_USER@
-diff --git a/src/sysv/systemd/sssd-ifp.service.in b/src/sysv/systemd/sssd-ifp.service.in
-index 8e7abdb0e8c5ec83f9423c688daf845a16c57e7e..05a9a602b2d27c54a4faa79c58e0ecba90267100 100644
---- a/src/sysv/systemd/sssd-ifp.service.in
-+++ b/src/sysv/systemd/sssd-ifp.service.in
-@@ -5,7 +5,8 @@ After=sssd.service
- BindsTo=sssd.service
- 
- [Service]
-+Environment=DEBUG_LOGGER=--logger=files
- Type=dbus
- BusName=org.freedesktop.sssd.infopipe
--ExecStart=@ifp_exec_cmd@
-+ExecStart=@ifp_exec_cmd@ ${DEBUG_LOGGER}
- @ifp_restart@
-diff --git a/src/sysv/systemd/sssd-kcm.service.in b/src/sysv/systemd/sssd-kcm.service.in
-index 1e2bee12dc3bedd17d41b86f91c9b2b52d985c40..92306f97ec73a775739bfdb4454df14956e5e133 100644
---- a/src/sysv/systemd/sssd-kcm.service.in
-+++ b/src/sysv/systemd/sssd-kcm.service.in
-@@ -6,4 +6,5 @@ Documentation=man:sssd-kcm(5)
- Also=sssd-kcm.socket
- 
- [Service]
--ExecStart=@libexecdir@/sssd/sssd_kcm --uid 0 --gid 0 --debug-to-files
-+Environment=DEBUG_LOGGER=--logger=files
-+ExecStart=@libexecdir@/sssd/sssd_kcm --uid 0 --gid 0 ${DEBUG_LOGGER}
-diff --git a/src/sysv/systemd/sssd-nss.service.in b/src/sysv/systemd/sssd-nss.service.in
-index 6a29078d5a36dff229e47bf7ce953e46443ce023..fe771ad0fa99968bb1d42037abf2f960271589b1 100644
---- a/src/sysv/systemd/sssd-nss.service.in
-+++ b/src/sysv/systemd/sssd-nss.service.in
-@@ -9,5 +9,6 @@ RefuseManualStart=true
- Also=sssd-nss.socket
- 
- [Service]
--ExecStart=@libexecdir@/sssd/sssd_nss --debug-to-files --socket-activated
-+Environment=DEBUG_LOGGER=--logger=files
-+ExecStart=@libexecdir@/sssd/sssd_nss ${DEBUG_LOGGER} --socket-activated
- Restart=on-failure
-diff --git a/src/sysv/systemd/sssd-pac.service.in b/src/sysv/systemd/sssd-pac.service.in
-index ffbfdec030ba6d5cf75c989854c27bc46b6983a5..dbd25abc476f579c9d8cce171fdeafa06e567610 100644
---- a/src/sysv/systemd/sssd-pac.service.in
-+++ b/src/sysv/systemd/sssd-pac.service.in
-@@ -9,8 +9,9 @@ RefuseManualStart=true
- Also=sssd-pac.socket
- 
- [Service]
-+Environment=DEBUG_LOGGER=--logger=files
- ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_pac.log
--ExecStart=@libexecdir@/sssd/sssd_pac --debug-to-files --socket-activated
-+ExecStart=@libexecdir@/sssd/sssd_pac ${DEBUG_LOGGER} --socket-activated
- Restart=on-failure
- User=@SSSD_USER@
- Group=@SSSD_USER@
-diff --git a/src/sysv/systemd/sssd-pam.service.in b/src/sysv/systemd/sssd-pam.service.in
-index 6dec46f0c5d384c500268dafcd00af894088e0b6..df722d1f3014bf62cc60114c30331424d14f411b 100644
---- a/src/sysv/systemd/sssd-pam.service.in
-+++ b/src/sysv/systemd/sssd-pam.service.in
-@@ -9,8 +9,9 @@ RefuseManualStart=true
- Also=sssd-pam.socket sssd-pam-priv.socket
- 
- [Service]
-+Environment=DEBUG_LOGGER=--logger=files
- ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_pam.log
--ExecStart=@libexecdir@/sssd/sssd_pam --debug-to-files --socket-activated
-+ExecStart=@libexecdir@/sssd/sssd_pam ${DEBUG_LOGGER} --socket-activated
- Restart=on-failure
- User=@SSSD_USER@
- Group=@SSSD_USER@
-diff --git a/src/sysv/systemd/sssd-secrets.service.in b/src/sysv/systemd/sssd-secrets.service.in
-index f45d647677a62900c01c7eb103597f2b1387498c..a7b41e0b16a5fa882546b41047e616fd2140329f 100644
---- a/src/sysv/systemd/sssd-secrets.service.in
-+++ b/src/sysv/systemd/sssd-secrets.service.in
-@@ -6,4 +6,5 @@ Documentation=man:sssd-secrets(5)
- Also=sssd-secrets.socket
- 
- [Service]
--ExecStart=@libexecdir@/sssd/sssd_secrets --uid 0 --gid 0 --debug-to-files
-+Environment=DEBUG_LOGGER=--logger=files
-+ExecStart=@libexecdir@/sssd/sssd_secrets --uid 0 --gid 0 ${DEBUG_LOGGER}
-diff --git a/src/sysv/systemd/sssd-ssh.service.in b/src/sysv/systemd/sssd-ssh.service.in
-index 6f233b4854018d79cc0ad9d67d53ebd67a49f7b7..f41249ea0fe19e5044d5d06ba195ab604d8e6a29 100644
---- a/src/sysv/systemd/sssd-ssh.service.in
-+++ b/src/sysv/systemd/sssd-ssh.service.in
-@@ -9,8 +9,9 @@ RefuseManualStart=true
- Also=sssd-ssh.socket
- 
- [Service]
-+Environment=DEBUG_LOGGER=--logger=files
- ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_ssh.log
--ExecStart=@libexecdir@/sssd/sssd_ssh --debug-to-files --socket-activated
-+ExecStart=@libexecdir@/sssd/sssd_ssh ${DEBUG_LOGGER} --socket-activated
- Restart=on-failure
- User=@SSSD_USER@
- Group=@SSSD_USER@
-diff --git a/src/sysv/systemd/sssd-sudo.service.in b/src/sysv/systemd/sssd-sudo.service.in
-index b59bcbcd817c3986d7ee245b1083f90ff5a3775a..da022f768af91e360182fad0ff885fad43ecfdc0 100644
---- a/src/sysv/systemd/sssd-sudo.service.in
-+++ b/src/sysv/systemd/sssd-sudo.service.in
-@@ -9,8 +9,9 @@ RefuseManualStart=true
- Also=sssd-sudo.socket
- 
- [Service]
-+Environment=DEBUG_LOGGER=--logger=files
- ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_sudo.log
--ExecStart=@libexecdir@/sssd/sssd_sudo --debug-to-files --socket-activated
-+ExecStart=@libexecdir@/sssd/sssd_sudo --socket-activated
- Restart=on-failure
- User=@SSSD_USER@
- Group=@SSSD_USER@
-diff --git a/src/sysv/systemd/sssd.service.in b/src/sysv/systemd/sssd.service.in
-index 05cfd3705084dbff8b46fb07e736612612c58b70..cea848fac80303d6fae12dd84316a91dbc60072d 100644
---- a/src/sysv/systemd/sssd.service.in
-+++ b/src/sysv/systemd/sssd.service.in
-@@ -5,8 +5,9 @@ Before=systemd-user-sessions.service nss-user-lookup.target
- Wants=nss-user-lookup.target
- 
- [Service]
-+Environment=DEBUG_LOGGER=--logger=files
- EnvironmentFile=-@environment_file@
--ExecStart=@sbindir@/sssd -i -f
-+ExecStart=@sbindir@/sssd -i ${DEBUG_LOGGER}
- Type=notify
- NotifyAccess=main
- 
--- 
-2.13.5
-
diff --git a/SOURCES/0018-TESTS-Add-regression-test-for-looking-up-users-with-.patch b/SOURCES/0018-TESTS-Add-regression-test-for-looking-up-users-with-.patch
new file mode 100644
index 0000000..109d6c0
--- /dev/null
+++ b/SOURCES/0018-TESTS-Add-regression-test-for-looking-up-users-with-.patch
@@ -0,0 +1,93 @@
+From 0cbf6070bccb6c1f904cea596f00af0cc6328bae Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Thu, 21 Jun 2018 12:37:57 +0200
+Subject: [PATCH] TESTS: Add regression test for looking up users with
+ conflicting e-mail addresses
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3607
+
+Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
+(cherry picked from commit 76ce965fc3abfdcf3a4a9518e57545ea060033d6)
+---
+ src/tests/intg/test_ldap.py | 64 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 64 insertions(+)
+
+diff --git a/src/tests/intg/test_ldap.py b/src/tests/intg/test_ldap.py
+index f71915a8086d395e9971a7c82e2744bdd7b931b6..d70ae39841f111fdf2d6c00c9acca8073725c5c5 100644
+--- a/src/tests/intg/test_ldap.py
++++ b/src/tests/intg/test_ldap.py
+@@ -1736,3 +1736,67 @@ def test_local_negative_timeout_disabled(ldap_conn,
+     assert res == NssReturnCode.SUCCESS
+ 
+     cleanup_ldap_entries(ldap_conn, ent_list)
++
++
++@pytest.fixture
++def users_with_email_setup(request, ldap_conn):
++    ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn)
++    ent_list.add_user("user1", 1001, 2001, mail="user1.email@LDAP")
++
++    ent_list.add_user("emailuser", 1002, 2002)
++    ent_list.add_user("emailuser2", 1003, 2003, mail="emailuser@LDAP")
++
++    ent_list.add_user("userx", 1004, 2004, mail="userxy@LDAP")
++    ent_list.add_user("usery", 1005, 2005, mail="userxy@LDAP")
++
++    create_ldap_fixture(request, ldap_conn, ent_list)
++
++    conf = format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS)
++    create_conf_fixture(request, conf)
++    create_sssd_fixture(request)
++    return None
++
++
++def test_lookup_by_email(ldap_conn, users_with_email_setup):
++    """
++    Test the simple case of looking up a user by e-mail
++    """
++    ent.assert_passwd_by_name("user1.email@LDAP",
++                              dict(name="user1", uid=1001, gid=2001))
++
++
++def test_conflicting_mail_addresses_and_fqdn(ldap_conn,
++                                             users_with_email_setup):
++    """
++    Test that we handle the case where one user's mail address is the
++    same as another user's FQDN
++
++    This is a regression test for https://pagure.io/SSSD/sssd/issue/3607
++    """
++    # With #3607 unfixed, these two lookups would prime the cache with
++    # nameAlias: emailuser@LDAP for both entries..
++    ent.assert_passwd_by_name("emailuser@LDAP",
++                              dict(name="emailuser", uid=1002, gid=2002))
++    ent.assert_passwd_by_name("emailuser2@LDAP",
++                              dict(name="emailuser2", uid=1003, gid=2003))
++
++    # ..and subsequently, emailuser would not be returned because the cache
++    # lookup would have had returned two entries which is an error
++    ent.assert_passwd_by_name("emailuser@LDAP",
++                              dict(name="emailuser", uid=1002, gid=2002))
++    ent.assert_passwd_by_name("emailuser2@LDAP",
++                              dict(name="emailuser2", uid=1003, gid=2003))
++
++
++def test_conflicting_mail_addresses(ldap_conn,
++                                    users_with_email_setup):
++    """
++    Negative test: looking up a user by e-mail which belongs to more than
++    one account fails in the back end.
++    """
++    with pytest.raises(KeyError):
++        pwd.getpwnam("userxy@LDAP")
++
++    # However resolving the users on their own must work
++    ent.assert_passwd_by_name("userx", dict(name="userx", uid=1004, gid=2004))
++    ent.assert_passwd_by_name("usery", dict(name="usery", uid=1005, gid=2005))
+-- 
+2.17.1
+
diff --git a/SOURCES/0019-MAN-Remove-outdated-notes-from-the-re_expression-des.patch b/SOURCES/0019-MAN-Remove-outdated-notes-from-the-re_expression-des.patch
new file mode 100644
index 0000000..4ce9fed
--- /dev/null
+++ b/SOURCES/0019-MAN-Remove-outdated-notes-from-the-re_expression-des.patch
@@ -0,0 +1,47 @@
+From 8d5241404e8eb2388a9fc45115f5210e3ada1f1b Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 22 Jun 2018 10:40:29 +0200
+Subject: [PATCH] MAN: Remove outdated notes from the re_expression description
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+These notes are only valid for very old pcre releases which hopefully
+nobody is using anymore.
+
+Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 4c79db69cbad88ed56e87e8fe61f697f72d7408d)
+
+DOWNSTREAM:
+Resolves: rhbz#1509691 - Document how to change the regular expression for SSSD so that group names with an @-sign can be parsed
+---
+ src/man/sssd.conf.5.xml | 12 ------------
+ 1 file changed, 12 deletions(-)
+
+diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
+index beed677072c9bbfb9e7749f25c2a90d743f9328d..558c97e834d7aaf46adb31b1573eb59705569782 100644
+--- a/src/man/sssd.conf.5.xml
++++ b/src/man/sssd.conf.5.xml
+@@ -2630,18 +2630,6 @@ pam_account_locked_message = Account locked, please contact help desk.
+                             the <quote>@</quote> sign, the domain everything
+                             after that"
+                         </para>
+-                        <para>
+-                            PLEASE NOTE: the support for non-unique named
+-                            subpatterns is not available on all platforms
+-                            (e.g. RHEL5 and SLES10). Only platforms with
+-                            libpcre version 7 or higher can support non-unique
+-                            named subpatterns.
+-                        </para>
+-                        <para>
+-                            PLEASE NOTE ALSO: older version of libpcre only
+-                            support the Python syntax (?P&lt;name&gt;) to label
+-                            subpatterns.
+-                        </para>
+                     </listitem>
+                 </varlistentry>
+                 <varlistentry>
+-- 
+2.17.1
+
diff --git a/SOURCES/0019-SYSTEMD-Add-environment-file-to-responder-service-fi.patch b/SOURCES/0019-SYSTEMD-Add-environment-file-to-responder-service-fi.patch
deleted file mode 100644
index 060c43e..0000000
--- a/SOURCES/0019-SYSTEMD-Add-environment-file-to-responder-service-fi.patch
+++ /dev/null
@@ -1,107 +0,0 @@
-From cc4f298024b2ef08cc0740ebbaf916bd494ef892 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Tue, 24 Oct 2017 12:15:48 +0200
-Subject: [PATCH 19/21] SYSTEMD: Add environment file to responder service
- files
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 115145f0fb7507c1b9c5489bc77398d422a66875)
----
- src/sysv/systemd/sssd-autofs.service.in | 1 +
- src/sysv/systemd/sssd-ifp.service.in    | 1 +
- src/sysv/systemd/sssd-nss.service.in    | 1 +
- src/sysv/systemd/sssd-pac.service.in    | 1 +
- src/sysv/systemd/sssd-pam.service.in    | 1 +
- src/sysv/systemd/sssd-ssh.service.in    | 1 +
- src/sysv/systemd/sssd-sudo.service.in   | 1 +
- 7 files changed, 7 insertions(+)
-
-diff --git a/src/sysv/systemd/sssd-autofs.service.in b/src/sysv/systemd/sssd-autofs.service.in
-index c2dc254c8f3f56cb6ae4dc481781688aa702b102..7f920ad66a46bb0785c3f947bc26c15d0e370259 100644
---- a/src/sysv/systemd/sssd-autofs.service.in
-+++ b/src/sysv/systemd/sssd-autofs.service.in
-@@ -10,6 +10,7 @@ Also=sssd-autofs.socket
- 
- [Service]
- Environment=DEBUG_LOGGER=--logger=files
-+EnvironmentFile=-@environment_file@
- ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_autofs.log
- ExecStart=@libexecdir@/sssd/sssd_autofs ${DEBUG_LOGGER} --socket-activated
- Restart=on-failure
-diff --git a/src/sysv/systemd/sssd-ifp.service.in b/src/sysv/systemd/sssd-ifp.service.in
-index 05a9a602b2d27c54a4faa79c58e0ecba90267100..f3bf92223ce8847858f57c2bb04b97c858be0ead 100644
---- a/src/sysv/systemd/sssd-ifp.service.in
-+++ b/src/sysv/systemd/sssd-ifp.service.in
-@@ -6,6 +6,7 @@ BindsTo=sssd.service
- 
- [Service]
- Environment=DEBUG_LOGGER=--logger=files
-+EnvironmentFile=-@environment_file@
- Type=dbus
- BusName=org.freedesktop.sssd.infopipe
- ExecStart=@ifp_exec_cmd@ ${DEBUG_LOGGER}
-diff --git a/src/sysv/systemd/sssd-nss.service.in b/src/sysv/systemd/sssd-nss.service.in
-index fe771ad0fa99968bb1d42037abf2f960271589b1..c671280f2c8a7f85fd09a72983a21db0c30df3b9 100644
---- a/src/sysv/systemd/sssd-nss.service.in
-+++ b/src/sysv/systemd/sssd-nss.service.in
-@@ -10,5 +10,6 @@ Also=sssd-nss.socket
- 
- [Service]
- Environment=DEBUG_LOGGER=--logger=files
-+EnvironmentFile=-@environment_file@
- ExecStart=@libexecdir@/sssd/sssd_nss ${DEBUG_LOGGER} --socket-activated
- Restart=on-failure
-diff --git a/src/sysv/systemd/sssd-pac.service.in b/src/sysv/systemd/sssd-pac.service.in
-index dbd25abc476f579c9d8cce171fdeafa06e567610..590449b01223fe799eebb12b63229dfb8f2438f9 100644
---- a/src/sysv/systemd/sssd-pac.service.in
-+++ b/src/sysv/systemd/sssd-pac.service.in
-@@ -10,6 +10,7 @@ Also=sssd-pac.socket
- 
- [Service]
- Environment=DEBUG_LOGGER=--logger=files
-+EnvironmentFile=-@environment_file@
- ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_pac.log
- ExecStart=@libexecdir@/sssd/sssd_pac ${DEBUG_LOGGER} --socket-activated
- Restart=on-failure
-diff --git a/src/sysv/systemd/sssd-pam.service.in b/src/sysv/systemd/sssd-pam.service.in
-index df722d1f3014bf62cc60114c30331424d14f411b..f2e938579c7ef4254bb2e05231bfe83d7e20f395 100644
---- a/src/sysv/systemd/sssd-pam.service.in
-+++ b/src/sysv/systemd/sssd-pam.service.in
-@@ -10,6 +10,7 @@ Also=sssd-pam.socket sssd-pam-priv.socket
- 
- [Service]
- Environment=DEBUG_LOGGER=--logger=files
-+EnvironmentFile=-@environment_file@
- ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_pam.log
- ExecStart=@libexecdir@/sssd/sssd_pam ${DEBUG_LOGGER} --socket-activated
- Restart=on-failure
-diff --git a/src/sysv/systemd/sssd-ssh.service.in b/src/sysv/systemd/sssd-ssh.service.in
-index f41249ea0fe19e5044d5d06ba195ab604d8e6a29..1c185466dfa8c13804cc980bbbdbc997d4ebe955 100644
---- a/src/sysv/systemd/sssd-ssh.service.in
-+++ b/src/sysv/systemd/sssd-ssh.service.in
-@@ -10,6 +10,7 @@ Also=sssd-ssh.socket
- 
- [Service]
- Environment=DEBUG_LOGGER=--logger=files
-+EnvironmentFile=-@environment_file@
- ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_ssh.log
- ExecStart=@libexecdir@/sssd/sssd_ssh ${DEBUG_LOGGER} --socket-activated
- Restart=on-failure
-diff --git a/src/sysv/systemd/sssd-sudo.service.in b/src/sysv/systemd/sssd-sudo.service.in
-index da022f768af91e360182fad0ff885fad43ecfdc0..f13d88107eccd9e80447390c9c0f8940ae933106 100644
---- a/src/sysv/systemd/sssd-sudo.service.in
-+++ b/src/sysv/systemd/sssd-sudo.service.in
-@@ -10,6 +10,7 @@ Also=sssd-sudo.socket
- 
- [Service]
- Environment=DEBUG_LOGGER=--logger=files
-+EnvironmentFile=-@environment_file@
- ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_sudo.log
- ExecStart=@libexecdir@/sssd/sssd_sudo --socket-activated
- Restart=on-failure
--- 
-2.13.5
-
diff --git a/SOURCES/0020-SUDO-Create-the-socket-with-stricter-permissions.patch b/SOURCES/0020-SUDO-Create-the-socket-with-stricter-permissions.patch
new file mode 100644
index 0000000..0b81675
--- /dev/null
+++ b/SOURCES/0020-SUDO-Create-the-socket-with-stricter-permissions.patch
@@ -0,0 +1,58 @@
+From e13d53326bc154c684ea1bef9efc5922b5228945 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Fri, 15 Jun 2018 22:29:34 +0200
+Subject: [PATCH] SUDO: Create the socket with stricter permissions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch switches the sudo responder from being created as a public
+responder where the permissions are open and not checked by the sssd
+deaamon to a private socket. In this case, sssd creates the pipes with
+strict permissions (see the umask in the call to create_pipe_fd() in
+set_unix_socket()) and additionaly checks the permissions with every read
+via the tevent integrations (see accept_fd_handler()).
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3766 (CVE-2018-10852)
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit ed90a20a0f0e936eb00d268080716c0384ffb01d)
+
+DOWNSTREAM:
+Resolves: rhbz#1590603 - EMBARGOED CVE-2018-10852 sssd: information leak from the sssd-sudo responder [rhel-7]
+---
+ src/responder/sudo/sudosrv.c         | 3 ++-
+ src/sysv/systemd/sssd-sudo.socket.in | 1 +
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c
+index ac4258710d3a9b48285522abd23bdd59ba42ad4e..e87a24499c2d82fafaa8e1f9b386e44332394266 100644
+--- a/src/responder/sudo/sudosrv.c
++++ b/src/responder/sudo/sudosrv.c
+@@ -79,7 +79,8 @@ int sudo_process_init(TALLOC_CTX *mem_ctx,
+     sudo_cmds = get_sudo_cmds();
+     ret = sss_process_init(mem_ctx, ev, cdb,
+                            sudo_cmds,
+-                           SSS_SUDO_SOCKET_NAME, -1, NULL, -1,
++                           NULL, -1,                   /* No public socket */
++                           SSS_SUDO_SOCKET_NAME, -1,   /* Private socket only */
+                            CONFDB_SUDO_CONF_ENTRY,
+                            SSS_SUDO_SBUS_SERVICE_NAME,
+                            SSS_SUDO_SBUS_SERVICE_VERSION,
+diff --git a/src/sysv/systemd/sssd-sudo.socket.in b/src/sysv/systemd/sssd-sudo.socket.in
+index c9abb875f0accbaf58d78846020fef74c7473528..96a8b0327ddb4d331c9b2e97ece3453f8f76872d 100644
+--- a/src/sysv/systemd/sssd-sudo.socket.in
++++ b/src/sysv/systemd/sssd-sudo.socket.in
+@@ -11,6 +11,7 @@ ExecStartPre=@libexecdir@/sssd/sssd_check_socket_activated_responders -r sudo
+ ListenStream=@pipepath@/sudo
+ SocketUser=@SSSD_USER@
+ SocketGroup=@SSSD_USER@
++SocketMode=0600
+ 
+ [Install]
+ WantedBy=sssd.service
+-- 
+2.17.1
+
diff --git a/SOURCES/0020-UTIL-Hide-and-deprecate-parameter-debug-to-files.patch b/SOURCES/0020-UTIL-Hide-and-deprecate-parameter-debug-to-files.patch
deleted file mode 100644
index 8ade838..0000000
--- a/SOURCES/0020-UTIL-Hide-and-deprecate-parameter-debug-to-files.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 65e47ac92a16c57058b955fe9ec2e17b838a37db Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Tue, 24 Oct 2017 12:07:46 +0200
-Subject: [PATCH 20/21] UTIL: Hide and deprecate parameter --debug-to-files
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Reviewed-by: Justin Stephenson <jstephen@redhat.com>
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 18a47bcc463c866de6b6b0327e6d85ceb1e0f7d6)
----
- src/man/sssd.8.xml | 4 ++++
- src/util/debug.h   | 2 +-
- 2 files changed, 5 insertions(+), 1 deletion(-)
-
-diff --git a/src/man/sssd.8.xml b/src/man/sssd.8.xml
-index 0b725628ff93f48f832140dd5dc15b040a8b179f..f2cbe015b844579af98aebd864770bc651dcf4b1 100644
---- a/src/man/sssd.8.xml
-+++ b/src/man/sssd.8.xml
-@@ -90,6 +90,10 @@
-                         log files are stored in <filename>/var/log/sssd</filename> and
-                         there are separate log files for every SSSD service and domain.
-                     </para>
-+                    <para>
-+                        This option is deprecated. It is replaced by
-+                        <option>--logger=files</option>.
-+                    </para>
-                 </listitem>
-             </varlistentry>
-             <varlistentry>
-diff --git a/src/util/debug.h b/src/util/debug.h
-index 4adafb7cfc03f7381c4d03071eb44edad04bee00..09f50cc9f3122f02d8ba2092dfb7ee633332de9b 100644
---- a/src/util/debug.h
-+++ b/src/util/debug.h
-@@ -101,7 +101,7 @@ int get_fd_from_debug_file(void);
- #define SSSD_DEBUG_OPTS \
-         {"debug-level", 'd', POPT_ARG_INT, &debug_level, 0, \
-          _("Debug level"), NULL}, \
--        {"debug-to-files", 'f', POPT_ARG_NONE, &debug_to_file, 0, \
-+        {"debug-to-files", 'f', POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_file, 0, \
-          _("Send the debug output to files instead of stderr"), NULL }, \
-         {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_stderr, 0, \
-          _("Send the debug output to stderr directly."), NULL }, \
--- 
-2.13.5
-
diff --git a/SOURCES/0021-LDAP-Bind-to-the-LDAP-server-also-in-the-auth.patch b/SOURCES/0021-LDAP-Bind-to-the-LDAP-server-also-in-the-auth.patch
deleted file mode 100644
index 6f138f1..0000000
--- a/SOURCES/0021-LDAP-Bind-to-the-LDAP-server-also-in-the-auth.patch
+++ /dev/null
@@ -1,213 +0,0 @@
-From 7ebfab326f94e508ce2910c7242a8dd7652ec8a2 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
-Date: Wed, 25 Oct 2017 11:25:09 +0200
-Subject: [PATCH 21/21] LDAP: Bind to the LDAP server also in the auth
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-When dealing with id_provider not being the same as auth_provider, SSSD
-has to bind the DN of the user which wants to authenticate with the
-ldap_default_bind_dn and the password provided by the user.
-
-In order to do so, the least intrusive way is just by replacing
-sdap_connect*() functions by sdap_cli_connect*() functions in the LDAP's
-auth module.
-
-The simple change also allowed us to remove some code that is already
-executed as part of sdap_cli_connect*() and some functions had their
-names adapted to reflect better their new purpose.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3451
-
-Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit add72860c7a7a2c418f4d8b6790b5caeaf7dfb7b)
----
- src/providers/ldap/ldap_auth.c | 114 +++++++++--------------------------------
- 1 file changed, 25 insertions(+), 89 deletions(-)
-
-diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
-index 00ddd889b6294e457c13218491547b84f1468266..a3b1480aae4272d2e10f105a1eaf3a5816c3487c 100644
---- a/src/providers/ldap/ldap_auth.c
-+++ b/src/providers/ldap/ldap_auth.c
-@@ -619,14 +619,11 @@ struct auth_state {
-     char *dn;
-     enum pwexpire pw_expire_type;
-     void *pw_expire_data;
--
--    struct fo_server *srv;
- };
- 
--static struct tevent_req *auth_get_server(struct tevent_req *req);
-+static struct tevent_req *auth_connect_send(struct tevent_req *req);
- static void auth_get_dn_done(struct tevent_req *subreq);
- static void auth_do_bind(struct tevent_req *req);
--static void auth_resolve_done(struct tevent_req *subreq);
- static void auth_connect_done(struct tevent_req *subreq);
- static void auth_bind_user_done(struct tevent_req *subreq);
- 
-@@ -659,7 +656,6 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx,
-     state->ctx = ctx;
-     state->username = username;
-     state->authtok = authtok;
--    state->srv = NULL;
-     if (try_chpass_service && ctx->chpass_service != NULL &&
-         ctx->chpass_service->name != NULL) {
-         state->sdap_service = ctx->chpass_service;
-@@ -667,7 +663,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx,
-         state->sdap_service = ctx->service;
-     }
- 
--    if (!auth_get_server(req)) goto fail;
-+    if (!auth_connect_send(req)) goto fail;
- 
-     return req;
- 
-@@ -676,75 +672,37 @@ fail:
-     return NULL;
- }
- 
--static struct tevent_req *auth_get_server(struct tevent_req *req)
-+static struct tevent_req *auth_connect_send(struct tevent_req *req)
- {
--    struct tevent_req *next_req;
-+    struct tevent_req *subreq;
-     struct auth_state *state = tevent_req_data(req,
-                                                struct auth_state);
--
--     /* NOTE: this call may cause service->uri to be refreshed
--      * with a new valid server. Do not use service->uri before */
--    next_req = be_resolve_server_send(state,
--                                      state->ev,
--                                      state->ctx->be,
--                                      state->sdap_service->name,
--                                      state->srv == NULL ? true : false);
--    if (!next_req) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "be_resolve_server_send failed.\n");
--        return NULL;
--    }
--
--    tevent_req_set_callback(next_req, auth_resolve_done, req);
--    return next_req;
--}
--
--static void auth_resolve_done(struct tevent_req *subreq)
--{
--    struct tevent_req *req = tevent_req_callback_data(subreq,
--                                                      struct tevent_req);
--    struct auth_state *state = tevent_req_data(req,
--                                                    struct auth_state);
--    int ret;
-     bool use_tls;
- 
--    ret = be_resolve_server_recv(subreq, state, &state->srv);
--    talloc_zfree(subreq);
--    if (ret) {
--        /* all servers have been tried and none
--         * was found good, go offline */
--        tevent_req_error(req, ETIMEDOUT);
--        return;
-+    /* Check for undocumented debugging feature to disable TLS
-+     * for authentication. This should never be used in production
-+     * for obvious reasons.
-+     */
-+    use_tls = !dp_opt_get_bool(state->ctx->opts->basic, SDAP_DISABLE_AUTH_TLS);
-+    if (!use_tls) {
-+        sss_log(SSS_LOG_ALERT, "LDAP authentication being performed over "
-+                               "insecure connection. This should be done "
-+                               "for debugging purposes only.");
-     }
- 
--    /* Determine whether we need to use TLS */
--    if (sdap_is_secure_uri(state->ctx->service->uri)) {
--        DEBUG(SSSDBG_TRACE_INTERNAL,
--              "[%s] is a secure channel. No need to run START_TLS\n",
--                  state->ctx->service->uri);
--        use_tls = false;
--    } else {
-+    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);
- 
--        /* Check for undocumented debugging feature to disable TLS
--         * for authentication. This should never be used in production
--         * for obvious reasons.
--         */
--        use_tls = !dp_opt_get_bool(state->ctx->opts->basic, SDAP_DISABLE_AUTH_TLS);
--        if (!use_tls) {
--            sss_log(SSS_LOG_ALERT, "LDAP authentication being performed over "
--                                   "insecure connection. This should be done "
--                                   "for debugging purposes only.");
--        }
--    }
--
--    subreq = sdap_connect_send(state, state->ev, state->ctx->opts,
--                               state->sdap_service->uri,
--                               state->sdap_service->sockaddr, use_tls);
--    if (!subreq) {
-+    if (subreq == NULL) {
-         tevent_req_error(req, ENOMEM);
--        return;
-+        return NULL;
-     }
- 
-     tevent_req_set_callback(subreq, auth_connect_done, req);
-+
-+    return subreq;
- }
- 
- static void auth_connect_done(struct tevent_req *subreq)
-@@ -755,35 +713,13 @@ static void auth_connect_done(struct tevent_req *subreq)
-                                                     struct auth_state);
-     int ret;
- 
--    ret = sdap_connect_recv(subreq, state, &state->sh);
-+    ret = sdap_cli_connect_recv(subreq, state, NULL, &state->sh, NULL);
-     talloc_zfree(subreq);
--    if (ret) {
--        if (state->srv) {
--            /* mark this server as bad if connection failed */
--            be_fo_set_port_status(state->ctx->be,
--                                  state->sdap_service->name,
--                                  state->srv, PORT_NOT_WORKING);
--        }
--
--        if (auth_get_server(req) == NULL) {
-+    if (ret != EOK) {
-+        if (auth_connect_send(req) == NULL) {
-             tevent_req_error(req, ENOMEM);
-         }
-         return;
--    } else if (state->srv) {
--        be_fo_set_port_status(state->ctx->be, state->sdap_service->name,
--                              state->srv, PORT_WORKING);
--    }
--
--    /* In case the ID provider is set to proxy, this might be the first
--     * LDAP operation at all, so we need to set the connection status
--     */
--    if (state->sh->connected == false) {
--        ret = sdap_set_connected(state->sh, state->ev);
--        if (ret) {
--            DEBUG(SSSDBG_OP_FAILURE, "Cannot set connected status\n");
--            tevent_req_error(req, ret);
--            return;
--        }
-     }
- 
-     ret = get_user_dn(state, state->ctx->be->domain,
-@@ -870,7 +806,7 @@ static void auth_bind_user_done(struct tevent_req *subreq)
-         break;
-     case ETIMEDOUT:
-     case ERR_NETWORK_IO:
--        if (auth_get_server(req) == NULL) {
-+        if (auth_connect_send(req) == NULL) {
-             tevent_req_error(req, ENOMEM);
-         }
-         return;
--- 
-2.13.5
-
diff --git a/SOURCES/0021-MAN-Give-information-regarding-priority-of-ldap-look.patch b/SOURCES/0021-MAN-Give-information-regarding-priority-of-ldap-look.patch
new file mode 100644
index 0000000..56e7687
--- /dev/null
+++ b/SOURCES/0021-MAN-Give-information-regarding-priority-of-ldap-look.patch
@@ -0,0 +1,49 @@
+From 7689f3c8b4661c16a019c4410b1557f6ae4229aa Mon Sep 17 00:00:00 2001
+From: amitkumar50 <amitkuma@redhat.com>
+Date: Fri, 15 Jun 2018 10:45:38 +0530
+Subject: [PATCH] MAN: Give information regarding priority of ldap lookup
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This PR provides information about priority of lookup
+similar to as provided by function select_principal_from_keytab().
+
+Resolves: https://pagure.io/SSSD/sssd/issue/3475
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit c5ef56b4f9ffb361742edae36b261a4ffd0e75ae)
+
+DOWNSTREAM:
+Resolves: rhbz#1450778 - Full information regarding priority of lookup of principal in keytab not in man page
+---
+ src/man/sssd-ldap.5.xml | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
+index f7617670c8b0fe1a5922c1a811b94e25bacecbfe..3145f0730341bf40159277ef2ae23be601154a89 100644
+--- a/src/man/sssd-ldap.5.xml
++++ b/src/man/sssd-ldap.5.xml
+@@ -1778,7 +1778,18 @@
+                             principal used for authentication to the directory.
+                             This option can either contain the full principal (for
+                             example host/myhost@EXAMPLE.COM) or just the principal name
+-                            (for example host/myhost).
++                            (for example host/myhost). By default, the value is not set
++                            and the following principals are used:
++                            <programlisting>
++hostname@REALM
++netbiosname$@REALM
++host/hostname@REALM
++*$@REALM
++host/*@REALM
++host/*
++                            </programlisting>
++                            If none of them are found, the first principal in keytab is
++                            returned.
+                         </para>
+                         <para>
+                             Default: host/hostname@REALM
+-- 
+2.17.1
+
diff --git a/SOURCES/0022-AD-LDAP-Do-not-misuse-the-ignore_mark_offline-to-che.patch b/SOURCES/0022-AD-LDAP-Do-not-misuse-the-ignore_mark_offline-to-che.patch
new file mode 100644
index 0000000..2806c55
--- /dev/null
+++ b/SOURCES/0022-AD-LDAP-Do-not-misuse-the-ignore_mark_offline-to-che.patch
@@ -0,0 +1,82 @@
+From 7b8ed13c2bac164fdc49227d1b51364bdf907a98 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 19 Jun 2018 16:09:30 +0200
+Subject: [PATCH] AD/LDAP: Do not misuse the ignore_mark_offline to check if a
+ connection needs to be checked for POSIX attribute presence
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The logic behind deciding whether to check if a server contains any
+POSIX attributes used the ignore_mark_offline flag. This was OK for some
+time, because this flag was only set for to true for Global Catalog
+connections, which are those that we need to check.
+
+However, in recent releases, the flag was also set for any connection
+towards a trusted domain. This had the unintended effect that any
+lookup, LDAP or GC against a trusted domain ran the wide POSIX presence
+check.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3754
+
+Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
+(cherry picked from commit 5e1641b104f159f9fa47c3008d84119dfd5ab226)
+
+DOWNSTREAM:
+Resolves: rhbz#1583725 - SSSD AD uses LDAP filter to detect POSIX attributes stored in AD GC also for regular AD DC queries
+---
+ src/providers/ad/ad_common.c     | 2 ++
+ src/providers/ldap/ldap_common.c | 2 +-
+ src/providers/ldap/ldap_common.h | 2 ++
+ 3 files changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
+index 8caaba6c0d06cfe83d9741536192d662fc936273..feeb5d09643a02b99be1a387b41842a034a323b8 100644
+--- a/src/providers/ad/ad_common.c
++++ b/src/providers/ad/ad_common.c
+@@ -1408,6 +1408,7 @@ ad_gc_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx,
+         clist[cindex] = ad_ctx->gc_ctx;
+         clist[cindex]->ignore_mark_offline = true;
+         clist[cindex]->no_mpg_user_fallback = true;
++        clist[cindex]->check_posix_attrs = true;
+         cindex++;
+     }
+ 
+@@ -1454,6 +1455,7 @@ ad_user_conn_list(TALLOC_CTX *mem_ctx,
+             && IS_SUBDOMAIN(dom)) {
+         clist[cindex] = ad_ctx->gc_ctx;
+         clist[cindex]->ignore_mark_offline = true;
++        clist[cindex]->check_posix_attrs = true;
+         cindex++;
+     }
+ 
+diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
+index 15377ee1f062c0167aabee30ef0757ebe7271682..a0a9b8523310b2551ee992f8d0c2e369dafaa56d 100644
+--- a/src/providers/ldap/ldap_common.c
++++ b/src/providers/ldap/ldap_common.c
+@@ -893,7 +893,7 @@ bool should_run_posix_check(struct sdap_id_ctx *ctx,
+     if (use_id_mapping == false &&
+             posix_request == true &&
+             ctx->opts->schema_type == SDAP_SCHEMA_AD &&
+-            conn->ignore_mark_offline == true &&
++            conn->check_posix_attrs == true &&
+             ctx->srv_opts &&
+             ctx->srv_opts->posix_checked == false) {
+         return true;
+diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
+index 3cefdd0bfb0e96b5a7f904fe753dfc457b2a45c2..3de3568cb28c258c00f9b522c0b9120adca81d81 100644
+--- a/src/providers/ldap/ldap_common.h
++++ b/src/providers/ldap/ldap_common.h
+@@ -59,6 +59,8 @@ struct sdap_id_conn_ctx {
+     bool ignore_mark_offline;
+     /* do not fall back to user lookups for mpg domains on this connection */
+     bool no_mpg_user_fallback;
++    /* check if this connection contains POSIX attributes */
++    bool check_posix_attrs;
+ };
+ 
+ struct sdap_id_ctx {
+-- 
+2.17.1
+
diff --git a/SOURCES/0022-sss_client-create-nss_common.h.patch b/SOURCES/0022-sss_client-create-nss_common.h.patch
deleted file mode 100644
index f695b2b..0000000
--- a/SOURCES/0022-sss_client-create-nss_common.h.patch
+++ /dev/null
@@ -1,143 +0,0 @@
-From 22c5575eb442f20230081cc06528d685397c8914 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 29 Sep 2017 21:38:54 +0200
-Subject: [PATCH 22/31] sss_client: create nss_common.h
-
-This patch makes sss_nss_getpw_readrep() and sss_nss_getgr_readrep()
-calls which parse SSSD's replies for user and group requests available
-to other components.
-
-Related to https://pagure.io/SSSD/sssd/issue/2478
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 7449b236523409cc8766fb957d6cba051fdfb483)
----
- Makefile.am                 |  1 +
- src/sss_client/nss_common.h | 43 +++++++++++++++++++++++++++++++++++++++++++
- src/sss_client/nss_group.c  | 10 +++-------
- src/sss_client/nss_passwd.c | 11 +++--------
- 4 files changed, 50 insertions(+), 15 deletions(-)
- create mode 100644 src/sss_client/nss_common.h
-
-diff --git a/Makefile.am b/Makefile.am
-index 5483375167d99568e8313c9a0488900419be6ec3..dc2f4b1857ce5bd376544488348731be29b6b293 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -3623,6 +3623,7 @@ libnss_sss_la_SOURCES = \
-     src/sss_client/nss_services.c \
-     src/sss_client/sss_cli.h \
-     src/sss_client/nss_compat.h \
-+    src/sss_client/nss_common.h \
-     src/sss_client/nss_mc_common.c \
-     src/util/io.c \
-     src/util/murmurhash3.c \
-diff --git a/src/sss_client/nss_common.h b/src/sss_client/nss_common.h
-new file mode 100644
-index 0000000000000000000000000000000000000000..e83b4f95a3136b5aa711194a4d37389eebfb607a
---- /dev/null
-+++ b/src/sss_client/nss_common.h
-@@ -0,0 +1,43 @@
-+/*
-+   SSSD
-+
-+   Common routines for classical and enhanced NSS interface
-+
-+   Authors:
-+        Sumit Bose <sbose@redhat.com>
-+
-+   Copyright (C) Red Hat, Inc 2007
-+
-+   This program is free software; you can redistribute it and/or modify
-+   it under the terms of the GNU Lesser General Public License as published by
-+   the Free Software Foundation; either version 3 of the License, or
-+   (at your option) any later version.
-+
-+   This program is distributed in the hope that it will be useful,
-+   but WITHOUT ANY WARRANTY; without even the implied warranty of
-+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+   GNU Lesser General Public License for more details.
-+
-+   You should have received a copy of the GNU Lesser General Public License
-+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+
-+
-+
-+struct sss_nss_pw_rep {
-+    struct passwd *result;
-+    char *buffer;
-+    size_t buflen;
-+};
-+
-+int sss_nss_getpw_readrep(struct sss_nss_pw_rep *pr,
-+                          uint8_t *buf, size_t *len);
-+
-+struct sss_nss_gr_rep {
-+    struct group *result;
-+    char *buffer;
-+    size_t buflen;
-+};
-+
-+int sss_nss_getgr_readrep(struct sss_nss_gr_rep *pr,
-+                          uint8_t *buf, size_t *len);
-diff --git a/src/sss_client/nss_group.c b/src/sss_client/nss_group.c
-index 0e686af43aeb84a5938315e3922e9fcf2fef4e83..42fba6242d23fc1d52cfd7be10cf10383010f091 100644
---- a/src/sss_client/nss_group.c
-+++ b/src/sss_client/nss_group.c
-@@ -29,6 +29,7 @@
- #include <stdbool.h>
- #include "sss_cli.h"
- #include "nss_mc.h"
-+#include "nss_common.h"
- 
- static struct sss_nss_getgrent_data {
-     size_t len;
-@@ -190,14 +191,9 @@ done:
-  *
-  *  FIXME: do we need to pad so that each result is 32 bit aligned ?
-  */
--struct sss_nss_gr_rep {
--    struct group *result;
--    char *buffer;
--    size_t buflen;
--};
- 
--static int sss_nss_getgr_readrep(struct sss_nss_gr_rep *pr,
--                                 uint8_t *buf, size_t *len)
-+int sss_nss_getgr_readrep(struct sss_nss_gr_rep *pr,
-+                          uint8_t *buf, size_t *len)
- {
-     errno_t ret;
-     size_t i, l, slen, ptmem, pad, dlen, glen;
-diff --git a/src/sss_client/nss_passwd.c b/src/sss_client/nss_passwd.c
-index c43f9bc50f43599b541e97f5a5aa60de036a5cdf..61e2a567e684fbc7664b5d425e81cfa28a98e845 100644
---- a/src/sss_client/nss_passwd.c
-+++ b/src/sss_client/nss_passwd.c
-@@ -28,6 +28,7 @@
- #include <string.h>
- #include "sss_cli.h"
- #include "nss_mc.h"
-+#include "nss_common.h"
- 
- static struct sss_nss_getpwent_data {
-     size_t len;
-@@ -63,14 +64,8 @@ static void sss_nss_getpwent_data_clean(void) {
-  *  8-X: sequence of 5, 0 terminated, strings (name, passwd, gecos, dir, shell)
-  */
- 
--struct sss_nss_pw_rep {
--    struct passwd *result;
--    char *buffer;
--    size_t buflen;
--};
--
--static int sss_nss_getpw_readrep(struct sss_nss_pw_rep *pr,
--                                 uint8_t *buf, size_t *len)
-+int sss_nss_getpw_readrep(struct sss_nss_pw_rep *pr,
-+                          uint8_t *buf, size_t *len)
- {
-     errno_t ret;
-     size_t i, slen, dlen;
--- 
-2.13.6
-
diff --git a/SOURCES/0023-AD-expose-the-helper-function-to-format-the-site-DNS.patch b/SOURCES/0023-AD-expose-the-helper-function-to-format-the-site-DNS.patch
new file mode 100644
index 0000000..4208977
--- /dev/null
+++ b/SOURCES/0023-AD-expose-the-helper-function-to-format-the-site-DNS.patch
@@ -0,0 +1,91 @@
+From 09fd8246f25dbfb80db638a0dd8f2fe4c1fba957 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 25 Jun 2018 13:03:38 +0200
+Subject: [PATCH] AD: expose the helper function to format the site DNS query
+
+This function will be used later in the patchset. Instead of exposing
+the format constant, expose the function that builds the DNS query for
+site discovery.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3291
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 29bbc8e017f2d9b98667890a9b7056128a93e572)
+
+DOWNSTREAM:
+Resolves: rhbz#1416528 - sssd in cross realm trust configuration should be able to use AD KDCs from a client site defined in sssd.conf or a snippet
+---
+ src/providers/ad/ad_srv.c | 21 +++++++++++++++------
+ src/providers/ad/ad_srv.h |  4 ++++
+ 2 files changed, 19 insertions(+), 6 deletions(-)
+
+diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c
+index 4fa1668605e131b2e31802b1401f49fc6e00a23b..5fd25f60e8bf38c3952823601593515b6c703284 100644
+--- a/src/providers/ad/ad_srv.c
++++ b/src/providers/ad/ad_srv.c
+@@ -38,6 +38,13 @@
+ 
+ #define AD_SITE_DOMAIN_FMT "%s._sites.%s"
+ 
++char *ad_site_dns_discovery_domain(TALLOC_CTX *mem_ctx,
++                                   const char *site,
++                                   const char *domain)
++{
++    return talloc_asprintf(mem_ctx, AD_SITE_DOMAIN_FMT, site, domain);
++}
++
+ static errno_t ad_sort_servers_by_dns(TALLOC_CTX *mem_ctx,
+                                       const char *domain,
+                                       struct fo_server_info **_srv,
+@@ -154,8 +161,8 @@ static struct tevent_req *ad_get_dc_servers_send(TALLOC_CTX *mem_ctx,
+         DEBUG(SSSDBG_TRACE_FUNC, "Looking up domain controllers in domain "
+               "%s and site %s\n", discovery_domain, site);
+ 
+-        domains[0] = talloc_asprintf(state, AD_SITE_DOMAIN_FMT,
+-                                     site, discovery_domain);
++        domains[0] = ad_site_dns_discovery_domain(domains,
++                                                  site, discovery_domain);
+         if (domains[0] == NULL) {
+             ret = ENOMEM;
+             goto immediately;
+@@ -775,9 +782,10 @@ static void ad_srv_plugin_site_done(struct tevent_req *subreq)
+         if (strcmp(state->service, "gc") == 0) {
+             if (state->forest != NULL) {
+                 if (state->site != NULL) {
+-                    primary_domain = talloc_asprintf(state, AD_SITE_DOMAIN_FMT,
+-                                                     state->site,
+-                                                     state->forest);
++                    primary_domain = ad_site_dns_discovery_domain(
++                                                            state,
++                                                            state->site,
++                                                            state->forest);
+                     if (primary_domain == NULL) {
+                         ret = ENOMEM;
+                         goto done;
+@@ -791,7 +799,8 @@ static void ad_srv_plugin_site_done(struct tevent_req *subreq)
+             }
+         } else {
+             if (state->site != NULL) {
+-                primary_domain = talloc_asprintf(state, AD_SITE_DOMAIN_FMT,
++                primary_domain = ad_site_dns_discovery_domain(
++                                                 state,
+                                                  state->site,
+                                                  state->discovery_domain);
+                 if (primary_domain == NULL) {
+diff --git a/src/providers/ad/ad_srv.h b/src/providers/ad/ad_srv.h
+index fddef686762e57bb95d648247131d39a797aa516..e553d594d77ad99f806af9634c2817754a80d4f5 100644
+--- a/src/providers/ad/ad_srv.h
++++ b/src/providers/ad/ad_srv.h
+@@ -49,4 +49,8 @@ errno_t ad_srv_plugin_recv(TALLOC_CTX *mem_ctx,
+                             struct fo_server_info **_backup_servers,
+                             size_t *_num_backup_servers);
+ 
++char *ad_site_dns_discovery_domain(TALLOC_CTX *mem_ctx,
++                                   const char *site,
++                                   const char *domain);
++
+ #endif /* __AD_SRV_H__ */
+-- 
+2.17.1
+
diff --git a/SOURCES/0023-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch b/SOURCES/0023-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch
deleted file mode 100644
index d6f9b89..0000000
--- a/SOURCES/0023-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch
+++ /dev/null
@@ -1,901 +0,0 @@
-From 15d7f1aeb541615314b914b6be1149f6e289d3e2 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 29 Sep 2017 16:16:01 +0200
-Subject: [PATCH 23/31] nss-idmap: add nss like calls with timeout and flags
-
-This patch adds new calls to libsss_nss_idmap to get NSS like user and
-group information directly from SSSD without using the system's NSS
-interfaces.
-
-Additionally a timeout and a flags options are added which are not
-available for system's NSS.
-
-Related to https://pagure.io/SSSD/sssd/issue/2478
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 5e6622722e84d594298a8324f3685a1bda2b5868)
----
- Makefile.am                                  |  22 +-
- configure.ac                                 |  13 +
- src/sss_client/common.c                      |   9 +-
- src/sss_client/common_private.h              |  41 +++
- src/sss_client/idmap/common_ex.c             | 105 +++++++
- src/sss_client/idmap/sss_nss_ex.c            | 402 +++++++++++++++++++++++++++
- src/sss_client/idmap/sss_nss_idmap.exports   |  10 +
- src/sss_client/idmap/sss_nss_idmap.h         | 135 +++++++++
- src/sss_client/idmap/sss_nss_idmap_private.h |  30 ++
- 9 files changed, 757 insertions(+), 10 deletions(-)
- create mode 100644 src/sss_client/common_private.h
- create mode 100644 src/sss_client/idmap/common_ex.c
- create mode 100644 src/sss_client/idmap/sss_nss_ex.c
- create mode 100644 src/sss_client/idmap/sss_nss_idmap_private.h
-
-diff --git a/Makefile.am b/Makefile.am
-index dc2f4b1857ce5bd376544488348731be29b6b293..dd25d1f7ea1be66388aa1b393bac290c4d7501a2 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -1159,13 +1159,28 @@ pkgconfig_DATA += src/sss_client/idmap/sss_nss_idmap.pc
- libsss_nss_idmap_la_DEPENDENCIES = src/sss_client/idmap/sss_nss_idmap.exports
- libsss_nss_idmap_la_SOURCES = \
-     src/sss_client/idmap/sss_nss_idmap.c \
-+    src/sss_client/idmap/sss_nss_ex.c \
-+    src/sss_client/idmap/sss_nss_idmap_private.h \
-     src/sss_client/common.c \
--    src/util/strtonum.c
-+    src/sss_client/idmap/common_ex.c \
-+    src/sss_client/nss_mc_passwd.c \
-+    src/sss_client/nss_passwd.c \
-+    src/sss_client/nss_mc_group.c \
-+    src/sss_client/nss_group.c \
-+    src/sss_client/nss_mc_initgr.c \
-+    src/sss_client/nss_mc_common.c \
-+    src/util/strtonum.c \
-+    src/util/murmurhash3.c \
-+    src/util/io.c \
-+    $(NULL)
- libsss_nss_idmap_la_LIBADD = \
--    $(CLIENT_LIBS)
-+    $(LIBCLOCK_GETTIME) \
-+    $(CLIENT_LIBS) \
-+    -lpthread \
-+    $(NULL)
- libsss_nss_idmap_la_LDFLAGS = \
-     -Wl,--version-script,$(srcdir)/src/sss_client/idmap/sss_nss_idmap.exports \
--    -version-info 3:0:3
-+    -version-info 4:0:4
- 
- dist_noinst_DATA += src/sss_client/idmap/sss_nss_idmap.exports
- 
-@@ -3624,6 +3639,7 @@ libnss_sss_la_SOURCES = \
-     src/sss_client/sss_cli.h \
-     src/sss_client/nss_compat.h \
-     src/sss_client/nss_common.h \
-+    src/sss_client/common_private.h \
-     src/sss_client/nss_mc_common.c \
-     src/util/io.c \
-     src/util/murmurhash3.c \
-diff --git a/configure.ac b/configure.ac
-index 7037927b5f7045b29d3774c85758e00e35e6def6..7e699d33e342c70d210d3f320c8a29a99e0c78a6 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -75,6 +75,19 @@ AC_SEARCH_LIBS([timer_create], [rt posix4],
- AC_SUBST([LIBADD_TIMER])
- LIBS=$SAVE_LIBS
- 
-+# Check library for the clock_gettime function
-+SAVE_LIBS=$LIBS
-+LIBS=
-+LIBCLOCK_GETTIME=
-+AC_SEARCH_LIBS([clock_gettime], [rt posix4],
-+    [AC_DEFINE([HAVE_LIBRT], [1],
-+         [Define if you have the librt library or equivalent.])
-+     LIBCLOCK_GETTIME="$LIBS"],
-+    [AC_MSG_ERROR([unable to find library for the clock_gettime() function])])
-+
-+AC_SUBST([LIBCLOCK_GETTIME])
-+LIBS=$SAVE_LIBS
-+
- # Check for presence of modern functions for setting file timestamps
- AC_CHECK_FUNCS([ utimensat \
-                  futimens ])
-diff --git a/src/sss_client/common.c b/src/sss_client/common.c
-index e5e0cbf854e4c977c03f9b1ca1ac90bfd8cbdb77..40252a35281dc4e94c712c3e7f8253af8b19b35a 100644
---- a/src/sss_client/common.c
-+++ b/src/sss_client/common.c
-@@ -43,6 +43,7 @@
- #include <libintl.h>
- #define _(STRING) dgettext (PACKAGE, STRING)
- #include "sss_cli.h"
-+#include "common_private.h"
- 
- #if HAVE_PTHREAD
- #include <pthread.h>
-@@ -1113,13 +1114,7 @@ errno_t sss_strnlen(const char *str, size_t maxlen, size_t *len)
- #if HAVE_PTHREAD
- typedef void (*sss_mutex_init)(void);
- 
--struct sss_mutex {
--    pthread_mutex_t mtx;
--
--    int old_cancel_state;
--};
--
--static struct sss_mutex sss_nss_mtx = { .mtx  = PTHREAD_MUTEX_INITIALIZER };
-+struct sss_mutex sss_nss_mtx = { .mtx  = PTHREAD_MUTEX_INITIALIZER };
- 
- static struct sss_mutex sss_pam_mtx = { .mtx  = PTHREAD_MUTEX_INITIALIZER };
- 
-diff --git a/src/sss_client/common_private.h b/src/sss_client/common_private.h
-new file mode 100644
-index 0000000000000000000000000000000000000000..a98d2c062caeecdbab02ecdaa6ae44d688a791bb
---- /dev/null
-+++ b/src/sss_client/common_private.h
-@@ -0,0 +1,41 @@
-+/*
-+    SSSD
-+
-+    SSS client - private calls
-+
-+    Authors:
-+        Sumit Bose <sbose@redhat.com>
-+
-+    Copyright (C) 2017 Red Hat
-+
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 3 of the License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
-+
-+    You should have received a copy of the GNU General Public License
-+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+
-+#ifndef COMMON_PRIVATE_H_
-+#define COMMON_PRIVATE_H_
-+
-+#include "config.h"
-+
-+#if HAVE_PTHREAD
-+#include <pthread.h>
-+
-+struct sss_mutex {
-+    pthread_mutex_t mtx;
-+
-+    int old_cancel_state;
-+};
-+
-+#endif /* HAVE_PTHREAD */
-+
-+#endif /* COMMON_PRIVATE_H_ */
-diff --git a/src/sss_client/idmap/common_ex.c b/src/sss_client/idmap/common_ex.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..5efe9fabed7896ce674615472dbb256c4eae2144
---- /dev/null
-+++ b/src/sss_client/idmap/common_ex.c
-@@ -0,0 +1,105 @@
-+/*
-+    Authors:
-+        Sumit Bose <sbose@redhat.com>
-+
-+    Copyright (C) 2017 Red Hat
-+
-+    SSSD's enhanced NSS API
-+
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 3 of the License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
-+
-+    You should have received a copy of the GNU General Public License
-+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+
-+#include <time.h>
-+#include <errno.h>
-+
-+#include "sss_cli.h"
-+#include "common_private.h"
-+
-+extern struct sss_mutex sss_nss_mtx;
-+
-+#define SEC_FROM_MSEC(ms) ((ms) / 1000)
-+#define NSEC_FROM_MSEC(ms) (((ms) % 1000) * 1000 * 1000)
-+
-+/* adopted from timersub() defined in /usr/include/sys/time.h */
-+#define TIMESPECSUB(a, b, result)                                             \
-+  do {                                                                        \
-+    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                             \
-+    (result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec;                          \
-+    if ((result)->tv_nsec < 0) {                                              \
-+      --(result)->tv_sec;                                                     \
-+      (result)->tv_nsec += 1000000000;                                        \
-+    }                                                                         \
-+  } while (0)
-+
-+#define TIMESPEC_TO_MS(ts) (  ((ts)->tv_sec * 1000) \
-+                            + ((ts)->tv_nsec) / (1000 * 1000) )
-+
-+static int sss_mt_timedlock(struct sss_mutex *m, struct timespec *endtime)
-+{
-+    int ret;
-+
-+    ret = pthread_mutex_timedlock(&m->mtx, endtime);
-+    if (ret != 0) {
-+        return ret;
-+    }
-+    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &m->old_cancel_state);
-+
-+    return 0;
-+}
-+
-+int sss_nss_timedlock(unsigned int timeout_ms, int *time_left_ms)
-+{
-+    int ret;
-+    int left;
-+    struct timespec starttime;
-+    struct timespec endtime;
-+    struct timespec diff;
-+
-+    /* make sure there is no overrun when calculating the time left */
-+    if (timeout_ms > INT_MAX) {
-+        timeout_ms = INT_MAX;
-+    }
-+
-+    ret = clock_gettime(CLOCK_REALTIME, &starttime);
-+    if (ret != 0) {
-+        return ret;
-+    }
-+    endtime.tv_sec = starttime.tv_sec + SEC_FROM_MSEC(timeout_ms);
-+    endtime.tv_nsec = starttime.tv_nsec + NSEC_FROM_MSEC(timeout_ms);
-+
-+    ret = sss_mt_timedlock(&sss_nss_mtx, &endtime);
-+
-+    if (ret == 0) {
-+        ret = clock_gettime(CLOCK_REALTIME, &endtime);
-+        if (ret != 0) {
-+            return ret;
-+        }
-+
-+        if (timeout_ms == 0) {
-+            *time_left_ms = 0;
-+        } else {
-+            TIMESPECSUB(&endtime, &starttime, &diff);
-+            left = timeout_ms - TIMESPEC_TO_MS(&diff);
-+            if (left <= 0) {
-+                return EIO;
-+            } else if (left > SSS_CLI_SOCKET_TIMEOUT) {
-+                *time_left_ms = SSS_CLI_SOCKET_TIMEOUT;
-+            } else {
-+                *time_left_ms = left;
-+            }
-+        }
-+    }
-+
-+    return ret;
-+}
-diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..582d1373ec35305cf128e04fd3d705457d304789
---- /dev/null
-+++ b/src/sss_client/idmap/sss_nss_ex.c
-@@ -0,0 +1,402 @@
-+/*
-+    SSSD
-+
-+    Extended NSS Responder Interface
-+
-+    Authors:
-+        Sumit Bose <sbose@redhat.com>
-+
-+    Copyright (C) 2017 Red Hat
-+
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 3 of the License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
-+
-+    You should have received a copy of the GNU General Public License
-+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+#include <stdlib.h>
-+#include <errno.h>
-+
-+#include <sys/param.h> /* for MIN() */
-+
-+#include "sss_client/sss_cli.h"
-+#include "sss_client/nss_mc.h"
-+#include "sss_client/nss_common.h"
-+#include "sss_client/idmap/sss_nss_idmap.h"
-+#include "sss_client/idmap/sss_nss_idmap_private.h"
-+
-+#ifndef discard_const
-+#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
-+#endif
-+
-+struct sss_nss_initgr_rep {
-+    gid_t *groups;
-+    long int *ngroups;
-+    long int *start;
-+};
-+
-+struct nss_input {
-+    union {
-+        const char *name;
-+        uid_t uid;
-+        gid_t gid;
-+    } input;
-+    struct sss_cli_req_data rd;
-+    enum sss_cli_command cmd;
-+    union {
-+        struct sss_nss_pw_rep pwrep;
-+        struct sss_nss_gr_rep grrep;
-+        struct sss_nss_initgr_rep initgrrep;
-+    } result;
-+};
-+
-+errno_t sss_nss_mc_get(struct nss_input *inp)
-+{
-+    switch(inp->cmd) {
-+    case SSS_NSS_GETPWNAM:
-+        return sss_nss_mc_getpwnam(inp->input.name, (inp->rd.len - 1),
-+                                   inp->result.pwrep.result,
-+                                   inp->result.pwrep.buffer,
-+                                   inp->result.pwrep.buflen);
-+        break;
-+    case SSS_NSS_GETPWUID:
-+        return sss_nss_mc_getpwuid(inp->input.uid,
-+                                   inp->result.pwrep.result,
-+                                   inp->result.pwrep.buffer,
-+                                   inp->result.pwrep.buflen);
-+        break;
-+    case SSS_NSS_GETGRNAM:
-+        return sss_nss_mc_getgrnam(inp->input.name, (inp->rd.len - 1),
-+                                   inp->result.grrep.result,
-+                                   inp->result.grrep.buffer,
-+                                   inp->result.grrep.buflen);
-+        break;
-+    case SSS_NSS_GETGRGID:
-+        return sss_nss_mc_getgrgid(inp->input.gid,
-+                                   inp->result.grrep.result,
-+                                   inp->result.grrep.buffer,
-+                                   inp->result.grrep.buflen);
-+        break;
-+    case SSS_NSS_INITGR:
-+        return sss_nss_mc_initgroups_dyn(inp->input.name, (inp->rd.len - 1),
-+                                         -1 /* currently ignored */,
-+                                         inp->result.initgrrep.start,
-+                                         inp->result.initgrrep.ngroups,
-+                                         &(inp->result.initgrrep.groups),
-+                                         *(inp->result.initgrrep.ngroups));
-+        break;
-+    default:
-+        return EINVAL;
-+    }
-+}
-+
-+int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout)
-+{
-+    uint8_t *repbuf = NULL;
-+    size_t replen;
-+    size_t len;
-+    uint32_t num_results;
-+    int ret;
-+    int time_left;
-+    int errnop;
-+    size_t c;
-+    gid_t *new_groups;
-+    size_t idx;
-+
-+    ret = sss_nss_mc_get(inp);
-+    switch (ret) {
-+    case 0:
-+        return 0;
-+    case ERANGE:
-+        return ERANGE;
-+    case ENOENT:
-+        /* fall through, we need to actively ask the parent
-+         * if no entry is found */
-+        break;
-+    default:
-+        /* if using the mmaped cache failed,
-+         * fall back to socket based comms */
-+        break;
-+    }
-+
-+    sss_nss_timedlock(timeout, &time_left);
-+
-+    /* previous thread might already initialize entry in mmap cache */
-+    ret = sss_nss_mc_get(inp);
-+    switch (ret) {
-+    case 0:
-+        ret = 0;
-+        goto out;
-+    case ERANGE:
-+        ret = ERANGE;
-+        goto out;
-+    case ENOENT:
-+        /* fall through, we need to actively ask the parent
-+         * if no entry is found */
-+        break;
-+    default:
-+        /* if using the mmaped cache failed,
-+         * fall back to socket based comms */
-+        break;
-+    }
-+
-+    ret = sss_nss_make_request_timeout(inp->cmd, &inp->rd, time_left,
-+                                       &repbuf, &replen, &errnop);
-+    if (ret != NSS_STATUS_SUCCESS) {
-+        ret = errnop != 0 ? errnop : EIO;
-+        goto out;
-+    }
-+
-+    /* Get number of results from repbuf. */
-+    SAFEALIGN_COPY_UINT32(&num_results, repbuf, NULL);
-+
-+    /* no results if not found */
-+    if (num_results == 0) {
-+        ret = ENOENT;
-+        goto out;
-+    }
-+
-+    if (inp->cmd == SSS_NSS_INITGR) {
-+        if ((*(inp->result.initgrrep.ngroups) - *(inp->result.initgrrep.start))
-+                    < num_results) {
-+            new_groups = realloc(inp->result.initgrrep.groups,
-+                                 (num_results + *(inp->result.initgrrep.start))
-+                                    * sizeof(gid_t));
-+            if (new_groups == NULL) {
-+                ret = ENOMEM;
-+                goto out;
-+            }
-+
-+            inp->result.initgrrep.groups = new_groups;
-+        }
-+        *(inp->result.initgrrep.ngroups) = num_results
-+                                            + *(inp->result.initgrrep.start);
-+
-+        idx = 2 * sizeof(uint32_t);
-+        for (c = 0; c < num_results; c++) {
-+            SAFEALIGN_COPY_UINT32(
-+                &(inp->result.initgrrep.groups[*(inp->result.initgrrep.start)]),
-+                repbuf + idx, &idx);
-+            *(inp->result.initgrrep.start) += 1;
-+        }
-+
-+        ret = 0;
-+        goto out;
-+    }
-+
-+    /* only 1 result is accepted for this function */
-+    if (num_results != 1) {
-+        ret = EBADMSG;
-+        goto out;
-+    }
-+
-+    len = replen - 8;
-+    if (inp->cmd == SSS_NSS_GETPWNAM || inp->cmd == SSS_NSS_GETPWUID) {
-+        ret = sss_nss_getpw_readrep(&(inp->result.pwrep), repbuf+8, &len);
-+    } else if (inp->cmd == SSS_NSS_GETGRNAM || inp->cmd == SSS_NSS_GETGRGID) {
-+        ret = sss_nss_getgr_readrep(&(inp->result.grrep), repbuf+8, &len);
-+    } else {
-+        ret = EINVAL;
-+        goto out;
-+    }
-+    if (ret) {
-+        goto out;
-+    }
-+
-+    if (len == 0) {
-+        /* no extra data */
-+        ret = 0;
-+        goto out;
-+    }
-+
-+out:
-+    free(repbuf);
-+
-+    sss_nss_unlock();
-+    return ret;
-+}
-+
-+int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd,
-+                             char *buffer, size_t buflen,
-+                             struct passwd **result,
-+                             uint32_t flags, unsigned int timeout)
-+{
-+    int ret;
-+    struct nss_input inp = {
-+        .input.name = name,
-+        .cmd = SSS_NSS_GETPWNAM,
-+        .rd.data = name,
-+        .result.pwrep.result = pwd,
-+        .result.pwrep.buffer = buffer,
-+        .result.pwrep.buflen = buflen};
-+
-+    if (buffer == NULL || buflen == 0) {
-+        return ERANGE;
-+    }
-+
-+    ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len);
-+    if (ret != 0) {
-+        return EINVAL;
-+    }
-+    inp.rd.len++;
-+
-+    *result = NULL;
-+
-+    ret = sss_get_ex(&inp, flags, timeout);
-+    if (ret == 0) {
-+        *result = inp.result.pwrep.result;
-+    }
-+    return ret;
-+}
-+
-+int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd,
-+                             char *buffer, size_t buflen,
-+                             struct passwd **result,
-+                             uint32_t flags, unsigned int timeout)
-+{
-+    int ret;
-+    uint32_t user_uid = uid;
-+    struct nss_input inp = {
-+        .input.uid = uid,
-+        .cmd = SSS_NSS_GETPWUID,
-+        .rd.len = sizeof(uint32_t),
-+        .rd.data = &user_uid,
-+        .result.pwrep.result = pwd,
-+        .result.pwrep.buffer = buffer,
-+        .result.pwrep.buflen = buflen};
-+
-+    if (buffer == NULL || buflen == 0) {
-+        return ERANGE;
-+    }
-+
-+    *result = NULL;
-+
-+    ret = sss_get_ex(&inp, flags, timeout);
-+    if (ret == 0) {
-+        *result = inp.result.pwrep.result;
-+    }
-+    return ret;
-+}
-+
-+int sss_nss_getgrnam_timeout(const char *name, struct group *grp,
-+                             char *buffer, size_t buflen, struct group **result,
-+                             uint32_t flags, unsigned int timeout)
-+{
-+    int ret;
-+    struct nss_input inp = {
-+        .input.name = name,
-+        .cmd = SSS_NSS_GETGRNAM,
-+        .rd.data = name,
-+        .result.grrep.result = grp,
-+        .result.grrep.buffer = buffer,
-+        .result.grrep.buflen = buflen};
-+
-+    if (buffer == NULL || buflen == 0) {
-+        return ERANGE;
-+    }
-+
-+    ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len);
-+    if (ret != 0) {
-+        return EINVAL;
-+    }
-+    inp.rd.len++;
-+
-+    *result = NULL;
-+
-+    ret = sss_get_ex(&inp, flags, timeout);
-+    if (ret == 0) {
-+        *result = inp.result.grrep.result;
-+    }
-+    return ret;
-+}
-+
-+int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp,
-+                             char *buffer, size_t buflen, struct group **result,
-+                             uint32_t flags, unsigned int timeout)
-+{
-+    int ret;
-+    uint32_t group_gid = gid;
-+    struct nss_input inp = {
-+        .input.gid = gid,
-+        .cmd = SSS_NSS_GETGRGID,
-+        .rd.len = sizeof(uint32_t),
-+        .rd.data = &group_gid,
-+        .result.grrep.result = grp,
-+        .result.grrep.buffer = buffer,
-+        .result.grrep.buflen = buflen};
-+
-+    if (buffer == NULL || buflen == 0) {
-+        return ERANGE;
-+    }
-+
-+    *result = NULL;
-+
-+    ret = sss_get_ex(&inp, flags, timeout);
-+    if (ret == 0) {
-+        *result = inp.result.grrep.result;
-+    }
-+    return ret;
-+}
-+
-+int sss_nss_getgrouplist_timeout(const char *name, gid_t group,
-+                                 gid_t *groups, int *ngroups,
-+                                 uint32_t flags, unsigned int timeout)
-+{
-+    int ret;
-+    gid_t *new_groups;
-+    long int new_ngroups;
-+    long int start = 1;
-+    struct nss_input inp = {
-+        .input.name = name,
-+        .cmd = SSS_NSS_INITGR,
-+        .rd.data = name};
-+
-+    if (groups == NULL || ngroups == NULL || *ngroups == 0) {
-+        return EINVAL;
-+    }
-+
-+    ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len);
-+    if (ret != 0) {
-+        return ret;
-+    }
-+    inp.rd.len++;
-+
-+    new_ngroups = MAX(1, *ngroups);
-+    new_groups = malloc(new_ngroups * sizeof(gid_t));
-+    if (new_groups == NULL) {
-+        free(discard_const(inp.rd.data));
-+        return ENOMEM;
-+    }
-+    new_groups[0] = group;
-+
-+    inp.result.initgrrep.groups = new_groups,
-+    inp.result.initgrrep.ngroups = &new_ngroups;
-+    inp.result.initgrrep.start = &start;
-+
-+
-+    ret = sss_get_ex(&inp, flags, timeout);
-+    free(discard_const(inp.rd.data));
-+    if (ret != 0) {
-+        free(new_groups);
-+        return ret;
-+    }
-+
-+    memcpy(groups, new_groups, MIN(*ngroups, start) * sizeof(gid_t));
-+    free(new_groups);
-+
-+    if (start > *ngroups) {
-+        ret = ERANGE;
-+    } else {
-+        ret = 0;
-+    }
-+    *ngroups = start;
-+
-+    return ret;
-+}
-diff --git a/src/sss_client/idmap/sss_nss_idmap.exports b/src/sss_client/idmap/sss_nss_idmap.exports
-index 49dac6fc9351b0ca98cd46e83b85ec8ef0075a0d..788d05ecc3bd56fa88e68a98b9c8096cf7140a09 100644
---- a/src/sss_client/idmap/sss_nss_idmap.exports
-+++ b/src/sss_client/idmap/sss_nss_idmap.exports
-@@ -31,3 +31,13 @@ SSS_NSS_IDMAP_0.3.0 {
-     global:
-         sss_nss_getlistbycert;
- } SSS_NSS_IDMAP_0.2.0;
-+
-+SSS_NSS_IDMAP_0.4.0 {
-+    # public functions
-+    global:
-+        sss_nss_getpwnam_timeout;
-+        sss_nss_getpwuid_timeout;
-+        sss_nss_getgrnam_timeout;
-+        sss_nss_getgrgid_timeout;
-+        sss_nss_getgrouplist_timeout;
-+} SSS_NSS_IDMAP_0.3.0;
-diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h
-index cbf19479ff9ec6e0d6e07e1f7e48a1571e147740..2334b6cb3fb8ef62e4ce3a7187c7affaeaa034e7 100644
---- a/src/sss_client/idmap/sss_nss_idmap.h
-+++ b/src/sss_client/idmap/sss_nss_idmap.h
-@@ -26,6 +26,9 @@
- #define SSS_NSS_IDMAP_H_
- 
- #include <stdint.h>
-+#include <sys/types.h>
-+#include <pwd.h>
-+#include <grp.h>
- 
- /**
-  * Object types
-@@ -159,4 +162,136 @@ int sss_nss_getlistbycert(const char *cert, char ***fq_name,
-  * @param[in] kv_list Key-value list returned by sss_nss_getorigbyname().
-  */
- void sss_nss_free_kv(struct sss_nss_kv *kv_list);
-+
-+/**
-+ * Flags to control the behavior and the results for sss_*_ex() calls
-+ */
-+
-+#define SSS_NSS_EX_FLAG_NO_FLAGS 0
-+
-+#ifdef IPA_389DS_PLUGIN_HELPER_CALLS
-+
-+/**
-+ * @brief Return user information based on the user name
-+ *
-+ * @param[in]  name       same as for getpwnam_r(3)
-+ * @param[in]  pwd        same as for getpwnam_r(3)
-+ * @param[in]  buffer     same as for getpwnam_r(3)
-+ * @param[in]  buflen     same as for getpwnam_r(3)
-+ * @param[out] result     same as for getpwnam_r(3)
-+ * @param[in]  flags      flags to control the behavior and the results of the
-+ *                        call
-+ * @param[in]  timeout    timeout in milliseconds
-+ *
-+ * @return
-+ *  - 0:
-+ *  - ENOENT:    no user with the given name found
-+ *  - ERANGE:    Insufficient buffer space supplied
-+ *  - ETIME:     request timed out but was send to SSSD
-+ *  - ETIMEDOUT: request timed out but was not send to SSSD
-+ */
-+int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd,
-+                             char *buffer, size_t buflen,
-+                             struct passwd **result,
-+                             uint32_t flags, unsigned int timeout);
-+
-+/**
-+ * @brief Return user information based on the user uid
-+ *
-+ * @param[in]  uid        same as for getpwuid_r(3)
-+ * @param[in]  pwd        same as for getpwuid_r(3)
-+ * @param[in]  buffer     same as for getpwuid_r(3)
-+ * @param[in]  buflen     same as for getpwuid_r(3)
-+ * @param[out] result     same as for getpwuid_r(3)
-+ * @param[in]  flags      flags to control the behavior and the results of the
-+ *                        call
-+ * @param[in]  timeout    timeout in milliseconds
-+ *
-+ * @return
-+ *  - 0:
-+ *  - ENOENT:    no user with the given uid found
-+ *  - ERANGE:    Insufficient buffer space supplied
-+ *  - ETIME:     request timed out but was send to SSSD
-+ *  - ETIMEDOUT: request timed out but was not send to SSSD
-+ */
-+int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd,
-+                             char *buffer, size_t buflen,
-+                             struct passwd **result,
-+                             uint32_t flags, unsigned int timeout);
-+
-+/**
-+ * @brief Return group information based on the group name
-+ *
-+ * @param[in]  name       same as for getgrnam_r(3)
-+ * @param[in]  pwd        same as for getgrnam_r(3)
-+ * @param[in]  buffer     same as for getgrnam_r(3)
-+ * @param[in]  buflen     same as for getgrnam_r(3)
-+ * @param[out] result     same as for getgrnam_r(3)
-+ * @param[in]  flags      flags to control the behavior and the results of the
-+ *                        call
-+ * @param[in]  timeout    timeout in milliseconds
-+ *
-+ * @return
-+ *  - 0:
-+ *  - ENOENT:    no group with the given name found
-+ *  - ERANGE:    Insufficient buffer space supplied
-+ *  - ETIME:     request timed out but was send to SSSD
-+ *  - ETIMEDOUT: request timed out but was not send to SSSD
-+ */
-+int sss_nss_getgrnam_timeout(const char *name, struct group *grp,
-+                             char *buffer, size_t buflen, struct group **result,
-+                             uint32_t flags, unsigned int timeout);
-+
-+/**
-+ * @brief Return group information based on the group gid
-+ *
-+ * @param[in]  gid        same as for getgrgid_r(3)
-+ * @param[in]  pwd        same as for getgrgid_r(3)
-+ * @param[in]  buffer     same as for getgrgid_r(3)
-+ * @param[in]  buflen     same as for getgrgid_r(3)
-+ * @param[out] result     same as for getgrgid_r(3)
-+ * @param[in]  flags      flags to control the behavior and the results of the
-+ *                        call
-+ * @param[in]  timeout    timeout in milliseconds
-+ *
-+ * @return
-+ *  - 0:
-+ *  - ENOENT:    no group with the given gid found
-+ *  - ERANGE:    Insufficient buffer space supplied
-+ *  - ETIME:     request timed out but was send to SSSD
-+ *  - ETIMEDOUT: request timed out but was not send to SSSD
-+ */
-+int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp,
-+                             char *buffer, size_t buflen, struct group **result,
-+                             uint32_t flags, unsigned int timeout);
-+
-+/**
-+ * @brief Return a list of groups to which a user belongs
-+ *
-+ * @param[in]      name       name of the user
-+ * @param[in]      group      same as second argument of getgrouplist(3)
-+ * @param[in]      groups     array of gid_t of size ngroups, will be filled
-+ *                            with GIDs of groups the user belongs to
-+ * @param[in,out]  ngroups    size of the groups array on input. On output it
-+ *                            will contain the actual number of groups the
-+ *                            user belongs to. With a return value of 0 the
-+ *                            groups array was large enough to hold all group.
-+ *                            With a return valu of ERANGE the array was not
-+ *                            large enough and ngroups will have the needed
-+ *                            size.
-+ * @param[in]  flags          flags to control the behavior and the results of
-+ *                            the call
-+ * @param[in]  timeout        timeout in milliseconds
-+ *
-+ * @return
-+ *  - 0:         success
-+ *  - ENOENT:    no user with the given name found
-+ *  - ERANGE:    Insufficient buffer space supplied
-+ *  - ETIME:     request timed out but was send to SSSD
-+ *  - ETIMEDOUT: request timed out but was not send to SSSD
-+ */
-+int sss_nss_getgrouplist_timeout(const char *name, gid_t group,
-+                                 gid_t *groups, int *ngroups,
-+                                 uint32_t flags, unsigned int timeout);
-+#endif /* IPA_389DS_PLUGIN_HELPER_CALLS */
- #endif /* SSS_NSS_IDMAP_H_ */
-diff --git a/src/sss_client/idmap/sss_nss_idmap_private.h b/src/sss_client/idmap/sss_nss_idmap_private.h
-new file mode 100644
-index 0000000000000000000000000000000000000000..afcd8e355981b9a2dc29a62bab143756b39ed654
---- /dev/null
-+++ b/src/sss_client/idmap/sss_nss_idmap_private.h
-@@ -0,0 +1,30 @@
-+/*
-+    SSSD
-+
-+    NSS Responder ID-mapping interface - private calls
-+
-+    Authors:
-+        Sumit Bose <sbose@redhat.com>
-+
-+    Copyright (C) 2017 Red Hat
-+
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 3 of the License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
-+
-+    You should have received a copy of the GNU General Public License
-+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+
-+#ifndef SSS_NSS_IDMAP_PRIVATE_H_
-+#define SSS_NSS_IDMAP_PRIVATE_H_
-+
-+int sss_nss_timedlock(unsigned int timeout_ms, int *time_left_ms);
-+
-+#endif /* SSS_NSS_IDMAP_PRIVATE_H_ */
--- 
-2.13.6
-
diff --git a/SOURCES/0024-NSS-add-_EX-version-of-some-requests.patch b/SOURCES/0024-NSS-add-_EX-version-of-some-requests.patch
deleted file mode 100644
index e97d92d..0000000
--- a/SOURCES/0024-NSS-add-_EX-version-of-some-requests.patch
+++ /dev/null
@@ -1,606 +0,0 @@
-From 8c6cb61cc65af7d3f243476dca66fb8f4750df80 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Wed, 11 Oct 2017 14:54:54 +0200
-Subject: [PATCH 24/31] NSS: add *_EX version of some requests
-
-To be able to send the flags to the SSSD responder new request types
-with an _EX postfix are added which expect and additional 32bit flag
-field after the name or the id of the requested object.
-
-Related to https://pagure.io/SSSD/sssd/issue/2478
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit cf93f7c2f2031078bbbff095dae01eb4f8deff85)
----
- src/responder/nss/nss_cmd.c       |  76 +++++++++++++++++++++-----
- src/responder/nss/nss_protocol.c  |  81 ++++++++++++++++++++++++++++
- src/responder/nss/nss_protocol.h  |   8 +++
- src/sss_client/idmap/sss_nss_ex.c | 110 +++++++++++++++++++++++++++-----------
- src/sss_client/sss_cli.h          |   7 +++
- 5 files changed, 237 insertions(+), 45 deletions(-)
-
-diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c
-index ebf66dfe0444b83aed20d58d36ddf70d2f4fa1f9..974eaccc93cea3a330007735676da69eb9b84141 100644
---- a/src/responder/nss/nss_cmd.c
-+++ b/src/responder/nss/nss_cmd.c
-@@ -54,6 +54,7 @@ static void nss_getby_done(struct tevent_req *subreq);
- static void nss_getlistby_done(struct tevent_req *subreq);
- 
- static errno_t nss_getby_name(struct cli_ctx *cli_ctx,
-+                              bool ex_version,
-                               enum cache_req_type type,
-                               const char **attrs,
-                               enum sss_mc_type memcache,
-@@ -64,6 +65,7 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx,
-     struct tevent_req *subreq;
-     const char *rawname;
-     errno_t ret;
-+    uint32_t flags = 0;
- 
-     cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, fill_fn);
-     if (cmd_ctx == NULL) {
-@@ -71,7 +73,11 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx,
-         goto done;
-     }
- 
--    ret = nss_protocol_parse_name(cli_ctx, &rawname);
-+    if (ex_version) {
-+        ret = nss_protocol_parse_name_ex(cli_ctx, &rawname, &flags);
-+    } else {
-+        ret = nss_protocol_parse_name(cli_ctx, &rawname);
-+    }
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request message!\n");
-         goto done;
-@@ -108,6 +114,7 @@ done:
- }
- 
- static errno_t nss_getby_id(struct cli_ctx *cli_ctx,
-+                            bool ex_version,
-                             enum cache_req_type type,
-                             const char **attrs,
-                             enum sss_mc_type memcache,
-@@ -118,6 +125,7 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx,
-     struct tevent_req *subreq;
-     uint32_t id;
-     errno_t ret;
-+    uint32_t flags = 0;
- 
-     cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, fill_fn);
-     if (cmd_ctx == NULL) {
-@@ -125,7 +133,11 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx,
-         goto done;
-     }
- 
--    ret = nss_protocol_parse_id(cli_ctx, &id);
-+    if (ex_version) {
-+        ret = nss_protocol_parse_id_ex(cli_ctx, &id, &flags);
-+    } else {
-+        ret = nss_protocol_parse_id(cli_ctx, &id);
-+    }
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request message!\n");
-         goto done;
-@@ -766,14 +778,26 @@ static errno_t nss_endent(struct cli_ctx *cli_ctx,
- 
- static errno_t nss_cmd_getpwnam(struct cli_ctx *cli_ctx)
- {
--    return nss_getby_name(cli_ctx, CACHE_REQ_USER_BY_NAME, NULL, SSS_MC_PASSWD,
--                          nss_protocol_fill_pwent);
-+    return nss_getby_name(cli_ctx, false, CACHE_REQ_USER_BY_NAME, NULL,
-+                          SSS_MC_PASSWD, nss_protocol_fill_pwent);
- }
- 
- static errno_t nss_cmd_getpwuid(struct cli_ctx *cli_ctx)
- {
--    return nss_getby_id(cli_ctx, CACHE_REQ_USER_BY_ID, NULL, SSS_MC_PASSWD,
--                        nss_protocol_fill_pwent);
-+    return nss_getby_id(cli_ctx, false, CACHE_REQ_USER_BY_ID, NULL,
-+                        SSS_MC_PASSWD, nss_protocol_fill_pwent);
-+}
-+
-+static errno_t nss_cmd_getpwnam_ex(struct cli_ctx *cli_ctx)
-+{
-+    return nss_getby_name(cli_ctx, true, CACHE_REQ_USER_BY_NAME, NULL,
-+                          SSS_MC_PASSWD, nss_protocol_fill_pwent);
-+}
-+
-+static errno_t nss_cmd_getpwuid_ex(struct cli_ctx *cli_ctx)
-+{
-+    return nss_getby_id(cli_ctx, true, CACHE_REQ_USER_BY_ID, NULL,
-+                        SSS_MC_PASSWD, nss_protocol_fill_pwent);
- }
- 
- static errno_t nss_cmd_setpwent(struct cli_ctx *cli_ctx)
-@@ -809,16 +833,29 @@ static errno_t nss_cmd_endpwent(struct cli_ctx *cli_ctx)
- 
- static errno_t nss_cmd_getgrnam(struct cli_ctx *cli_ctx)
- {
--    return nss_getby_name(cli_ctx, CACHE_REQ_GROUP_BY_NAME, NULL, SSS_MC_GROUP,
--                          nss_protocol_fill_grent);
-+    return nss_getby_name(cli_ctx, false, CACHE_REQ_GROUP_BY_NAME, NULL,
-+                          SSS_MC_GROUP, nss_protocol_fill_grent);
- }
- 
- static errno_t nss_cmd_getgrgid(struct cli_ctx *cli_ctx)
- {
--    return nss_getby_id(cli_ctx, CACHE_REQ_GROUP_BY_ID, NULL, SSS_MC_GROUP,
--                        nss_protocol_fill_grent);
-+    return nss_getby_id(cli_ctx, false, CACHE_REQ_GROUP_BY_ID, NULL,
-+                        SSS_MC_GROUP, nss_protocol_fill_grent);
- }
- 
-+static errno_t nss_cmd_getgrnam_ex(struct cli_ctx *cli_ctx)
-+{
-+    return nss_getby_name(cli_ctx, true, CACHE_REQ_GROUP_BY_NAME, NULL,
-+                          SSS_MC_GROUP, nss_protocol_fill_grent);
-+}
-+
-+static errno_t nss_cmd_getgrgid_ex(struct cli_ctx *cli_ctx)
-+{
-+    return nss_getby_id(cli_ctx, true, CACHE_REQ_GROUP_BY_ID, NULL,
-+                        SSS_MC_GROUP, nss_protocol_fill_grent);
-+}
-+
-+
- static errno_t nss_cmd_setgrent(struct cli_ctx *cli_ctx)
- {
-     struct nss_ctx *nss_ctx;
-@@ -852,7 +889,13 @@ static errno_t nss_cmd_endgrent(struct cli_ctx *cli_ctx)
- 
- static errno_t nss_cmd_initgroups(struct cli_ctx *cli_ctx)
- {
--    return nss_getby_name(cli_ctx, CACHE_REQ_INITGROUPS, NULL,
-+    return nss_getby_name(cli_ctx, false, CACHE_REQ_INITGROUPS, NULL,
-+                          SSS_MC_INITGROUPS, nss_protocol_fill_initgr);
-+}
-+
-+static errno_t nss_cmd_initgroups_ex(struct cli_ctx *cli_ctx)
-+{
-+    return nss_getby_name(cli_ctx, true, CACHE_REQ_INITGROUPS, NULL,
-                           SSS_MC_INITGROUPS, nss_protocol_fill_initgr);
- }
- 
-@@ -943,7 +986,7 @@ static errno_t nss_cmd_getsidbyname(struct cli_ctx *cli_ctx)
- {
-     const char *attrs[] = { SYSDB_SID_STR, NULL };
- 
--    return nss_getby_name(cli_ctx, CACHE_REQ_OBJECT_BY_NAME, attrs,
-+    return nss_getby_name(cli_ctx, false, CACHE_REQ_OBJECT_BY_NAME, attrs,
-                           SSS_MC_NONE, nss_protocol_fill_sid);
- }
- 
-@@ -951,7 +994,7 @@ static errno_t nss_cmd_getsidbyid(struct cli_ctx *cli_ctx)
- {
-     const char *attrs[] = { SYSDB_SID_STR, NULL };
- 
--    return nss_getby_id(cli_ctx, CACHE_REQ_OBJECT_BY_ID, attrs,
-+    return nss_getby_id(cli_ctx, false, CACHE_REQ_OBJECT_BY_ID, attrs,
-                         SSS_MC_NONE, nss_protocol_fill_sid);
- }
- 
-@@ -1006,7 +1049,7 @@ static errno_t nss_cmd_getorigbyname(struct cli_ctx *cli_ctx)
-         attrs = defattrs;
-     }
- 
--    return nss_getby_name(cli_ctx, CACHE_REQ_OBJECT_BY_NAME, attrs,
-+    return nss_getby_name(cli_ctx, false, CACHE_REQ_OBJECT_BY_NAME, attrs,
-                           SSS_MC_NONE, nss_protocol_fill_orig);
- }
- 
-@@ -1051,6 +1094,11 @@ struct sss_cmd_table *get_nss_cmds(void)
-         { SSS_NSS_GETORIGBYNAME, nss_cmd_getorigbyname },
-         { SSS_NSS_GETNAMEBYCERT, nss_cmd_getnamebycert },
-         { SSS_NSS_GETLISTBYCERT, nss_cmd_getlistbycert },
-+        { SSS_NSS_GETPWNAM_EX, nss_cmd_getpwnam_ex },
-+        { SSS_NSS_GETPWUID_EX, nss_cmd_getpwuid_ex },
-+        { SSS_NSS_GETGRNAM_EX, nss_cmd_getgrnam_ex },
-+        { SSS_NSS_GETGRGID_EX, nss_cmd_getgrgid_ex },
-+        { SSS_NSS_INITGR_EX, nss_cmd_initgroups_ex },
-         { SSS_CLI_NULL, NULL }
-     };
- 
-diff --git a/src/responder/nss/nss_protocol.c b/src/responder/nss/nss_protocol.c
-index 06fc4d00a7877a7990402f4f2633ddc0bd640b41..17bfc4f4e71960a72e9e04622eac95b94a865ec7 100644
---- a/src/responder/nss/nss_protocol.c
-+++ b/src/responder/nss/nss_protocol.c
-@@ -134,6 +134,61 @@ nss_protocol_parse_name(struct cli_ctx *cli_ctx, const char **_rawname)
- }
- 
- errno_t
-+nss_protocol_parse_name_ex(struct cli_ctx *cli_ctx, const char **_rawname,
-+                           uint32_t *_flags)
-+{
-+    struct cli_protocol *pctx;
-+    const char *rawname;
-+    uint8_t *body;
-+    size_t blen;
-+    uint8_t *p;
-+    uint32_t flags;
-+
-+    pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol);
-+
-+    sss_packet_get_body(pctx->creq->in, &body, &blen);
-+
-+    if (blen < 1 + sizeof(uint32_t)) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Body too short!\n");
-+        return EINVAL;
-+    }
-+
-+    /* If first argument not terminated fail. */
-+    if (body[blen - 1 - sizeof(uint32_t)] != '\0') {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Body is not null terminated!\n");
-+        return EINVAL;
-+    }
-+
-+    p = memchr(body, '\0', blen);
-+
-+    /* If the body isn't valid UTF-8, fail */
-+    if (!sss_utf8_check(body, (p - body))) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "First argument is not UTF-8 string!\n");
-+        return EINVAL;
-+    }
-+
-+    rawname = (const char *)body;
-+    if (rawname[0] == '\0') {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "An empty name was provided!\n");
-+        return EINVAL;
-+    }
-+
-+    p++;
-+    if ((p - body) + sizeof(uint32_t) != blen) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Body has unexpected size!\n");
-+        return EINVAL;
-+    }
-+
-+    SAFEALIGN_COPY_UINT32(&flags, p, NULL);
-+    p += sizeof(uint32_t);
-+
-+    *_rawname = rawname;
-+    *_flags = flags;
-+
-+    return EOK;
-+}
-+
-+errno_t
- nss_protocol_parse_id(struct cli_ctx *cli_ctx, uint32_t *_id)
- {
-     struct cli_protocol *pctx;
-@@ -157,6 +212,32 @@ nss_protocol_parse_id(struct cli_ctx *cli_ctx, uint32_t *_id)
- }
- 
- errno_t
-+nss_protocol_parse_id_ex(struct cli_ctx *cli_ctx, uint32_t *_id,
-+                         uint32_t *_flags)
-+{
-+    struct cli_protocol *pctx;
-+    uint8_t *body;
-+    size_t blen;
-+    uint32_t id;
-+    uint32_t flags;
-+
-+    pctx = talloc_get_type(cli_ctx->protocol_ctx, struct cli_protocol);
-+
-+    sss_packet_get_body(pctx->creq->in, &body, &blen);
-+
-+    if (blen != 2 * sizeof(uint32_t)) {
-+        return EINVAL;
-+    }
-+
-+    SAFEALIGN_COPY_UINT32(&id, body, NULL);
-+    SAFEALIGN_COPY_UINT32(&flags, body + sizeof(uint32_t), NULL);
-+
-+    *_id = id;
-+
-+    return EOK;
-+}
-+
-+errno_t
- nss_protocol_parse_limit(struct cli_ctx *cli_ctx, uint32_t *_limit)
- {
-     return nss_protocol_parse_id(cli_ctx, _limit);
-diff --git a/src/responder/nss/nss_protocol.h b/src/responder/nss/nss_protocol.h
-index 417b0891615dcb8771d49f7b2f4d276342ca3150..ca5b040237dc18acdca9a7a3a7a7dbb64265aa95 100644
---- a/src/responder/nss/nss_protocol.h
-+++ b/src/responder/nss/nss_protocol.h
-@@ -89,9 +89,17 @@ errno_t
- nss_protocol_parse_name(struct cli_ctx *cli_ctx, const char **_rawname);
- 
- errno_t
-+nss_protocol_parse_name_ex(struct cli_ctx *cli_ctx, const char **_rawname,
-+                           uint32_t *_flags);
-+
-+errno_t
- nss_protocol_parse_id(struct cli_ctx *cli_ctx, uint32_t *_id);
- 
- errno_t
-+nss_protocol_parse_id_ex(struct cli_ctx *cli_ctx, uint32_t *_id,
-+                         uint32_t *_flags);
-+
-+errno_t
- nss_protocol_parse_limit(struct cli_ctx *cli_ctx, uint32_t *_limit);
- 
- errno_t
-diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c
-index 582d1373ec35305cf128e04fd3d705457d304789..dc7610a4e528b5126f0d25d84cd3c1a22f683b75 100644
---- a/src/sss_client/idmap/sss_nss_ex.c
-+++ b/src/sss_client/idmap/sss_nss_ex.c
-@@ -61,31 +61,37 @@ errno_t sss_nss_mc_get(struct nss_input *inp)
- {
-     switch(inp->cmd) {
-     case SSS_NSS_GETPWNAM:
--        return sss_nss_mc_getpwnam(inp->input.name, (inp->rd.len - 1),
-+    case SSS_NSS_GETPWNAM_EX:
-+        return sss_nss_mc_getpwnam(inp->input.name, strlen(inp->input.name),
-                                    inp->result.pwrep.result,
-                                    inp->result.pwrep.buffer,
-                                    inp->result.pwrep.buflen);
-         break;
-     case SSS_NSS_GETPWUID:
-+    case SSS_NSS_GETPWUID_EX:
-         return sss_nss_mc_getpwuid(inp->input.uid,
-                                    inp->result.pwrep.result,
-                                    inp->result.pwrep.buffer,
-                                    inp->result.pwrep.buflen);
-         break;
-     case SSS_NSS_GETGRNAM:
--        return sss_nss_mc_getgrnam(inp->input.name, (inp->rd.len - 1),
-+    case SSS_NSS_GETGRNAM_EX:
-+        return sss_nss_mc_getgrnam(inp->input.name, strlen(inp->input.name),
-                                    inp->result.grrep.result,
-                                    inp->result.grrep.buffer,
-                                    inp->result.grrep.buflen);
-         break;
-     case SSS_NSS_GETGRGID:
-+    case SSS_NSS_GETGRGID_EX:
-         return sss_nss_mc_getgrgid(inp->input.gid,
-                                    inp->result.grrep.result,
-                                    inp->result.grrep.buffer,
-                                    inp->result.grrep.buflen);
-         break;
-     case SSS_NSS_INITGR:
--        return sss_nss_mc_initgroups_dyn(inp->input.name, (inp->rd.len - 1),
-+    case SSS_NSS_INITGR_EX:
-+        return sss_nss_mc_initgroups_dyn(inp->input.name,
-+                                         strlen(inp->input.name),
-                                          -1 /* currently ignored */,
-                                          inp->result.initgrrep.start,
-                                          inp->result.initgrrep.ngroups,
-@@ -163,7 +169,7 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout)
-         goto out;
-     }
- 
--    if (inp->cmd == SSS_NSS_INITGR) {
-+    if (inp->cmd == SSS_NSS_INITGR || inp->cmd == SSS_NSS_INITGR_EX) {
-         if ((*(inp->result.initgrrep.ngroups) - *(inp->result.initgrrep.start))
-                     < num_results) {
-             new_groups = realloc(inp->result.initgrrep.groups,
-@@ -198,15 +204,24 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout)
-     }
- 
-     len = replen - 8;
--    if (inp->cmd == SSS_NSS_GETPWNAM || inp->cmd == SSS_NSS_GETPWUID) {
-+
-+    switch(inp->cmd) {
-+    case SSS_NSS_GETPWNAM:
-+    case SSS_NSS_GETPWUID:
-+    case SSS_NSS_GETPWNAM_EX:
-+    case SSS_NSS_GETPWUID_EX:
-         ret = sss_nss_getpw_readrep(&(inp->result.pwrep), repbuf+8, &len);
--    } else if (inp->cmd == SSS_NSS_GETGRNAM || inp->cmd == SSS_NSS_GETGRGID) {
-+        break;
-+    case SSS_NSS_GETGRNAM:
-+    case SSS_NSS_GETGRGID:
-+    case SSS_NSS_GETGRNAM_EX:
-+    case SSS_NSS_GETGRGID_EX:
-         ret = sss_nss_getgr_readrep(&(inp->result.grrep), repbuf+8, &len);
--    } else {
-+        break;
-+    default:
-         ret = EINVAL;
--        goto out;
-     }
--    if (ret) {
-+    if (ret != 0) {
-         goto out;
-     }
- 
-@@ -223,6 +238,39 @@ out:
-     return ret;
- }
- 
-+static int make_name_flag_req_data(const char *name, uint32_t flags,
-+                                   struct sss_cli_req_data *rd)
-+{
-+    size_t len;
-+    size_t name_len;
-+    uint8_t *data;
-+    int ret;
-+
-+    if (name == NULL) {
-+        return EINVAL;
-+    }
-+
-+    ret = sss_strnlen(name, SSS_NAME_MAX, &name_len);
-+    if (ret != 0) {
-+        return ret;
-+    }
-+    name_len++;
-+
-+    len = name_len + sizeof(uint32_t);
-+    data = malloc(len);
-+    if (data == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    memcpy(data, name, name_len);
-+    SAFEALIGN_COPY_UINT32(data + name_len, &flags, NULL);
-+
-+    rd->len = len;
-+    rd->data = data;
-+
-+    return 0;
-+}
-+
- int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd,
-                              char *buffer, size_t buflen,
-                              struct passwd **result,
-@@ -231,8 +279,7 @@ int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd,
-     int ret;
-     struct nss_input inp = {
-         .input.name = name,
--        .cmd = SSS_NSS_GETPWNAM,
--        .rd.data = name,
-+        .cmd = SSS_NSS_GETPWNAM_EX,
-         .result.pwrep.result = pwd,
-         .result.pwrep.buffer = buffer,
-         .result.pwrep.buflen = buflen};
-@@ -241,15 +288,15 @@ int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd,
-         return ERANGE;
-     }
- 
--    ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len);
-+    ret = make_name_flag_req_data(name, flags, &inp.rd);
-     if (ret != 0) {
--        return EINVAL;
-+        return ret;
-     }
--    inp.rd.len++;
- 
-     *result = NULL;
- 
-     ret = sss_get_ex(&inp, flags, timeout);
-+    free(discard_const(inp.rd.data));
-     if (ret == 0) {
-         *result = inp.result.pwrep.result;
-     }
-@@ -262,12 +309,12 @@ int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd,
-                              uint32_t flags, unsigned int timeout)
- {
-     int ret;
--    uint32_t user_uid = uid;
-+    uint32_t req_data[2];
-     struct nss_input inp = {
-         .input.uid = uid,
--        .cmd = SSS_NSS_GETPWUID,
--        .rd.len = sizeof(uint32_t),
--        .rd.data = &user_uid,
-+        .cmd = SSS_NSS_GETPWUID_EX,
-+        .rd.len = 2 * sizeof(uint32_t),
-+        .rd.data = &req_data,
-         .result.pwrep.result = pwd,
-         .result.pwrep.buffer = buffer,
-         .result.pwrep.buflen = buflen};
-@@ -276,6 +323,8 @@ int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd,
-         return ERANGE;
-     }
- 
-+    SAFEALIGN_COPY_UINT32(&req_data[0], &uid, NULL);
-+    SAFEALIGN_COPY_UINT32(&req_data[1], &flags, NULL);
-     *result = NULL;
- 
-     ret = sss_get_ex(&inp, flags, timeout);
-@@ -292,8 +341,7 @@ int sss_nss_getgrnam_timeout(const char *name, struct group *grp,
-     int ret;
-     struct nss_input inp = {
-         .input.name = name,
--        .cmd = SSS_NSS_GETGRNAM,
--        .rd.data = name,
-+        .cmd = SSS_NSS_GETGRNAM_EX,
-         .result.grrep.result = grp,
-         .result.grrep.buffer = buffer,
-         .result.grrep.buflen = buflen};
-@@ -302,15 +350,15 @@ int sss_nss_getgrnam_timeout(const char *name, struct group *grp,
-         return ERANGE;
-     }
- 
--    ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len);
-+    ret = make_name_flag_req_data(name, flags, &inp.rd);
-     if (ret != 0) {
--        return EINVAL;
-+        return ret;
-     }
--    inp.rd.len++;
- 
-     *result = NULL;
- 
-     ret = sss_get_ex(&inp, flags, timeout);
-+    free(discard_const(inp.rd.data));
-     if (ret == 0) {
-         *result = inp.result.grrep.result;
-     }
-@@ -322,12 +370,12 @@ int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp,
-                              uint32_t flags, unsigned int timeout)
- {
-     int ret;
--    uint32_t group_gid = gid;
-+    uint32_t req_data[2];
-     struct nss_input inp = {
-         .input.gid = gid,
--        .cmd = SSS_NSS_GETGRGID,
--        .rd.len = sizeof(uint32_t),
--        .rd.data = &group_gid,
-+        .cmd = SSS_NSS_GETGRGID_EX,
-+        .rd.len = 2 * sizeof(uint32_t),
-+        .rd.data = &req_data,
-         .result.grrep.result = grp,
-         .result.grrep.buffer = buffer,
-         .result.grrep.buflen = buflen};
-@@ -336,6 +384,8 @@ int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp,
-         return ERANGE;
-     }
- 
-+    SAFEALIGN_COPY_UINT32(&req_data[0], &gid, NULL);
-+    SAFEALIGN_COPY_UINT32(&req_data[1], &flags, NULL);
-     *result = NULL;
- 
-     ret = sss_get_ex(&inp, flags, timeout);
-@@ -355,18 +405,16 @@ int sss_nss_getgrouplist_timeout(const char *name, gid_t group,
-     long int start = 1;
-     struct nss_input inp = {
-         .input.name = name,
--        .cmd = SSS_NSS_INITGR,
--        .rd.data = name};
-+        .cmd = SSS_NSS_INITGR_EX};
- 
-     if (groups == NULL || ngroups == NULL || *ngroups == 0) {
-         return EINVAL;
-     }
- 
--    ret = sss_strnlen(name, SSS_NAME_MAX, &inp.rd.len);
-+    ret = make_name_flag_req_data(name, flags, &inp.rd);
-     if (ret != 0) {
-         return ret;
-     }
--    inp.rd.len++;
- 
-     new_ngroups = MAX(1, *ngroups);
-     new_groups = malloc(new_ngroups * sizeof(gid_t));
-diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
-index 5329651a9385d138b8ea7237cb5cf4e2b8e5f371..9d2cc00c9957f5680548461129e3e6b777da5091 100644
---- a/src/sss_client/sss_cli.h
-+++ b/src/sss_client/sss_cli.h
-@@ -79,6 +79,9 @@ enum sss_cli_command {
-     SSS_NSS_GETPWENT       = 0x0014,
-     SSS_NSS_ENDPWENT       = 0x0015,
- 
-+    SSS_NSS_GETPWNAM_EX    = 0x0019,
-+    SSS_NSS_GETPWUID_EX    = 0x001A,
-+
- /* group */
- 
-     SSS_NSS_GETGRNAM       = 0x0021,
-@@ -88,6 +91,10 @@ enum sss_cli_command {
-     SSS_NSS_ENDGRENT       = 0x0025,
-     SSS_NSS_INITGR         = 0x0026,
- 
-+    SSS_NSS_GETGRNAM_EX    = 0x0029,
-+    SSS_NSS_GETGRGID_EX    = 0x002A,
-+    SSS_NSS_INITGR_EX      = 0x002E,
-+
- #if 0
- /* aliases */
- 
--- 
-2.13.6
-
diff --git a/SOURCES/0024-RESOLV-Add-a-resolv_hostport_list-request.patch b/SOURCES/0024-RESOLV-Add-a-resolv_hostport_list-request.patch
new file mode 100644
index 0000000..e19eb54
--- /dev/null
+++ b/SOURCES/0024-RESOLV-Add-a-resolv_hostport_list-request.patch
@@ -0,0 +1,265 @@
+From e73e35f2a1ef037d89f73b4ce5609e2567dc8714 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 25 Jun 2018 12:46:51 +0200
+Subject: [PATCH] RESOLV: Add a resolv_hostport_list request
+
+Adds a request that resolves a list of (host,port) tuples and returns a
+list of structures that contain the resolv_hostent structure as other
+resolver requests do, but also a pointer to the original request tuple.
+
+This is done because the request skips any unresolvable inputs, so it
+might be handy to know which input an output maps to.
+
+It is expected that the request will be used in the future also for cases
+where we want to e.g. try the connectivity to a serve using a mechanism
+such as an LDAP ping.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3291
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 6f80bccc6f8203381c387080bd0563ba10994487)
+---
+ src/resolv/async_resolv.c | 187 ++++++++++++++++++++++++++++++++++++++
+ src/resolv/async_resolv.h |  30 ++++++
+ 2 files changed, 217 insertions(+)
+
+diff --git a/src/resolv/async_resolv.c b/src/resolv/async_resolv.c
+index ba6fabf285533153ea440394ce1cc224aa42cbd3..bb27011548b73c0cc62f6638401847ab9e0b175c 100644
+--- a/src/resolv/async_resolv.c
++++ b/src/resolv/async_resolv.c
+@@ -2322,3 +2322,190 @@ resolv_sort_srv_reply(struct ares_srv_reply **reply)
+ 
+     return EOK;
+ }
++
++struct resolv_hostport_list_state {
++    struct tevent_context *ev;
++    struct resolv_ctx *ctx;
++    struct resolv_hostport *hostport_list;
++    size_t list_size;
++    size_t limit;
++    enum restrict_family family_order;
++    enum host_database *db;
++
++    size_t hpindex;
++
++    struct resolv_hostport_addr **rhp_addrs;
++    size_t addrindex;
++};
++
++static errno_t resolv_hostport_list_step(struct tevent_req *req);
++static void resolv_hostport_list_resolv_hostname_done(struct tevent_req *subreq);
++
++struct tevent_req *resolv_hostport_list_send(TALLOC_CTX *mem_ctx,
++                                             struct tevent_context *ev,
++                                             struct resolv_ctx *ctx,
++                                             struct resolv_hostport *hostport_list,
++                                             size_t list_size,
++                                             size_t limit,
++                                             enum restrict_family family_order,
++                                             enum host_database *db)
++{
++    struct resolv_hostport_list_state *state;
++    struct tevent_req *req;
++    errno_t ret;
++
++    req = tevent_req_create(mem_ctx, &state,
++                            struct resolv_hostport_list_state);
++    if (req == NULL) {
++        return NULL;
++    }
++    state->ev = ev;
++    state->ctx = ctx;
++    state->hostport_list = hostport_list;
++    state->family_order = family_order;
++    state->db = db;
++    state->list_size = list_size;
++    state->limit = limit;
++
++    state->rhp_addrs = talloc_array(state,
++                                    struct resolv_hostport_addr *,
++                                    state->list_size);
++    if (state->rhp_addrs == NULL) {
++        ret = ENOMEM;
++        goto immediately;
++    }
++
++    ret = resolv_hostport_list_step(req);
++    if (ret != EAGAIN) {
++        goto immediately;
++    }
++
++    return req;
++
++immediately:
++    if (ret != EOK) {
++        tevent_req_error(req, ret);
++    } else {
++        tevent_req_done(req);
++    }
++    tevent_req_post(req, ev);
++    return req;
++}
++
++static errno_t resolv_hostport_list_step(struct tevent_req *req)
++{
++    struct tevent_req *subreq = NULL;
++    struct resolv_hostport_list_state *state = tevent_req_data(req,
++                                        struct resolv_hostport_list_state);
++
++    if (state->hpindex >= state->list_size) {
++        DEBUG(SSSDBG_TRACE_INTERNAL, "Done\n");
++        return EOK;
++    }
++
++    subreq = resolv_gethostbyname_send(state,
++                                       state->ev,
++                                       state->ctx,
++                                       state->hostport_list[state->hpindex].host,
++                                       state->family_order,
++                                       state->db);
++    if (subreq == NULL) {
++        return ENOMEM;
++    }
++    tevent_req_set_callback(subreq,
++                            resolv_hostport_list_resolv_hostname_done, req);
++    return EAGAIN;
++}
++
++static struct resolv_hostport_addr*
++resolv_hostport_addr_new(TALLOC_CTX *mem_ctx,
++                         const char *host,
++                         int port,
++                         struct resolv_hostent *reply)
++{
++    struct resolv_hostport_addr *rhp_addr;
++
++    rhp_addr = talloc_zero(mem_ctx, struct resolv_hostport_addr);
++    if (rhp_addr == NULL) {
++        return NULL;
++    }
++
++    rhp_addr->origin.host = talloc_strdup(rhp_addr, host);
++    if (rhp_addr->origin.host == NULL) {
++        return NULL;
++    }
++
++    rhp_addr->origin.port = port;
++    rhp_addr->reply = talloc_steal(rhp_addr, reply);
++    return rhp_addr;
++}
++
++static void resolv_hostport_list_resolv_hostname_done(struct tevent_req *subreq)
++{
++    errno_t ret;
++    struct tevent_req *req =
++            tevent_req_callback_data(subreq, struct tevent_req);
++    struct resolv_hostport_list_state *state = tevent_req_data(req,
++                                        struct resolv_hostport_list_state);
++    struct resolv_hostent *rhostent;
++    int resolv_status;
++
++    ret = resolv_gethostbyname_recv(subreq, state, &resolv_status, NULL,
++                                    &rhostent);
++    talloc_zfree(subreq);
++
++    if (ret != EOK) {
++        /* Don't abort the request, just go to the next one */
++        DEBUG(SSSDBG_OP_FAILURE,
++              "Could not resolve address for this machine, error [%d]: %s, "
++              "resolver returned: [%d]: %s\n", ret, sss_strerror(ret),
++              resolv_status, resolv_strerror(resolv_status));
++    } else {
++        state->rhp_addrs[state->addrindex] = \
++            resolv_hostport_addr_new(state->rhp_addrs,
++                                     state->hostport_list[state->hpindex].host,
++                                     state->hostport_list[state->hpindex].port,
++                                     rhostent);
++        state->addrindex++;
++
++        if (state->limit > 0 && state->addrindex >= state->limit) {
++            DEBUG(SSSDBG_TRACE_INTERNAL,
++                "Reached the limit or addresses to resolve\n");
++            tevent_req_done(req);
++            return;
++        }
++    }
++
++    state->hpindex++;
++
++    ret = resolv_hostport_list_step(req);
++    if (ret == EOK) {
++        tevent_req_done(req);
++        return;
++    } else if (ret != EAGAIN) {
++        tevent_req_error(req, ret);
++        return;
++    }
++    /* Next iteration .. */
++}
++
++int resolv_hostport_list_recv(struct tevent_req *req,
++                              TALLOC_CTX *mem_ctx,
++                              size_t *_rhp_len,
++                              struct resolv_hostport_addr ***_rhp_addrs)
++{
++    struct resolv_hostport_list_state *state = tevent_req_data(req,
++                                        struct resolv_hostport_list_state);
++
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++
++    if (_rhp_len) {
++        *_rhp_len = state->addrindex;
++    }
++
++    if (_rhp_addrs) {
++        *_rhp_addrs = talloc_steal(mem_ctx, state->rhp_addrs);
++    }
++
++    return EOK;
++}
+diff --git a/src/resolv/async_resolv.h b/src/resolv/async_resolv.h
+index b602a425c21b5f3bfd0098ce3208f6750d4ed1ad..90ed037075c7becb0f8bcd580b218092f2d8579e 100644
+--- a/src/resolv/async_resolv.h
++++ b/src/resolv/async_resolv.h
+@@ -112,6 +112,36 @@ int resolv_gethostbyname_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                               int *status, int *timeouts,
+                               struct resolv_hostent **rhostent);
+ 
++struct resolv_hostport {
++    const char *host;
++    int port;
++};
++
++struct resolv_hostport_addr {
++    struct resolv_hostport origin;
++    struct resolv_hostent *reply;
++};
++
++/* Resolves a list of resolv_hostport tuples into a list of
++ * resolv_hostport_addr. Any unresolvable addresses are skipped.
++ *
++ * Optionally takes a limit argument and stops after the request
++ * had resolved addresses up to the limit.
++ */
++struct tevent_req *resolv_hostport_list_send(TALLOC_CTX *mem_ctx,
++                                             struct tevent_context *ev,
++                                             struct resolv_ctx *ctx,
++                                             struct resolv_hostport *hostport_list,
++                                             size_t list_size,
++                                             size_t limit,
++                                             enum restrict_family family_order,
++                                             enum host_database *db);
++
++int resolv_hostport_list_recv(struct tevent_req *req,
++                              TALLOC_CTX *mem_ctx,
++                              size_t *_rhp_len,
++                              struct resolv_hostport_addr ***_rhp_addrs);
++
+ char *
+ resolv_get_string_address_index(TALLOC_CTX *mem_ctx,
+                                 struct resolv_hostent *hostent,
+-- 
+2.17.1
+
diff --git a/SOURCES/0025-KRB5-IPA-AD-Add-a-utility-function-to-create-a-krb5_.patch b/SOURCES/0025-KRB5-IPA-AD-Add-a-utility-function-to-create-a-krb5_.patch
new file mode 100644
index 0000000..53d87db
--- /dev/null
+++ b/SOURCES/0025-KRB5-IPA-AD-Add-a-utility-function-to-create-a-krb5_.patch
@@ -0,0 +1,246 @@
+From 95cb7de6221dad54b37f7dd05dbfc3b717168488 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 25 Jun 2018 13:08:25 +0200
+Subject: [PATCH] KRB5/IPA/AD: Add a utility function to create a krb5_service
+ instance
+
+Each Kerberized provider used hand-crafted copy-paste code to set up its
+copy of the krb5_service structure. Instead of adding yet another copy in
+this patchset in the IPA subdomains code, create a utility function instead.
+
+Due to IPA provider first creating the krb5_service in the common setup
+function, but only later reading the auth options in the auth provider
+constructor, the code first uses the default true value for the use_kdcinfo
+flag and then overrides it with the configured value in the auth constructor
+-- it would be preferable to create the structure with the right value at
+creation time, but this would require bigger refactoring. Also, the code
+before this change was even less correct as the flag was initially set the
+"false" due to the structure being allocated with talloc_zero(). At least
+now it uses the default value.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3291
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit a9a9f39342ebd26425cb1b3baedfea2429d88b04)
+---
+ src/providers/ad/ad_common.c     | 26 ++--------------
+ src/providers/ipa/ipa_common.c   | 35 +++++++++-------------
+ src/providers/krb5/krb5_common.c | 51 ++++++++++++++++++++++----------
+ src/providers/krb5/krb5_common.h |  6 ++++
+ 4 files changed, 58 insertions(+), 60 deletions(-)
+
+diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
+index feeb5d09643a02b99be1a387b41842a034a323b8..b103410e5915a380d0404e18da869517e4d4e355 100644
+--- a/src/providers/ad/ad_common.c
++++ b/src/providers/ad/ad_common.c
+@@ -757,20 +757,14 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
+         goto done;
+     }
+ 
+-    service->krb5_service = talloc_zero(service, struct krb5_service);
++    service->krb5_service = krb5_service_new(service, bectx,
++                                             ad_service, krb5_realm,
++                                             use_kdcinfo);
+     if (!service->krb5_service) {
+         ret = ENOMEM;
+         goto done;
+     }
+ 
+-    /* Set flag that controls whether we want to write the
+-     * kdcinfo files at all
+-     */
+-    service->krb5_service->write_kdcinfo = use_kdcinfo;
+-    DEBUG(SSSDBG_CONF_SETTINGS, "write_kdcinfo for realm %s set to %s\n",
+-                       krb5_realm,
+-                       service->krb5_service->write_kdcinfo ? "true" : "false");
+-
+     ret = be_fo_add_service(bectx, ad_service, ad_user_data_cmp);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create failover service!\n");
+@@ -783,12 +777,6 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
+         goto done;
+     }
+ 
+-    service->krb5_service->name = talloc_strdup(service->krb5_service,
+-                                                ad_service);
+-    if (!service->krb5_service->name) {
+-        ret = ENOMEM;
+-        goto done;
+-    }
+     service->sdap->kinit_service_name = service->krb5_service->name;
+     service->gc->kinit_service_name = service->krb5_service->name;
+ 
+@@ -797,14 +785,6 @@ ad_failover_init(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
+         ret = EINVAL;
+         goto done;
+     }
+-    service->krb5_service->realm =
+-        talloc_strdup(service->krb5_service, krb5_realm);
+-    if (!service->krb5_service->realm) {
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    service->krb5_service->be_ctx = bectx;
+ 
+     if (!primary_servers) {
+         DEBUG(SSSDBG_CONF_SETTINGS,
+diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
+index dcbb54a744358718e444972b9827ee64887e5e33..5808513bfd570c43bc1712114aabba5749ba0fec 100644
+--- a/src/providers/ipa/ipa_common.c
++++ b/src/providers/ipa/ipa_common.c
+@@ -965,6 +965,13 @@ int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+         return ENOMEM;
+     }
+ 
++    realm = dp_opt_get_string(options->basic, IPA_KRB5_REALM);
++    if (!realm) {
++        DEBUG(SSSDBG_CRIT_FAILURE, "No Kerberos realm set\n");
++        ret = EINVAL;
++        goto done;
++    }
++
+     service = talloc_zero(tmp_ctx, struct ipa_service);
+     if (!service) {
+         ret = ENOMEM;
+@@ -975,7 +982,13 @@ int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+         ret = ENOMEM;
+         goto done;
+     }
+-    service->krb5_service = talloc_zero(service, struct krb5_service);
++
++    service->krb5_service = krb5_service_new(service, ctx,
++                                             "IPA", realm,
++                                             true); /* The configured value
++                                                     * will be set later when
++                                                     * the auth provider is set up
++                                                     */
+     if (!service->krb5_service) {
+         ret = ENOMEM;
+         goto done;
+@@ -993,28 +1006,8 @@ int ipa_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+         goto done;
+     }
+ 
+-    service->krb5_service->name = talloc_strdup(service, "IPA");
+-    if (!service->krb5_service->name) {
+-        ret = ENOMEM;
+-        goto done;
+-    }
+     service->sdap->kinit_service_name = service->krb5_service->name;
+ 
+-    realm = dp_opt_get_string(options->basic, IPA_KRB5_REALM);
+-    if (!realm) {
+-        DEBUG(SSSDBG_CRIT_FAILURE, "No Kerberos realm set\n");
+-        ret = EINVAL;
+-        goto done;
+-    }
+-    service->krb5_service->realm =
+-        talloc_strdup(service->krb5_service, realm);
+-    if (!service->krb5_service->realm) {
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    service->krb5_service->be_ctx = ctx;
+-
+     if (!primary_servers) {
+         DEBUG(SSSDBG_CONF_SETTINGS,
+               "No primary servers defined, using service discovery\n");
+diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
+index d064a09ac3726c4185c2fa1eeac76ef6c261d33b..2a50dfec55c29b8d7f8b8751c904977c22aa906a 100644
+--- a/src/providers/krb5/krb5_common.c
++++ b/src/providers/krb5/krb5_common.c
+@@ -807,6 +807,40 @@ static int krb5_user_data_cmp(void *ud1, void *ud2)
+     return strcasecmp((char*) ud1, (char*) ud2);
+ }
+ 
++struct krb5_service *krb5_service_new(TALLOC_CTX *mem_ctx,
++                                      struct be_ctx *be_ctx,
++                                      const char *service_name,
++                                      const char *realm,
++                                      bool use_kdcinfo)
++{
++    struct krb5_service *service;
++
++    service = talloc_zero(mem_ctx, struct krb5_service);
++    if (service == NULL) {
++        return NULL;
++    }
++
++    service->name = talloc_strdup(service, service_name);
++    if (service->name == NULL) {
++        talloc_free(service);
++        return NULL;
++    }
++
++    service->realm = talloc_strdup(service, realm);
++    if (service->realm == NULL) {
++        talloc_free(service);
++        return NULL;
++    }
++
++    DEBUG(SSSDBG_CONF_SETTINGS,
++          "write_kdcinfo for realm %s set to %s\n",
++          realm,
++          use_kdcinfo ? "true" : "false");
++    service->write_kdcinfo = use_kdcinfo;
++    service->be_ctx = be_ctx;
++    return service;
++}
++
+ int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+                       const char *service_name,
+                       const char *primary_servers,
+@@ -824,7 +858,7 @@ int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+         return ENOMEM;
+     }
+ 
+-    service = talloc_zero(tmp_ctx, struct krb5_service);
++    service = krb5_service_new(tmp_ctx, ctx, service_name, realm, use_kdcinfo);
+     if (!service) {
+         ret = ENOMEM;
+         goto done;
+@@ -836,21 +870,6 @@ int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+         goto done;
+     }
+ 
+-    service->name = talloc_strdup(service, service_name);
+-    if (!service->name) {
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    service->realm = talloc_strdup(service, realm);
+-    if (!service->realm) {
+-        ret = ENOMEM;
+-        goto done;
+-    }
+-
+-    service->write_kdcinfo = use_kdcinfo;
+-    service->be_ctx = ctx;
+-
+     if (!primary_servers) {
+         DEBUG(SSSDBG_CONF_SETTINGS,
+               "No primary servers defined, using service discovery\n");
+diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h
+index 3529d740b89fee91281f936fdafd1bdb99e95bd7..1c12d5652ccef7e1738177eedad1c9de543916b7 100644
+--- a/src/providers/krb5/krb5_common.h
++++ b/src/providers/krb5/krb5_common.h
+@@ -164,6 +164,12 @@ errno_t write_krb5info_file(struct krb5_service *krb5_service,
+                             const char *server,
+                             const char *service);
+ 
++struct krb5_service *krb5_service_new(TALLOC_CTX *mem_ctx,
++                                      struct be_ctx *be_ctx,
++                                      const char *service_name,
++                                      const char *realm,
++                                      bool use_kdcinfo);
++
+ int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,
+                       const char *service_name,
+                       const char *primary_servers,
+-- 
+2.17.1
+
diff --git a/SOURCES/0025-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch b/SOURCES/0025-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch
deleted file mode 100644
index 637d39b..0000000
--- a/SOURCES/0025-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch
+++ /dev/null
@@ -1,149 +0,0 @@
-From 21633dc4ad13c0ebae0f2b4e4f4188556202113e Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 12 Oct 2017 10:42:41 +0200
-Subject: [PATCH 25/31] NSS: add support for SSS_NSS_EX_FLAG_NO_CACHE
-
-If SSS_NSS_EX_FLAG_NO_CACHE is set the object is refresh by directly
-looking it up in the backend.
-
-Related to https://pagure.io/SSSD/sssd/issue/2478
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit ac6b267ff3df6d0417062a128ec16b184ea2c1b7)
----
- src/responder/nss/nss_cmd.c          |  8 ++++
- src/sss_client/idmap/sss_nss_ex.c    | 71 ++++++++++++++++++++----------------
- src/sss_client/idmap/sss_nss_idmap.h |  4 ++
- 3 files changed, 52 insertions(+), 31 deletions(-)
-
-diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c
-index 974eaccc93cea3a330007735676da69eb9b84141..c5ddd2f2cc2122cd169ea991b94a14eb5bad095f 100644
---- a/src/responder/nss/nss_cmd.c
-+++ b/src/responder/nss/nss_cmd.c
-@@ -92,6 +92,10 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx,
-         goto done;
-     }
- 
-+    if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) {
-+        cache_req_data_set_bypass_cache(data, true);
-+    }
-+
-     subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx,
-                                  data, memcache, rawname, 0);
-     if (subreq == NULL) {
-@@ -152,6 +156,10 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx,
-         goto done;
-     }
- 
-+    if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) {
-+        cache_req_data_set_bypass_cache(data, true);
-+    }
-+
-     subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx,
-                                  data, memcache, NULL, id);
-     if (subreq == NULL) {
-diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c
-index dc7610a4e528b5126f0d25d84cd3c1a22f683b75..edb3ea652ef7032b76c8f815b9f83fe185a669ea 100644
---- a/src/sss_client/idmap/sss_nss_ex.c
-+++ b/src/sss_client/idmap/sss_nss_ex.c
-@@ -115,42 +115,51 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout)
-     size_t c;
-     gid_t *new_groups;
-     size_t idx;
-+    bool skip_mc = false;
- 
--    ret = sss_nss_mc_get(inp);
--    switch (ret) {
--    case 0:
--        return 0;
--    case ERANGE:
--        return ERANGE;
--    case ENOENT:
--        /* fall through, we need to actively ask the parent
--         * if no entry is found */
--        break;
--    default:
--        /* if using the mmaped cache failed,
--         * fall back to socket based comms */
--        break;
-+    if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) {
-+        skip_mc = true;
-+    }
-+
-+    if (!skip_mc) {
-+        ret = sss_nss_mc_get(inp);
-+        switch (ret) {
-+        case 0:
-+            return 0;
-+        case ERANGE:
-+            return ERANGE;
-+        case ENOENT:
-+            /* fall through, we need to actively ask the parent
-+             * if no entry is found */
-+            break;
-+        default:
-+            /* if using the mmaped cache failed,
-+             * fall back to socket based comms */
-+            break;
-+        }
-     }
- 
-     sss_nss_timedlock(timeout, &time_left);
- 
--    /* previous thread might already initialize entry in mmap cache */
--    ret = sss_nss_mc_get(inp);
--    switch (ret) {
--    case 0:
--        ret = 0;
--        goto out;
--    case ERANGE:
--        ret = ERANGE;
--        goto out;
--    case ENOENT:
--        /* fall through, we need to actively ask the parent
--         * if no entry is found */
--        break;
--    default:
--        /* if using the mmaped cache failed,
--         * fall back to socket based comms */
--        break;
-+    if (!skip_mc) {
-+        /* previous thread might already initialize entry in mmap cache */
-+        ret = sss_nss_mc_get(inp);
-+        switch (ret) {
-+        case 0:
-+            ret = 0;
-+            goto out;
-+        case ERANGE:
-+            ret = ERANGE;
-+            goto out;
-+        case ENOENT:
-+            /* fall through, we need to actively ask the parent
-+             * if no entry is found */
-+            break;
-+        default:
-+            /* if using the mmaped cache failed,
-+             * fall back to socket based comms */
-+            break;
-+        }
-     }
- 
-     ret = sss_nss_make_request_timeout(inp->cmd, &inp->rd, time_left,
-diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h
-index 2334b6cb3fb8ef62e4ce3a7187c7affaeaa034e7..1649830afbb80c617fd339f054aef8bc8e585fb9 100644
---- a/src/sss_client/idmap/sss_nss_idmap.h
-+++ b/src/sss_client/idmap/sss_nss_idmap.h
-@@ -169,6 +169,10 @@ void sss_nss_free_kv(struct sss_nss_kv *kv_list);
- 
- #define SSS_NSS_EX_FLAG_NO_FLAGS 0
- 
-+/** Always request data from the server side, client must be privileged to do
-+ *  so, see nss_trusted_users option in man sssd.conf for details */
-+#define SSS_NSS_EX_FLAG_NO_CACHE (1 << 0)
-+
- #ifdef IPA_389DS_PLUGIN_HELPER_CALLS
- 
- /**
--- 
-2.13.6
-
diff --git a/SOURCES/0026-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch b/SOURCES/0026-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch
deleted file mode 100644
index e0dd792..0000000
--- a/SOURCES/0026-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch
+++ /dev/null
@@ -1,112 +0,0 @@
-From 102ea8cf91207d3dc05537d5c558d98e4756027a Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 23 Oct 2017 18:26:55 +0200
-Subject: [PATCH 26/31] CACHE_REQ: Add cache_req_data_set_bypass_dp()
-
-Similar to cache_req_data_set_bypass_cache()
-cache_req_data_set_bypass_dp() can be used to control how the cache_req
-framework performs the lookup. If cache_req_data_set_bypass_dp() is used
-with 'true' only a cache lookup is performed and no request is send to
-the backend even if no entry was found.
-
-Related to https://pagure.io/SSSD/sssd/issue/2478
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 52e675ec4b160720515c81ae8c0e5a95feb50c57)
----
- src/responder/common/cache_req/cache_req.c         | 15 +++++++++++++++
- src/responder/common/cache_req/cache_req.h         |  3 +++
- src/responder/common/cache_req/cache_req_data.c    | 12 ++++++++++++
- src/responder/common/cache_req/cache_req_private.h |  2 ++
- 4 files changed, 32 insertions(+)
-
-diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c
-index 5fed7a2ab8beded2fee91f679a12f9a0ff6013ec..110df561101be538e3f0496addfa2e14e42ea918 100644
---- a/src/responder/common/cache_req/cache_req.c
-+++ b/src/responder/common/cache_req/cache_req.c
-@@ -142,6 +142,13 @@ cache_req_create(TALLOC_CTX *mem_ctx,
- 
-     cr->cache_first = rctx->cache_first;
-     cr->bypass_cache = cr->plugin->bypass_cache || cr->data->bypass_cache;
-+    cr->bypass_dp = cr->data->bypass_dp;
-+    if (cr->bypass_cache && cr->bypass_dp) {
-+        CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr,
-+                        "Cannot bypass cache and dp at the same time!");
-+        talloc_free(cr);
-+        return NULL;
-+    }
- 
-     return cr;
- }
-@@ -661,6 +668,14 @@ static bool cache_req_search_schema(struct cache_req *cr,
-         if (!first_iteration) {
-             return false;
-         }
-+    } else if (cr->bypass_dp) {
-+        /* The caller wants to lookup only in the cache */
-+        bypass_cache = false;
-+        bypass_dp = true;
-+
-+        if (!first_iteration) {
-+            return false;
-+        }
-     } else if (input_domain != NULL) {
-         /* We will search only one domain. */
-         bypass_cache = false;
-diff --git a/src/responder/common/cache_req/cache_req.h b/src/responder/common/cache_req/cache_req.h
-index c04b2fba6f0445dcfcc9cfe1b5963ac975c39118..2c88853887fc816bba2182d9d9beaa32fa384158 100644
---- a/src/responder/common/cache_req/cache_req.h
-+++ b/src/responder/common/cache_req/cache_req.h
-@@ -127,6 +127,9 @@ void
- cache_req_data_set_bypass_cache(struct cache_req_data *data,
-                                 bool bypass_cache);
- 
-+void
-+cache_req_data_set_bypass_dp(struct cache_req_data *data,
-+                             bool bypass_dp);
- /* Output data. */
- 
- struct cache_req_result {
-diff --git a/src/responder/common/cache_req/cache_req_data.c b/src/responder/common/cache_req/cache_req_data.c
-index 48264a321dc603f9708ba71c44542363b11a71ba..ed378274a9a0a68ede8ac99805f3ea4a041382e6 100644
---- a/src/responder/common/cache_req/cache_req_data.c
-+++ b/src/responder/common/cache_req/cache_req_data.c
-@@ -365,3 +365,15 @@ cache_req_data_set_bypass_cache(struct cache_req_data *data,
- 
-     data->bypass_cache = bypass_cache;
- }
-+
-+void
-+cache_req_data_set_bypass_dp(struct cache_req_data *data,
-+                             bool bypass_dp)
-+{
-+    if (data == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "cache_req_data should never be NULL\n");
-+        return;
-+    }
-+
-+    data->bypass_dp = bypass_dp;
-+}
-diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h
-index 9b706ff7d678f543effb77089857a7e8a42a9c51..0f630542d38a277d1819063fa4134bd7d2525c90 100644
---- a/src/responder/common/cache_req/cache_req_private.h
-+++ b/src/responder/common/cache_req/cache_req_private.h
-@@ -42,6 +42,7 @@ struct cache_req {
-     struct sss_domain_info *domain;
-     bool cache_first;
-     bool bypass_cache;
-+    bool bypass_dp;
-     /* Only contact domains with this type */
-     enum cache_req_dom_type req_dom_type;
- 
-@@ -90,6 +91,7 @@ struct cache_req_data {
-     } svc;
- 
-     bool bypass_cache;
-+    bool bypass_dp;
- };
- 
- struct tevent_req *
--- 
-2.13.6
-
diff --git a/SOURCES/0026-KRB5-Allow-writing-multiple-addresses-to-the-kdcinfo.patch b/SOURCES/0026-KRB5-Allow-writing-multiple-addresses-to-the-kdcinfo.patch
new file mode 100644
index 0000000..87a0435
--- /dev/null
+++ b/SOURCES/0026-KRB5-Allow-writing-multiple-addresses-to-the-kdcinfo.patch
@@ -0,0 +1,246 @@
+From 73f452058c8ac83117cb86c12d4d266c8caccc57 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Tue, 26 Jun 2018 10:35:15 +0200
+Subject: [PATCH] KRB5: Allow writing multiple addresses to the kdcinfo plugin
+
+Turns the previous write_krb5info_file() function into a static function
+that writes whatever input it recevies. Adds a wrapper around it that
+accepts a list of strings, turns that into a newline-separated string
+which is then passed to the original function.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3291
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 8971399c872c21769d5c62cf753c5f9df4caf8cb)
+---
+ src/providers/ad/ad_common.c     | 12 ++---
+ src/providers/ipa/ipa_common.c   |  8 ++--
+ src/providers/krb5/krb5_common.c | 75 +++++++++++++++++++++++++-------
+ src/providers/krb5/krb5_common.h |  2 +-
+ 4 files changed, 70 insertions(+), 27 deletions(-)
+
+diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
+index b103410e5915a380d0404e18da869517e4d4e355..eaf0814f1aaf51a5085e992efa633240f32c498e 100644
+--- a/src/providers/ad/ad_common.c
++++ b/src/providers/ad/ad_common.c
+@@ -848,7 +848,7 @@ ad_resolve_callback(void *private_data, struct fo_server *server)
+     struct resolv_hostent *srvaddr;
+     struct sockaddr_storage *sockaddr;
+     char *address;
+-    const char *safe_address;
++    char *safe_addr_list[2] = { NULL, NULL };
+     char *new_uri;
+     int new_port;
+     const char *srv_name;
+@@ -957,17 +957,17 @@ ad_resolve_callback(void *private_data, struct fo_server *server)
+     if ((sdata == NULL || sdata->gc == false) &&
+         service->krb5_service->write_kdcinfo) {
+         /* Write krb5 info files */
+-        safe_address = sss_escape_ip_address(tmp_ctx,
+-                                            srvaddr->family,
+-                                            address);
+-        if (safe_address == NULL) {
++        safe_addr_list[0] = sss_escape_ip_address(tmp_ctx,
++                                                  srvaddr->family,
++                                                  address);
++        if (safe_addr_list[0] == NULL) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "sss_escape_ip_address failed.\n");
+             ret = ENOMEM;
+             goto done;
+         }
+ 
+         ret = write_krb5info_file(service->krb5_service,
+-                                  safe_address,
++                                  safe_addr_list,
+                                   SSS_KRB5KDC_FO_SRV);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_MINOR_FAILURE,
+diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
+index 5808513bfd570c43bc1712114aabba5749ba0fec..0614019764287e5114aa8b8b5c670b717732068b 100644
+--- a/src/providers/ipa/ipa_common.c
++++ b/src/providers/ipa/ipa_common.c
+@@ -766,7 +766,7 @@ static void ipa_resolve_callback(void *private_data, struct fo_server *server)
+     struct resolv_hostent *srvaddr;
+     struct sockaddr_storage *sockaddr;
+     char *address;
+-    const char *safe_address;
++    char *safe_addr_list[2] = { NULL, NULL };
+     char *new_uri;
+     const char *srv_name;
+     int ret;
+@@ -829,17 +829,17 @@ static void ipa_resolve_callback(void *private_data, struct fo_server *server)
+     service->sdap->sockaddr = talloc_steal(service, sockaddr);
+ 
+     if (service->krb5_service->write_kdcinfo) {
+-        safe_address = sss_escape_ip_address(tmp_ctx,
++        safe_addr_list[0] = sss_escape_ip_address(tmp_ctx,
+                                              srvaddr->family,
+                                              address);
+-        if (safe_address == NULL) {
++        if (safe_addr_list[0] == NULL) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "sss_escape_ip_address failed.\n");
+             talloc_free(tmp_ctx);
+             return;
+         }
+ 
+         ret = write_krb5info_file(service->krb5_service,
+-                                  safe_address,
++                                  safe_addr_list,
+                                   SSS_KRB5KDC_FO_SRV);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE,
+diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
+index 2a50dfec55c29b8d7f8b8751c904977c22aa906a..2b003e1642b449e8db20ba4259ba13273e21212f 100644
+--- a/src/providers/krb5/krb5_common.c
++++ b/src/providers/krb5/krb5_common.c
+@@ -466,10 +466,9 @@ done:
+     return ret;
+ }
+ 
+-
+-errno_t write_krb5info_file(struct krb5_service *krb5_service,
+-                            const char *server,
+-                            const char *service)
++static errno_t write_krb5info_file_contents(struct krb5_service *krb5_service,
++                                            const char *contents,
++                                            const char *service)
+ {
+     int ret;
+     int fd = -1;
+@@ -482,7 +481,7 @@ errno_t write_krb5info_file(struct krb5_service *krb5_service,
+ 
+     if (krb5_service == NULL || krb5_service->realm == NULL
+                              || *krb5_service->realm == '\0'
+-                             || server == NULL || *server == '\0'
++                             || contents == NULL || *contents == '\0'
+                              || service == NULL || *service == '\0') {
+         DEBUG(SSSDBG_CRIT_FAILURE,
+               "Missing or empty realm, server or service.\n");
+@@ -505,7 +504,7 @@ errno_t write_krb5info_file(struct krb5_service *krb5_service,
+         return EINVAL;
+     }
+ 
+-    server_len = strlen(server);
++    server_len = strlen(contents);
+ 
+     tmp_ctx = talloc_new(NULL);
+     if (tmp_ctx == NULL) {
+@@ -535,7 +534,7 @@ errno_t write_krb5info_file(struct krb5_service *krb5_service,
+     }
+ 
+     errno = 0;
+-    written = sss_atomic_write_s(fd, discard_const(server), server_len);
++    written = sss_atomic_write_s(fd, discard_const(contents), server_len);
+     if (written == -1) {
+         ret = errno;
+         DEBUG(SSSDBG_CRIT_FAILURE,
+@@ -592,12 +591,56 @@ done:
+     return ret;
+ }
+ 
++errno_t write_krb5info_file(struct krb5_service *krb5_service,
++                            char **server_list,
++                            const char *service)
++{
++    int i;
++    errno_t ret;
++    TALLOC_CTX *tmp_ctx = NULL;
++    char *contents = NULL;
++
++    if (krb5_service == NULL || server_list == NULL || service == NULL) {
++        return EINVAL;
++    }
++
++    if (server_list[0] == NULL) {
++        return EOK;
++    }
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        return ENOMEM;
++    }
++
++    contents = talloc_strdup(tmp_ctx, "");
++    if (contents == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    i = 0;
++    do {
++        contents = talloc_asprintf_append(contents, "%s\n", server_list[i]);
++        if (contents == NULL) {
++            ret = ENOMEM;
++            goto done;
++        }
++        i++;
++    } while (server_list[i] != NULL);
++
++    ret = write_krb5info_file_contents(krb5_service, contents, service);
++done:
++    talloc_free(tmp_ctx);
++    return ret;
++}
++
+ static void krb5_resolve_callback(void *private_data, struct fo_server *server)
+ {
+     struct krb5_service *krb5_service;
+     struct resolv_hostent *srvaddr;
+     char *address;
+-    char *safe_address;
++    char *safe_addr_list[2] = { NULL, NULL };
+     int ret;
+     TALLOC_CTX *tmp_ctx = NULL;
+ 
+@@ -630,26 +673,26 @@ static void krb5_resolve_callback(void *private_data, struct fo_server *server)
+         return;
+     }
+ 
+-    safe_address = sss_escape_ip_address(tmp_ctx,
+-                                         srvaddr->family,
+-                                         address);
+-    if (safe_address == NULL) {
++    safe_addr_list[0] = sss_escape_ip_address(tmp_ctx,
++                                              srvaddr->family,
++                                              address);
++    if (safe_addr_list[0] == NULL) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "sss_escape_ip_address failed.\n");
+         talloc_free(tmp_ctx);
+         return;
+     }
+ 
+     if (krb5_service->write_kdcinfo) {
+-        safe_address = talloc_asprintf_append(safe_address, ":%d",
+-                                            fo_get_server_port(server));
+-        if (safe_address == NULL) {
++        safe_addr_list[0] = talloc_asprintf_append(safe_addr_list[0], ":%d",
++                                                   fo_get_server_port(server));
++        if (safe_addr_list[0] == NULL) {
+             DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf_append failed.\n");
+             talloc_free(tmp_ctx);
+             return;
+         }
+ 
+         ret = write_krb5info_file(krb5_service,
+-                                  safe_address,
++                                  safe_addr_list,
+                                   krb5_service->name);
+         if (ret != EOK) {
+             DEBUG(SSSDBG_OP_FAILURE,
+diff --git a/src/providers/krb5/krb5_common.h b/src/providers/krb5/krb5_common.h
+index 1c12d5652ccef7e1738177eedad1c9de543916b7..bf36a551a92877ec838d8d3a041903144f22bc8f 100644
+--- a/src/providers/krb5/krb5_common.h
++++ b/src/providers/krb5/krb5_common.h
+@@ -161,7 +161,7 @@ errno_t sss_krb5_get_options(TALLOC_CTX *memctx, struct confdb_ctx *cdb,
+                              const char *conf_path, struct dp_option **_opts);
+ 
+ errno_t write_krb5info_file(struct krb5_service *krb5_service,
+-                            const char *server,
++                            char **server_list,
+                             const char *service);
+ 
+ struct krb5_service *krb5_service_new(TALLOC_CTX *mem_ctx,
+-- 
+2.17.1
+
diff --git a/SOURCES/0027-IPA-Add-the-options-that-the-IPA-subdomains-code-wil.patch b/SOURCES/0027-IPA-Add-the-options-that-the-IPA-subdomains-code-wil.patch
new file mode 100644
index 0000000..b000355
--- /dev/null
+++ b/SOURCES/0027-IPA-Add-the-options-that-the-IPA-subdomains-code-wil.patch
@@ -0,0 +1,67 @@
+From 51354c3e23aa59d88e0340fb7cdbb9b7d4990743 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 25 Jun 2018 13:10:34 +0200
+Subject: [PATCH] IPA: Add the options that the IPA subdomains code will read
+ for trusted domains on the client
+
+With this patchset, IPA clients will read and evaluate the ad_server and
+ad_site options. This patch just adds the required structures for later
+usage.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3291
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 1cce549e0f88f4873c320577d6213dcaeb08766f)
+---
+ src/providers/ipa/ipa_common.h | 7 +++++++
+ src/providers/ipa/ipa_opts.c   | 6 ++++++
+ src/providers/ipa/ipa_opts.h   | 2 ++
+ 3 files changed, 15 insertions(+)
+
+diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
+index 725e0e93728f7643bdf2220a4cb7ecfbbb8b958a..31e671eb50393f77225281226558d9848b3d3d78 100644
+--- a/src/providers/ipa/ipa_common.h
++++ b/src/providers/ipa/ipa_common.h
+@@ -175,6 +175,13 @@ enum ipa_sudocmd_attrs {
+     IPA_OPTS_SUDOCMD
+ };
+ 
++enum ipa_cli_ad_subdom_attrs {
++    IPA_CLI_AD_SERVER,
++    IPA_CLI_AD_SITE,
++
++    IPA_OPTS_CLI_AD_SUBDOM
++};
++
+ struct ipa_auth_ctx {
+     struct krb5_ctx *krb5_auth_ctx;
+     struct sdap_id_ctx *sdap_id_ctx;
+diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c
+index 9419cdcc3913c58e2bcefe238b56fb75e8aa52ec..485ad4fe3ff9808343a94b1792f8c632a3d4b481 100644
+--- a/src/providers/ipa/ipa_opts.c
++++ b/src/providers/ipa/ipa_opts.c
+@@ -389,3 +389,9 @@ struct sdap_attr_map ipa_sudocmd_map[] = {
+     { "ipa_sudocmd_memberof", "memberOf", SYSDB_MEMBEROF, NULL },
+     SDAP_ATTR_MAP_TERMINATOR
+ };
++
++struct dp_option ipa_cli_ad_subdom_opts [] = {
++    { "ad_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },
++    { "ad_site", DP_OPT_STRING, NULL_STRING, NULL_STRING },
++    DP_OPTION_TERMINATOR
++};
+diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
+index 68326b8649a268232394a8fe970d932feb01d46e..378a9922c7b58fc4374262250efbd61b4b6a932f 100644
+--- a/src/providers/ipa/ipa_opts.h
++++ b/src/providers/ipa/ipa_opts.h
+@@ -64,4 +64,6 @@ extern struct sdap_attr_map ipa_sudocmdgroup_map[];
+ 
+ extern struct sdap_attr_map ipa_sudocmd_map[];
+ 
++extern struct dp_option ipa_cli_ad_subdom_opts[];
++
+ #endif /* IPA_OPTS_H_ */
+-- 
+2.17.1
+
diff --git a/SOURCES/0027-nss-make-memcache_delete_entry-public.patch b/SOURCES/0027-nss-make-memcache_delete_entry-public.patch
deleted file mode 100644
index 6d0c026..0000000
--- a/SOURCES/0027-nss-make-memcache_delete_entry-public.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From fd798bd98d932bc847afc60817f5fdb744eee2a4 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 24 Oct 2017 12:50:43 +0200
-Subject: [PATCH 27/31] nss: make memcache_delete_entry() public
-
-Related to https://pagure.io/SSSD/sssd/issue/2478
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit a7d6ca275d6b2e5d396cbefb18d0ee880011e271)
----
- src/responder/nss/nss_get_object.c | 2 +-
- src/responder/nss/nss_private.h    | 8 ++++++++
- 2 files changed, 9 insertions(+), 1 deletion(-)
-
-diff --git a/src/responder/nss/nss_get_object.c b/src/responder/nss/nss_get_object.c
-index e56480af5e3369963d2e8bb17d74d1603af8e014..15faced006f754134415e766284377f0c86af0ac 100644
---- a/src/responder/nss/nss_get_object.c
-+++ b/src/responder/nss/nss_get_object.c
-@@ -86,7 +86,7 @@ memcache_delete_entry_by_id(struct nss_ctx *nss_ctx,
-     return ret;
- }
- 
--static errno_t
-+errno_t
- memcache_delete_entry(struct nss_ctx *nss_ctx,
-                       struct resp_ctx *rctx,
-                       struct sss_domain_info *domain,
-diff --git a/src/responder/nss/nss_private.h b/src/responder/nss/nss_private.h
-index a0b573d6ecba2d8ba6f55db0adcd7ee29cbec991..5fc19d26be9adda4d967086e7b239e49a78866ee 100644
---- a/src/responder/nss/nss_private.h
-+++ b/src/responder/nss/nss_private.h
-@@ -92,6 +92,14 @@ struct sss_cmd_table *get_nss_cmds(void);
- 
- int nss_connection_setup(struct cli_ctx *cli_ctx);
- 
-+errno_t
-+memcache_delete_entry(struct nss_ctx *nss_ctx,
-+                      struct resp_ctx *rctx,
-+                      struct sss_domain_info *domain,
-+                      const char *name,
-+                      uint32_t id,
-+                      enum sss_mc_type type);
-+
- struct tevent_req *
- nss_get_object_send(TALLOC_CTX *mem_ctx,
-                     struct tevent_context *ev,
--- 
-2.13.6
-
diff --git a/SOURCES/0028-IPA-Populate-kdcinfo-files-on-trust-clients-with-con.patch b/SOURCES/0028-IPA-Populate-kdcinfo-files-on-trust-clients-with-con.patch
new file mode 100644
index 0000000..abbcae1
--- /dev/null
+++ b/SOURCES/0028-IPA-Populate-kdcinfo-files-on-trust-clients-with-con.patch
@@ -0,0 +1,800 @@
+From f1780cea77deb98789cc9c53cb6d7c83e2931e70 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Mon, 25 Jun 2018 13:10:39 +0200
+Subject: [PATCH] IPA: Populate kdcinfo files on trust clients with configured
+ AD servers
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3291
+
+Adds a new request into the IPA subdomains provider. This request runs on
+IPA clients only.
+
+The request looks into the configuration for either the ad_site or ad_server
+options for each subdomain. If none are found, the subdomain is skipped.
+
+If either is found, the request resolves the server names, or first the
+site and then the server names from the site and writes their addresses
+to the kdcinfo files for each subdomain. This allows programs such as
+kinit but also SSSD's krb5_child to use the configured servers.
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 18b7f0a30b4745b7d61b3e599e5fb8cd399c23f3)
+---
+ src/providers/ipa/ipa_subdomains.c | 718 ++++++++++++++++++++++++++++-
+ 1 file changed, 716 insertions(+), 2 deletions(-)
+
+diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
+index a8a18ad8a3ec08c137994a84d51851e996aad6dc..1b443559eada3b8feeb9c91fbebd4e2dcca87a23 100644
+--- a/src/providers/ipa/ipa_subdomains.c
++++ b/src/providers/ipa/ipa_subdomains.c
+@@ -76,6 +76,18 @@
+                               "("IPA_ENABLED_FLAG"="IPA_TRUE_VALUE"))" \
+                           "("OBJECTCLASS"="IPA_OC_CERTMAP_CONFIG_OBJECT"))"
+ 
++/* It doesn't make sense to resolve more servers than this from the SRV
++ * lookup because kinit would time out before we are able to cycle
++ * through the whole list
++ */
++#define MAX_SERVERS_FROM_SRV    5
++
++struct ipa_sd_k5_svc_list {
++    struct krb5_service *k5svc;
++
++    struct ipa_sd_k5_svc_list *next;
++    struct ipa_sd_k5_svc_list *prev;
++};
+ 
+ struct ipa_subdomains_ctx {
+     struct be_ctx *be_ctx;
+@@ -88,6 +100,11 @@ struct ipa_subdomains_ctx {
+ 
+     time_t last_refreshed;
+     bool view_read_at_init;
++    /* List of krb5_service structures for each subdomain
++     * in order to write the kdcinfo files. For use on
++     * the client only
++     */
++    struct ipa_sd_k5_svc_list *k5svc_list;
+ };
+ 
+ static errno_t
+@@ -635,6 +652,69 @@ done:
+     return ret;
+ }
+ 
++static struct krb5_service *
++ipa_subdom_get_k5_svc(struct ipa_subdomains_ctx *ctx,
++                      struct sss_domain_info *dom,
++                      bool use_kdcinfo)
++{
++    struct ipa_sd_k5_svc_list *k5svc_ent;
++
++    /* get the service by realm */
++    DLIST_FOR_EACH(k5svc_ent, ctx->k5svc_list) {
++        if (strcasecmp(dom->realm, k5svc_ent->k5svc->realm) == 0) {
++            break;
++        }
++    }
++
++    if (k5svc_ent != NULL) {
++        /* Already exists */
++        return k5svc_ent->k5svc;
++    }
++
++    /* Create a new service */
++    k5svc_ent = talloc_zero(ctx, struct ipa_sd_k5_svc_list);
++    if (k5svc_ent == NULL) {
++        return NULL;
++    }
++
++    k5svc_ent->k5svc = krb5_service_new(k5svc_ent,
++                                        ctx->be_ctx,
++                                        "IPA",
++                                        dom->realm,
++                                        use_kdcinfo);
++    if (k5svc_ent->k5svc == NULL) {
++        talloc_free(k5svc_ent);
++        return NULL;
++    }
++    DLIST_ADD(ctx->k5svc_list, k5svc_ent);
++
++    return k5svc_ent->k5svc;
++}
++
++static void ipa_subdom_remove_k5_svc(struct ipa_subdomains_ctx *ctx)
++{
++    /* Domain going away is such a rare operation that it makes
++     * more sense to just throw away the whole k5svc_list and let
++     * the write_kdcinfo request recreate them all again instead
++     * of coding up complex logic..
++     */
++    talloc_zfree(ctx->k5svc_list);
++}
++
++static void ipa_subdom_remove_step(struct ipa_subdomains_ctx *ctx,
++                                   struct sss_domain_info *dom)
++{
++    if (dp_opt_get_bool(ctx->ipa_id_ctx->ipa_options->basic,
++                        IPA_SERVER_MODE) == false) {
++        /* IPA clients keep track of krb5_service wrappers */
++        return ipa_subdom_remove_k5_svc(ctx);
++    } else {
++        /* IPA servers keeps track of AD contexts */
++        return ipa_ad_subdom_remove(ctx->be_ctx, ctx->ipa_id_ctx, dom);
++    }
++
++}
++
+ static void ipa_subdom_store_step(struct sss_domain_info *parent,
+                                   struct ipa_id_ctx *id_ctx,
+                                   struct sdap_idmap_ctx *sdap_idmap_ctx,
+@@ -697,8 +777,7 @@ static errno_t ipa_subdomains_refresh(struct ipa_subdomains_ctx *ctx,
+                 goto done;
+             }
+ 
+-            /* Remove the AD ID ctx from the list of LDAP domains */
+-            ipa_ad_subdom_remove(ctx->be_ctx, ctx->ipa_id_ctx, dom);
++            ipa_subdom_remove_step(ctx, dom);
+         } else {
+             /* ok let's try to update it */
+             ipa_subdom_store_step(parent, ctx->ipa_id_ctx,
+@@ -1917,6 +1996,611 @@ static errno_t ipa_domain_resolution_order_recv(struct tevent_req *req)
+     return EOK;
+ }
+ 
++struct kdcinfo_from_server_list_state {
++    struct resolv_hostport *hostport_list;
++    enum host_database db[2];
++
++    struct resolv_hostport_addr **rhp_addrs;
++    size_t rhp_len;
++};
++
++static void kdcinfo_from_server_list_done(struct tevent_req *subreq);
++
++static struct tevent_req *
++kdcinfo_from_server_list_send(TALLOC_CTX *mem_ctx,
++                              struct tevent_context *ev,
++                              struct be_resolv_ctx *be_res,
++                              const char *servers)
++{
++    struct kdcinfo_from_server_list_state *state;
++    struct tevent_req *req;
++    struct tevent_req *subreq;
++    errno_t ret;
++    int server_list_len;
++    char **server_list;
++
++    req = tevent_req_create(mem_ctx, &state,
++                            struct kdcinfo_from_server_list_state);
++    if (req == NULL) {
++        return NULL;
++    }
++    state->db[0] = DB_DNS;
++    state->db[1] = DB_SENTINEL;
++
++    if (servers == NULL) {
++        ret = EOK;
++        goto immediately;
++    }
++
++    ret = split_on_separator(state, servers, ',', true, true,
++                             &server_list,
++                             &server_list_len);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE, "Failed to parse server list!\n");
++        goto immediately;
++    }
++
++    state->hostport_list = talloc_array(state,
++                                        struct resolv_hostport,
++                                        server_list_len);
++    if (state->hostport_list == NULL) {
++        ret = ENOMEM;
++        goto immediately;
++    }
++
++    for (int i = 0; i < server_list_len; i++) {
++        state->hostport_list[i].host = server_list[i];
++        state->hostport_list[i].port = 0;
++    }
++
++    subreq = resolv_hostport_list_send(state,
++                                       ev,
++                                       be_res->resolv,
++                                       state->hostport_list,
++                                       server_list_len,
++                                       0,
++                                       be_res->family_order,
++                                       state->db);
++    if (subreq == NULL) {
++        ret = ENOMEM;
++        goto immediately;
++    }
++    tevent_req_set_callback(subreq, kdcinfo_from_server_list_done, req);
++    return req;
++
++immediately:
++    if (ret != EOK) {
++        tevent_req_error(req, ret);
++    } else {
++        tevent_req_done(req);
++    }
++    tevent_req_post(req, ev);
++    return req;
++}
++
++static void kdcinfo_from_server_list_done(struct tevent_req *subreq)
++{
++    errno_t ret;
++    struct tevent_req *req =
++            tevent_req_callback_data(subreq, struct tevent_req);
++    struct kdcinfo_from_server_list_state *state = tevent_req_data(req,
++                                        struct kdcinfo_from_server_list_state);
++
++    ret = resolv_hostport_list_recv(subreq,
++                                    state,
++                                    &state->rhp_len,
++                                    &state->rhp_addrs);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "Failed to resolve address list [%d]: %s\n", ret, sss_strerror(ret));
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    tevent_req_done(req);
++}
++
++static errno_t kdcinfo_from_server_list_recv(TALLOC_CTX *mem_ctx,
++                                             struct tevent_req *req,
++                                             struct resolv_hostport_addr ***_rhp_addrs,
++                                             size_t *_rhp_len)
++{
++    struct kdcinfo_from_server_list_state *state = tevent_req_data(req,
++                                        struct kdcinfo_from_server_list_state);
++
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++
++    if (_rhp_addrs != NULL) {
++        *_rhp_addrs = talloc_steal(mem_ctx, state->rhp_addrs);
++    }
++
++    if (_rhp_len != NULL) {
++        *_rhp_len = state->rhp_len;
++    }
++
++    return EOK;
++}
++
++struct kdcinfo_from_site_state {
++    struct tevent_context *ev;
++    struct be_resolv_ctx *be_res;
++
++    const char *discovery_domains[2];
++    struct resolv_hostport *hostport_list;
++    enum host_database db[2];
++
++    struct resolv_hostport_addr **rhp_addrs;
++    size_t rhp_len;
++};
++
++static void kdcinfo_from_site_srv_done(struct tevent_req *subreq);
++static void kdcinfo_from_site_server_list_done(struct tevent_req *subreq);
++
++static struct tevent_req *
++kdcinfo_from_site_send(TALLOC_CTX *mem_ctx,
++                       struct tevent_context *ev,
++                       struct be_resolv_ctx *be_res,
++                       const char *site,
++                       const char *domain)
++{
++    struct kdcinfo_from_site_state *state;
++    struct tevent_req *req;
++    struct tevent_req *subreq;
++    errno_t ret;
++
++    req = tevent_req_create(mem_ctx, &state,
++                            struct kdcinfo_from_site_state);
++    if (req == NULL) {
++        return NULL;
++    }
++    state->ev = ev;
++    state->be_res = be_res;
++    state->db[0] = DB_DNS;
++    state->db[1] = DB_SENTINEL;
++
++    state->discovery_domains[0] = ad_site_dns_discovery_domain(state,
++                                                               site,
++                                                               domain);
++    if (state->discovery_domains[0] == NULL) {
++        ret = ENOMEM;
++        goto immediately;
++    }
++    state->discovery_domains[1] = NULL;
++
++    subreq = fo_discover_srv_send(state,
++                                  state->ev,
++                                  state->be_res->resolv,
++                                  "kerberos", "tcp",
++                                  state->discovery_domains);
++    if (subreq == NULL) {
++        ret = ENOMEM;
++        goto immediately;
++    }
++    tevent_req_set_callback(subreq, kdcinfo_from_site_srv_done, req);
++    return req;
++
++immediately:
++    if (ret != EOK) {
++        tevent_req_error(req, ret);
++    } else {
++        tevent_req_done(req);
++    }
++    tevent_req_post(req, ev);
++    return req;
++}
++
++static void kdcinfo_from_site_srv_done(struct tevent_req *subreq)
++{
++    errno_t ret;
++    struct tevent_req *req =
++            tevent_req_callback_data(subreq, struct tevent_req);
++    struct kdcinfo_from_site_state *state = tevent_req_data(req,
++                                        struct kdcinfo_from_site_state);
++    struct fo_server_info *servers;
++    size_t num_servers;
++
++    ret = fo_discover_srv_recv(state, subreq,
++                               NULL, NULL, /* not interested in TTL etc */
++                               &servers, &num_servers);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "Could not resolve the site [%d]: %s\n", ret, sss_strerror(ret));
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    state->hostport_list = talloc_array(state,
++                                        struct resolv_hostport,
++                                        num_servers);
++    if (state->hostport_list == NULL) {
++        tevent_req_error(req, ENOMEM);
++        return;
++    }
++
++    for (size_t i = 0; i < num_servers; i++) {
++        state->hostport_list[i].host = servers[i].host;
++        state->hostport_list[i].port = servers[i].port;
++    }
++
++    subreq = resolv_hostport_list_send(state,
++                                       state->ev,
++                                       state->be_res->resolv,
++                                       state->hostport_list,
++                                       num_servers,
++                                       MAX_SERVERS_FROM_SRV,
++                                       state->be_res->family_order,
++                                       state->db);
++    if (subreq == NULL) {
++        tevent_req_error(req, ENOMEM);
++        return;
++    }
++    tevent_req_set_callback(subreq, kdcinfo_from_site_server_list_done, req);
++}
++
++static void kdcinfo_from_site_server_list_done(struct tevent_req *subreq)
++{
++    errno_t ret;
++    struct tevent_req *req =
++            tevent_req_callback_data(subreq, struct tevent_req);
++    struct kdcinfo_from_site_state *state = tevent_req_data(req,
++                                        struct kdcinfo_from_site_state);
++
++    ret = resolv_hostport_list_recv(subreq,
++                                    state,
++                                    &state->rhp_len,
++                                    &state->rhp_addrs);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "Failed to resolve address list [%d]: %s\n",
++              ret, sss_strerror(ret));
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    tevent_req_done(req);
++}
++
++
++static errno_t kdcinfo_from_site_recv(TALLOC_CTX *mem_ctx,
++                                      struct tevent_req *req,
++                                      struct resolv_hostport_addr ***_rhp_addrs,
++                                      size_t *_rhp_len)
++{
++    struct kdcinfo_from_site_state *state = tevent_req_data(req,
++                                        struct kdcinfo_from_site_state);
++
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++
++    if (_rhp_addrs != NULL) {
++        *_rhp_addrs = talloc_steal(mem_ctx, state->rhp_addrs);
++    }
++
++    if (_rhp_len != NULL) {
++        *_rhp_len = state->rhp_len;
++    }
++
++    return EOK;
++}
++
++/* Anything per-domain in this request goes here so that we
++ * can just free the whole struct without mixing data from
++ * different domains or the overhead of another request
++ */
++struct ipa_sd_per_dom_kdcinfo_ctx {
++    struct sss_domain_info *dom;
++
++    const char *servers;
++    const char *site;
++
++    const char *discovery_domains[2];
++    struct krb5_service *krb5_service;
++};
++
++struct ipa_subdomains_write_kdcinfo_state {
++    struct tevent_context *ev;
++    struct ipa_subdomains_ctx *ipa_sd_ctx;
++    struct be_ctx *be_ctx;
++
++    bool use_kdcinfo;
++    struct ipa_sd_per_dom_kdcinfo_ctx *pdctx;
++};
++
++static errno_t ipa_subdomains_write_kdcinfo_domain_step(struct sss_domain_info *start_dom,
++                                                        struct tevent_req *req);
++static void ipa_subdomains_write_kdcinfo_domain_done(struct tevent_req *subreq);
++static errno_t ipa_subdomains_write_kdcinfo_write_step(struct sss_domain_info *dom,
++                                                       struct krb5_service *krb5_service,
++                                                       struct resolv_hostport_addr **rhp_addrs,
++                                                       size_t rhp_len);
++
++static struct tevent_req *
++ipa_subdomains_write_kdcinfo_send(TALLOC_CTX *mem_ctx,
++                                  struct tevent_context *ev,
++                                  struct ipa_subdomains_ctx *ipa_sd_ctx,
++                                  struct be_ctx *be_ctx)
++{
++    struct ipa_subdomains_write_kdcinfo_state *state;
++    struct tevent_req *req;
++    errno_t ret;
++
++    req = tevent_req_create(mem_ctx, &state,
++                            struct ipa_subdomains_write_kdcinfo_state);
++    if (req == NULL) {
++        return NULL;
++    }
++    state->ev = ev;
++    state->ipa_sd_ctx = ipa_sd_ctx;
++    state->be_ctx = be_ctx;
++
++    if (ipa_sd_ctx->ipa_id_ctx->server_mode != NULL) {
++        /* This request is valid for clients only */
++        ret = EOK;
++        goto immediately;
++    }
++
++    state->use_kdcinfo = dp_opt_get_bool(ipa_sd_ctx->ipa_id_ctx->ipa_options->auth,
++                                         KRB5_USE_KDCINFO);
++    if (state->use_kdcinfo == false) {
++        DEBUG(SSSDBG_CONF_SETTINGS, "kdcinfo creation disabled\n");
++        ret = EOK;
++        goto immediately;
++    }
++
++    if (be_ctx->domain->subdomains == NULL) {
++        DEBUG(SSSDBG_CONF_SETTINGS, "No subdomains, done\n");
++        ret = EOK;
++        goto immediately;
++    }
++
++    ret = ipa_subdomains_write_kdcinfo_domain_step(be_ctx->domain->subdomains,
++                                                   req);
++    if (ret != EAGAIN) {
++        goto immediately;
++    }
++    return req;
++
++immediately:
++    if (ret == EOK) {
++        tevent_req_done(req);
++    } else {
++        tevent_req_error(req, ret);
++    }
++    tevent_req_post(req, ev);
++    return req;
++}
++
++static errno_t ipa_subdomains_write_kdcinfo_domain_step(struct sss_domain_info *start_dom,
++                                                        struct tevent_req *req)
++{
++    struct ipa_subdomains_write_kdcinfo_state *state = \
++                tevent_req_data(req,
++                                struct ipa_subdomains_write_kdcinfo_state);
++    struct dp_option *ipa_ad_subdom_opts;
++    struct tevent_req *subreq = NULL;
++    char *subdom_conf_path;
++    errno_t ret;
++    const char *servers;
++    const char *site;
++
++    for (struct sss_domain_info *dom = start_dom;
++            dom != NULL;
++            dom = get_next_domain(dom, 0)) {
++
++        talloc_zfree(state->pdctx);
++
++        subdom_conf_path = subdomain_create_conf_path(state, dom);
++        if (subdom_conf_path == NULL) {
++            DEBUG(SSSDBG_MINOR_FAILURE,
++                  "subdom_conf_path failed for %s\n", dom->name);
++            /* Not fatal */
++            continue;
++        }
++
++        ret = dp_get_options(state, state->be_ctx->cdb,
++                             subdom_conf_path,
++                             ipa_cli_ad_subdom_opts,
++                             IPA_OPTS_CLI_AD_SUBDOM,
++                             &ipa_ad_subdom_opts);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE,
++                  "Cannot get options for %s: [%d]: %s\n",
++                  dom->name, ret, sss_strerror(ret));
++            /* Not fatal */
++            continue;
++        }
++
++        servers = dp_opt_get_string(ipa_ad_subdom_opts, IPA_CLI_AD_SERVER);
++        site = dp_opt_get_string(ipa_ad_subdom_opts, IPA_CLI_AD_SITE);
++
++        if (servers == NULL && site == NULL) {
++            /* If neither is set, just go to the next domain */
++            DEBUG(SSSDBG_TRACE_INTERNAL,
++                  "No site or server defined for %s, skipping\n",
++                  dom->name);
++            continue;
++        }
++
++        /* We will resolve this domain, create a per-domain context */
++        state->pdctx = talloc_zero(state, struct ipa_sd_per_dom_kdcinfo_ctx);
++        if (state->pdctx == NULL) {
++            return ENOMEM;
++        }
++        state->pdctx->dom = dom;
++        state->pdctx->servers = servers;
++        state->pdctx->site = site;
++        state->pdctx->krb5_service = ipa_subdom_get_k5_svc(state->ipa_sd_ctx,
++                                                           dom,
++                                                           state->use_kdcinfo);
++        if (state->pdctx->krb5_service == NULL) {
++            continue;
++        }
++
++        if (state->pdctx->servers != NULL) {
++            DEBUG(SSSDBG_CONF_SETTINGS,
++                  "Resolving servers [%s] for domain %s\n",
++                  state->pdctx->servers, dom->name);
++
++            subreq = kdcinfo_from_server_list_send(state,
++                                                   state->ev,
++                                                   state->be_ctx->be_res,
++                                                   state->pdctx->servers);
++        } else if (state->pdctx->site != NULL) {
++            DEBUG(SSSDBG_CONF_SETTINGS,
++                  "Resolving site %s for domain %s\n",
++                  state->pdctx->site, dom->name);
++
++            subreq = kdcinfo_from_site_send(state,
++                                            state->ev,
++                                            state->be_ctx->be_res,
++                                            state->pdctx->site,
++                                            state->pdctx->dom->name);
++        } else {
++            /* We should never get here */
++            return EINVAL;
++        }
++
++        if (subreq == NULL) {
++            return ENOMEM;
++        }
++        tevent_req_set_callback(subreq, ipa_subdomains_write_kdcinfo_domain_done, req);
++        return EAGAIN;
++    }
++
++    return EOK;
++}
++
++static void ipa_subdomains_write_kdcinfo_domain_done(struct tevent_req *subreq)
++{
++    errno_t ret;
++    struct tevent_req *req =
++            tevent_req_callback_data(subreq, struct tevent_req);
++    struct ipa_subdomains_write_kdcinfo_state *state = \
++                tevent_req_data(req,
++                                struct ipa_subdomains_write_kdcinfo_state);
++    struct sss_domain_info *next_domain;
++    struct resolv_hostport_addr **rhp_addrs;
++    size_t rhp_len;
++
++    if (state->pdctx->servers != NULL) {
++        ret = kdcinfo_from_server_list_recv(state->pdctx, subreq,
++                                            &rhp_addrs, &rhp_len);
++    } else if (state->pdctx->site != NULL) {
++        ret = kdcinfo_from_site_recv(state->pdctx, subreq,
++                                     &rhp_addrs, &rhp_len);
++    } else {
++        DEBUG(SSSDBG_CRIT_FAILURE, "Neither site nor servers set\n");
++        ret = EINVAL;
++    }
++
++    if (ret == EOK) {
++        ret = ipa_subdomains_write_kdcinfo_write_step(state->pdctx->dom,
++                                                      state->pdctx->krb5_service,
++                                                      rhp_addrs, rhp_len);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE,
++                  "Could not write kdcinfo file for %s\n", state->pdctx->dom->name);
++            /* Not fatal, loop to the next domain below */
++        }
++    } else {
++        DEBUG(SSSDBG_MINOR_FAILURE,
++              "Could not get address list for %s\n", state->pdctx->dom->name);
++        /* Not fatal, loop to the next domain below */
++    }
++
++    next_domain = get_next_domain(state->pdctx->dom, 0);
++    ret = ipa_subdomains_write_kdcinfo_domain_step(next_domain, req);
++    if (ret == EOK) {
++        tevent_req_done(req);
++        return;
++    } else if (ret != EAGAIN) {
++        /* the loop in ipa_subdomains_write_kdcinfo_domain_step already
++         * tries to be quite permissive, so any error is fatal
++         */
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    /* Continue to the next domain */
++}
++
++static errno_t ipa_subdomains_write_kdcinfo_write_step(struct sss_domain_info *dom,
++                                                       struct krb5_service *krb5_service,
++                                                       struct resolv_hostport_addr **rhp_addrs,
++                                                       size_t rhp_len)
++{
++    errno_t ret;
++    char *address = NULL;
++    char *safe_address = NULL;
++    char **safe_addr_list;
++    int addr_index = 0;
++    TALLOC_CTX *tmp_ctx = NULL;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        return ENOMEM;
++    }
++
++    safe_addr_list = talloc_zero_array(tmp_ctx, char *, rhp_len+1);
++    if (safe_addr_list == NULL) {
++        ret = ENOMEM;
++        goto done;
++    }
++
++    for (size_t i = 0; i < rhp_len; i++) {
++        address = resolv_get_string_address(tmp_ctx, rhp_addrs[i]->reply);
++        if (address == NULL) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "resolv_get_string_address failed.\n");
++            continue;
++        }
++
++        if (rhp_addrs[i]->origin.port != 0) {
++            address = talloc_asprintf_append(address,
++                                             ":%d",
++                                             rhp_addrs[i]->origin.port);
++        }
++
++        safe_address = sss_escape_ip_address(tmp_ctx,
++                                             rhp_addrs[i]->reply->family,
++                                             address);
++        talloc_zfree(address);
++        if (safe_address == NULL) {
++            DEBUG(SSSDBG_CRIT_FAILURE, "sss_escape_ip_address failed.\n");
++            continue;
++        }
++
++        DEBUG(SSSDBG_CONF_SETTINGS,
++              "Will write [%s] for %s\n",
++              safe_address, dom->name);
++
++        safe_addr_list[addr_index] = talloc_steal(safe_addr_list,
++                                                  safe_address);
++        addr_index++;
++    }
++
++    ret = write_krb5info_file(krb5_service,
++                              safe_addr_list,
++                              SSS_KRB5KDC_FO_SRV);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++                "write_krb5info_file failed, authentication might fail.\n");
++        goto done;
++    }
++
++    ret = EOK;
++done:
++    talloc_free(tmp_ctx);
++    return ret;
++}
++
++static errno_t ipa_subdomains_write_kdcinfo_recv(struct tevent_req *req)
++{
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++    return EOK;
++}
++
+ struct ipa_subdomains_refresh_state {
+     struct tevent_context *ev;
+     struct ipa_subdomains_ctx *sd_ctx;
+@@ -1933,6 +2617,7 @@ static void ipa_subdomains_refresh_view_name_done(struct tevent_req *subreq);
+ static void ipa_subdomains_refresh_view_domain_resolution_order_done(
+                                                     struct tevent_req *subreq);
+ static void ipa_domain_refresh_resolution_order_done(struct tevent_req *subreq);
++static void ipa_domain_refresh_kdcinfo_done(struct tevent_req *subreq);
+ 
+ static struct tevent_req *
+ ipa_subdomains_refresh_send(TALLOC_CTX *mem_ctx,
+@@ -2253,6 +2938,35 @@ ipa_domain_refresh_resolution_order_done(struct tevent_req *subreq)
+         return;
+     }
+ 
++    subreq = ipa_subdomains_write_kdcinfo_send(state,
++                                               state->ev,
++                                               state->sd_ctx,
++                                               state->sd_ctx->be_ctx);
++    if (subreq == NULL) {
++        tevent_req_error(req, ENOMEM);
++        return;
++    }
++    tevent_req_set_callback(subreq, ipa_domain_refresh_kdcinfo_done, req);
++}
++
++static void
++ipa_domain_refresh_kdcinfo_done(struct tevent_req *subreq)
++{
++    struct tevent_req *req;
++    errno_t ret;
++
++    req = tevent_req_callback_data(subreq, struct tevent_req);
++
++    ret = ipa_subdomains_write_kdcinfo_recv(subreq);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_MINOR_FAILURE,
++              "Unable to write the kdc info files, authentication might "
++              "fail or time out [%d]: %s\n",
++              ret, sss_strerror(ret));
++        /* Not fatal, let's hope DNS is set correctly */
++    }
++
+     tevent_req_done(req);
+ }
+ 
+-- 
+2.17.1
+
diff --git a/SOURCES/0028-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch b/SOURCES/0028-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch
deleted file mode 100644
index 04cc5a0..0000000
--- a/SOURCES/0028-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch
+++ /dev/null
@@ -1,365 +0,0 @@
-From fe54de0824cac1822d6f9485165adc64bf4e0fa7 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 24 Oct 2017 14:10:53 +0200
-Subject: [PATCH 28/31] NSS: add support for SSS_NSS_EX_FLAG_INVALIDATE_CACHE
-
-The patch adds support for the SSS_NSS_EX_FLAG_INVALIDATE_CACHE flag and
-makes the existing code more flexible and handle additional flags.
-
-If SSS_NSS_EX_FLAG_INVALIDATE_CACHE is set the requested object is only
-looked up in the cache and if it was found on-disk and memory cache
-entries will be invalidated.
-
-Related to https://pagure.io/SSSD/sssd/issue/2478
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 55f7d8034d783c01789d76a2b9ffc901045e8af8)
----
- src/responder/nss/nss_cmd.c            | 141 +++++++++++++++++++++++++++++++--
- src/responder/nss/nss_protocol.c       |   1 +
- src/responder/nss/nss_protocol.h       |   1 +
- src/responder/nss/nss_protocol_grent.c |   9 ++-
- src/responder/nss/nss_protocol_pwent.c |   6 +-
- src/sss_client/idmap/sss_nss_ex.c      |  20 ++++-
- src/sss_client/idmap/sss_nss_idmap.h   |   8 +-
- 7 files changed, 171 insertions(+), 15 deletions(-)
-
-diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c
-index c5ddd2f2cc2122cd169ea991b94a14eb5bad095f..545257a0be7e91e9de767a57848bb77c5791db4e 100644
---- a/src/responder/nss/nss_cmd.c
-+++ b/src/responder/nss/nss_cmd.c
-@@ -50,6 +50,26 @@ nss_cmd_ctx_create(TALLOC_CTX *mem_ctx,
-     return cmd_ctx;
- }
- 
-+static errno_t eval_flags(struct nss_cmd_ctx *cmd_ctx,
-+                          struct cache_req_data *data)
-+{
-+    if ((cmd_ctx->flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0
-+            && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Flags SSS_NSS_EX_FLAG_NO_CACHE and "
-+                                   "SSS_NSS_EX_FLAG_INVALIDATE_CACHE are "
-+                                   "mutually exclusive.\n");
-+        return EINVAL;
-+    }
-+
-+    if ((cmd_ctx->flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) {
-+        cache_req_data_set_bypass_cache(data, true);
-+    } else if ((cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) {
-+        cache_req_data_set_bypass_dp(data, true);
-+    }
-+
-+    return EOK;
-+}
-+
- static void nss_getby_done(struct tevent_req *subreq);
- static void nss_getlistby_done(struct tevent_req *subreq);
- 
-@@ -65,7 +85,6 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx,
-     struct tevent_req *subreq;
-     const char *rawname;
-     errno_t ret;
--    uint32_t flags = 0;
- 
-     cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, fill_fn);
-     if (cmd_ctx == NULL) {
-@@ -73,8 +92,9 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx,
-         goto done;
-     }
- 
-+    cmd_ctx->flags = 0;
-     if (ex_version) {
--        ret = nss_protocol_parse_name_ex(cli_ctx, &rawname, &flags);
-+        ret = nss_protocol_parse_name_ex(cli_ctx, &rawname, &cmd_ctx->flags);
-     } else {
-         ret = nss_protocol_parse_name(cli_ctx, &rawname);
-     }
-@@ -92,8 +112,10 @@ static errno_t nss_getby_name(struct cli_ctx *cli_ctx,
-         goto done;
-     }
- 
--    if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) {
--        cache_req_data_set_bypass_cache(data, true);
-+    ret = eval_flags(cmd_ctx, data);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "eval_flags failed.\n");
-+        goto done;
-     }
- 
-     subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx,
-@@ -129,7 +151,6 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx,
-     struct tevent_req *subreq;
-     uint32_t id;
-     errno_t ret;
--    uint32_t flags = 0;
- 
-     cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, fill_fn);
-     if (cmd_ctx == NULL) {
-@@ -138,7 +159,7 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx,
-     }
- 
-     if (ex_version) {
--        ret = nss_protocol_parse_id_ex(cli_ctx, &id, &flags);
-+        ret = nss_protocol_parse_id_ex(cli_ctx, &id, &cmd_ctx->flags);
-     } else {
-         ret = nss_protocol_parse_id(cli_ctx, &id);
-     }
-@@ -156,8 +177,10 @@ static errno_t nss_getby_id(struct cli_ctx *cli_ctx,
-         goto done;
-     }
- 
--    if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) {
--        cache_req_data_set_bypass_cache(data, true);
-+    ret = eval_flags(cmd_ctx, data);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "eval_flags failed.\n");
-+        goto done;
-     }
- 
-     subreq = nss_get_object_send(cmd_ctx, cli_ctx->ev, cli_ctx,
-@@ -425,6 +448,98 @@ done:
-     return EOK;
- }
- 
-+static errno_t invalidate_cache(struct nss_cmd_ctx *cmd_ctx,
-+                                struct cache_req_result *result)
-+{
-+    int ret;
-+    enum sss_mc_type memcache_type;
-+    const char *name;
-+    char *output_name = NULL;
-+    bool is_user;
-+    struct sysdb_attrs *attrs = NULL;
-+
-+    switch (cmd_ctx->type) {
-+    case CACHE_REQ_INITGROUPS:
-+    case CACHE_REQ_INITGROUPS_BY_UPN:
-+        memcache_type = SSS_MC_INITGROUPS;
-+        is_user = true;
-+        break;
-+    case CACHE_REQ_USER_BY_NAME:
-+    case CACHE_REQ_USER_BY_ID:
-+        memcache_type = SSS_MC_PASSWD;
-+        is_user = true;
-+        break;
-+    case CACHE_REQ_GROUP_BY_NAME:
-+    case CACHE_REQ_GROUP_BY_ID:
-+        memcache_type = SSS_MC_GROUP;
-+        is_user = false;
-+        break;
-+    default:
-+        /* nothing to do */
-+        return EOK;
-+    }
-+
-+    /* Find output name to invalidate memory cache entry*/
-+    name = sss_get_name_from_msg(result->domain, result->msgs[0]);
-+    if (name == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Found object has no name.\n");
-+        return EINVAL;
-+    }
-+    ret = sss_output_fqname(cmd_ctx, result->domain, name,
-+                            cmd_ctx->nss_ctx->rctx->override_space,
-+                            &output_name);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sss_output_fqname failed.\n");
-+        return ret;
-+    }
-+
-+    memcache_delete_entry(cmd_ctx->nss_ctx, cmd_ctx->nss_ctx->rctx, NULL,
-+                          output_name, 0, memcache_type);
-+    if (memcache_type == SSS_MC_INITGROUPS) {
-+        /* Invalidate the passwd data as well */
-+        memcache_delete_entry(cmd_ctx->nss_ctx, cmd_ctx->nss_ctx->rctx,
-+                              result->domain, output_name, 0, SSS_MC_PASSWD);
-+    }
-+    talloc_free(output_name);
-+
-+    /* Use sysdb name to invalidate disk cache entry */
-+    name = ldb_msg_find_attr_as_string(result->msgs[0], SYSDB_NAME, NULL);
-+    if (name == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Found object has no name.\n");
-+        return EINVAL;
-+    }
-+
-+    if (memcache_type == SSS_MC_INITGROUPS) {
-+        attrs = sysdb_new_attrs(cmd_ctx);
-+        if (attrs == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
-+            return ENOMEM;
-+        }
-+
-+        ret = sysdb_attrs_add_time_t(attrs, SYSDB_INITGR_EXPIRE, 1);
-+        if (ret != EOK) {
-+            talloc_free(attrs);
-+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_time_t failed.\n");
-+            return ret;
-+        }
-+
-+        ret = sysdb_set_user_attr(result->domain, name, attrs, SYSDB_MOD_REP);
-+        talloc_free(attrs);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_user_attr failed.\n");
-+            return ret;
-+        }
-+    }
-+
-+    ret = sysdb_invalidate_cache_entry(result->domain, name, is_user);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_invalidate_cache_entry failed.\n");
-+        return ret;
-+    }
-+
-+    return EOK;
-+}
-+
- static void nss_getby_done(struct tevent_req *subreq)
- {
-     struct cache_req_result *result;
-@@ -440,6 +555,16 @@ static void nss_getby_done(struct tevent_req *subreq)
-         goto done;
-     }
- 
-+    if ((cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) {
-+        ret = invalidate_cache(cmd_ctx, result);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "Failed to invalidate cache for [%s].\n",
-+                                     cmd_ctx->rawname);
-+            nss_protocol_done(cmd_ctx->cli_ctx, ret);
-+            goto done;
-+        }
-+    }
-+
-     nss_protocol_reply(cmd_ctx->cli_ctx, cmd_ctx->nss_ctx, cmd_ctx,
-                        result, cmd_ctx->fill_fn);
- 
-diff --git a/src/responder/nss/nss_protocol.c b/src/responder/nss/nss_protocol.c
-index 17bfc4f4e71960a72e9e04622eac95b94a865ec7..2655386498754c46fbb363bdd1f976f9ded6a434 100644
---- a/src/responder/nss/nss_protocol.c
-+++ b/src/responder/nss/nss_protocol.c
-@@ -233,6 +233,7 @@ nss_protocol_parse_id_ex(struct cli_ctx *cli_ctx, uint32_t *_id,
-     SAFEALIGN_COPY_UINT32(&flags, body + sizeof(uint32_t), NULL);
- 
-     *_id = id;
-+    *_flags = flags;
- 
-     return EOK;
- }
-diff --git a/src/responder/nss/nss_protocol.h b/src/responder/nss/nss_protocol.h
-index ca5b040237dc18acdca9a7a3a7a7dbb64265aa95..76724d2b2db7b11c9147fa927e39abab731328b2 100644
---- a/src/responder/nss/nss_protocol.h
-+++ b/src/responder/nss/nss_protocol.h
-@@ -50,6 +50,7 @@ struct nss_cmd_ctx {
-     struct nss_ctx *nss_ctx;
-     struct nss_state_ctx *state_ctx;
-     nss_protocol_fill_packet_fn fill_fn;
-+    uint32_t flags;
- 
-     /* For initgroups- */
-     const char *rawname;
-diff --git a/src/responder/nss/nss_protocol_grent.c b/src/responder/nss/nss_protocol_grent.c
-index ee228c722a153a1ba7aa8a1b30a1e551108424bb..6f6ae57dd97b000ad3cf174b0f649d46981563e2 100644
---- a/src/responder/nss/nss_protocol_grent.c
-+++ b/src/responder/nss/nss_protocol_grent.c
-@@ -274,8 +274,10 @@ nss_protocol_fill_grent(struct nss_ctx *nss_ctx,
- 
-         num_results++;
- 
--        /* Do not store entry in memory cache during enumeration. */
--        if (!cmd_ctx->enumeration) {
-+        /* Do not store entry in memory cache during enumeration or when
-+         * requested. */
-+        if (!cmd_ctx->enumeration
-+                && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) == 0) {
-             members = (char *)&body[rp_members];
-             members_size = body_len - rp_members;
-             ret = sss_mmap_cache_gr_store(&nss_ctx->grp_mc_ctx, name, &pwfield,
-@@ -390,7 +392,8 @@ nss_protocol_fill_initgr(struct nss_ctx *nss_ctx,
-         num_results++;
-     }
- 
--    if (nss_ctx->initgr_mc_ctx) {
-+    if (nss_ctx->initgr_mc_ctx
-+                && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) == 0) {
-         to_sized_string(&rawname, cmd_ctx->rawname);
-         to_sized_string(&unique_name, result->lookup_name);
- 
-diff --git a/src/responder/nss/nss_protocol_pwent.c b/src/responder/nss/nss_protocol_pwent.c
-index db5c071e2ff172a2267c08c9817fecfbcc7cabc3..f449ec69b6a86a6db2aaed368e217c1a791faaa2 100644
---- a/src/responder/nss/nss_protocol_pwent.c
-+++ b/src/responder/nss/nss_protocol_pwent.c
-@@ -295,8 +295,10 @@ nss_protocol_fill_pwent(struct nss_ctx *nss_ctx,
- 
-         num_results++;
- 
--        /* Do not store entry in memory cache during enumeration. */
--        if (!cmd_ctx->enumeration) {
-+        /* Do not store entry in memory cache during enumeration or when
-+         * requested. */
-+        if (!cmd_ctx->enumeration
-+                && (cmd_ctx->flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) == 0) {
-             ret = sss_mmap_cache_pw_store(&nss_ctx->pwd_mc_ctx, name, &pwfield,
-                                           uid, gid, &gecos, &homedir, &shell);
-             if (ret != EOK) {
-diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c
-index edb3ea652ef7032b76c8f815b9f83fe185a669ea..148eb7b35ec236b6272dd203a0035399cfdef73d 100644
---- a/src/sss_client/idmap/sss_nss_ex.c
-+++ b/src/sss_client/idmap/sss_nss_ex.c
-@@ -103,6 +103,18 @@ errno_t sss_nss_mc_get(struct nss_input *inp)
-     }
- }
- 
-+static int check_flags(uint32_t flags)
-+{
-+    /* SSS_NSS_EX_FLAG_NO_CACHE and SSS_NSS_EX_FLAG_INVALIDATE_CACHE are
-+     * mutually exclusive */
-+    if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0
-+            && (flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) {
-+        return EINVAL;
-+    }
-+
-+    return 0;
-+}
-+
- int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout)
- {
-     uint8_t *repbuf = NULL;
-@@ -117,7 +129,13 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout)
-     size_t idx;
-     bool skip_mc = false;
- 
--    if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0) {
-+    ret = check_flags(flags);
-+    if (ret != 0) {
-+        return ret;
-+    }
-+
-+    if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0
-+            || (flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) {
-         skip_mc = true;
-     }
- 
-diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h
-index 1649830afbb80c617fd339f054aef8bc8e585fb9..3755643312f05a31d1cf1aa76dfc22848ef1e3ec 100644
---- a/src/sss_client/idmap/sss_nss_idmap.h
-+++ b/src/sss_client/idmap/sss_nss_idmap.h
-@@ -170,9 +170,15 @@ void sss_nss_free_kv(struct sss_nss_kv *kv_list);
- #define SSS_NSS_EX_FLAG_NO_FLAGS 0
- 
- /** Always request data from the server side, client must be privileged to do
-- *  so, see nss_trusted_users option in man sssd.conf for details */
-+ *  so, see nss_trusted_users option in man sssd.conf for details.
-+ *  This flag cannot be used together with SSS_NSS_EX_FLAG_INVALIDATE_CACHE */
- #define SSS_NSS_EX_FLAG_NO_CACHE (1 << 0)
- 
-+/** Invalidate the data in the caches, client must be privileged to do
-+ *  so, see nss_trusted_users option in man sssd.conf for details.
-+ *  This flag cannot be used together with SSS_NSS_EX_FLAG_NO_CACHE */
-+#define SSS_NSS_EX_FLAG_INVALIDATE_CACHE (1 << 1)
-+
- #ifdef IPA_389DS_PLUGIN_HELPER_CALLS
- 
- /**
--- 
-2.13.6
-
diff --git a/SOURCES/0029-MAN-Document-the-options-available-for-AD-trusted-do.patch b/SOURCES/0029-MAN-Document-the-options-available-for-AD-trusted-do.patch
new file mode 100644
index 0000000..ef6ab6e
--- /dev/null
+++ b/SOURCES/0029-MAN-Document-the-options-available-for-AD-trusted-do.patch
@@ -0,0 +1,120 @@
+From 731f098767ce352722dc4d4525c6a520cc5b5dab Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 27 Jun 2018 09:59:42 +0200
+Subject: [PATCH] MAN: Document the options available for AD trusted domains
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3291
+
+Reviewed-by: Sumit Bose <sbose@redhat.com>
+(cherry picked from commit 014e7d8ab6aa4cf3051764052326258230c0bc86)
+---
+ src/man/sssd-ipa.5.xml | 92 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 92 insertions(+)
+
+diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
+index e4e58afaf6616f759ef82c77e339bdc738939dbe..e46957d5f742bafc11774992afe08d32443d061f 100644
+--- a/src/man/sssd-ipa.5.xml
++++ b/src/man/sssd-ipa.5.xml
+@@ -728,6 +728,98 @@
+         </para>
+     </refsect1>
+ 
++    <refsect1 id='trusted_domains'>
++        <title>TRUSTED DOMAINS CONFIGURATION</title>
++        <para>
++            Some configuration options can be also set for a trusted domain.
++            A trusted domain configuration can either be done using
++            a subsection, for example:
++<programlisting>
++[domain/ipa.domain.com/ad.domain.com]
++ad_server = dc.ad.domain.com
++</programlisting>
++        </para>
++        <para>
++            In addition, some options can be set in the parent domain
++            and inherited by the trusted domain using the
++            <quote>subdomain_inherit</quote> option. For more details,
++            see the
++            <citerefentry>
++                <refentrytitle>sssd.conf</refentrytitle>
++                <manvolnum>5</manvolnum>
++            </citerefentry> manual page.
++        </para>
++        <para>
++            Different configuration options are tunable for a trusted
++            domain depending on whether you are configuring SSSD on an
++            IPA server or an IPA client.
++        </para>
++        <refsect2 id='server_configuration'>
++            <title>OPTIONS TUNABLE ON IPA MASTERS</title>
++            <para>
++                The following options can be set in a subdomain
++                section on an IPA master:
++                <itemizedlist>
++                    <listitem>
++                        <para>ad_server</para>
++                    </listitem>
++                    <listitem>
++                        <para>ad_backup_server</para>
++                    </listitem>
++                    <listitem>
++                        <para>ad_site</para>
++                    </listitem>
++                    <listitem>
++                        <para>ldap_search_base</para>
++                    </listitem>
++                    <listitem>
++                        <para>ldap_user_search_base</para>
++                    </listitem>
++                    <listitem>
++                        <para>ldap_group_search_base</para>
++                    </listitem>
++                    <listitem>
++                        <para>use_fully_qualified_names</para>
++                    </listitem>
++                </itemizedlist>
++            </para>
++        </refsect2>
++        <refsect2 id='client_configuration'>
++            <title>OPTIONS TUNABLE ON IPA CLIENTS</title>
++            <para>
++                The following options can be set in a subdomain
++                section on an IPA client:
++                <itemizedlist>
++                    <listitem>
++                        <para>ad_server</para>
++                    </listitem>
++                    <listitem>
++                        <para>ad_site</para>
++                    </listitem>
++                </itemizedlist>
++            </para>
++            <para>
++                Note that if both options are set, only
++                <quote>ad_server</quote> is evaluated.
++            </para>
++            <para>
++                Since any request for a user or a group identity from a
++                trusted domain triggered from an IPA client is resolved
++                by the IPA server, the <quote>ad_server</quote> and
++                <quote>ad_site</quote> options only affect which AD DC will
++                the authentication be performed against. In particular,
++                the addresses resolved from these lists will be written to
++                <quote>kdcinfo</quote> files read by the Kerberos locator
++                plugin. Please refer to the
++                <citerefentry>
++                    <refentrytitle>sssd_krb5_locator_plugin</refentrytitle>
++                    <manvolnum>8</manvolnum>
++                </citerefentry> manual page for more details on the Kerberos
++                locator plugin.
++            </para>
++        </refsect2>
++    </refsect1>
++
+     <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/failover.xml" />
+ 
+     <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/service_discovery.xml" />
+-- 
+2.17.1
+
diff --git a/SOURCES/0029-NSS-TESTS-add-unit-tests-for-_EX-requests.patch b/SOURCES/0029-NSS-TESTS-add-unit-tests-for-_EX-requests.patch
deleted file mode 100644
index 384ca17..0000000
--- a/SOURCES/0029-NSS-TESTS-add-unit-tests-for-_EX-requests.patch
+++ /dev/null
@@ -1,590 +0,0 @@
-From e0f1d81bc24416da1d6d646a0cd3a14bd7e3e02d Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Wed, 25 Oct 2017 21:31:54 +0200
-Subject: [PATCH 29/31] NSS/TESTS: add unit tests for *_EX requests
-
-The patch adds unit tests for the new *_EX requests with different input
-types and flags.
-
-Related to https://pagure.io/SSSD/sssd/issue/2478
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 85da8a5e90bffc8b0fef5e0ea364a8d3cb50de86)
----
- src/tests/cmocka/test_nss_srv.c | 539 ++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 539 insertions(+)
-
-diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
-index ccedf96beaecfaa4232bbe456d5e5a8394098483..6aa726153183b5a871a75d398727ea7132358ca6 100644
---- a/src/tests/cmocka/test_nss_srv.c
-+++ b/src/tests/cmocka/test_nss_srv.c
-@@ -255,6 +255,45 @@ static void mock_input_user_or_group(const char *input)
-     mock_parse_inp(shortname, domname, EOK);
- }
- 
-+static void mock_input_user_or_group_ex(bool do_parse_inp, const char *input,
-+                                        uint32_t flags)
-+{
-+    const char *copy;
-+    const char *shortname;
-+    const char *domname;
-+    char *separator;
-+    uint8_t *data;
-+    size_t len;
-+
-+    len = strlen(input);
-+    len++;
-+    data = talloc_size(nss_test_ctx, len + sizeof(uint32_t));
-+    assert_non_null(data);
-+    memcpy(data, input, len);
-+    SAFEALIGN_COPY_UINT32(data + len, &flags, NULL);
-+
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER);
-+    will_return(__wrap_sss_packet_get_body, data);
-+    will_return(__wrap_sss_packet_get_body, len + sizeof(uint32_t));
-+
-+    if (do_parse_inp) {
-+        copy = talloc_strdup(nss_test_ctx, input);
-+        assert_non_null(copy);
-+
-+        separator = strrchr(copy, '@');
-+        if (separator == NULL) {
-+            shortname = input;
-+            domname = NULL;
-+        } else {
-+            *separator = '\0';
-+            shortname = copy;
-+            domname = separator + 1;
-+        }
-+
-+        mock_parse_inp(shortname, domname, EOK);
-+    }
-+}
-+
- static void mock_input_upn(const char *upn)
- {
-     will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER);
-@@ -291,6 +330,20 @@ static void mock_input_id(TALLOC_CTX *mem_ctx, uint32_t id)
-     will_return(__wrap_sss_packet_get_body, sizeof(uint32_t));
- }
- 
-+static void mock_input_id_ex(TALLOC_CTX *mem_ctx, uint32_t id, uint32_t flags)
-+{
-+    uint8_t *body;
-+
-+    body = talloc_zero_array(mem_ctx, uint8_t, 8);
-+    if (body == NULL) return;
-+
-+    SAFEALIGN_SETMEM_UINT32(body, id, NULL);
-+    SAFEALIGN_SETMEM_UINT32(body + sizeof(uint32_t), flags, NULL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER);
-+    will_return(__wrap_sss_packet_get_body, body);
-+    will_return(__wrap_sss_packet_get_body, 2 * sizeof(uint32_t));
-+}
-+
- static void mock_fill_user(void)
- {
-     /* One packet for the entry and one for num entries */
-@@ -4143,6 +4196,482 @@ void test_nss_getsidbyname_neg(void **state)
-     assert_int_equal(ret, ENOENT);
- }
- 
-+static int test_nss_EINVAL_check(uint32_t status, uint8_t *body, size_t blen)
-+{
-+    assert_int_equal(status, EINVAL);
-+    assert_int_equal(blen, 0);
-+
-+    return EOK;
-+}
-+
-+#define RESET_TCTX do { \
-+    nss_test_ctx->tctx->done = false; \
-+    nss_test_ctx->tctx->error = EIO; \
-+} while (0)
-+
-+void test_nss_getpwnam_ex(void **state)
-+{
-+    errno_t ret;
-+
-+    ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom,
-+                     &getpwnam_usr, NULL, 0);
-+    assert_int_equal(ret, EOK);
-+
-+    mock_input_user_or_group_ex(true, "testuser", 0);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM_EX);
-+    mock_fill_user();
-+
-+    /* Query for that user, call a callback when command finishes */
-+    set_cmd_cb(test_nss_getpwnam_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use old input format, expect EINVAL */
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER);
-+    will_return(__wrap_sss_packet_get_body, "testuser");
-+    will_return(__wrap_sss_packet_get_body, 0);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM_EX);
-+
-+    set_cmd_cb(test_nss_EINVAL_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use unsupported flag combination, expect EINVAL */
-+    mock_input_user_or_group_ex(false, "testuser",
-+                                SSS_NSS_EX_FLAG_NO_CACHE
-+                                    |SSS_NSS_EX_FLAG_INVALIDATE_CACHE);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM_EX);
-+
-+    set_cmd_cb(test_nss_EINVAL_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use flag SSS_NSS_EX_FLAG_NO_CACHE,
-+     * will cause a backend lookup -> mock_account_recv_simple() */
-+    mock_input_user_or_group_ex(true, "testuser", SSS_NSS_EX_FLAG_NO_CACHE);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM_EX);
-+    mock_fill_user();
-+    mock_account_recv_simple();
-+
-+    set_cmd_cb(test_nss_getpwnam_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use flag SSS_NSS_EX_FLAG_INVALIDATE_CACHE */
-+    mock_input_user_or_group_ex(true, "testuser",
-+                                SSS_NSS_EX_FLAG_INVALIDATE_CACHE);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWNAM_EX);
-+    mock_fill_user();
-+
-+    set_cmd_cb(test_nss_getpwnam_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWNAM_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
-+void test_nss_getpwuid_ex(void **state)
-+{
-+    errno_t ret;
-+    uint32_t id = 101;
-+
-+    /* Prime the cache with a valid user */
-+    ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom,
-+                     &getpwuid_usr, NULL, 0);
-+    assert_int_equal(ret, EOK);
-+
-+    mock_input_id_ex(nss_test_ctx, id, 0);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID_EX);
-+    mock_fill_user();
-+
-+    /* Query for that id, call a callback when command finishes */
-+    set_cmd_cb(test_nss_getpwuid_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use old input format, expect failure */
-+    mock_input_id(nss_test_ctx, id);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID_EX);
-+
-+    set_cmd_cb(test_nss_EINVAL_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use unsupported flag combination, expect EINVAL */
-+    mock_input_id_ex(nss_test_ctx, id, SSS_NSS_EX_FLAG_NO_CACHE
-+                                            |SSS_NSS_EX_FLAG_INVALIDATE_CACHE);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID_EX);
-+
-+    set_cmd_cb(test_nss_EINVAL_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use flag SSS_NSS_EX_FLAG_NO_CACHE,
-+     * will cause a backend lookup -> mock_account_recv_simple() */
-+    mock_input_id_ex(nss_test_ctx, id, SSS_NSS_EX_FLAG_NO_CACHE);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID_EX);
-+    mock_fill_user();
-+    mock_account_recv_simple();
-+
-+    set_cmd_cb(test_nss_getpwuid_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use flag SSS_NSS_EX_FLAG_INVALIDATE_CACHE */
-+    mock_input_id_ex(nss_test_ctx, id, SSS_NSS_EX_FLAG_INVALIDATE_CACHE);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID_EX);
-+    mock_fill_user();
-+
-+    set_cmd_cb(test_nss_getpwuid_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
-+void test_nss_getgrnam_ex_no_members(void **state)
-+{
-+    errno_t ret;
-+
-+    /* Test group is still in the cache */
-+
-+    mock_input_user_or_group_ex(true, getgrnam_no_members.gr_name, 0);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM_EX);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+
-+    /* Query for that group, call a callback when command finishes */
-+    set_cmd_cb(test_nss_getgrnam_no_members_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use old input format, expect failure */
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER);
-+    will_return(__wrap_sss_packet_get_body, "testgroup");
-+    will_return(__wrap_sss_packet_get_body, 0);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM_EX);
-+
-+    set_cmd_cb(test_nss_EINVAL_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use unsupported flag combination, expect EINVAL */
-+    mock_input_user_or_group_ex(false, getgrnam_no_members.gr_name,
-+                                SSS_NSS_EX_FLAG_NO_CACHE
-+                                    |SSS_NSS_EX_FLAG_INVALIDATE_CACHE);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM_EX);
-+
-+    set_cmd_cb(test_nss_EINVAL_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use flag SSS_NSS_EX_FLAG_NO_CACHE,
-+     * will cause a backend lookup -> mock_account_recv_simple() */
-+    mock_input_user_or_group_ex(true, getgrnam_no_members.gr_name,
-+                                SSS_NSS_EX_FLAG_NO_CACHE);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM_EX);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    mock_account_recv_simple();
-+
-+    set_cmd_cb(test_nss_getgrnam_no_members_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use flag SSS_NSS_EX_FLAG_INVALIDATE_CACHE */
-+    mock_input_user_or_group_ex(true, getgrnam_no_members.gr_name,
-+                                SSS_NSS_EX_FLAG_INVALIDATE_CACHE);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRNAM_EX);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+
-+    set_cmd_cb(test_nss_getgrnam_no_members_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRNAM_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
-+void test_nss_getgrgid_ex_no_members(void **state)
-+{
-+    errno_t ret;
-+
-+    /* Test group is still in the cache */
-+
-+    mock_input_id_ex(nss_test_ctx, getgrnam_no_members.gr_gid, 0);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRGID_EX);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    mock_account_recv_simple();
-+
-+    /* Query for that group, call a callback when command finishes */
-+    set_cmd_cb(test_nss_getgrnam_no_members_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRGID_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use old input format, expect failure */
-+    mock_input_id(nss_test_ctx, getgrnam_no_members.gr_gid);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRGID_EX);
-+
-+    set_cmd_cb(test_nss_EINVAL_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRGID_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use unsupported flag combination, expect EINVAL */
-+    mock_input_id_ex(nss_test_ctx, getgrnam_no_members.gr_gid,
-+                     SSS_NSS_EX_FLAG_NO_CACHE
-+                        |SSS_NSS_EX_FLAG_INVALIDATE_CACHE);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRGID_EX);
-+
-+    set_cmd_cb(test_nss_EINVAL_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRGID_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use flag SSS_NSS_EX_FLAG_NO_CACHE,
-+     * will cause a backend lookup -> mock_account_recv_simple() */
-+    mock_input_id_ex(nss_test_ctx, getgrnam_no_members.gr_gid,
-+                     SSS_NSS_EX_FLAG_NO_CACHE);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRGID_EX);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    mock_account_recv_simple();
-+    mock_account_recv_simple();
-+
-+    set_cmd_cb(test_nss_getgrnam_no_members_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRGID_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use flag SSS_NSS_EX_FLAG_INVALIDATE_CACHE */
-+    mock_input_id_ex(nss_test_ctx, getgrnam_no_members.gr_gid,
-+                     SSS_NSS_EX_FLAG_INVALIDATE_CACHE);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETGRGID_EX);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-+
-+    set_cmd_cb(test_nss_getgrnam_no_members_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETGRGID_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
-+void test_nss_initgroups_ex(void **state)
-+{
-+    errno_t ret;
-+    struct sysdb_attrs *attrs;
-+
-+    attrs = sysdb_new_attrs(nss_test_ctx);
-+    assert_non_null(attrs);
-+
-+    ret = sysdb_attrs_add_time_t(attrs, SYSDB_INITGR_EXPIRE,
-+                                 time(NULL) + 300);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = sysdb_attrs_add_string(attrs, SYSDB_UPN, "upninitgr@upndomain.test");
-+    assert_int_equal(ret, EOK);
-+
-+    ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom,
-+                     &testinitgr_usr, attrs, 0);
-+    assert_int_equal(ret, EOK);
-+
-+    mock_input_user_or_group_ex(true, "testinitgr", 0);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR_EX);
-+    mock_fill_user();
-+
-+    /* Query for that user, call a callback when command finishes */
-+    set_cmd_cb(test_nss_initgr_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use old input format, expect failure */
-+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER);
-+    will_return(__wrap_sss_packet_get_body, "testinitgr");
-+    will_return(__wrap_sss_packet_get_body, 0);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR_EX);
-+
-+    set_cmd_cb(test_nss_EINVAL_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use unsupported flag combination, expect EINVAL */
-+    mock_input_user_or_group_ex(false, "testinitgr",
-+                                SSS_NSS_EX_FLAG_NO_CACHE
-+                                    |SSS_NSS_EX_FLAG_INVALIDATE_CACHE);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR_EX);
-+
-+    set_cmd_cb(test_nss_EINVAL_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use flag SSS_NSS_EX_FLAG_NO_CACHE,
-+     * will cause a backend lookup -> mock_account_recv_simple() */
-+    mock_input_user_or_group_ex(true, "testinitgr",
-+                                SSS_NSS_EX_FLAG_NO_CACHE);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR_EX);
-+    mock_fill_user();
-+    mock_account_recv_simple();
-+
-+    set_cmd_cb(test_nss_initgr_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+    RESET_TCTX;
-+
-+    /* Use flag SSS_NSS_EX_FLAG_INVALIDATE_CACHE */
-+    mock_input_user_or_group_ex(true, "testinitgr",
-+                                SSS_NSS_EX_FLAG_INVALIDATE_CACHE);
-+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_INITGR_EX);
-+    mock_fill_user();
-+
-+    set_cmd_cb(test_nss_initgr_check);
-+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_INITGR_EX,
-+                          nss_test_ctx->nss_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(nss_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
- int main(int argc, const char *argv[])
- {
-     int rv;
-@@ -4288,6 +4817,16 @@ int main(int argc, const char *argv[])
-                                         nss_test_setup, nss_test_teardown),
-         cmocka_unit_test_setup_teardown(test_nss_getsidbyname_neg,
-                                         nss_test_setup, nss_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_nss_getpwnam_ex,
-+                                        nss_test_setup, nss_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_nss_getpwuid_ex,
-+                                        nss_test_setup, nss_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_nss_getgrnam_ex_no_members,
-+                                        nss_test_setup, nss_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_nss_getgrgid_ex_no_members,
-+                                        nss_test_setup, nss_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_nss_initgroups_ex,
-+                                        nss_test_setup, nss_test_teardown),
-     };
- 
-     /* Set debug level to invalid value so we can deside if -d 0 was used. */
--- 
-2.13.6
-
diff --git a/SOURCES/0030-AD-consider-resource_groups-in-PAC-as-well.patch b/SOURCES/0030-AD-consider-resource_groups-in-PAC-as-well.patch
new file mode 100644
index 0000000..212bab0
--- /dev/null
+++ b/SOURCES/0030-AD-consider-resource_groups-in-PAC-as-well.patch
@@ -0,0 +1,334 @@
+From a7b308a01914458234bc05539e773e4c0762ad4b Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 28 Jun 2018 12:41:41 +0200
+Subject: [PATCH] AD: consider resource_groups in PAC as well
+
+With recent versions of Active Directory the SIDs of Domain Local groups
+might be only available in the resource_groups section of the PAC, this
+feature is also called SID compression. To get a complete list of groups
+the user is a member of the SIDs from this section must be extracted as
+well.
+
+Resolves https://pagure.io/SSSD/sssd/issue/3767
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 13c8450788a429fa49ba532b40ebfd7f3a4132e4)
+
+DOWNSTREAM:
+Resolves: rhbz#1592964 - Groups go missing with PAC enabled in sssd
+---
+ src/external/samba.m4             |   8 ++
+ src/providers/ad/ad_pac.c         | 130 ++++++++++++++++++++++++------
+ src/tests/cmocka/test_ad_common.c |  95 ++++++++++++++++++++++
+ 3 files changed, 210 insertions(+), 23 deletions(-)
+
+diff --git a/src/external/samba.m4 b/src/external/samba.m4
+index 794cac2461d7fbd5e690ea105cd346cbe6fcce9a..7a8c1eb7b9069f18def4e915b0fb9ab054a68e01 100644
+--- a/src/external/samba.m4
++++ b/src/external/samba.m4
+@@ -122,3 +122,11 @@ int main(void)
+     AC_DEFINE_UNQUOTED(SMB_IDMAP_INTERFACE_VERSION, $idmap_version,
+                        [Detected version of Samba's idmap plugin interface])
+ fi
++
++SAVE_CFLAGS=$CFLAGS
++CFLAGS="$CFLAGS $SMBCLIENT_CFLAGS $NDR_NBT_CFLAGS $NDR_KRB5PAC_CFLAGS -I/usr/include/samba-4.0"
++AC_CHECK_MEMBERS([struct PAC_LOGON_INFO.resource_groups], , ,
++                 [[ #include <ndr.h>
++                    #include <gen_ndr/krb5pac.h>
++                    #include <gen_ndr/krb5pac.h>]])
++CFLAGS=$SAVE_CFLAGS
+diff --git a/src/providers/ad/ad_pac.c b/src/providers/ad/ad_pac.c
+index 1a344725fbf57d4d95c46163f2e31d44e69b3e65..80424b44e334958402cb8cfebedc1898f1e2f9c8 100644
+--- a/src/providers/ad/ad_pac.c
++++ b/src/providers/ad/ad_pac.c
+@@ -146,6 +146,87 @@ errno_t check_if_pac_is_available(TALLOC_CTX *mem_ctx,
+     return EOK;
+ }
+ 
++static errno_t
++add_sids_from_rid_array_to_hash_table(struct dom_sid *dom_sid,
++                                      struct samr_RidWithAttributeArray *groups,
++                                      struct sss_idmap_ctx *idmap_ctx,
++                                      hash_table_t *sid_table)
++{
++    enum idmap_error_code err;
++    char *dom_sid_str = NULL;
++    size_t dom_sid_str_len;
++    char *sid_str = NULL;
++    char *rid_start;
++    hash_key_t key;
++    hash_value_t value;
++    int ret;
++    size_t c;
++    TALLOC_CTX *tmp_ctx = NULL;
++
++    tmp_ctx = talloc_new(NULL);
++    if (tmp_ctx == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
++        return ENOMEM;
++    }
++
++    key.type = HASH_KEY_STRING;
++    value.type = HASH_VALUE_ULONG;
++
++    err = sss_idmap_smb_sid_to_sid(idmap_ctx, dom_sid, &dom_sid_str);
++    if (err != IDMAP_SUCCESS) {
++        DEBUG(SSSDBG_OP_FAILURE, "sss_idmap_smb_sid_to_sid failed.\n");
++        ret = EFAULT;
++        goto done;
++    }
++
++    dom_sid_str_len = strlen(dom_sid_str);
++    sid_str = talloc_zero_size(tmp_ctx, dom_sid_str_len + 12);
++    if (sid_str == NULL) {
++        DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n");
++        ret = ENOMEM;
++        goto done;
++    }
++    rid_start = sid_str + dom_sid_str_len;
++
++    memcpy(sid_str, dom_sid_str, dom_sid_str_len);
++
++    for (c = 0; c < groups->count; c++) {
++        memset(rid_start, '\0', 12);
++        ret = snprintf(rid_start, 12, "-%lu",
++                       (unsigned long) groups->rids[c].rid);
++        if (ret < 0 || ret > 12) {
++            DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n");
++            ret = EIO;
++            goto done;
++        }
++
++        key.str = sid_str;
++        value.ul = 0;
++
++        ret = hash_enter(sid_table, &key, &value);
++        if (ret != HASH_SUCCESS) {
++            DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n",
++                                      ret, hash_error_string(ret));
++            ret = EIO;
++            goto done;
++        }
++
++    }
++
++    ret = EOK;
++
++done:
++    sss_idmap_free_sid(idmap_ctx, dom_sid_str);
++    talloc_free(tmp_ctx);
++
++    return ret;
++}
++
++struct resource_groups {
++    struct dom_sid2 *domain_sid;
++    struct samr_RidWithAttributeArray groups;
++};
++
+ errno_t ad_get_sids_from_pac(TALLOC_CTX *mem_ctx,
+                              struct sss_idmap_ctx *idmap_ctx,
+                              struct PAC_LOGON_INFO *logon_info,
+@@ -157,6 +238,7 @@ errno_t ad_get_sids_from_pac(TALLOC_CTX *mem_ctx,
+     int ret;
+     size_t s;
+     struct netr_SamInfo3 *info3;
++    struct resource_groups resource_groups = { 0 };
+     char *sid_str = NULL;
+     char *msid_str = NULL;
+     char *user_dom_sid_str = NULL;
+@@ -188,9 +270,15 @@ errno_t ad_get_sids_from_pac(TALLOC_CTX *mem_ctx,
+     }
+ 
+     info3 = &logon_info->info3;
++#ifdef HAVE_STRUCT_PAC_LOGON_INFO_RESOURCE_GROUPS
++    resource_groups.domain_sid = logon_info->resource_groups.domain_sid;
++    resource_groups.groups.count = logon_info->resource_groups.groups.count;
++    resource_groups.groups.rids = logon_info->resource_groups.groups.rids;
++#endif
+ 
+     ret = sss_hash_create(tmp_ctx,
+-                          info3->sidcount + info3->base.groups.count + 2,
++                          info3->sidcount + info3->base.groups.count + 2
++                                          + resource_groups.groups.count,
+                           &sid_table);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "sss_hash_create failed.\n");
+@@ -265,28 +353,13 @@ errno_t ad_get_sids_from_pac(TALLOC_CTX *mem_ctx,
+         goto done;
+     }
+ 
+-
+-    for (s = 0; s < info3->base.groups.count; s++) {
+-        memset(rid_start, '\0', 12);
+-        ret = snprintf(rid_start, 12, "-%lu",
+-                                (unsigned long) info3->base.groups.rids[s].rid);
+-        if (ret < 0 || ret > 12) {
+-            DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n");
+-            ret = EIO;
+-            goto done;
+-        }
+-
+-        key.str = sid_str;
+-        value.ul = 0;
+-
+-        ret = hash_enter(sid_table, &key, &value);
+-        if (ret != HASH_SUCCESS) {
+-            DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n",
+-                                      ret, hash_error_string(ret));
+-            ret = EIO;
+-            goto done;
+-        }
+-
++    ret = add_sids_from_rid_array_to_hash_table(info3->base.domain_sid,
++                                                &info3->base.groups,
++                                                idmap_ctx, sid_table);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "add_sids_from_rid_array_to_hash_table failed.\n");
++        goto done;
+     }
+ 
+     for(s = 0; s < info3->sidcount; s++) {
+@@ -311,6 +384,17 @@ errno_t ad_get_sids_from_pac(TALLOC_CTX *mem_ctx,
+         }
+     }
+ 
++    if (resource_groups.domain_sid != NULL) {
++        ret = add_sids_from_rid_array_to_hash_table(resource_groups.domain_sid,
++                                                    &resource_groups.groups,
++                                                    idmap_ctx, sid_table);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_OP_FAILURE,
++                  "add_sids_from_rid_array_to_hash_table failed.\n");
++            goto done;
++        }
++    }
++
+     num_sids = hash_count(sid_table);
+     sid_list = talloc_array(tmp_ctx, char *, num_sids);
+     if (sid_list == NULL) {
+diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c
+index 39ebbc63324ca40d071f30582d2f15d732f6c466..ac3b0d0ab3c7b0a0ee4d21d96e1b4783ff1b4139 100644
+--- a/src/tests/cmocka/test_ad_common.c
++++ b/src/tests/cmocka/test_ad_common.c
+@@ -207,6 +207,29 @@ static void test_check_if_pac_is_available(void **state)
+     "BEAEUAVgBFAEwAdv///4yBQZ5ZQnp3qwj2lKGcd0UAAAAAdv//" \
+     "/39fn4UneD5l6YxP8w/U0coAAAAA"
+ 
++#define TEST_PAC_RESOURCE_GROUPS_BASE64 \
++    "BQAAAAAAAAABAAAA8AEAAFgAAAAAAAAACgAAABQAAABIAgAA" \
++    "AAAAAAwAAABYAAAAYAIAAAAAAAAGAAAAEAAAALgCAAAAAAAA" \
++    "BwAAABQAAADIAgAAAAAAAAEQCADMzMzM4AEAAAAAAAAAAAIA" \
++    "Rr0gPUQO1AH/////////f/////////9/TRPNRwtu0wFN0zZy" \
++    "1G7TAf////////9/CgAKAAQAAgAKAAoACAACAAAAAAAMAAIA" \
++    "AAAAABAAAgAAAAAAFAACAAAAAAAYAAIACwAAAFEEAAABAgAA" \
++    "AwAAABwAAgAgAgAAAAAAAAAAAAAAAAAAAAAAAAQABgAgAAIA" \
++    "BgAIACQAAgAoAAIAAAAAAAAAAAAQAgAAAAAAAAAAAAAAAAAA" \
++    "AAAAAAAAAAAAAAAAAAAAAAEAAAAsAAIANAACAAEAAAA4AAIA" \
++    "BQAAAAAAAAAFAAAAdAB1AHMAZQByAAAABQAAAAAAAAAFAAAA" \
++    "dAB1AHMAZQByAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" \
++    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAECAAAHAAAA" \
++    "YgQAAAcAAABjBAAABwAAAAMAAAAAAAAAAgAAAEQAQwAEAAAA" \
++    "AAAAAAMAAABXAEkATgAAAAQAAAABBAAAAAAABRUAAAAkYm0r" \
++    "SyFumd73jX0BAAAAMAACAAcAAAABAAAAAQEAAAAAABIBAAAA" \
++    "BAAAAAEEAAAAAAAFFQAAACRibStLIW6Z3veNfQEAAABoBAAA" \
++    "BwAAIAAAAACAEuVfRA7UAQoAdAB1AHMAZQByAAAAAAAoABAA" \
++    "HAA4AAAAAAAAAAAAdAB1AHMAZQByAEAAdwBpAG4ALgB0AHIA" \
++    "dQBzAHQALgB0AGUAcwB0AFcASQBOAC4AVABSAFUAUwBUAC4A" \
++    "VABFAFMAVAAAAAAAEAAAAOGTj7I9Qn7XebOqdHb///+fHhrZ" \
++    "kBt0So4jOFBk84sDAAAAAA=="
++
+ static void test_ad_get_data_from_pac(void **state)
+ {
+     int ret;
+@@ -303,6 +326,73 @@ static void test_ad_get_sids_from_pac(void **state)
+     sss_idmap_free(idmap_ctx);
+ }
+ 
++#ifdef HAVE_STRUCT_PAC_LOGON_INFO_RESOURCE_GROUPS
++static void test_ad_get_sids_from_pac_with_resource_groups(void **state)
++{
++    int ret;
++    struct PAC_LOGON_INFO *logon_info;
++    uint8_t *test_pac_blob;
++    size_t test_pac_blob_size;
++    char *user_sid;
++    char *primary_group_sid;
++    size_t num_sids;
++    char **sid_list;
++    struct sss_idmap_ctx *idmap_ctx;
++    enum idmap_error_code err;
++    size_t c;
++    size_t s;
++
++    const char *sid_check_list[] = { "S-1-5-21-728588836-2574131531-2106456030-513",
++                                     "S-1-5-21-728588836-2574131531-2106456030-1122",
++                                     "S-1-5-21-728588836-2574131531-2106456030-1123",
++                                     "S-1-5-21-728588836-2574131531-2106456030-1128",
++                                     "S-1-18-1",
++                                     NULL };
++
++    struct ad_common_test_ctx *test_ctx = talloc_get_type(*state,
++                                                  struct ad_common_test_ctx);
++
++    err = sss_idmap_init(sss_idmap_talloc, test_ctx, sss_idmap_talloc_free,
++                         &idmap_ctx);
++    assert_int_equal(err, IDMAP_SUCCESS);
++
++    test_pac_blob = sss_base64_decode(test_ctx, TEST_PAC_RESOURCE_GROUPS_BASE64,
++                                      &test_pac_blob_size);
++    assert_non_null(test_pac_blob_size);
++
++    ret = ad_get_data_from_pac(test_ctx, test_pac_blob, test_pac_blob_size,
++                               &logon_info);
++    assert_int_equal(ret, EOK);
++
++    ret = ad_get_sids_from_pac(test_ctx, idmap_ctx, logon_info, &user_sid,
++                               &primary_group_sid, &num_sids, &sid_list);
++    assert_int_equal(ret, EOK);
++    assert_string_equal(user_sid,
++                        "S-1-5-21-728588836-2574131531-2106456030-1105");
++    assert_string_equal(primary_group_sid,
++                        "S-1-5-21-728588836-2574131531-2106456030-513");
++    assert_int_equal(num_sids, 5);
++
++    for (c = 0; sid_check_list[c] != NULL; c++) {
++        for (s = 0; s < num_sids; s++) {
++            if (strcmp(sid_check_list[c], sid_list[s]) == 0) {
++                break;
++            }
++        }
++        if (s == num_sids) {
++            fail_msg("SID [%s] not found in SID list.", sid_check_list[c]);
++        }
++    }
++
++    talloc_free(test_pac_blob);
++    talloc_free(logon_info);
++    talloc_free(user_sid);
++    talloc_free(primary_group_sid);
++    talloc_free(sid_list);
++    sss_idmap_free(idmap_ctx);
++}
++#endif
++
+ static void test_ad_get_pac_data_from_user_entry(void **state)
+ {
+     int ret;
+@@ -912,6 +1002,11 @@ int main(int argc, const char *argv[])
+         cmocka_unit_test_setup_teardown(test_ad_get_sids_from_pac,
+                                         test_ad_common_setup,
+                                         test_ad_common_teardown),
++#ifdef HAVE_STRUCT_PAC_LOGON_INFO_RESOURCE_GROUPS
++        cmocka_unit_test_setup_teardown(test_ad_get_sids_from_pac_with_resource_groups,
++                                        test_ad_common_setup,
++                                        test_ad_common_teardown),
++#endif
+         cmocka_unit_test_setup_teardown(test_ad_get_pac_data_from_user_entry,
+                                         test_ad_common_setup,
+                                         test_ad_common_teardown),
+-- 
+2.17.1
+
diff --git a/SOURCES/0030-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch b/SOURCES/0030-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch
deleted file mode 100644
index caf0dc0..0000000
--- a/SOURCES/0030-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch
+++ /dev/null
@@ -1,494 +0,0 @@
-From a12e6ac8001025174cf201bcaa2143edb1b0c017 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 2 Nov 2017 10:32:41 +0100
-Subject: [PATCH 30/31] nss-idmap: add timeout version of old sss_nss_* calls
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit e54db68cbb9c12d8a6867f2c7766fb2115ab0997)
----
- Makefile.am                                   |   2 +-
- src/sss_client/idmap/sss_nss_idmap.c          | 126 ++++++++++++++++++--------
- src/sss_client/idmap/sss_nss_idmap.exports    |   7 ++
- src/sss_client/idmap/sss_nss_idmap.h          | 124 +++++++++++++++++++++++++
- src/sss_client/idmap/sss_nss_idmap.unit_tests |   2 +-
- src/tests/cmocka/sss_nss_idmap-tests.c        |  13 +--
- 6 files changed, 229 insertions(+), 45 deletions(-)
-
-diff --git a/Makefile.am b/Makefile.am
-index dd25d1f7ea1be66388aa1b393bac290c4d7501a2..286ba47e3c421864362717be5258de960efca9f2 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -2974,7 +2974,6 @@ test_sysdb_domain_resolution_order_LDADD = \
- 
- test_wbc_calls_SOURCES = \
-     src/tests/cmocka/test_wbc_calls.c \
--    src/sss_client/idmap/sss_nss_idmap.c \
-     src/sss_client/libwbclient/wbc_sid_sssd.c \
-     src/sss_client/libwbclient/wbclient_common.c \
-     src/sss_client/libwbclient/wbc_sid_common.c \
-@@ -2993,6 +2992,7 @@ test_wbc_calls_LDADD = \
-     $(TALLOC_LIBS) \
-     $(SSSD_INTERNAL_LTLIBS) \
-     libsss_test_common.la \
-+    libsss_nss_idmap.la \
-     $(NULL)
- 
- test_be_ptask_SOURCES = \
-diff --git a/src/sss_client/idmap/sss_nss_idmap.c b/src/sss_client/idmap/sss_nss_idmap.c
-index 6f3af267a1e763e7dce77e3862be377ae2bfe984..6e7685d2b1d80956b6a6668e9bbb146abd9e86ed 100644
---- a/src/sss_client/idmap/sss_nss_idmap.c
-+++ b/src/sss_client/idmap/sss_nss_idmap.c
-@@ -28,10 +28,13 @@
- 
- #include "sss_client/sss_cli.h"
- #include "sss_client/idmap/sss_nss_idmap.h"
-+#include "sss_client/idmap/sss_nss_idmap_private.h"
- #include "util/strtonum.h"
- 
- #define DATA_START (3 * sizeof(uint32_t))
- #define LIST_START (2 * sizeof(uint32_t))
-+#define NO_TIMEOUT ((unsigned int) -1)
-+
- union input {
-     const char *str;
-     uint32_t id;
-@@ -198,8 +201,8 @@ done:
-     return ret;
- }
- 
--static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd ,
--                               struct output *out)
-+static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd,
-+                               unsigned int timeout, struct output *out)
- {
-     int ret;
-     size_t inp_len;
-@@ -215,6 +218,7 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd ,
-     struct sss_nss_kv *kv_list;
-     char **names;
-     enum sss_id_type *types;
-+    int time_left = SSS_CLI_SOCKET_TIMEOUT;
- 
-     switch (cmd) {
-     case SSS_NSS_GETSIDBYNAME:
-@@ -250,9 +254,14 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd ,
-         return EINVAL;
-     }
- 
--    sss_nss_lock();
-+    if (timeout == NO_TIMEOUT) {
-+        sss_nss_lock();
-+    } else {
-+        sss_nss_timedlock(timeout, &time_left);
-+    }
- 
--    nret = sss_nss_make_request(cmd, &rd, &repbuf, &replen, &errnop);
-+    nret = sss_nss_make_request_timeout(cmd, &rd, time_left, &repbuf, &replen,
-+                                        &errnop);
-     if (nret != NSS_STATUS_SUCCESS) {
-         ret = nss_status_to_errno(nret);
-         goto done;
-@@ -347,8 +356,8 @@ done:
-     return ret;
- }
- 
--int sss_nss_getsidbyname(const char *fq_name, char **sid,
--                         enum sss_id_type *type)
-+int sss_nss_getsidbyname_timeout(const char *fq_name, unsigned int timeout,
-+                                 char **sid, enum sss_id_type *type)
- {
-     int ret;
-     union input inp;
-@@ -360,7 +369,7 @@ int sss_nss_getsidbyname(const char *fq_name, char **sid,
- 
-     inp.str = fq_name;
- 
--    ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETSIDBYNAME, &out);
-+    ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETSIDBYNAME, timeout, &out);
-     if (ret == EOK) {
-         *sid = out.d.str;
-         *type = out.type;
-@@ -369,7 +378,14 @@ int sss_nss_getsidbyname(const char *fq_name, char **sid,
-     return ret;
- }
- 
--int sss_nss_getsidbyid(uint32_t id, char **sid, enum sss_id_type *type)
-+int sss_nss_getsidbyname(const char *fq_name, char **sid,
-+                         enum sss_id_type *type)
-+{
-+    return sss_nss_getsidbyname_timeout(fq_name, NO_TIMEOUT, sid, type);
-+}
-+
-+int sss_nss_getsidbyid_timeout(uint32_t id, unsigned int timeout,
-+                               char **sid, enum sss_id_type *type)
- {
-     int ret;
-     union input inp;
-@@ -381,7 +397,7 @@ int sss_nss_getsidbyid(uint32_t id, char **sid, enum sss_id_type *type)
- 
-     inp.id = id;
- 
--    ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETSIDBYID, &out);
-+    ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETSIDBYID, timeout, &out);
-     if (ret == EOK) {
-         *sid = out.d.str;
-         *type = out.type;
-@@ -390,8 +406,13 @@ int sss_nss_getsidbyid(uint32_t id, char **sid, enum sss_id_type *type)
-     return ret;
- }
- 
--int sss_nss_getnamebysid(const char *sid, char **fq_name,
--                         enum sss_id_type *type)
-+int sss_nss_getsidbyid(uint32_t id, char **sid, enum sss_id_type *type)
-+{
-+    return sss_nss_getsidbyid_timeout(id, NO_TIMEOUT, sid, type);
-+}
-+
-+int sss_nss_getnamebysid_timeout(const char *sid, unsigned int timeout,
-+                                 char **fq_name, enum sss_id_type *type)
- {
-     int ret;
-     union input inp;
-@@ -403,7 +424,7 @@ int sss_nss_getnamebysid(const char *sid, char **fq_name,
- 
-     inp.str = sid;
- 
--    ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETNAMEBYSID, &out);
-+    ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETNAMEBYSID, timeout, &out);
-     if (ret == EOK) {
-         *fq_name = out.d.str;
-         *type = out.type;
-@@ -412,7 +433,14 @@ int sss_nss_getnamebysid(const char *sid, char **fq_name,
-     return ret;
- }
- 
--int sss_nss_getidbysid(const char *sid, uint32_t *id, enum sss_id_type *id_type)
-+int sss_nss_getnamebysid(const char *sid, char **fq_name,
-+                         enum sss_id_type *type)
-+{
-+    return sss_nss_getnamebysid_timeout(sid, NO_TIMEOUT, fq_name, type);
-+}
-+
-+int sss_nss_getidbysid_timeout(const char *sid, unsigned int timeout,
-+                               uint32_t *id, enum sss_id_type *id_type)
- {
-     int ret;
-     union input inp;
-@@ -424,7 +452,7 @@ int sss_nss_getidbysid(const char *sid, uint32_t *id, enum sss_id_type *id_type)
- 
-     inp.str = sid;
- 
--    ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETIDBYSID, &out);
-+    ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETIDBYSID, timeout, &out);
-     if (ret == EOK) {
-         *id = out.d.id;
-         *id_type = out.type;
-@@ -433,8 +461,14 @@ int sss_nss_getidbysid(const char *sid, uint32_t *id, enum sss_id_type *id_type)
-     return ret;
- }
- 
--int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list,
--                         enum sss_id_type *type)
-+int sss_nss_getidbysid(const char *sid, uint32_t *id, enum sss_id_type *id_type)
-+{
-+    return sss_nss_getidbysid_timeout(sid, NO_TIMEOUT, id, id_type);
-+}
-+
-+int sss_nss_getorigbyname_timeout(const char *fq_name, unsigned int timeout,
-+                                  struct sss_nss_kv **kv_list,
-+                                  enum sss_id_type *type)
- {
-     int ret;
-     union input inp;
-@@ -446,7 +480,7 @@ int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list,
- 
-     inp.str = fq_name;
- 
--    ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETORIGBYNAME, &out);
-+    ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETORIGBYNAME, timeout, &out);
-     if (ret == EOK) {
-         *kv_list = out.d.kv_list;
-         *type = out.type;
-@@ -455,30 +489,42 @@ int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list,
-     return ret;
- }
- 
-+int sss_nss_getorigbyname(const char *fq_name, struct sss_nss_kv **kv_list,
-+                          enum sss_id_type *type)
-+{
-+    return sss_nss_getorigbyname_timeout(fq_name, NO_TIMEOUT, kv_list, type);
-+}
-+
-+int sss_nss_getnamebycert_timeout(const char *cert, unsigned int timeout,
-+                                  char **fq_name, enum sss_id_type *type)
-+{
-+    int ret;
-+    union input inp;
-+    struct output out;
-+
-+    if (fq_name == NULL || cert == NULL || *cert == '\0') {
-+        return EINVAL;
-+    }
-+
-+    inp.str = cert;
-+
-+    ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETNAMEBYCERT, timeout, &out);
-+    if (ret == EOK) {
-+        *fq_name = out.d.str;
-+        *type = out.type;
-+    }
-+
-+    return ret;
-+}
-+
- int sss_nss_getnamebycert(const char *cert, char **fq_name,
-                           enum sss_id_type *type)
- {
--    int ret;
--    union input inp;
--    struct output out;
--
--    if (fq_name == NULL || cert == NULL || *cert == '\0') {
--        return EINVAL;
--    }
--
--    inp.str = cert;
--
--    ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETNAMEBYCERT, &out);
--    if (ret == EOK) {
--        *fq_name = out.d.str;
--        *type = out.type;
--    }
--
--    return ret;
-+    return sss_nss_getnamebycert_timeout(cert, NO_TIMEOUT, fq_name, type);
- }
- 
--int sss_nss_getlistbycert(const char *cert, char ***fq_name,
--                          enum sss_id_type **type)
-+int sss_nss_getlistbycert_timeout(const char *cert, unsigned int timeout,
-+                                  char ***fq_name, enum sss_id_type **type)
- {
-     int ret;
-     union input inp;
-@@ -490,7 +536,7 @@ int sss_nss_getlistbycert(const char *cert, char ***fq_name,
- 
-     inp.str = cert;
- 
--    ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETLISTBYCERT, &out);
-+    ret = sss_nss_getyyybyxxx(inp, SSS_NSS_GETLISTBYCERT, timeout, &out);
-     if (ret == EOK) {
-         *fq_name = out.d.names;
-         *type = out.types;
-@@ -498,3 +544,9 @@ int sss_nss_getlistbycert(const char *cert, char ***fq_name,
- 
-     return ret;
- }
-+
-+int sss_nss_getlistbycert(const char *cert, char ***fq_name,
-+                          enum sss_id_type **type)
-+{
-+    return sss_nss_getlistbycert_timeout(cert, NO_TIMEOUT, fq_name, type);
-+}
-diff --git a/src/sss_client/idmap/sss_nss_idmap.exports b/src/sss_client/idmap/sss_nss_idmap.exports
-index 788d05ecc3bd56fa88e68a98b9c8096cf7140a09..8d0a24f42aa3fb3dd9c2ed125bf79e2c7792993f 100644
---- a/src/sss_client/idmap/sss_nss_idmap.exports
-+++ b/src/sss_client/idmap/sss_nss_idmap.exports
-@@ -40,4 +40,11 @@ SSS_NSS_IDMAP_0.4.0 {
-         sss_nss_getgrnam_timeout;
-         sss_nss_getgrgid_timeout;
-         sss_nss_getgrouplist_timeout;
-+        sss_nss_getsidbyname_timeout;
-+        sss_nss_getsidbyid_timeout;
-+        sss_nss_getnamebysid_timeout;
-+        sss_nss_getidbysid_timeout;
-+        sss_nss_getorigbyname_timeout;
-+        sss_nss_getnamebycert_timeout;
-+        sss_nss_getlistbycert_timeout;
- } SSS_NSS_IDMAP_0.3.0;
-diff --git a/src/sss_client/idmap/sss_nss_idmap.h b/src/sss_client/idmap/sss_nss_idmap.h
-index 3755643312f05a31d1cf1aa76dfc22848ef1e3ec..125e72a6486f5916f90d37f27e1743d181bfa3e5 100644
---- a/src/sss_client/idmap/sss_nss_idmap.h
-+++ b/src/sss_client/idmap/sss_nss_idmap.h
-@@ -303,5 +303,129 @@ int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp,
- int sss_nss_getgrouplist_timeout(const char *name, gid_t group,
-                                  gid_t *groups, int *ngroups,
-                                  uint32_t flags, unsigned int timeout);
-+/**
-+ * @brief Find SID by fully qualified name with timeout
-+ *
-+ * @param[in] fq_name  Fully qualified name of a user or a group
-+ * @param[in] timeout  timeout in milliseconds
-+ * @param[out] sid     String representation of the SID of the requested user
-+ *                     or group, must be freed by the caller
-+ * @param[out] type    Type of the object related to the given name
-+ *
-+ * @return
-+ *  - 0 (EOK): success, sid contains the requested SID
-+ *  - ENOENT: requested object was not found in the domain extracted from the given name
-+ *  - ENETUNREACH: SSSD does not know how to handle the domain extracted from the given name
-+ *  - ENOSYS: this call is not supported by the configured provider
-+ *  - EINVAL: input cannot be parsed
-+ *  - EIO: remote servers cannot be reached
-+ *  - EFAULT: any other error
-+ *  - ETIME:     request timed out but was send to SSSD
-+ *  - ETIMEDOUT: request timed out but was not send to SSSD
-+ */
-+int sss_nss_getsidbyname_timeout(const char *fq_name, unsigned int timeout,
-+                                 char **sid, enum sss_id_type *type);
-+
-+/**
-+ * @brief Find SID by a POSIX UID or GID with timeout
-+ *
-+ * @param[in] id       POSIX UID or GID
-+ * @param[in] timeout  timeout in milliseconds
-+ * @param[out] sid     String representation of the SID of the requested user
-+ *                     or group, must be freed by the caller
-+ * @param[out] type    Type of the object related to the given ID
-+ *
-+ * @return
-+ *  - see #sss_nss_getsidbyname_timeout
-+ */
-+int sss_nss_getsidbyid_timeout(uint32_t id, unsigned int timeout,
-+                               char **sid, enum sss_id_type *type);
-+
-+/**
-+ * @brief Return the fully qualified name for the given SID with timeout
-+ *
-+ * @param[in] sid      String representation of the SID
-+ * @param[in] timeout  timeout in milliseconds
-+ * @param[out] fq_name Fully qualified name of a user or a group,
-+ *                     must be freed by the caller
-+ * @param[out] type    Type of the object related to the SID
-+ *
-+ * @return
-+ *  - see #sss_nss_getsidbyname_timeout
-+ */
-+int sss_nss_getnamebysid_timeout(const char *sid, unsigned int timeout,
-+                                 char **fq_name, enum sss_id_type *type);
-+
-+/**
-+ * @brief Return the POSIX ID for the given SID with timeout
-+ *
-+ * @param[in] sid      String representation of the SID
-+ * @param[in] timeout  timeout in milliseconds
-+ * @param[out] id      POSIX ID related to the SID
-+ * @param[out] id_type Type of the object related to the SID
-+ *
-+ * @return
-+ *  - see #sss_nss_getsidbyname_timeout
-+ */
-+int sss_nss_getidbysid_timeout(const char *sid, unsigned int timeout,
-+                               uint32_t *id, enum sss_id_type *id_type);
-+
-+/**
-+ * @brief Find original data by fully qualified name with timeout
-+ *
-+ * @param[in] fq_name  Fully qualified name of a user or a group
-+ * @param[in] timeout  timeout in milliseconds
-+ * @param[out] kv_list A NULL terminate list of key-value pairs where the key
-+ *                     is the attribute name in the cache of SSSD,
-+ *                     must be freed by the caller with sss_nss_free_kv()
-+ * @param[out] type    Type of the object related to the given name
-+ *
-+ * @return
-+ *  - 0 (EOK): success, sid contains the requested SID
-+ *  - ENOENT: requested object was not found in the domain extracted from the given name
-+ *  - ENETUNREACH: SSSD does not know how to handle the domain extracted from the given name
-+ *  - ENOSYS: this call is not supported by the configured provider
-+ *  - EINVAL: input cannot be parsed
-+ *  - EIO: remote servers cannot be reached
-+ *  - EFAULT: any other error
-+ *  - ETIME:     request timed out but was send to SSSD
-+ *  - ETIMEDOUT: request timed out but was not send to SSSD
-+ */
-+int sss_nss_getorigbyname_timeout(const char *fq_name, unsigned int timeout,
-+                                  struct sss_nss_kv **kv_list,
-+                                  enum sss_id_type *type);
-+
-+/**
-+ * @brief Return the fully qualified name for the given base64 encoded
-+ * X.509 certificate in DER format with timeout
-+ *
-+ * @param[in] cert     base64 encoded certificate
-+ * @param[in] timeout  timeout in milliseconds
-+ * @param[out] fq_name Fully qualified name of a user or a group,
-+ *                     must be freed by the caller
-+ * @param[out] type    Type of the object related to the cert
-+ *
-+ * @return
-+ *  - see #sss_nss_getsidbyname_timeout
-+ */
-+int sss_nss_getnamebycert_timeout(const char *cert, unsigned int timeout,
-+                                  char **fq_name, enum sss_id_type *type);
-+
-+/**
-+ * @brief Return a list of fully qualified names for the given base64 encoded
-+ * X.509 certificate in DER format with timeout
-+ *
-+ * @param[in] cert     base64 encoded certificate
-+ * @param[in] timeout  timeout in milliseconds
-+ * @param[out] fq_name List of fully qualified name of users or groups,
-+ *                     must be freed by the caller
-+ * @param[out] type    List of types of the objects related to the cert
-+ *
-+ * @return
-+ *  - see #sss_nss_getsidbyname_timeout
-+ */
-+int sss_nss_getlistbycert_timeout(const char *cert, unsigned int timeout,
-+                                  char ***fq_name, enum sss_id_type **type);
-+
- #endif /* IPA_389DS_PLUGIN_HELPER_CALLS */
- #endif /* SSS_NSS_IDMAP_H_ */
-diff --git a/src/sss_client/idmap/sss_nss_idmap.unit_tests b/src/sss_client/idmap/sss_nss_idmap.unit_tests
-index 361cc3b134ead52cf458afe27c055739d6728441..05c474f008e1d59aae5976acfd81613c3c3e6540 100644
---- a/src/sss_client/idmap/sss_nss_idmap.unit_tests
-+++ b/src/sss_client/idmap/sss_nss_idmap.unit_tests
-@@ -2,5 +2,5 @@
- UNIT_TEST_ONLY {
-     # should not be part of installed library
-     global:
--        sss_nss_make_request;
-+        sss_nss_make_request_timeout;
- };
-diff --git a/src/tests/cmocka/sss_nss_idmap-tests.c b/src/tests/cmocka/sss_nss_idmap-tests.c
-index 8807eca619d7b07d919168e5629042cf38f654ac..2e37040d2d3523bea157804706685fa0b36df16a 100644
---- a/src/tests/cmocka/sss_nss_idmap-tests.c
-+++ b/src/tests/cmocka/sss_nss_idmap-tests.c
-@@ -61,10 +61,11 @@ uint8_t buf_orig1[] = {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0
-  #error "unknow endianess"
- #endif
- 
--enum nss_status sss_nss_make_request(enum sss_cli_command cmd,
--                      struct sss_cli_req_data *rd,
--                      uint8_t **repbuf, size_t *replen,
--                      int *errnop)
-+enum nss_status sss_nss_make_request_timeout(enum sss_cli_command cmd,
-+                                             struct sss_cli_req_data *rd,
-+                                             int timeout,
-+                                             uint8_t **repbuf, size_t *replen,
-+                                             int *errnop)
- {
-     struct sss_nss_make_request_test_data *d;
- 
-@@ -114,7 +115,7 @@ void test_getsidbyname(void **state)
-     sid = NULL;
- 
-     for (c = 0; d[c].d.repbuf != NULL; c++) {
--        will_return(sss_nss_make_request, &d[0].d);
-+        will_return(sss_nss_make_request_timeout, &d[0].d);
- 
-         ret = sss_nss_getsidbyname("test", &sid, &type);
-         assert_int_equal(ret, d[0].ret);
-@@ -134,7 +135,7 @@ void test_getorigbyname(void **state)
-     enum sss_id_type type;
-     struct sss_nss_make_request_test_data d = {buf_orig1, sizeof(buf_orig1), 0, NSS_STATUS_SUCCESS};
- 
--    will_return(sss_nss_make_request, &d);
-+    will_return(sss_nss_make_request_timeout, &d);
-     ret = sss_nss_getorigbyname("test", &kv_list, &type);
-     assert_int_equal(ret, EOK);
-     assert_int_equal(type, SSS_ID_TYPE_UID);
--- 
-2.13.6
-
diff --git a/SOURCES/0031-LDAP-Remove-the-legacy-POSIX-check-itself.patch b/SOURCES/0031-LDAP-Remove-the-legacy-POSIX-check-itself.patch
new file mode 100644
index 0000000..86f9235
--- /dev/null
+++ b/SOURCES/0031-LDAP-Remove-the-legacy-POSIX-check-itself.patch
@@ -0,0 +1,321 @@
+From 5fcce16c212037b5193556dc2f6bcb7e4d7f0f85 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sat, 30 Jun 2018 13:21:18 +0200
+Subject: [PATCH] LDAP: Remove the legacy POSIX check itself
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This code is no longer needed now.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3755
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 5b2b6493dfb3c1f2cb945356e34c70d8c5d64185)
+
+DOWNSTREAM:
+Resolves: rhbz#1582975 - The search filter for detecting POSIX attributes in global catalog is too broad and can cause a high load on the servers
+---
+ src/providers/ad/ad_common.c     |   2 -
+ src/providers/ldap/ldap_common.c |  17 ---
+ src/providers/ldap/ldap_common.h |   7 --
+ src/providers/ldap/sdap.h        |   1 -
+ src/providers/ldap/sdap_async.c  | 174 -------------------------------
+ src/providers/ldap/sdap_async.h  |  13 ---
+ 6 files changed, 214 deletions(-)
+
+diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
+index eaf0814f1aaf51a5085e992efa633240f32c498e..6d395cfb1d4148e803a656a8f7205fe13570085b 100644
+--- a/src/providers/ad/ad_common.c
++++ b/src/providers/ad/ad_common.c
+@@ -1388,7 +1388,6 @@ ad_gc_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx,
+         clist[cindex] = ad_ctx->gc_ctx;
+         clist[cindex]->ignore_mark_offline = true;
+         clist[cindex]->no_mpg_user_fallback = true;
+-        clist[cindex]->check_posix_attrs = true;
+         cindex++;
+     }
+ 
+@@ -1435,7 +1434,6 @@ ad_user_conn_list(TALLOC_CTX *mem_ctx,
+             && IS_SUBDOMAIN(dom)) {
+         clist[cindex] = ad_ctx->gc_ctx;
+         clist[cindex]->ignore_mark_offline = true;
+-        clist[cindex]->check_posix_attrs = true;
+         cindex++;
+     }
+ 
+diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
+index a0a9b8523310b2551ee992f8d0c2e369dafaa56d..9cd8ec09c7fdc6bd1c8d64da150178f483f2a5a3 100644
+--- a/src/providers/ldap/ldap_common.c
++++ b/src/providers/ldap/ldap_common.c
+@@ -884,20 +884,3 @@ sdap_id_ctx_new(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
+ 
+     return sdap_ctx;
+ }
+-
+-bool should_run_posix_check(struct sdap_id_ctx *ctx,
+-                            struct sdap_id_conn_ctx *conn,
+-                            bool use_id_mapping,
+-                            bool posix_request)
+-{
+-    if (use_id_mapping == false &&
+-            posix_request == true &&
+-            ctx->opts->schema_type == SDAP_SCHEMA_AD &&
+-            conn->check_posix_attrs == true &&
+-            ctx->srv_opts &&
+-            ctx->srv_opts->posix_checked == false) {
+-        return true;
+-    }
+-
+-    return false;
+-}
+diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
+index 3de3568cb28c258c00f9b522c0b9120adca81d81..6c08d789b339424649c938b845e7118f5ea88f73 100644
+--- a/src/providers/ldap/ldap_common.h
++++ b/src/providers/ldap/ldap_common.h
+@@ -59,8 +59,6 @@ struct sdap_id_conn_ctx {
+     bool ignore_mark_offline;
+     /* do not fall back to user lookups for mpg domains on this connection */
+     bool no_mpg_user_fallback;
+-    /* check if this connection contains POSIX attributes */
+-    bool check_posix_attrs;
+ };
+ 
+ struct sdap_id_ctx {
+@@ -309,11 +307,6 @@ char *get_enterprise_principal_string_filter(TALLOC_CTX *mem_ctx,
+                                              const char *princ,
+                                              struct dp_option *sdap_basic_opts);
+ 
+-bool should_run_posix_check(struct sdap_id_ctx *ctx,
+-                            struct sdap_id_conn_ctx *conn,
+-                            bool id_mapping,
+-                            bool posix_request);
+-
+ char *sdap_get_access_filter(TALLOC_CTX *mem_ctx,
+                              const char *base_filter);
+ 
+diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
+index e892c407103b18a296ae6baaf3dcfff11ca4bf31..0790544818633e26ee5a8fbdca556b8230b1df3f 100644
+--- a/src/providers/ldap/sdap.h
++++ b/src/providers/ldap/sdap.h
+@@ -511,7 +511,6 @@ struct sdap_server_opts {
+     char *max_group_value;
+     char *max_service_value;
+     char *max_sudo_value;
+-    bool posix_checked;
+ };
+ 
+ struct sdap_id_ctx;
+diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
+index 1e77b1c3c612d28a7d1f7e686cbc0b094b07c89d..8fc832ae5720acac07b0e2a24255f6c5e3d6994b 100644
+--- a/src/providers/ldap/sdap_async.c
++++ b/src/providers/ldap/sdap_async.c
+@@ -2572,180 +2572,6 @@ int sdap_asq_search_recv(struct tevent_req *req,
+     return EOK;
+ }
+ 
+-/* ==POSIX attribute presence test================================= */
+-static void sdap_gc_posix_check_done(struct tevent_req *subreq);
+-static errno_t sdap_gc_posix_check_parse(struct sdap_handle *sh,
+-                                         struct sdap_msg *msg,
+-                                         void *pvt);
+-
+-struct sdap_gc_posix_check_state {
+-    struct tevent_context *ev;
+-    struct sdap_options *opts;
+-    struct sdap_handle *sh;
+-    int timeout;
+-
+-    const char **attrs;
+-    const char *filter;
+-
+-    bool has_posix;
+-};
+-
+-struct tevent_req *
+-sdap_gc_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
+-                         struct sdap_options *opts, struct sdap_handle *sh,
+-                         int timeout)
+-{
+-    struct tevent_req *req = NULL;
+-    struct tevent_req *subreq = NULL;
+-    struct sdap_gc_posix_check_state *state;
+-    errno_t ret;
+-
+-    req = tevent_req_create(memctx, &state, struct sdap_gc_posix_check_state);
+-    if (req == NULL) {
+-        return NULL;
+-    }
+-    state->ev = ev;
+-    state->sh = sh;
+-    state->opts = opts;
+-    state->timeout = timeout;
+-
+-    state->attrs = talloc_array(state, const char *, 4);
+-    if (state->attrs == NULL) {
+-        ret = ENOMEM;
+-        goto fail;
+-    }
+-    state->attrs[0] = "objectclass";
+-    state->attrs[1] = opts->user_map[SDAP_AT_USER_UID].name;
+-    state->attrs[2] = opts->group_map[SDAP_AT_GROUP_GID].name;
+-    state->attrs[3] = NULL;
+-
+-    state->filter = talloc_asprintf(state,
+-        "(|(&(%s=*)(objectclass=%s))(&(%s=*)(objectclass=%s)))",
+-                                    opts->user_map[SDAP_AT_USER_UID].name,
+-                                    opts->user_map[SDAP_OC_USER].name,
+-                                    opts->group_map[SDAP_AT_GROUP_GID].name,
+-                                    opts->group_map[SDAP_OC_GROUP].name);
+-    if (state->filter == NULL) {
+-        ret = ENOMEM;
+-        goto fail;
+-    }
+-
+-    subreq = sdap_get_generic_ext_send(state, state->ev, state->opts,
+-                                 state->sh,
+-                                 "",
+-                                 LDAP_SCOPE_SUBTREE, state->filter,
+-                                 state->attrs,
+-                                 NULL, NULL, 1, state->timeout,
+-                                 sdap_gc_posix_check_parse, state,
+-                                 SDAP_SRCH_FLG_SIZELIMIT_SILENT);
+-    if (subreq == NULL) {
+-        ret = ENOMEM;
+-        goto fail;
+-    }
+-    tevent_req_set_callback(subreq, sdap_gc_posix_check_done, req);
+-
+-    return req;
+-
+-fail:
+-    tevent_req_error(req, ret);
+-    tevent_req_post(req, ev);
+-    return req;
+-}
+-
+-static errno_t sdap_gc_posix_check_parse(struct sdap_handle *sh,
+-                                         struct sdap_msg *msg,
+-                                         void *pvt)
+-{
+-    struct berval **vals = NULL;
+-    struct sdap_gc_posix_check_state *state =
+-        talloc_get_type(pvt, struct sdap_gc_posix_check_state);
+-    char *dn;
+-    char *endptr;
+-
+-    dn = ldap_get_dn(sh->ldap, msg->msg);
+-    if (dn == NULL) {
+-        DEBUG(SSSDBG_TRACE_LIBS,
+-              "Search did not find any entry with POSIX attributes\n");
+-        goto done;
+-    }
+-    DEBUG(SSSDBG_TRACE_LIBS, "Found [%s] with POSIX attributes\n", dn);
+-    ldap_memfree(dn);
+-
+-    vals = ldap_get_values_len(sh->ldap, msg->msg,
+-                               state->opts->user_map[SDAP_AT_USER_UID].name);
+-    if (vals == NULL) {
+-        vals = ldap_get_values_len(sh->ldap, msg->msg,
+-                               state->opts->group_map[SDAP_AT_GROUP_GID].name);
+-        if (vals == NULL) {
+-            DEBUG(SSSDBG_TRACE_LIBS, "Entry does not have POSIX attrs?\n");
+-            goto done;
+-        }
+-    }
+-
+-    if (vals[0] == NULL) {
+-        DEBUG(SSSDBG_TRACE_LIBS, "No value for POSIX attr\n");
+-        goto done;
+-    }
+-
+-    errno = 0;
+-    strtouint32(vals[0]->bv_val, &endptr, 10);
+-    if (errno || *endptr || (vals[0]->bv_val == endptr)) {
+-        DEBUG(SSSDBG_MINOR_FAILURE,
+-              "POSIX attribute is not a number: %s\n", vals[0]->bv_val);
+-    }
+-
+-    state->has_posix = true;
+-done:
+-    ldap_value_free_len(vals);
+-    return EOK;
+-}
+-
+-static void sdap_gc_posix_check_done(struct tevent_req *subreq)
+-{
+-    struct tevent_req *req = tevent_req_callback_data(subreq,
+-                                                      struct tevent_req);
+-    struct sdap_gc_posix_check_state *state =
+-        tevent_req_data(req, struct sdap_gc_posix_check_state);
+-    errno_t ret;
+-
+-    ret = sdap_get_generic_ext_recv(subreq, NULL, NULL, NULL);
+-    talloc_zfree(subreq);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_OP_FAILURE,
+-              "sdap_get_generic_ext_recv failed [%d]: %s\n",
+-              ret, strerror(ret));
+-        tevent_req_error(req, ret);
+-        return;
+-    }
+-
+-    /* Positive hit is definitive, no need to search other bases */
+-    if (state->has_posix == true) {
+-        DEBUG(SSSDBG_FUNC_DATA, "Server has POSIX attributes. Global Catalog will "
+-                                "be used for user and group lookups. Note that if "
+-                                "only a subset of POSIX attributes is present "
+-                                "in GC, the non-replicated attributes are "
+-                                "currently not read from the LDAP port\n");
+-        tevent_req_done(req);
+-        return;
+-    }
+-
+-    /* All bases done! */
+-    DEBUG(SSSDBG_TRACE_LIBS, "Cycled through all bases\n");
+-    tevent_req_done(req);
+-}
+-
+-int sdap_gc_posix_check_recv(struct tevent_req *req,
+-                             bool *_has_posix)
+-{
+-    struct sdap_gc_posix_check_state *state = tevent_req_data(req,
+-                                            struct sdap_gc_posix_check_state);
+-
+-    TEVENT_REQ_RETURN_ON_ERROR(req);
+-
+-    *_has_posix = state->has_posix;
+-    return EOK;
+-}
+-
+ /* ==Generic Deref Search============================================ */
+ enum sdap_deref_type {
+     SDAP_DEREF_OPENLDAP,
+diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
+index 6ca3ed8d82ea7e4cb049b1c65c639b2773b8c296..6d09aca7a3465df4503991f0dc82e2af3871ccd5 100644
+--- a/src/providers/ldap/sdap_async.h
++++ b/src/providers/ldap/sdap_async.h
+@@ -281,19 +281,6 @@ int sdap_deref_search_recv(struct tevent_req *req,
+                            size_t *reply_count,
+                            struct sdap_deref_attrs ***reply);
+ 
+-/*
+- * This request should only be ran against a Global Catalog connection
+- * because it uses a NULL search base to search all domains in the forest,
+- * which would return an error with an LDAP port:
+- *  https://technet.microsoft.com/en-us/library/cc755809(v=ws.10).aspx
+- */
+-struct tevent_req *
+-sdap_gc_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
+-                         struct sdap_options *opts, struct sdap_handle *sh,
+-                         int timeout);
+-
+-int sdap_gc_posix_check_recv(struct tevent_req *req,
+-                             bool *_has_posix);
+ 
+ struct tevent_req *
+ sdap_sd_search_send(TALLOC_CTX *memctx,
+-- 
+2.17.1
+
diff --git a/SOURCES/0031-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch b/SOURCES/0031-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch
deleted file mode 100644
index 7724a87..0000000
--- a/SOURCES/0031-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch
+++ /dev/null
@@ -1,184 +0,0 @@
-From 464a19ecef7c4a0aad22cd9d2c7b2364e3680351 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 2 Nov 2017 11:09:20 +0100
-Subject: [PATCH 31/31] nss-idmap: allow empty buffer with
- SSS_NSS_EX_FLAG_INVALIDATE_CACHE
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 859bddc2bf51dc426a3dc56bd9f365e9c5722b65)
----
- src/sss_client/idmap/sss_nss_ex.c | 89 ++++++++++++++++++++++++++-------------
- 1 file changed, 60 insertions(+), 29 deletions(-)
-
-diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c
-index 148eb7b35ec236b6272dd203a0035399cfdef73d..dcd9619a8b07ced7498f61b7e809fa46ebffe09e 100644
---- a/src/sss_client/idmap/sss_nss_ex.c
-+++ b/src/sss_client/idmap/sss_nss_ex.c
-@@ -103,8 +103,11 @@ errno_t sss_nss_mc_get(struct nss_input *inp)
-     }
- }
- 
--static int check_flags(uint32_t flags)
-+static int check_flags(struct nss_input *inp, uint32_t flags,
-+                       bool *skip_mc, bool *skip_data)
- {
-+    bool no_data = false;
-+
-     /* SSS_NSS_EX_FLAG_NO_CACHE and SSS_NSS_EX_FLAG_INVALIDATE_CACHE are
-      * mutually exclusive */
-     if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0
-@@ -112,6 +115,52 @@ static int check_flags(uint32_t flags)
-         return EINVAL;
-     }
- 
-+    *skip_mc = false;
-+    if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0
-+            || (flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) {
-+        *skip_mc = true;
-+    }
-+
-+    switch(inp->cmd) {
-+    case SSS_NSS_GETPWNAM:
-+    case SSS_NSS_GETPWNAM_EX:
-+    case SSS_NSS_GETPWUID:
-+    case SSS_NSS_GETPWUID_EX:
-+        if (inp->result.pwrep.buffer == NULL
-+                || inp->result.pwrep.buflen == 0) {
-+            no_data = true;
-+        }
-+        break;
-+    case SSS_NSS_GETGRNAM:
-+    case SSS_NSS_GETGRNAM_EX:
-+    case SSS_NSS_GETGRGID:
-+    case SSS_NSS_GETGRGID_EX:
-+        if (inp->result.grrep.buffer == NULL
-+                || inp->result.grrep.buflen == 0) {
-+            no_data = true;
-+        }
-+        break;
-+    case SSS_NSS_INITGR:
-+    case SSS_NSS_INITGR_EX:
-+        if (inp->result.initgrrep.ngroups == 0
-+                || inp->result.initgrrep.groups == NULL) {
-+            return EINVAL;
-+        }
-+        break;
-+    default:
-+        return EINVAL;
-+    }
-+
-+    *skip_data = false;
-+    /* Allow empty buffer with SSS_NSS_EX_FLAG_INVALIDATE_CACHE */
-+    if (no_data) {
-+        if ((flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) {
-+            *skip_data = true;
-+        } else {
-+            return ERANGE;
-+        }
-+    }
-+
-     return 0;
- }
- 
-@@ -128,18 +177,14 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout)
-     gid_t *new_groups;
-     size_t idx;
-     bool skip_mc = false;
-+    bool skip_data = false;
- 
--    ret = check_flags(flags);
-+    ret = check_flags(inp, flags, &skip_mc, &skip_data);
-     if (ret != 0) {
-         return ret;
-     }
- 
--    if ((flags & SSS_NSS_EX_FLAG_NO_CACHE) != 0
--            || (flags & SSS_NSS_EX_FLAG_INVALIDATE_CACHE) != 0) {
--        skip_mc = true;
--    }
--
--    if (!skip_mc) {
-+    if (!skip_mc && !skip_data) {
-         ret = sss_nss_mc_get(inp);
-         switch (ret) {
-         case 0:
-@@ -159,7 +204,7 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout)
- 
-     sss_nss_timedlock(timeout, &time_left);
- 
--    if (!skip_mc) {
-+    if (!skip_mc && !skip_data) {
-         /* previous thread might already initialize entry in mmap cache */
-         ret = sss_nss_mc_get(inp);
-         switch (ret) {
-@@ -196,6 +241,12 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout)
-         goto out;
-     }
- 
-+    if (skip_data) {
-+        /* No data requested, just return the return code */
-+        ret = 0;
-+        goto out;
-+    }
-+
-     if (inp->cmd == SSS_NSS_INITGR || inp->cmd == SSS_NSS_INITGR_EX) {
-         if ((*(inp->result.initgrrep.ngroups) - *(inp->result.initgrrep.start))
-                     < num_results) {
-@@ -311,10 +362,6 @@ int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd,
-         .result.pwrep.buffer = buffer,
-         .result.pwrep.buflen = buflen};
- 
--    if (buffer == NULL || buflen == 0) {
--        return ERANGE;
--    }
--
-     ret = make_name_flag_req_data(name, flags, &inp.rd);
-     if (ret != 0) {
-         return ret;
-@@ -346,10 +393,6 @@ int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd,
-         .result.pwrep.buffer = buffer,
-         .result.pwrep.buflen = buflen};
- 
--    if (buffer == NULL || buflen == 0) {
--        return ERANGE;
--    }
--
-     SAFEALIGN_COPY_UINT32(&req_data[0], &uid, NULL);
-     SAFEALIGN_COPY_UINT32(&req_data[1], &flags, NULL);
-     *result = NULL;
-@@ -373,10 +416,6 @@ int sss_nss_getgrnam_timeout(const char *name, struct group *grp,
-         .result.grrep.buffer = buffer,
-         .result.grrep.buflen = buflen};
- 
--    if (buffer == NULL || buflen == 0) {
--        return ERANGE;
--    }
--
-     ret = make_name_flag_req_data(name, flags, &inp.rd);
-     if (ret != 0) {
-         return ret;
-@@ -407,10 +446,6 @@ int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp,
-         .result.grrep.buffer = buffer,
-         .result.grrep.buflen = buflen};
- 
--    if (buffer == NULL || buflen == 0) {
--        return ERANGE;
--    }
--
-     SAFEALIGN_COPY_UINT32(&req_data[0], &gid, NULL);
-     SAFEALIGN_COPY_UINT32(&req_data[1], &flags, NULL);
-     *result = NULL;
-@@ -434,10 +469,6 @@ int sss_nss_getgrouplist_timeout(const char *name, gid_t group,
-         .input.name = name,
-         .cmd = SSS_NSS_INITGR_EX};
- 
--    if (groups == NULL || ngroups == NULL || *ngroups == 0) {
--        return EINVAL;
--    }
--
-     ret = make_name_flag_req_data(name, flags, &inp.rd);
-     if (ret != 0) {
-         return ret;
--- 
-2.13.6
-
diff --git a/SOURCES/0032-BUILD-Properly-expand-variables-in-sssd-ifp.service.patch b/SOURCES/0032-BUILD-Properly-expand-variables-in-sssd-ifp.service.patch
deleted file mode 100644
index be96f01..0000000
--- a/SOURCES/0032-BUILD-Properly-expand-variables-in-sssd-ifp.service.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-From 1925a1bb1e0ea210bd40ec3374726948fb6e4760 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Tue, 7 Nov 2017 17:11:52 +0100
-Subject: [PATCH 32/35] BUILD: Properly expand variables in sssd-ifp.service
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-systemd[1]: [/usr/lib/systemd/system/sssd-ifp.service:9]
-    Path '-@environment_file@' is not absolute, ignoring.
-
-sh-4.2# systemctl cat sssd-ifp.service
- # /usr/lib/systemd/system/sssd-ifp.service
-[Unit]
-Description=SSSD IFP Service responder
-Documentation=man:sssd-ifp(5)
-After=sssd.service
-BindsTo=sssd.service
-
-[Service]
-Environment=DEBUG_LOGGER=--logger=files
-EnvironmentFile=-@environment_file@
-Type=dbus
-BusName=org.freedesktop.sssd.infopipe
-ExecStart=/usr/libexec/sssd/sssd_ifp --uid 0 --gid 0 --dbus-activated ${DEBUG_LOGGER}
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3433
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit b495522f3eadde9ad4bb8d125fd70b0d5f07596a)
----
- Makefile.am | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/Makefile.am b/Makefile.am
-index 286ba47e3c421864362717be5258de960efca9f2..bbc90d9bad4d22ca0284ea95281a487d42399c05 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -1491,7 +1491,7 @@ EXTRA_DIST += \
-     src/responder/ifp/org.freedesktop.sssd.infopipe.service.in \
-     $(NULL)
- 
--ifp_edit_cmd = $(SED) \
-+ifp_edit_cmd = $(edit_cmd) \
-         -e 's|@ifp_exec_cmd[@]|$(ifp_exec_cmd)|g' \
-         -e 's|@ifp_systemdservice[@]|$(ifp_systemdservice)|g' \
-         -e 's|@ifp_restart[@]|$(ifp_restart)|g'
--- 
-2.13.6
-
diff --git a/SOURCES/0032-LDAP-AD-Remove-the-legacy-POSIX-check-from-user-grou.patch b/SOURCES/0032-LDAP-AD-Remove-the-legacy-POSIX-check-from-user-grou.patch
new file mode 100644
index 0000000..430f309
--- /dev/null
+++ b/SOURCES/0032-LDAP-AD-Remove-the-legacy-POSIX-check-from-user-grou.patch
@@ -0,0 +1,385 @@
+From ba23021935fcc984b1000bc007fcd3e52fa752cd Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sat, 30 Jun 2018 12:31:13 +0200
+Subject: [PATCH] LDAP/AD: Remove the legacy POSIX check from user, group and
+ enumeration searches
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This code is superseded by the POSIX check in the subdomains provider.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3755
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 8d78119811e2572bb1a05da5abb7c5a2d43d1f97)
+---
+ src/providers/ad/ad_id.c             |  43 +---------
+ src/providers/ldap/ldap_id.c         | 121 ---------------------------
+ src/providers/ldap/sdap_async_enum.c | 105 +----------------------
+ 3 files changed, 4 insertions(+), 265 deletions(-)
+
+diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
+index 782d9bc402e71d6b20976367f6afbae82bd25750..96c5677c681e40419172c2e5aa3c32b8403147b1 100644
+--- a/src/providers/ad/ad_id.c
++++ b/src/providers/ad/ad_id.c
+@@ -29,28 +29,6 @@
+ #include "providers/ldap/sdap_idmap.h"
+ #include "providers/ldap/sdap_async.h"
+ 
+-static void
+-disable_gc(struct ad_options *ad_options)
+-{
+-    errno_t ret;
+-
+-    if (dp_opt_get_bool(ad_options->basic, AD_ENABLE_GC) == false) {
+-        return;
+-    }
+-
+-    DEBUG(SSSDBG_IMPORTANT_INFO, "POSIX attributes were requested "
+-          "but are not present on the server side. Global Catalog "
+-          "lookups will be disabled\n");
+-
+-    ret = dp_opt_set_bool(ad_options->basic,
+-                          AD_ENABLE_GC, false);
+-    if (ret != EOK) {
+-        DEBUG(SSSDBG_MINOR_FAILURE,
+-                "Could not turn off GC support\n");
+-        /* Not fatal */
+-    }
+-}
+-
+ static bool ad_account_can_shortcut(struct sdap_idmap_ctx *idmap_ctx,
+                                     struct sss_domain_info *domain,
+                                     int filter_type,
+@@ -296,14 +274,12 @@ ad_handle_acct_info_done(struct tevent_req *subreq)
+     if (sdap_err == EOK) {
+         tevent_req_done(req);
+         return;
+-    } else if (sdap_err == ERR_NO_POSIX) {
+-        disable_gc(state->ad_options);
+     } else if (sdap_err != ENOENT) {
+         ret = EIO;
+         goto fail;
+     }
+ 
+-    /* Ret is only ENOENT or ERR_NO_POSIX now. Try the next connection */
++    /* Ret is only ENOENT now. Try the next connection */
+     state->cindex++;
+     ret = ad_handle_acct_info_step(req);
+     if (ret != EAGAIN) {
+@@ -710,22 +686,7 @@ ad_enumeration_done(struct tevent_req *subreq)
+ 
+     ret = sdap_dom_enum_ex_recv(subreq);
+     talloc_zfree(subreq);
+-    if (ret == ERR_NO_POSIX) {
+-        /* Retry enumerating the same domain again, this time w/o
+-         * connecting to GC
+-         */
+-        disable_gc(state->id_ctx->ad_options);
+-        ret = ad_enum_sdom(req, state->sditer, state->id_ctx);
+-        if (ret != EOK) {
+-            DEBUG(SSSDBG_OP_FAILURE,
+-                "Could not retry domain %s\n", state->sditer->dom->name);
+-            tevent_req_error(req, ret);
+-            return;
+-        }
+-
+-        /* Execution will resume in ad_enumeration_done */
+-        return;
+-    } else if (ret != EOK) {
++    if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE,
+               "Could not enumerate domain %s\n", state->sditer->dom->name);
+         tevent_req_error(req, ret);
+diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
+index ebf5d9cb2e2d1cc4b356d431965a00588a876444..9e8289904e60512e088aae77666bcd765bfe3392 100644
+--- a/src/providers/ldap/ldap_id.c
++++ b/src/providers/ldap/ldap_id.c
+@@ -66,7 +66,6 @@ struct users_get_state {
+ 
+ static int users_get_retry(struct tevent_req *req);
+ static void users_get_connect_done(struct tevent_req *subreq);
+-static void users_get_posix_check_done(struct tevent_req *subreq);
+ static void users_get_search(struct tevent_req *req);
+ static void users_get_done(struct tevent_req *subreq);
+ 
+@@ -408,66 +407,6 @@ static void users_get_connect_done(struct tevent_req *subreq)
+         return;
+     }
+ 
+-    /* If POSIX attributes have been requested with an AD server and we
+-     * have no idea about POSIX attributes support, run a one-time check
+-     */
+-    if (should_run_posix_check(state->ctx,
+-                               state->conn,
+-                               state->use_id_mapping,
+-                               !state->non_posix)) {
+-        subreq = sdap_gc_posix_check_send(state, state->ev, state->ctx->opts,
+-                                          sdap_id_op_handle(state->op),
+-                                          dp_opt_get_int(state->ctx->opts->basic,
+-                                                         SDAP_SEARCH_TIMEOUT));
+-        if (subreq == NULL) {
+-            tevent_req_error(req, ENOMEM);
+-            return;
+-        }
+-        tevent_req_set_callback(subreq, users_get_posix_check_done, req);
+-        return;
+-    }
+-
+-    users_get_search(req);
+-}
+-
+-static void users_get_posix_check_done(struct tevent_req *subreq)
+-{
+-    errno_t ret;
+-    errno_t ret2;
+-    bool has_posix;
+-    int dp_error;
+-    struct tevent_req *req = tevent_req_callback_data(subreq,
+-                                                      struct tevent_req);
+-    struct users_get_state *state = tevent_req_data(req,
+-                                                    struct users_get_state);
+-
+-    ret = sdap_gc_posix_check_recv(subreq, &has_posix);
+-    talloc_zfree(subreq);
+-    if (ret != EOK) {
+-        /* We can only finish the id_op on error as the connection
+-         * is re-used by the user search
+-         */
+-        ret2 = sdap_id_op_done(state->op, ret, &dp_error);
+-        if (dp_error == DP_ERR_OK && ret2 != EOK) {
+-            /* retry */
+-            ret = users_get_retry(req);
+-            if (ret != EOK) {
+-                tevent_req_error(req, ret);
+-            }
+-            return;
+-        }
+-    }
+-
+-    state->ctx->srv_opts->posix_checked = true;
+-
+-    /* If the check ran to completion, we know for certain about the attributes
+-     */
+-    if (ret == EOK && has_posix == false) {
+-        state->sdap_ret = ERR_NO_POSIX;
+-        tevent_req_done(req);
+-        return;
+-    }
+-
+     users_get_search(req);
+ }
+ 
+@@ -691,7 +630,6 @@ struct groups_get_state {
+ 
+ static int groups_get_retry(struct tevent_req *req);
+ static void groups_get_connect_done(struct tevent_req *subreq);
+-static void groups_get_posix_check_done(struct tevent_req *subreq);
+ static void groups_get_mpg_done(struct tevent_req *subreq);
+ static errno_t groups_get_handle_no_group(struct tevent_req *req);
+ static void groups_get_search(struct tevent_req *req);
+@@ -953,65 +891,6 @@ static void groups_get_connect_done(struct tevent_req *subreq)
+         return;
+     }
+ 
+-    /* If POSIX attributes have been requested with an AD server and we
+-     * have no idea about POSIX attributes support, run a one-time check
+-     */
+-    if (should_run_posix_check(state->ctx,
+-                               state->conn,
+-                               state->use_id_mapping,
+-                               !state->non_posix)) {
+-        subreq = sdap_gc_posix_check_send(state, state->ev, state->ctx->opts,
+-                                          sdap_id_op_handle(state->op),
+-                                          dp_opt_get_int(state->ctx->opts->basic,
+-                                                         SDAP_SEARCH_TIMEOUT));
+-        if (subreq == NULL) {
+-            tevent_req_error(req, ENOMEM);
+-            return;
+-        }
+-        tevent_req_set_callback(subreq, groups_get_posix_check_done, req);
+-        return;
+-    }
+-
+-    groups_get_search(req);
+-}
+-
+-static void groups_get_posix_check_done(struct tevent_req *subreq)
+-{
+-    errno_t ret;
+-    bool has_posix;
+-    int dp_error;
+-    struct tevent_req *req = tevent_req_callback_data(subreq,
+-                                                      struct tevent_req);
+-    struct groups_get_state *state = tevent_req_data(req,
+-                                                     struct groups_get_state);
+-
+-    ret = sdap_gc_posix_check_recv(subreq, &has_posix);
+-    talloc_zfree(subreq);
+-    if (ret != EOK) {
+-        /* We can only finish the id_op on error as the connection
+-         * is re-used by the group search
+-         */
+-        ret = sdap_id_op_done(state->op, ret, &dp_error);
+-        if (dp_error == DP_ERR_OK && ret != EOK) {
+-            /* retry */
+-            ret = groups_get_retry(req);
+-            if (ret != EOK) {
+-                tevent_req_error(req, ret);
+-            }
+-            return;
+-        }
+-    }
+-
+-    state->ctx->srv_opts->posix_checked = true;
+-
+-    /* If the check ran to completion, we know for certain about the attributes
+-     */
+-    if (has_posix == false) {
+-        state->sdap_ret = ERR_NO_POSIX;
+-        tevent_req_done(req);
+-        return;
+-    }
+-
+     groups_get_search(req);
+ }
+ 
+diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
+index ea9d51adc7f94145cd7e689893bf7fd81028c5bb..899d59d3831bf473a98b44a7bf4d2007fac84c5e 100644
+--- a/src/providers/ldap/sdap_async_enum.c
++++ b/src/providers/ldap/sdap_async_enum.c
+@@ -69,8 +69,6 @@ static errno_t sdap_dom_enum_ex_retry(struct tevent_req *req,
+                                       tevent_req_fn tcb);
+ static bool sdap_dom_enum_ex_connected(struct tevent_req *subreq);
+ static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq);
+-static void sdap_dom_enum_ex_posix_check_done(struct tevent_req *subreq);
+-static errno_t sdap_dom_enum_search_users(struct tevent_req *req);
+ static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq);
+ static void sdap_dom_enum_ex_get_groups(struct tevent_req *subreq);
+ static void sdap_dom_enum_ex_groups_done(struct tevent_req *subreq);
+@@ -181,118 +179,19 @@ static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq)
+                                                       struct tevent_req);
+     struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+                                                 struct sdap_dom_enum_ex_state);
+-    bool use_id_mapping;
+-    errno_t ret;
+ 
+     if (sdap_dom_enum_ex_connected(subreq) == false) {
+         return;
+     }
+ 
+-    use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
+-                                            state->ctx->opts->idmap_ctx,
+-                                            state->sdom->dom->name,
+-                                            state->sdom->dom->domain_id);
+-
+-    /* If POSIX attributes have been requested with an AD server and we
+-     * have no idea about POSIX attributes support, run a one-time check
+-     */
+-    if (should_run_posix_check(state->ctx,
+-                               state->user_conn,
+-                               use_id_mapping,
+-                               true)) {
+-        subreq = sdap_gc_posix_check_send(state, state->ev, state->ctx->opts,
+-                                          sdap_id_op_handle(state->user_op),
+-                                          dp_opt_get_int(state->ctx->opts->basic,
+-                                                         SDAP_SEARCH_TIMEOUT));
+-        if (subreq == NULL) {
+-            tevent_req_error(req, ENOMEM);
+-            return;
+-        }
+-        tevent_req_set_callback(subreq,
+-                                sdap_dom_enum_ex_posix_check_done, req);
+-        return;
+-    }
+-
+-
+-    ret = sdap_dom_enum_search_users(req);
+-    if (ret != EOK) {
+-        tevent_req_error(req, ret);
+-        return;
+-    }
+-    /* Execution resumes in sdap_dom_enum_ex_users_done */
+-}
+-
+-static void sdap_dom_enum_ex_posix_check_done(struct tevent_req *subreq)
+-{
+-    errno_t ret;
+-    bool has_posix;
+-    int dp_error;
+-
+-    struct tevent_req *req = tevent_req_callback_data(subreq,
+-                                                      struct tevent_req);
+-    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+-                                                struct sdap_dom_enum_ex_state);
+-
+-    ret = sdap_gc_posix_check_recv(subreq, &has_posix);
+-    talloc_zfree(subreq);
+-    if (ret != EOK && ret != ERR_NO_POSIX) {
+-        /* We can only finish the id_op on error as the connection
+-         * is re-used by the user search
+-         */
+-        ret = sdap_id_op_done(state->user_op, ret, &dp_error);
+-        if (dp_error == DP_ERR_OK && ret != EOK) {
+-            /* retry */
+-            ret = sdap_dom_enum_ex_retry(req, state->user_op,
+-                                         sdap_dom_enum_ex_get_users);
+-            if (ret != EOK) {
+-                tevent_req_error(req, ret);
+-            }
+-            return;
+-        } else if (dp_error == DP_ERR_OFFLINE) {
+-            DEBUG(SSSDBG_TRACE_FUNC, "Backend is offline, retrying later\n");
+-            tevent_req_done(req);
+-            return;
+-        } else {
+-            /* Non-recoverable error */
+-            DEBUG(SSSDBG_OP_FAILURE,
+-                "POSIX check failed: %d: %s\n", ret, sss_strerror(ret));
+-            tevent_req_error(req, ret);
+-            return;
+-        }
+-    }
+-
+-    state->ctx->srv_opts->posix_checked = true;
+-
+-    /* If the check ran to completion, we know for certain about the attributes
+-     */
+-    if (has_posix == false) {
+-        tevent_req_error(req, ERR_NO_POSIX);
+-        return;
+-    }
+-
+-
+-    ret = sdap_dom_enum_search_users(req);
+-    if (ret != EOK) {
+-        tevent_req_error(req, ret);
+-        return;
+-    }
+-    /* Execution resumes in sdap_dom_enum_ex_users_done */
+-}
+-
+-static errno_t sdap_dom_enum_search_users(struct tevent_req *req)
+-{
+-    struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+-                                                struct sdap_dom_enum_ex_state);
+-    struct tevent_req *subreq;
+-
+     subreq = enum_users_send(state, state->ev,
+                              state->ctx, state->sdom,
+                              state->user_op, state->purge);
+     if (subreq == NULL) {
+-        return ENOMEM;
++        tevent_req_error(req, ENOMEM);
++        return;
+     }
+     tevent_req_set_callback(subreq, sdap_dom_enum_ex_users_done, req);
+-    return EOK;
+ }
+ 
+ static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq)
+-- 
+2.17.1
+
diff --git a/SOURCES/0033-AD-Remove-the-legacy-check-from-ad_get_account_domai.patch b/SOURCES/0033-AD-Remove-the-legacy-check-from-ad_get_account_domai.patch
new file mode 100644
index 0000000..2862524
--- /dev/null
+++ b/SOURCES/0033-AD-Remove-the-legacy-check-from-ad_get_account_domai.patch
@@ -0,0 +1,122 @@
+From dcf8f47b85c0c93dd0c70d5a2093fff82f333e91 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 4 Jul 2018 20:10:30 +0200
+Subject: [PATCH] AD: Remove the legacy check from
+ ad_get_account_domain_posix_check request
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Previously, the POSIX attribute presence check was run as part of the ID
+request, so it was necessary to also run the check as part of the
+get-domain-for-ID request.
+
+Since moving the POSIX check to being a part of the subdomain provider,
+this is no longer needed as the subdomain provider disables the GC
+support on its own if required. Therefore we can just remove the POSIX
+check from the get-domain-for-ID request.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3755
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit 4273ac0490eeef72d2daa0c7f6cee80d65b6b34d)
+---
+ src/providers/ad/ad_id.c | 74 ----------------------------------------
+ 1 file changed, 74 deletions(-)
+
+diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
+index 96c5677c681e40419172c2e5aa3c32b8403147b1..1da48433eeb01b069ea6e2829122d93a696fb8a3 100644
+--- a/src/providers/ad/ad_id.c
++++ b/src/providers/ad/ad_id.c
+@@ -1041,7 +1041,6 @@ ad_enumeration_recv(struct tevent_req *req)
+ static errno_t ad_get_account_domain_prepare_search(struct tevent_req *req);
+ static errno_t ad_get_account_domain_connect_retry(struct tevent_req *req);
+ static void ad_get_account_domain_connect_done(struct tevent_req *subreq);
+-static void ad_get_account_domain_posix_check_done(struct tevent_req *subreq);
+ static void ad_get_account_domain_search(struct tevent_req *req);
+ static void ad_get_account_domain_search_done(struct tevent_req *subreq);
+ static void ad_get_account_domain_evaluate(struct tevent_req *req);
+@@ -1264,79 +1263,6 @@ static void ad_get_account_domain_connect_done(struct tevent_req *subreq)
+         return;
+     }
+ 
+-    /* If POSIX attributes have been requested with an AD server and we
+-     * have no idea about POSIX attributes support, run a one-time check
+-     */
+-    if (state->sdap_id_ctx->srv_opts &&
+-        state->sdap_id_ctx->srv_opts->posix_checked == false) {
+-        subreq = sdap_gc_posix_check_send(state,
+-                                          state->ev,
+-                                          state->sdap_id_ctx->opts,
+-                                          sdap_id_op_handle(state->op),
+-                                          dp_opt_get_int(
+-                                              state->sdap_id_ctx->opts->basic,
+-                                              SDAP_SEARCH_TIMEOUT));
+-        if (subreq == NULL) {
+-            tevent_req_error(req, ENOMEM);
+-            return;
+-        }
+-        tevent_req_set_callback(subreq, ad_get_account_domain_posix_check_done, req);
+-        return;
+-    }
+-
+-    ad_get_account_domain_search(req);
+-}
+-
+-static void ad_get_account_domain_posix_check_done(struct tevent_req *subreq)
+-{
+-    struct tevent_req *req = tevent_req_callback_data(subreq,
+-                                                      struct tevent_req);
+-    struct ad_get_account_domain_state *state = tevent_req_data(req,
+-                                          struct ad_get_account_domain_state);
+-    int dp_error = DP_ERR_FATAL;
+-    bool has_posix;
+-    errno_t ret;
+-    errno_t ret2;
+-
+-    ret = sdap_gc_posix_check_recv(subreq, &has_posix);
+-    talloc_zfree(subreq);
+-    if (ret != EOK) {
+-        /* We can only finish the id_op on error as the connection
+-         * is re-used by the real search
+-         */
+-        ret2 = sdap_id_op_done(state->op, ret, &dp_error);
+-        if (dp_error == DP_ERR_OK && ret2 != EOK) {
+-            /* retry */
+-            ret = ad_get_account_domain_connect_retry(req);
+-            if (ret != EOK) {
+-                tevent_req_error(req, ret);
+-            }
+-            return;
+-        }
+-
+-        tevent_req_error(req, ret);
+-        return;
+-    }
+-
+-    state->sdap_id_ctx->srv_opts->posix_checked = true;
+-
+-    /*
+-     * If the GC has no POSIX attributes, there is nothing we can do.
+-     * Return an error and let the responders disable the functionality
+-     * from now on.
+-     */
+-    if (has_posix == false) {
+-        DEBUG(SSSDBG_CONF_SETTINGS,
+-              "The Global Catalog has no POSIX attributes\n");
+-
+-        disable_gc(state->id_ctx->ad_options);
+-        dp_reply_std_set(&state->reply,
+-                         DP_ERR_DECIDE, ERR_GET_ACCT_DOM_NOT_SUPPORTED,
+-                         NULL);
+-        tevent_req_done(req);
+-        return;
+-    }
+-
+     ad_get_account_domain_search(req);
+ }
+ 
+-- 
+2.17.1
+
diff --git a/SOURCES/0033-SYSTEMD-Clean-pid-file-in-corner-cases.patch b/SOURCES/0033-SYSTEMD-Clean-pid-file-in-corner-cases.patch
deleted file mode 100644
index ce1c4ec..0000000
--- a/SOURCES/0033-SYSTEMD-Clean-pid-file-in-corner-cases.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From 7f4a89ff4e7dc7c3ffac24ac87187dca1e9e7d1e Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Wed, 8 Nov 2017 14:09:36 +0100
-Subject: [PATCH 33/35] SYSTEMD: Clean pid file in corner cases
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-SSSD can cleanup pid file in case of standard stopping of daemon.
-It's done in function monitor_cleanup. However monitor does not have a
-change to cleanup file in case of OOM or sending SIGKILL to monitor.
-
-Even though PIDFile is not necessary for services with Type notify
-we should let systemd to clean this file in unexpected situations.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3528
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit f4b808c83ecbaf36c7069440535d62990e32d55d)
----
- src/sysv/systemd/sssd.service.in | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/src/sysv/systemd/sssd.service.in b/src/sysv/systemd/sssd.service.in
-index cea848fac80303d6fae12dd84316a91dbc60072d..0c515d34caaa3ea397c4c7e95eef0188df170840 100644
---- a/src/sysv/systemd/sssd.service.in
-+++ b/src/sysv/systemd/sssd.service.in
-@@ -10,6 +10,7 @@ EnvironmentFile=-@environment_file@
- ExecStart=@sbindir@/sssd -i ${DEBUG_LOGGER}
- Type=notify
- NotifyAccess=main
-+PIDFile=@localstatedir@/run/sssd.pid
- 
- [Install]
- WantedBy=multi-user.target
--- 
-2.13.6
-
diff --git a/SOURCES/0034-AD-Add-Global-Catalog-usability-check-in-subdomain-c.patch b/SOURCES/0034-AD-Add-Global-Catalog-usability-check-in-subdomain-c.patch
new file mode 100644
index 0000000..0c323ec
--- /dev/null
+++ b/SOURCES/0034-AD-Add-Global-Catalog-usability-check-in-subdomain-c.patch
@@ -0,0 +1,423 @@
+From 7f9567ba8d62536c4aeb68897316781e82116c21 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 4 Jul 2018 13:14:40 +0200
+Subject: [PATCH] AD: Add Global Catalog usability check in subdomain code by
+ looking at the schema
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Addsa a new tevent request which checks for the presence of uidNumber
+and gidNumber under the schema naming context, which is typically
+cn=schema,cn=configuration,$BASEDN. For both objects representing each of
+the attributes, the isMemberOfPartialAttributeSet attribute is requested. If
+this attribute is set to TRUE, then the attribute corresponding to this
+schema object had been replicated to the Global Catalog.
+
+Because the isMemberOfPartialAttributeSet is not replicated to the GC
+itself, we use the LDAP connection for the search.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3755
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit ba96e7b839b875946f03787a3a57f259230a0fef)
+---
+ src/providers/ad/ad_subdomains.c | 308 +++++++++++++++++++++++++++++--
+ 1 file changed, 288 insertions(+), 20 deletions(-)
+
+diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
+index 84886e920b37f8803d85ce0903b74e6c809a8904..549c2c1f76d4bbccdf03c6ab619fba5f9186358f 100644
+--- a/src/providers/ad/ad_subdomains.c
++++ b/src/providers/ad/ad_subdomains.c
+@@ -54,9 +54,39 @@
+ #define SLAVE_DOMAIN_FILTER      "(&"SLAVE_DOMAIN_FILTER_BASE")"
+ #define FOREST_ROOT_FILTER_FMT   "(&"SLAVE_DOMAIN_FILTER_BASE"(cn=%s))"
+ 
++/* Attributes of schema objects. See e.g.
++ * https://docs.microsoft.com/en-us/windows/desktop/AD/characteristics-of-attributes
++ * for more details
++ */
++#define AD_SCHEMA_AT_OC         "attributeSchema"
++#define AD_AT_SCHEMA_NAME       "cn"
++#define AD_AT_SCHEMA_IS_REPL    "isMemberOfPartialAttributeSet"
++
+ /* do not refresh more often than every 5 seconds for now */
+ #define AD_SUBDOMAIN_REFRESH_LIMIT 5
+ 
++static void
++ad_disable_gc(struct ad_options *ad_options)
++{
++    errno_t ret;
++
++    if (dp_opt_get_bool(ad_options->basic, AD_ENABLE_GC) == false) {
++        return;
++    }
++
++    DEBUG(SSSDBG_IMPORTANT_INFO, "POSIX attributes were requested "
++          "but are not present on the server side. Global Catalog "
++          "lookups will be disabled\n");
++
++    ret = dp_opt_set_bool(ad_options->basic,
++                          AD_ENABLE_GC, false);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_MINOR_FAILURE,
++                "Could not turn off GC support\n");
++        /* Not fatal */
++    }
++}
++
+ static struct sss_domain_info *
+ ads_get_root_domain(struct be_ctx *be_ctx, struct sysdb_attrs *attrs)
+ {
+@@ -1261,6 +1291,212 @@ static errno_t ad_get_root_domain_recv(TALLOC_CTX *mem_ctx,
+     return EOK;
+ }
+ 
++static void ad_check_gc_usability_search_done(struct tevent_req *subreq);
++
++struct ad_check_gc_usability_state {
++    struct sdap_options *sdap_opts;
++
++    const char *attrs[3];
++
++    bool is_gc_usable;
++};
++
++static struct tevent_req *
++ad_check_gc_usability_send(TALLOC_CTX *mem_ctx,
++                           struct tevent_context *ev,
++                           struct ad_options *ad_options,
++                           struct sdap_options *sdap_opts,
++                           struct sdap_id_op *op,
++                           const char *domain_name,
++                           const char *domain_sid)
++{
++    struct ad_check_gc_usability_state *state = NULL;
++    struct tevent_req *req = NULL;
++    struct tevent_req *subreq = NULL;
++    const char *filter = NULL;
++    errno_t ret;
++    bool uses_id_mapping;
++
++    req = tevent_req_create(mem_ctx, &state,
++                            struct ad_check_gc_usability_state);
++    if (req == NULL) {
++        return NULL;
++    }
++    state->sdap_opts = sdap_opts;
++    state->is_gc_usable = false;
++
++    if (dp_opt_get_bool(ad_options->basic, AD_ENABLE_GC) == false) {
++        DEBUG(SSSDBG_TRACE_FUNC, "GC explicitly disabled\n");
++        state->is_gc_usable = false;
++        ret = EOK;
++        goto immediately;
++    }
++
++    uses_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
++                                                        sdap_opts->idmap_ctx,
++                                                        domain_name,
++                                                        domain_sid);
++    if (uses_id_mapping == true) {
++        DEBUG(SSSDBG_TRACE_FUNC, "GC always usable while ID mapping\n");
++        state->is_gc_usable = true;
++        ret = EOK;
++        goto immediately;
++    }
++
++    /* The schema partition is replicated across all DCs in the forest, so
++     * it's safe to use the baseDN even if e.g. joined to a child domain
++     * even though the base DN "looks" like a part of the forest root
++     * tree. On the other hand, it doesn't make sense to guess the value
++     * if we can't detect it from the rootDSE.
++     */
++    if (state->sdap_opts->schema_basedn == NULL) {
++        DEBUG(SSSDBG_TRACE_FUNC,
++              "No idea where to look for the schema, disabling GC\n");
++        state->is_gc_usable = false;
++        ret = EOK;
++        goto immediately;
++    }
++
++    state->attrs[0] = AD_AT_SCHEMA_NAME;
++    state->attrs[1] = AD_AT_SCHEMA_IS_REPL;
++    state->attrs[2] = NULL;
++
++    DEBUG(SSSDBG_TRACE_FUNC, "Checking for POSIX attributes in GC\n");
++
++    filter = talloc_asprintf(
++                        state,
++                        "(&(objectclass=%s)(|(%s=%s)(%s=%s)))",
++                        AD_SCHEMA_AT_OC,
++                        AD_AT_SCHEMA_NAME,
++                        state->sdap_opts->user_map[SDAP_AT_USER_UID].name,
++                        AD_AT_SCHEMA_NAME,
++                        state->sdap_opts->group_map[SDAP_AT_GROUP_GID].name);
++    if (filter == NULL) {
++        ret = ENOMEM;
++        goto immediately;
++    }
++
++    subreq = sdap_get_generic_send(state,
++                                   ev,
++                                   state->sdap_opts,
++                                   sdap_id_op_handle(op),
++                                   state->sdap_opts->schema_basedn,
++                                   LDAP_SCOPE_SUBTREE,
++                                   filter,
++                                   state->attrs,
++                                   NULL, 0,
++                                   dp_opt_get_int(state->sdap_opts->basic,
++                                                  SDAP_SEARCH_TIMEOUT),
++                                   false);
++    if (subreq == NULL) {
++        ret = ENOMEM;
++        goto immediately;
++    }
++    tevent_req_set_callback(subreq, ad_check_gc_usability_search_done, req);
++
++    return req;
++
++immediately:
++    if (ret == EOK) {
++        tevent_req_done(req);
++    } else {
++        tevent_req_error(req, ret);
++    }
++    tevent_req_post(req, ev);
++
++    return req;
++}
++
++static void ad_check_gc_usability_search_done(struct tevent_req *subreq)
++{
++    struct tevent_req *req = tevent_req_callback_data(subreq,
++                                                      struct tevent_req);
++    struct ad_check_gc_usability_state *state = tevent_req_data(req,
++                                          struct ad_check_gc_usability_state);
++    errno_t ret;
++    size_t reply_count;
++    struct sysdb_attrs **reply = NULL;
++    bool uid = false;
++    bool gid = false;
++
++    ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_OP_FAILURE,
++              "sdap_get_generic_recv failed [%d]: %s\n",
++              ret, strerror(ret));
++        /* We continue to finish sdap_id_op. */
++    }
++
++    if (reply_count == 0) {
++        DEBUG(SSSDBG_TRACE_LIBS,
++              "Nothing found, so no POSIX attrs can exist\n");
++        state->is_gc_usable = false;
++        tevent_req_done(req);
++        return;
++    }
++
++    for (size_t i = 0; i < reply_count; i++) {
++        const char *name = NULL;
++        const char *is_in_partial_set = NULL;
++        bool *val = NULL;
++
++        ret = sysdb_attrs_get_string(reply[i], AD_AT_SCHEMA_NAME, &name);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Cannot get "AD_AT_SCHEMA_NAME);
++            continue;
++        }
++
++        if (strcasecmp(name, state->sdap_opts->user_map[SDAP_AT_USER_UID].name) == 0) {
++            val = &uid;
++        } else if (strcasecmp(name, state->sdap_opts->user_map[SDAP_AT_USER_GID].name) == 0) {
++            val = &gid;
++        } else {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Unexpected attribute\n");
++            continue;
++        }
++
++        ret = sysdb_attrs_get_string(reply[i],
++                                     AD_AT_SCHEMA_IS_REPL,
++                                     &is_in_partial_set);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_MINOR_FAILURE, "Cannot get "AD_AT_SCHEMA_IS_REPL);
++            continue;
++        }
++
++        if (strcasecmp(is_in_partial_set, "true") == 0) {
++            *val = true;
++        }
++    }
++
++    if (uid == true && gid == true) {
++        state->is_gc_usable = true;
++    }
++
++    if (state->is_gc_usable == true) {
++        DEBUG(SSSDBG_FUNC_DATA, "Server has POSIX attributes. Global Catalog will "
++                                "be used for user and group lookups. Note that if "
++                                "only a subset of POSIX attributes is present "
++                                "in GC, the non-replicated attributes are "
++                                "currently not read from the LDAP port\n");
++    }
++
++    tevent_req_done(req);
++}
++
++static errno_t ad_check_gc_usability_recv(struct tevent_req *req,
++                                          bool *_is_gc_usable)
++{
++    struct ad_check_gc_usability_state *state = NULL;
++
++    state = tevent_req_data(req, struct ad_check_gc_usability_state);
++
++    TEVENT_REQ_RETURN_ON_ERROR(req);
++
++    *_is_gc_usable = state->is_gc_usable;
++    return EOK;
++}
++
+ struct ad_subdomains_refresh_state {
+     struct tevent_context *ev;
+     struct be_ctx *be_ctx;
+@@ -1268,11 +1504,14 @@ struct ad_subdomains_refresh_state {
+     struct sdap_id_op *sdap_op;
+     struct sdap_id_ctx *id_ctx;
+     struct ad_options *ad_options;
++
++    char *forest;
+ };
+ 
+ static errno_t ad_subdomains_refresh_retry(struct tevent_req *req);
+ static void ad_subdomains_refresh_connect_done(struct tevent_req *subreq);
+ static void ad_subdomains_refresh_master_done(struct tevent_req *subreq);
++static void ad_subdomains_refresh_gc_check_done(struct tevent_req *subreq);
+ static void ad_subdomains_refresh_root_done(struct tevent_req *subreq);
+ static void ad_subdomains_refresh_done(struct tevent_req *subreq);
+ 
+@@ -1385,37 +1624,73 @@ static void ad_subdomains_refresh_master_done(struct tevent_req *subreq)
+     struct ad_subdomains_refresh_state *state;
+     struct tevent_req *req;
+     const char *realm;
+-    const char *ad_domain;
+     char *master_sid;
+     char *flat_name;
+-    char *forest;
+     errno_t ret;
+ 
+     req = tevent_req_callback_data(subreq, struct tevent_req);
+     state = tevent_req_data(req, struct ad_subdomains_refresh_state);
+ 
+     ret = ad_master_domain_recv(subreq, state, &flat_name, &master_sid,
+-                                NULL, &forest);
++                                NULL, &state->forest);
+     talloc_zfree(subreq);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get master domain information "
+               "[%d]: %s\n", ret, sss_strerror(ret));
+-        goto done;
++        tevent_req_error(req, ret);
++        return;
+     }
+ 
+     realm = dp_opt_get_cstring(state->ad_options->basic, AD_KRB5_REALM);
+     if (realm == NULL) {
+         DEBUG(SSSDBG_CONF_SETTINGS, "Missing realm.\n");
+-        ret = EINVAL;
+-        goto done;
++        tevent_req_error(req, EINVAL);
++        return;
+     }
+ 
+     ret = sysdb_master_domain_add_info(state->be_ctx->domain, realm,
+-                                       flat_name, master_sid, forest, NULL);
++                                       flat_name, master_sid, state->forest, NULL);
+     if (ret != EOK) {
+         DEBUG(SSSDBG_OP_FAILURE, "Cannot save master domain info [%d]: %s\n",
+               ret, sss_strerror(ret));
+-        goto done;
++        tevent_req_error(req, ret);
++        return;
++    }
++
++    subreq = ad_check_gc_usability_send(state,
++                                        state->ev,
++                                        state->ad_options,
++                                        state->id_ctx->opts,
++                                        state->sdap_op,
++                                        state->be_ctx->domain->name,
++                                        master_sid);
++    if (subreq == NULL) {
++        tevent_req_error(req, ENOMEM);
++        return;
++    }
++    tevent_req_set_callback(subreq, ad_subdomains_refresh_gc_check_done, req);
++}
++
++static void ad_subdomains_refresh_gc_check_done(struct tevent_req *subreq)
++{
++    struct ad_subdomains_refresh_state *state;
++    struct tevent_req *req;
++    const char *ad_domain;
++    bool is_gc_usable;
++    errno_t ret;
++
++    req = tevent_req_callback_data(subreq, struct tevent_req);
++    state = tevent_req_data(req, struct ad_subdomains_refresh_state);
++
++    ret = ad_check_gc_usability_recv(subreq, &is_gc_usable);
++    talloc_zfree(subreq);
++    if (ret != EOK) {
++        DEBUG(SSSDBG_MINOR_FAILURE, "Unable to get GC usability status\n");
++        is_gc_usable = false;
++    }
++
++    if (is_gc_usable == false) {
++        ad_disable_gc(state->ad_options);
+     }
+ 
+     /*
+@@ -1428,7 +1703,8 @@ static void ad_subdomains_refresh_master_done(struct tevent_req *subreq)
+                            state->be_ctx->domain->name) == 0) {
+                 DEBUG(SSSDBG_TRACE_FUNC,
+                       "No other enabled domain than master.\n");
+-                goto done;
++                tevent_req_done(req);
++                return;
+             }
+         }
+     }
+@@ -1440,24 +1716,16 @@ static void ad_subdomains_refresh_master_done(struct tevent_req *subreq)
+         ad_domain = state->sd_ctx->be_ctx->domain->name;
+     }
+ 
+-    subreq = ad_get_root_domain_send(state, state->ev, ad_domain, forest,
++    subreq = ad_get_root_domain_send(state, state->ev, ad_domain, state->forest,
+                                      sdap_id_op_handle(state->sdap_op),
+                                      state->sd_ctx);
+     if (subreq == NULL) {
+-        ret = ENOMEM;
+-        goto done;
++        tevent_req_error(req, ENOMEM);
++        return;
+     }
+ 
+     tevent_req_set_callback(subreq, ad_subdomains_refresh_root_done, req);
+     return;
+-
+-done:
+-    if (ret != EOK) {
+-        tevent_req_error(req, ret);
+-        return;
+-    }
+-
+-    tevent_req_done(req);
+ }
+ 
+ static void ad_subdomains_refresh_root_done(struct tevent_req *subreq)
+-- 
+2.17.1
+
diff --git a/SOURCES/0034-CHILD-Pass-information-about-logger-to-children.patch b/SOURCES/0034-CHILD-Pass-information-about-logger-to-children.patch
deleted file mode 100644
index a254cd8..0000000
--- a/SOURCES/0034-CHILD-Pass-information-about-logger-to-children.patch
+++ /dev/null
@@ -1,198 +0,0 @@
-From 3ada67750d3d0dc6188c03cc996b98e7578971a4 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Wed, 8 Nov 2017 08:13:02 +0100
-Subject: [PATCH 34/35] CHILD: Pass information about logger to children
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Variables debug_to_file or debug_to_stderr were not set
-because back-end already user parameter --logger=%s.
-And therefore logs were not sent to files.
-
-It could only work in case of direct usage of --debug-to-files in back-end via
-command configuration option.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3433
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit a24954cc19285b197fb287bfa7aa01949c92b17d)
----
- src/p11_child/p11_child_nss.c     |  4 +++-
- src/providers/ad/ad_gpo_child.c   |  3 ++-
- src/providers/ipa/selinux_child.c |  3 ++-
- src/providers/krb5/krb5_child.c   |  3 ++-
- src/providers/ldap/ldap_child.c   |  3 ++-
- src/util/child_common.c           | 24 ++++++++++--------------
- 6 files changed, 21 insertions(+), 19 deletions(-)
-
-diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
-index e7dbcb689220d1cd2585fbde5f26e84f8fa15cc2..b0ec69be321c4b4186ce851c07bfcc3e1afe9694 100644
---- a/src/p11_child/p11_child_nss.c
-+++ b/src/p11_child/p11_child_nss.c
-@@ -537,7 +537,7 @@ int main(int argc, const char *argv[])
-     int opt;
-     poptContext pc;
-     int debug_fd = -1;
--    char *opt_logger = NULL;
-+    const char *opt_logger = NULL;
-     errno_t ret;
-     TALLOC_CTX *main_ctx = NULL;
-     char *cert;
-@@ -673,7 +673,9 @@ int main(int argc, const char *argv[])
-         if (ret != EOK) {
-             DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n");
-         }
-+        opt_logger = sss_logger_str[FILES_LOGGER];
-     }
-+
-     sss_set_logger(opt_logger);
- 
-     DEBUG(SSSDBG_TRACE_FUNC, "p11_child started.\n");
-diff --git a/src/providers/ad/ad_gpo_child.c b/src/providers/ad/ad_gpo_child.c
-index 5375cc691e8649c289672b74c4bfe5266c8222c9..a0bd6e13a31fe0f92924d49302d1b8b17bac4d67 100644
---- a/src/providers/ad/ad_gpo_child.c
-+++ b/src/providers/ad/ad_gpo_child.c
-@@ -687,7 +687,7 @@ main(int argc, const char *argv[])
-     int opt;
-     poptContext pc;
-     int debug_fd = -1;
--    char *opt_logger = NULL;
-+    const char *opt_logger = NULL;
-     errno_t ret;
-     int sysvol_gpt_version;
-     int result;
-@@ -744,6 +744,7 @@ main(int argc, const char *argv[])
-         if (ret != EOK) {
-             DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n");
-         }
-+        opt_logger = sss_logger_str[FILES_LOGGER];
-     }
- 
-     sss_set_logger(opt_logger);
-diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c
-index 120492686963241b7e419413f489cc38953e32f2..a7e20f715626d0f3ecef7cc06f3de5d44b6a15c1 100644
---- a/src/providers/ipa/selinux_child.c
-+++ b/src/providers/ipa/selinux_child.c
-@@ -206,7 +206,7 @@ int main(int argc, const char *argv[])
-     struct response *resp = NULL;
-     ssize_t written;
-     bool needs_update;
--    char *opt_logger = NULL;
-+    const char *opt_logger = NULL;
- 
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-@@ -254,6 +254,7 @@ int main(int argc, const char *argv[])
-         if (ret != EOK) {
-             DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n");
-         }
-+        opt_logger = sss_logger_str[FILES_LOGGER];
-     }
- 
-     sss_set_logger(opt_logger);
-diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
-index 700338e47a3f9ac6fcf11b4c92364dbdb4f9bcf7..7b56002377ac22472c3eea1aef687109757c22db 100644
---- a/src/providers/krb5/krb5_child.c
-+++ b/src/providers/krb5/krb5_child.c
-@@ -3020,7 +3020,7 @@ int main(int argc, const char *argv[])
-     int opt;
-     poptContext pc;
-     int debug_fd = -1;
--    char *opt_logger = NULL;
-+    const char *opt_logger = NULL;
-     errno_t ret;
-     krb5_error_code kerr;
-     uid_t fast_uid;
-@@ -3097,6 +3097,7 @@ int main(int argc, const char *argv[])
-         if (ret != EOK) {
-             DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n");
-         }
-+        opt_logger = sss_logger_str[FILES_LOGGER];
-     }
- 
-     sss_set_logger(opt_logger);
-diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c
-index baeed239db5dc7ffa482edcbc155f25f718c8249..c0618d6d8828f102c32cf56731995e2b370590e7 100644
---- a/src/providers/ldap/ldap_child.c
-+++ b/src/providers/ldap/ldap_child.c
-@@ -599,7 +599,7 @@ int main(int argc, const char *argv[])
-     int kerr;
-     int opt;
-     int debug_fd = -1;
--    char *opt_logger = NULL;
-+    const char *opt_logger = NULL;
-     poptContext pc;
-     TALLOC_CTX *main_ctx = NULL;
-     uint8_t *buf = NULL;
-@@ -657,6 +657,7 @@ int main(int argc, const char *argv[])
-         if (ret != EOK) {
-             DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n");
-         }
-+        opt_logger = sss_logger_str[FILES_LOGGER];
-     }
- 
-     sss_set_logger(opt_logger);
-diff --git a/src/util/child_common.c b/src/util/child_common.c
-index dc070f26446305e07cbb34edd1e4d72db72aedc5..203c115f9e7c4ecc2178b5660473d4f960fbbb6d 100644
---- a/src/util/child_common.c
-+++ b/src/util/child_common.c
-@@ -630,14 +630,11 @@ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx,
-     }
- 
-     /* Save the current state in case an interrupt changes it */
--    bool child_debug_to_file = debug_to_file;
-     bool child_debug_timestamps = debug_timestamps;
-     bool child_debug_microseconds = debug_microseconds;
--    bool child_debug_stderr = debug_to_stderr;
- 
-     if (!extra_args_only) {
--        if (child_debug_to_file) argc++;
--        if (child_debug_stderr) argc++;
-+        argc++;
-     }
- 
-     if (extra_argv) {
-@@ -675,21 +672,20 @@ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx,
-             goto fail;
-         }
- 
--        if (child_debug_stderr) {
--            argv[--argc] = talloc_strdup(argv, "--logger=stderr");
--            if (argv[argc] == NULL) {
--                ret = ENOMEM;
--                goto fail;
--            }
--        }
--
--        if (child_debug_to_file) {
-+        if (sss_logger == FILES_LOGGER) {
-             argv[--argc] = talloc_asprintf(argv, "--debug-fd=%d",
-                                            child_debug_fd);
-             if (argv[argc] == NULL) {
-                 ret = ENOMEM;
-                 goto fail;
-             }
-+        } else {
-+            argv[--argc] = talloc_asprintf(argv, "--logger=%s",
-+                                           sss_logger_str[sss_logger]);
-+            if (argv[argc] == NULL) {
-+                ret = ENOMEM;
-+                goto fail;
-+            }
-         }
- 
-         argv[--argc] = talloc_asprintf(argv, "--debug-timestamps=%d",
-@@ -816,7 +812,7 @@ errno_t child_debug_init(const char *logfile, int *debug_fd)
-         return EOK;
-     }
- 
--    if (debug_to_file != 0 && *debug_fd == -1) {
-+    if (sss_logger == FILES_LOGGER && *debug_fd == -1) {
-         ret = open_debug_file_ex(logfile, &debug_filep, false);
-         if (ret != EOK) {
-             DEBUG(SSSDBG_FATAL_FAILURE, "Error setting up logging (%d) [%s]\n",
--- 
-2.13.6
-
diff --git a/SOURCES/0035-LDAP-Improve-error-treatment-from-sdap_cli_connect-i.patch b/SOURCES/0035-LDAP-Improve-error-treatment-from-sdap_cli_connect-i.patch
deleted file mode 100644
index 0854ab3..0000000
--- a/SOURCES/0035-LDAP-Improve-error-treatment-from-sdap_cli_connect-i.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-From 1f46fa6760913de0f757e39106936d24e5736912 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
-Date: Tue, 7 Nov 2017 23:34:42 +0100
-Subject: [PATCH 35/35] LDAP: Improve error treatment from sdap_cli_connect()
- in ldap_auth
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Because we weren't treating the errors coming from
-sdap_cli_connect_recv() properly we ended up introducing a regression in
-the commit add72860c7, related to offline authentication.
-
-From now on, let's properly treat errors coming from auth_connect_send(),
-which were treated before by going offline when be_resolve_server_recv()
-failed, and propagate ETIMEDOUT to the request, thus going offline and
-allowing offline authentication on those cases.
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3451
-
-Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 20d18db36096e3fa2636143a83a12a2e3a7f26d6)
----
- src/providers/ldap/ldap_auth.c | 16 ++++++++++++++--
- 1 file changed, 14 insertions(+), 2 deletions(-)
-
-diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c
-index a3b1480aae4272d2e10f105a1eaf3a5816c3487c..2e0e2cfd6f8af2bf0c9ad15bd956a55a34777a3c 100644
---- a/src/providers/ldap/ldap_auth.c
-+++ b/src/providers/ldap/ldap_auth.c
-@@ -716,8 +716,20 @@ static void auth_connect_done(struct tevent_req *subreq)
-     ret = sdap_cli_connect_recv(subreq, state, NULL, &state->sh, NULL);
-     talloc_zfree(subreq);
-     if (ret != EOK) {
--        if (auth_connect_send(req) == NULL) {
--            tevent_req_error(req, ENOMEM);
-+        /* As sdap_cli_connect_recv() returns EIO in case all the servers are
-+         * down and we have to go offline, let's treat it accordingly here and
-+         * allow the PAM responder to with to offline authentication.
-+         *
-+         * Unfortunately, there's not much pattern within our code and the way
-+         * to indicate we're going down in this part of the code is returning
-+         * an ETIMEDOUT.
-+         */
-+        if (ret == EIO) {
-+            tevent_req_error(req, ETIMEDOUT);
-+        } else {
-+            if (auth_connect_send(req) == NULL) {
-+                tevent_req_error(req, ENOMEM);
-+            }
-         }
-         return;
-     }
--- 
-2.13.6
-
diff --git a/SOURCES/0035-SDAP-Detect-schemaNamingContext-from-the-rootDSE.patch b/SOURCES/0035-SDAP-Detect-schemaNamingContext-from-the-rootDSE.patch
new file mode 100644
index 0000000..6397fc5
--- /dev/null
+++ b/SOURCES/0035-SDAP-Detect-schemaNamingContext-from-the-rootDSE.patch
@@ -0,0 +1,92 @@
+From bf4580b2f893cfb29d804a9fe6bb2d6247bb5cf2 Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Sun, 8 Jul 2018 22:17:41 +0200
+Subject: [PATCH] SDAP: Detect schemaNamingContext from the rootDSE
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Whether an attribute is replicated to the Global Catalog or not can be
+detected by checking the value of the isMemberOfPartialAttributeSet
+attribute:
+https://docs.microsoft.com/en-us/windows/desktop/ADSchema/a-ismemberofpartialattributeset
+
+This attribute is present in all objects with the objectClass
+attributeSchema in AD:
+https://docs.microsoft.com/en-us/windows/desktop/AD/characteristics-of-attributes
+
+And finally, the attributeSchema objects in AD are present in a schema
+naming context. The schema naming context is replicated to all DCs in the
+forest even though their own naming context might be different:
+https://docs.microsoft.com/en-us/windows/desktop/ad/naming-contexts-and-partitions
+
+Where the schema naming context is located is given by the
+schemaNamingContext attribute of the rootDSE.
+
+This patch is trivial on its own and just reads schemaNamingContext from
+the rootDSE and stores it in the sdap_options structure for later use.
+
+Related:
+https://pagure.io/SSSD/sssd/issue/3755
+
+Reviewed-by: Pavel Březina <pbrezina@redhat.com>
+(cherry picked from commit c8d1c1b734a1763b3e1233f060cc5c8d6db078e9)
+---
+ src/providers/ldap/sdap.c | 10 ++++++++++
+ src/providers/ldap/sdap.h |  3 +++
+ 2 files changed, 13 insertions(+)
+
+diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
+index 0241a99e49e94345753399d5d62639c99b95ee77..5c9d0a45dfb96e8901467aa6a3391b8df84f6d42 100644
+--- a/src/providers/ldap/sdap.c
++++ b/src/providers/ldap/sdap.c
+@@ -1284,6 +1284,7 @@ int sdap_get_server_opts_from_rootdse(TALLOC_CTX *memctx,
+     const char *last_usn_name;
+     const char *last_usn_value;
+     const char *entry_usn_name;
++    const char *schema_nc = NULL;
+     char *endptr = NULL;
+     int ret;
+     int i;
+@@ -1400,6 +1401,15 @@ int sdap_get_server_opts_from_rootdse(TALLOC_CTX *memctx,
+                    "(%s). Continuing without AD performance enhancements\n",
+                    strerror(ret));
+         }
++
++        ret = sysdb_attrs_get_string(rootdse,
++                                     SDAP_ROOTDSE_ATTR_AD_SCHEMA_NC,
++                                     &schema_nc);
++        if (ret == EOK) {
++            DEBUG(SSSDBG_CONF_SETTINGS,
++                  "Will look for schema at [%s]\n", schema_nc);
++            opts->schema_basedn = talloc_strdup(opts, schema_nc);
++        }
+     }
+ 
+     if (!last_usn_name) {
+diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
+index 0790544818633e26ee5a8fbdca556b8230b1df3f..31c25c32f059b4290a7511600cee638ee7a269e8 100644
+--- a/src/providers/ldap/sdap.h
++++ b/src/providers/ldap/sdap.h
+@@ -130,6 +130,7 @@ struct sdap_ppolicy_data {
+ #define SDAP_ROOTDSE_ATTR_NAMING_CONTEXTS "namingContexts"
+ #define SDAP_ROOTDSE_ATTR_DEFAULT_NAMING_CONTEXT "defaultNamingContext"
+ #define SDAP_ROOTDSE_ATTR_AD_VERSION "domainControllerFunctionality"
++#define SDAP_ROOTDSE_ATTR_AD_SCHEMA_NC "schemaNamingContext"
+ 
+ #define SDAP_IPA_USN "entryUSN"
+ #define SDAP_IPA_LAST_USN "lastUSN"
+@@ -496,8 +497,10 @@ struct sdap_options {
+     /* The search bases for the domain or its subdomain */
+     struct sdap_domain *sdom;
+ 
++    /* The options below are normally only used with AD */
+     bool support_matching_rule;
+     enum dc_functional_level dc_functional_level;
++    const char *schema_basedn;
+ 
+     /* Certificate mapping support */
+     struct sdap_certmap_ctx *sdap_certmap_ctx;
+-- 
+2.17.1
+
diff --git a/SOURCES/0036-deskprofile-don-t-bail-if-we-fail-to-save-one-profil.patch b/SOURCES/0036-deskprofile-don-t-bail-if-we-fail-to-save-one-profil.patch
new file mode 100644
index 0000000..820722b
--- /dev/null
+++ b/SOURCES/0036-deskprofile-don-t-bail-if-we-fail-to-save-one-profil.patch
@@ -0,0 +1,45 @@
+From ef96cf36996d9e5802e529e5e812515ec3bda65c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
+Date: Thu, 12 Jul 2018 23:55:03 +0200
+Subject: [PATCH] deskprofile: don't bail if we fail to save one profile
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Due to different reasons (a bug on fleet-commander, for instance?) we
+may face the situation where one profile ends up stored in freeipa on a
+half-broken state (with no data, for instance).
+
+In case it happens, we should try our best to save the not broken
+profiles and just skip the broken ones instead of bailing the whole
+operation.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3773
+
+Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit efd6702e5f70bb3df0f840dd3ce9f8f9264661ba)
+
+DOWNSTREAM:
+Resolves: rhbz#1600822 - SSSD bails out saving desktop profiles in case an invalid profile is found
+---
+ src/providers/ipa/ipa_session.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/providers/ipa/ipa_session.c b/src/providers/ipa/ipa_session.c
+index 25ad5ce519e6923d7a4d8aa81e72b109ae36dbe1..33c64e5b7af9bd3353770f422be42a0b6ac23e09 100644
+--- a/src/providers/ipa/ipa_session.c
++++ b/src/providers/ipa/ipa_session.c
+@@ -768,7 +768,7 @@ ipa_pam_session_handler_save_deskprofile_rules(
+             DEBUG(SSSDBG_OP_FAILURE,
+                   "Failed to save a Desktop Profile Rule to disk [%d]: %s\n",
+                   ret, sss_strerror(ret));
+-            goto done;
++            continue;
+         }
+     }
+ 
+-- 
+2.17.1
+
diff --git a/SOURCES/0036-p11_child-return-multiple-certs.patch b/SOURCES/0036-p11_child-return-multiple-certs.patch
deleted file mode 100644
index d504f7f..0000000
--- a/SOURCES/0036-p11_child-return-multiple-certs.patch
+++ /dev/null
@@ -1,598 +0,0 @@
-From 426dd731fe7c804c4b9d96c62d1a60a9022dcb09 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 17 Jan 2017 15:55:18 +0100
-Subject: [PATCH 36/46] p11_child: return multiple certs
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This patch refactors the handling of certificates in p11_child. Not only
-the first but all certificates suitable for authentication are returned.
-The PAM responder component calling p11_child is refactored to handle
-multiple certificate returned by p11_child but so far only returns the
-first one to its callers.
-
-Related to https://pagure.io/SSSD/sssd/issue/3560
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Tested-by: Scott Poore <spoore@redhat.com>
-(cherry picked from commit 39fd336e4390ece3a8465714735ef4203f329e54)
----
- src/p11_child/p11_child_nss.c  | 131 +++++++++++++---------
- src/responder/pam/pamsrv.h     |   2 +
- src/responder/pam/pamsrv_p11.c | 242 +++++++++++++++++++++++------------------
- 3 files changed, 219 insertions(+), 156 deletions(-)
-
-diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
-index b0ec69be321c4b4186ce851c07bfcc3e1afe9694..50bde2f4f91f6c00260b0db383d0962112686ebc 100644
---- a/src/p11_child/p11_child_nss.c
-+++ b/src/p11_child/p11_child_nss.c
-@@ -72,8 +72,7 @@ static char *password_passthrough(PK11SlotInfo *slot, PRBool retry, void *arg)
- int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in,
-             enum op_mode mode, const char *pin,
-             struct cert_verify_opts *cert_verify_opts,
--            char **cert, char **token_name_out, char **module_name_out,
--            char **key_id_out)
-+            char **_multi)
- {
-     int ret;
-     SECStatus rv;
-@@ -110,7 +109,10 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in,
-     PK11SlotListElement *le;
-     SECItem *key_id = NULL;
-     char *key_id_str = NULL;
--
-+    CERTCertList *valid_certs = NULL;
-+    char *cert_b64 = NULL;
-+    char *multi = NULL;
-+    PRCList *node;
- 
-     nss_ctx = NSS_InitContext(nss_db, "", "", SECMOD_DB, &parameters, flags);
-     if (nss_ctx == NULL) {
-@@ -303,6 +305,14 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in,
-     }
- 
-     found_cert = NULL;
-+    valid_certs = CERT_NewCertList();
-+    if (valid_certs == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "CERT_NewCertList failed [%d].\n",
-+                                 PR_GetError());
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-     DEBUG(SSSDBG_TRACE_ALL, "Filtered certificates:\n");
-     for (cert_list_node = CERT_LIST_HEAD(cert_list);
-                 !CERT_LIST_END(cert_list_node, cert_list);
-@@ -326,6 +336,13 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in,
-                 }
-             }
- 
-+            rv = CERT_AddCertToListTail(valid_certs, cert_list_node->cert);
-+            if (rv != SECSuccess) {
-+                DEBUG(SSSDBG_OP_FAILURE,
-+                      "CERT_AddCertToListTail failed [%d].\n", PR_GetError());
-+                ret = EIO;
-+                goto done;
-+            }
- 
-             if (found_cert == NULL) {
-                 found_cert = cert_list_node->cert;
-@@ -352,9 +369,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in,
- 
-     if (found_cert == NULL) {
-         DEBUG(SSSDBG_TRACE_ALL, "No certificate found.\n");
--        *cert = NULL;
--        *token_name_out = NULL;
--        *module_name_out = NULL;
-+        *_multi = NULL;
-         ret = EOK;
-         goto done;
-     }
-@@ -421,51 +436,55 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in,
-               "Certificate verified and validated.\n");
-     }
- 
--    key_id = PK11_GetLowLevelKeyIDForCert(slot, found_cert, NULL);
--    if (key_id == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "PK11_GetLowLevelKeyIDForCert failed [%d].\n",
--                                 PR_GetError());
--        ret = EINVAL;
--        goto done;
--    }
--
--    key_id_str = CERT_Hexify(key_id, PR_FALSE);
--    if (key_id_str == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d].\n", PR_GetError());
-+    multi = talloc_strdup(mem_ctx, "");
-+    if (multi == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create output string.\n");
-         ret = ENOMEM;
-         goto done;
-     }
- 
--    DEBUG(SSSDBG_TRACE_ALL, "Found certificate has key id [%s].\n", key_id_str);
-+    for (cert_list_node = CERT_LIST_HEAD(valid_certs);
-+                !CERT_LIST_END(cert_list_node, valid_certs);
-+                cert_list_node = CERT_LIST_NEXT(cert_list_node)) {
- 
--    *key_id_out = talloc_strdup(mem_ctx, key_id_str);
--    if (*key_id_out == NULL) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy key id.\n");
--        ret = ENOMEM;
--        goto done;
--    }
-+        found_cert = cert_list_node->cert;
- 
--    *cert = sss_base64_encode(mem_ctx, found_cert->derCert.data,
--                                       found_cert->derCert.len);
--    if (*cert == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "sss_base64_encode failed.\n");
--        ret = ENOMEM;
--        goto done;
--    }
-+        SECITEM_FreeItem(key_id, PR_TRUE);
-+        PORT_Free(key_id_str);
-+        key_id = PK11_GetLowLevelKeyIDForCert(slot, found_cert, NULL);
-+        if (key_id == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "PK11_GetLowLevelKeyIDForCert failed [%d].\n",
-+                  PR_GetError());
-+            ret = EINVAL;
-+            goto done;
-+        }
- 
--    *token_name_out = talloc_strdup(mem_ctx, token_name);
--    if (*token_name_out == NULL) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy slot name.\n");
--        ret = ENOMEM;
--        goto done;
--    }
-+        key_id_str = CERT_Hexify(key_id, PR_FALSE);
-+        if (key_id_str == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d].\n",
-+                  PR_GetError());
-+            ret = ENOMEM;
-+            goto done;
-+        }
- 
--    *module_name_out = talloc_strdup(mem_ctx, module_name);
--    if (*module_name_out == NULL) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy module_name_out name.\n");
--        ret = ENOMEM;
--        goto done;
-+        talloc_free(cert_b64);
-+        cert_b64 = sss_base64_encode(mem_ctx, found_cert->derCert.data,
-+                                     found_cert->derCert.len);
-+        if (cert_b64 == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "sss_base64_encode failed.\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+
-+        DEBUG(SSSDBG_TRACE_ALL, "Found certificate has key id [%s].\n",
-+              key_id_str);
-+
-+        multi = talloc_asprintf_append(multi, "%s\n%s\n%s\n%s\n",
-+                                       token_name, module_name, key_id_str,
-+                                       cert_b64);
-     }
-+    *_multi = multi;
- 
-     ret = EOK;
- 
-@@ -474,6 +493,18 @@ done:
-         PK11_FreeSlot(slot);
-     }
- 
-+    if (valid_certs != NULL) {
-+        /* The certificates can be found in valid_certs and cert_list and
-+         * CERT_DestroyCertList() will free the certificates as well. To avoid
-+         * a double free the nodes from valid_certs are removed first because
-+         * valid_certs will only have a sub-set of the certificates. */
-+        while (!PR_CLIST_IS_EMPTY(&valid_certs->list)) {
-+            node = PR_LIST_HEAD(&valid_certs->list);
-+            PR_REMOVE_LINK(node);
-+        }
-+        CERT_DestroyCertList(valid_certs);
-+    }
-+
-     if (cert_list != NULL) {
-         CERT_DestroyCertList(cert_list);
-     }
-@@ -483,6 +514,8 @@ done:
- 
-     PORT_Free(signed_random_value.data);
- 
-+    talloc_free(cert_b64);
-+
-     rv = NSS_ShutdownContext(nss_ctx);
-     if (rv != SECSuccess) {
-         DEBUG(SSSDBG_OP_FAILURE, "NSS_ShutdownContext failed [%d].\n",
-@@ -540,17 +573,14 @@ int main(int argc, const char *argv[])
-     const char *opt_logger = NULL;
-     errno_t ret;
-     TALLOC_CTX *main_ctx = NULL;
--    char *cert;
-     enum op_mode mode = OP_NONE;
-     enum pin_mode pin_mode = PIN_NONE;
-     char *pin = NULL;
-     char *slot_name_in = NULL;
--    char *token_name_out = NULL;
--    char *module_name_out = NULL;
--    char *key_id_out = NULL;
-     char *nss_db = NULL;
-     struct cert_verify_opts *cert_verify_opts;
-     char *verify_opts = NULL;
-+    char *multi = NULL;
- 
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-@@ -715,17 +745,14 @@ int main(int argc, const char *argv[])
-     }
- 
-     ret = do_work(main_ctx, nss_db, slot_name_in, mode, pin, cert_verify_opts,
--                  &cert, &token_name_out, &module_name_out, &key_id_out);
-+                  &multi);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "do_work failed.\n");
-         goto fail;
-     }
- 
--    if (cert != NULL) {
--        fprintf(stdout, "%s\n", token_name_out);
--        fprintf(stdout, "%s\n", module_name_out);
--        fprintf(stdout, "%s\n", key_id_out);
--        fprintf(stdout, "%s\n", cert);
-+    if (multi != NULL) {
-+        fprintf(stdout, "%s", multi);
-     }
- 
-     talloc_free(main_ctx);
-diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
-index 57a37b72594f030995f5e22255eb7a8fcd63d10e..896f71befbc9947a53b5eb20cba0bb3d104c4cf2 100644
---- a/src/responder/pam/pamsrv.h
-+++ b/src/responder/pam/pamsrv.h
-@@ -88,6 +88,8 @@ int LOCAL_pam_handler(struct pam_auth_req *preq);
- 
- errno_t p11_child_init(struct pam_ctx *pctx);
- 
-+struct cert_auth_info;
-+
- struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
-                                        struct tevent_context *ev,
-                                        int child_debug_fd,
-diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
-index 4dce43800c3c6b026c545df35c846269cbb49610..ff32d1e726808caa36ca7cca557220866ef1a9ab 100644
---- a/src/responder/pam/pamsrv_p11.c
-+++ b/src/responder/pam/pamsrv_p11.c
-@@ -35,6 +35,15 @@
- #define P11_CHILD_LOG_FILE "p11_child"
- #define P11_CHILD_PATH SSSD_LIBEXEC_PATH"/p11_child"
- 
-+struct cert_auth_info {
-+    char *cert;
-+    char *token_name;
-+    char *module_name;
-+    char *key_id;
-+    struct cert_auth_info *prev;
-+    struct cert_auth_info *next;
-+};
-+
- errno_t p11_child_init(struct pam_ctx *pctx)
- {
-     return child_debug_init(P11_CHILD_LOG_FILE, &pctx->p11_child_debug_fd);
-@@ -132,18 +141,15 @@ static errno_t get_p11_child_write_buffer(TALLOC_CTX *mem_ctx,
- }
- 
- static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf,
--                                        ssize_t buf_len, char **_cert,
--                                        char **_token_name, char **_module_name,
--                                        char **_key_id)
-+                                        ssize_t buf_len,
-+                                        struct cert_auth_info **_cert_list)
- {
-     int ret;
-     TALLOC_CTX *tmp_ctx = NULL;
-     uint8_t *p;
-     uint8_t *pn;
--    char *cert = NULL;
--    char *token_name = NULL;
--    char *module_name = NULL;
--    char *key_id = NULL;
-+    struct cert_auth_info *cert_list = NULL;
-+    struct cert_auth_info *cert_auth_info;
- 
-     if (buf_len < 0) {
-         DEBUG(SSSDBG_CRIT_FAILURE,
-@@ -157,108 +163,132 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf,
-         goto done;
-     }
- 
--    p = memchr(buf, '\n', buf_len);
--    if (p == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "Missing new-line in p11_child response.\n");
--        return EINVAL;
--    }
--    if (p == buf) {
--        DEBUG(SSSDBG_OP_FAILURE, "Missing counter in p11_child response.\n");
--        return EINVAL;
--    }
--
-     tmp_ctx = talloc_new(NULL);
-     if (tmp_ctx == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
-         return ENOMEM;
-     }
- 
--    token_name = talloc_strndup(tmp_ctx, (char*) buf, (p - buf));
--    if (token_name == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
--        ret = ENOMEM;
--        goto done;
--    }
-+    p = buf;
- 
--    p++;
--    pn = memchr(p, '\n', buf_len - (p - buf));
--    if (pn == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE,
--              "Missing new-line in p11_child response.\n");
--        ret = EINVAL;
--        goto done;
--    }
-+    do {
-+        cert_auth_info = talloc_zero(tmp_ctx, struct cert_auth_info);
-+        if (cert_auth_info == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
-+            return ENOMEM;
-+        }
- 
--    if (pn == p) {
--        DEBUG(SSSDBG_OP_FAILURE,
--              "Missing module name in p11_child response.\n");
--        ret = EINVAL;
--        goto done;
--    }
-+        pn = memchr(p, '\n', buf_len - (p - buf));
-+        if (pn == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Missing new-line in p11_child response.\n");
-+            return EINVAL;
-+        }
-+        if (pn == p) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Missing counter in p11_child response.\n");
-+            return EINVAL;
-+        }
- 
--    module_name = talloc_strndup(tmp_ctx, (char *) p, (pn - p));
--    if (module_name == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
--        ret = ENOMEM;
--        goto done;
--    }
--    DEBUG(SSSDBG_TRACE_ALL, "Found module name [%s].\n", module_name);
-+        cert_auth_info->token_name = talloc_strndup(cert_auth_info, (char *)p,
-+                                                    (pn - p));
-+        if (cert_auth_info->token_name == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+        DEBUG(SSSDBG_TRACE_ALL, "Found token name [%s].\n",
-+              cert_auth_info->token_name);
- 
--    p = ++pn;
--    pn = memchr(p, '\n', buf_len - (p - buf));
--    if (pn == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE,
--              "Missing new-line in p11_child response.\n");
--        ret = EINVAL;
--        goto done;
--    }
-+        p = ++pn;
-+        pn = memchr(p, '\n', buf_len - (p - buf));
-+        if (pn == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Missing new-line in p11_child response.\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
- 
--    if (pn == p) {
--        DEBUG(SSSDBG_OP_FAILURE,
--              "Missing key id in p11_child response.\n");
--        ret = EINVAL;
--        goto done;
--    }
-+        if (pn == p) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Missing module name in p11_child response.\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
- 
--    key_id = talloc_strndup(tmp_ctx, (char *) p, (pn - p));
--    if (key_id == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
--        ret = ENOMEM;
--        goto done;
--    }
--    DEBUG(SSSDBG_TRACE_ALL, "Found key id [%s].\n", key_id);
-+        cert_auth_info->module_name = talloc_strndup(cert_auth_info, (char *)p,
-+                                                     (pn - p));
-+        if (cert_auth_info->module_name == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+        DEBUG(SSSDBG_TRACE_ALL, "Found module name [%s].\n",
-+              cert_auth_info->module_name);
- 
--    p = pn + 1;
--    pn = memchr(p, '\n', buf_len - (p - buf));
--    if (pn == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE,
--              "Missing new-line in p11_child response.\n");
--        ret = EINVAL;
--        goto done;
--    }
-+        p = ++pn;
-+        pn = memchr(p, '\n', buf_len - (p - buf));
-+        if (pn == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Missing new-line in p11_child response.\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
- 
--    if (pn == p) {
--        DEBUG(SSSDBG_OP_FAILURE, "Missing cert in p11_child response.\n");
--        ret = EINVAL;
--        goto done;
--    }
-+        if (pn == p) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Missing key id in p11_child response.\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
- 
--    cert = talloc_strndup(tmp_ctx, (char *) p, (pn - p));
--    if(cert == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
--        ret = ENOMEM;
--        goto done;
--    }
--    DEBUG(SSSDBG_TRACE_ALL, "Found cert [%s].\n", cert);
-+        cert_auth_info->key_id = talloc_strndup(cert_auth_info, (char *)p,
-+                                                (pn - p));
-+        if (cert_auth_info->key_id == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+        DEBUG(SSSDBG_TRACE_ALL, "Found key id [%s].\n", cert_auth_info->key_id);
-+
-+        p = ++pn;
-+        pn = memchr(p, '\n', buf_len - (p - buf));
-+        if (pn == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Missing new-line in p11_child response.\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
-+
-+        if (pn == p) {
-+            DEBUG(SSSDBG_OP_FAILURE, "Missing cert in p11_child response.\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
-+
-+        cert_auth_info->cert = talloc_strndup(cert_auth_info, (char *)p,
-+                                              (pn - p));
-+        if (cert_auth_info->cert == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+        DEBUG(SSSDBG_TRACE_ALL, "Found cert [%s].\n", cert_auth_info->cert);
-+
-+        DLIST_ADD(cert_list, cert_auth_info);
-+
-+        p = ++pn;
-+    } while ((pn - buf) < buf_len);
- 
-     ret = EOK;
- 
- done:
-     if (ret == EOK) {
--        *_token_name = talloc_steal(mem_ctx, token_name);
--        *_cert = talloc_steal(mem_ctx, cert);
--        *_module_name = talloc_steal(mem_ctx, module_name);
--        *_key_id = talloc_steal(mem_ctx, key_id);
-+        DLIST_FOR_EACH(cert_auth_info, cert_list) {
-+            talloc_steal(mem_ctx, cert_auth_info);
-+        }
-+
-+        *_cert_list = cert_list;
-     }
- 
-     talloc_free(tmp_ctx);
-@@ -273,10 +303,8 @@ struct pam_check_cert_state {
-     struct tevent_context *ev;
- 
-     struct child_io_fds *io;
--    char *cert;
--    char *token_name;
--    char *module_name;
--    char *key_id;
-+
-+    struct cert_auth_info *cert_list;
- };
- 
- static void p11_child_write_done(struct tevent_req *subreq);
-@@ -349,9 +377,6 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
- 
-     state->ev = ev;
-     state->child_status = EFAULT;
--    state->cert = NULL;
--    state->token_name = NULL;
--    state->module_name = NULL;
-     state->io = talloc(state, struct child_io_fds);
-     if (state->io == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
-@@ -514,11 +539,9 @@ static void p11_child_done(struct tevent_req *subreq)
- 
-     PIPE_FD_CLOSE(state->io->read_from_child_fd);
- 
--    ret = parse_p11_child_response(state, buf, buf_len, &state->cert,
--                                   &state->token_name, &state->module_name,
--                                   &state->key_id);
-+    ret = parse_p11_child_response(state, buf, buf_len, &state->cert_list);
-     if (ret != EOK) {
--        DEBUG(SSSDBG_OP_FAILURE, "parse_p11_child_respose failed.\n");
-+        DEBUG(SSSDBG_OP_FAILURE, "parse_p11_child_response failed.\n");
-         tevent_req_error(req, ret);
-         return;
-     }
-@@ -551,20 +574,31 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
- 
-     TEVENT_REQ_RETURN_ON_ERROR(req);
- 
-+    if (state->cert_list == NULL) {
-+        *token_name = NULL;
-+        *cert = NULL;
-+        *module_name = NULL;
-+        *key_id = NULL;
-+    }
-+
-     if (cert != NULL) {
--        *cert = talloc_steal(mem_ctx, state->cert);
-+        *cert = (state->cert_list == NULL) ? NULL
-+                                : talloc_steal(mem_ctx, state->cert_list->cert);
-     }
- 
-     if (token_name != NULL) {
--        *token_name = talloc_steal(mem_ctx, state->token_name);
-+        *token_name = (state->cert_list == NULL) ? NULL
-+                          : talloc_steal(mem_ctx, state->cert_list->token_name);
-     }
- 
-     if (module_name != NULL) {
--        *module_name = talloc_steal(mem_ctx, state->module_name);
-+        *module_name = (state->cert_list == NULL) ? NULL
-+                         : talloc_steal(mem_ctx, state->cert_list->module_name);
-     }
- 
-     if (key_id != NULL) {
--        *key_id = talloc_steal(mem_ctx, state->key_id);
-+        *key_id = (state->cert_list == NULL) ? NULL
-+                              : talloc_steal(mem_ctx, state->cert_list->key_id);
-     }
- 
-     return EOK;
--- 
-2.13.6
-
diff --git a/SOURCES/0037-PAM-handled-multiple-certs-in-the-responder.patch b/SOURCES/0037-PAM-handled-multiple-certs-in-the-responder.patch
deleted file mode 100644
index dfac98b..0000000
--- a/SOURCES/0037-PAM-handled-multiple-certs-in-the-responder.patch
+++ /dev/null
@@ -1,1074 +0,0 @@
-From f4cac6544b5b6fb094d2088bf75f443fb74028bc Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 25 Aug 2017 12:51:09 +0200
-Subject: [PATCH 37/47] PAM: handled multiple certs in the responder
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This patch refactors the handling of the certificate and the attributes
-to address the certificate on the Smartcard (module name, token name and
-key id). Instead of using individual variables the values are put into a
-new struct cert_auth_info. Since the new struct can be used as a list
-the PAM responder can now handle multiple certificates on the Smartcard
-and can send the needed data to pam_sss with multiple SSS_PAM_CERT_INFO
-messages.
-
-Unit tests are added to confirm the expected behavior.
-
-Related to https://pagure.io/SSSD/sssd/issue/3560
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Tested-by: Scott Poore <spoore@redhat.com>
-(cherry picked from commit 0bdd8800c16f39b8fe308d20694ad905c669dff3)
-
-The following binaries have been removed from the original patch:
-- src/tests/cmocka/p11_nssdb_2certs/cert9.db
-- src/tests/cmocka/p11_nssdb_2certs/key4.db
-
-The reason for that is that we can't apply a patch which is a binary
-file using rpm, thus removing the patches here and adding them as source
-files in the sssd.spec seems to be the best solution.
----
- Makefile.am                                  |   2 +
- src/responder/pam/pamsrv.h                   |  25 ++-
- src/responder/pam/pamsrv_cmd.c               | 257 ++++++++++++++++++---------
- src/responder/pam/pamsrv_p11.c               | 181 ++++++++++++++-----
- src/tests/cmocka/p11_nssdb_2certs/pkcs11.txt |   4 +
- src/tests/cmocka/test_pam_srv.c              | 216 +++++++++++++++++++++-
- src/tests/whitespace_test                    |   2 +-
- 7 files changed, 538 insertions(+), 149 deletions(-)
- create mode 100644 src/tests/cmocka/p11_nssdb_2certs/pkcs11.txt
-
-diff --git a/Makefile.am b/Makefile.am
-index bbc90d9bad4d22ca0284ea95281a487d42399c05..4ed872a532daf9b934537cc5f64ce77778121e2a 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -481,6 +481,8 @@ dist_noinst_DATA = \
-     contrib/ci/sssd.supp \
-     src/tests/cmocka/p11_nssdb/cert9.db \
-     src/tests/cmocka/p11_nssdb/key4.db \
-+    src/tests/cmocka/p11_nssdb_2certs/cert9.db \
-+    src/tests/cmocka/p11_nssdb_2certs/key4.db \
-     $(SYSTEMTAP_PROBES) \
-     $(NULL)
- 
-diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
-index 896f71befbc9947a53b5eb20cba0bb3d104c4cf2..f15f7f19f1f38626288416c9f2038371c6f58b47 100644
---- a/src/responder/pam/pamsrv.h
-+++ b/src/responder/pam/pamsrv.h
-@@ -73,10 +73,8 @@ struct pam_auth_req {
-     struct pam_auth_dp_req *dpreq_spy;
- 
-     struct ldb_message *user_obj;
--    struct ldb_result *cert_user_objs;
--    char *token_name;
--    char *module_name;
--    char *key_id;
-+    struct cert_auth_info *cert_list;
-+    struct cert_auth_info *current_cert;
-     bool cert_auth_local;
- };
- 
-@@ -89,6 +87,16 @@ int LOCAL_pam_handler(struct pam_auth_req *preq);
- errno_t p11_child_init(struct pam_ctx *pctx);
- 
- struct cert_auth_info;
-+const char *sss_cai_get_cert(struct cert_auth_info *i);
-+const char *sss_cai_get_token_name(struct cert_auth_info *i);
-+const char *sss_cai_get_module_name(struct cert_auth_info *i);
-+const char *sss_cai_get_key_id(struct cert_auth_info *i);
-+struct cert_auth_info *sss_cai_get_next(struct cert_auth_info *i);
-+struct ldb_result *sss_cai_get_cert_user_objs(struct cert_auth_info *i);
-+void sss_cai_set_cert_user_objs(struct cert_auth_info *i,
-+                                struct ldb_result *cert_user_objs);
-+void sss_cai_check_users(struct cert_auth_info **list, size_t *_cert_count,
-+                         size_t *_cert_user_count);
- 
- struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
-                                        struct tevent_context *ev,
-@@ -98,12 +106,11 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
-                                        const char *verify_opts,
-                                        struct pam_data *pd);
- errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
--                            char **cert, char **token_name, char **module_name,
--                            char **key_id);
-+                            struct cert_auth_info **cert_list);
- 
--errno_t add_pam_cert_response(struct pam_data *pd, const char *user,
--                              const char *token_name, const char *module_name,
--                              const char *key_id, enum response_type type);
-+errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username,
-+                              struct cert_auth_info *cert_info,
-+                              enum response_type type);
- 
- bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd);
- 
-diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
-index 51d8185650cf823da289a3398b10133065d82ae4..8b2c086e206796ad4c977495be957c56b3255e7f 100644
---- a/src/responder/pam/pamsrv_cmd.c
-+++ b/src/responder/pam/pamsrv_cmd.c
-@@ -1389,21 +1389,17 @@ done:
-     return pam_check_user_done(preq, ret);
- }
- 
-+static errno_t pam_user_by_cert_step(struct pam_auth_req *preq);
- static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req);
- static void pam_forwarder_cert_cb(struct tevent_req *req)
- {
-     struct pam_auth_req *preq = tevent_req_callback_data(req,
-                                                          struct pam_auth_req);
--    struct cli_ctx *cctx = preq->cctx;
-     struct pam_data *pd;
-     errno_t ret = EOK;
--    char *cert;
--    struct pam_ctx *pctx =
--            talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
-+    const char *cert;
- 
--    ret = pam_check_cert_recv(req, preq, &cert, &preq->token_name,
--                                                &preq->module_name,
--                                                &preq->key_id);
-+    ret = pam_check_cert_recv(req, preq, &preq->cert_list);
-     talloc_free(req);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "get_cert request failed.\n");
-@@ -1412,6 +1408,8 @@ static void pam_forwarder_cert_cb(struct tevent_req *req)
- 
-     pd = preq->pd;
- 
-+    cert = sss_cai_get_cert(preq->cert_list);
-+
-     if (cert == NULL) {
-         if (pd->logon_name == NULL) {
-             DEBUG(SSSDBG_CRIT_FAILURE,
-@@ -1431,21 +1429,42 @@ static void pam_forwarder_cert_cb(struct tevent_req *req)
-         goto done;
-     }
- 
-+    preq->current_cert = preq->cert_list;
-+    ret = pam_user_by_cert_step(preq);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "pam_user_by_cert_step failed.\n");
-+        goto done;
-+    }
-+
-+    return;
-+
-+done:
-+    pam_check_user_done(preq, ret);
-+}
-+
-+static errno_t pam_user_by_cert_step(struct pam_auth_req *preq)
-+{
-+    struct cli_ctx *cctx = preq->cctx;
-+    struct tevent_req *req;
-+    struct pam_ctx *pctx =
-+            talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
-+
-+    if (preq->current_cert == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Missing certificate data.\n");
-+        return EINVAL;
-+    }
- 
-     req = cache_req_user_by_cert_send(preq, cctx->ev, cctx->rctx,
-                                       pctx->rctx->ncache, 0,
-                                       preq->req_dom_type, NULL,
--                                      cert);
-+                                      sss_cai_get_cert(preq->current_cert));
-     if (req == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n");
--        ret = ENOMEM;
--        goto done;
-+        return ENOMEM;
-     }
-+
-     tevent_req_set_callback(req, pam_forwarder_lookup_by_cert_done, preq);
--    return;
--
--done:
--    pam_check_user_done(preq, ret);
-+    return EOK;
- }
- 
- static errno_t get_results_from_all_domains(TALLOC_CTX *mem_ctx,
-@@ -1511,6 +1530,9 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
-     struct pam_auth_req *preq = tevent_req_callback_data(req,
-                                                          struct pam_auth_req);
-     const char *cert_user = NULL;
-+    size_t cert_count = 0;
-+    size_t cert_user_count = 0;
-+    struct ldb_result *cert_user_objs;
- 
-     ret = cache_req_recv(preq, req, &results);
-     talloc_zfree(req);
-@@ -1521,12 +1543,39 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
- 
-     if (ret == EOK) {
-         ret = get_results_from_all_domains(preq, results,
--                                           &preq->cert_user_objs);
-+                                           &cert_user_objs);
-         if (ret != EOK) {
-             DEBUG(SSSDBG_OP_FAILURE, "get_results_from_all_domains failed.\n");
-             goto done;
-         }
- 
-+        sss_cai_set_cert_user_objs(preq->current_cert, cert_user_objs);
-+    }
-+
-+    preq->current_cert = sss_cai_get_next(preq->current_cert);
-+    if (preq->current_cert != NULL) {
-+        ret = pam_user_by_cert_step(preq);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "pam_user_by_cert_step failed.\n");
-+            goto done;
-+        }
-+        return;
-+    }
-+
-+    sss_cai_check_users(&preq->cert_list, &cert_count, &cert_user_count);
-+    DEBUG(SSSDBG_TRACE_ALL,
-+          "Found [%zu] certificates and [%zu] related users.\n",
-+          cert_count, cert_user_count);
-+
-+    if (cert_user_count == 0) {
-+        if (preq->pd->logon_name == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Missing logon name and no certificate user found.\n");
-+            ret = ENOENT;
-+            goto done;
-+        }
-+    } else {
-+
-         if (preq->pd->logon_name == NULL) {
-             if (preq->pd->cmd != SSS_PAM_PREAUTH) {
-                 DEBUG(SSSDBG_CRIT_FAILURE,
-@@ -1535,9 +1584,39 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
-                 goto done;
-             }
- 
--            if (preq->cert_user_objs->count == 1) {
-+            if (cert_count > 1) {
-+                for (preq->current_cert = preq->cert_list;
-+                     preq->current_cert != NULL;
-+                     preq->current_cert = sss_cai_get_next(preq->current_cert)) {
-+
-+                    ret = add_pam_cert_response(preq->pd, "",
-+                                       preq->current_cert,
-+                                       preq->cctx->rctx->domains->user_name_hint
-+                                            ? SSS_PAM_CERT_INFO_WITH_HINT
-+                                            : SSS_PAM_CERT_INFO);
-+                    if (ret != EOK) {
-+                        DEBUG(SSSDBG_OP_FAILURE,
-+                              "add_pam_cert_response failed.\n");
-+                        preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
-+                    }
-+                }
-+
-+                ret = EOK;
-+                preq->pd->pam_status = PAM_SUCCESS;
-+                pam_reply(preq);
-+                goto done;
-+            }
-+
-+            if (cert_user_count == 1) {
-+                cert_user_objs = sss_cai_get_cert_user_objs(preq->cert_list);
-+                if (cert_user_objs == NULL) {
-+                    DEBUG(SSSDBG_CRIT_FAILURE, "Missing certificate user.\n");
-+                    ret = ENOENT;
-+                    goto done;
-+                }
-+
-                 cert_user = ldb_msg_find_attr_as_string(
--                                                  preq->cert_user_objs->msgs[0],
-+                                                  cert_user_objs->msgs[0],
-                                                   SYSDB_NAME, NULL);
-                 if (cert_user == NULL) {
-                     DEBUG(SSSDBG_CRIT_FAILURE,
-@@ -1564,9 +1643,7 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
- 
-             if (preq->cctx->rctx->domains->user_name_hint) {
-                 ret = add_pam_cert_response(preq->pd, cert_user,
--                                            preq->token_name,
--                                            preq->module_name,
--                                            preq->key_id,
-+                                            preq->cert_list,
-                                             SSS_PAM_CERT_INFO_WITH_HINT);
-                 preq->pd->pam_status = PAM_SUCCESS;
-                 if (ret != EOK) {
-@@ -1596,13 +1673,6 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
-                 goto done;
-             }
-         }
--    } else {
--        if (preq->pd->logon_name == NULL) {
--            DEBUG(SSSDBG_CRIT_FAILURE,
--                  "Missing logon name and no certificate user found.\n");
--            ret = ENOENT;
--            goto done;
--        }
-     }
- 
-     if (preq->user_obj == NULL) {
-@@ -1884,7 +1954,9 @@ static void pam_dom_forwarder(struct pam_auth_req *preq)
-     struct pam_ctx *pctx =
-             talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
-     const char *cert_user;
-+    struct ldb_result *cert_user_objs;
-     size_t c;
-+    bool found = false;
- 
-     if (!preq->pd->domain) {
-         preq->pd->domain = preq->domain->name;
-@@ -1921,76 +1993,87 @@ static void pam_dom_forwarder(struct pam_auth_req *preq)
-         return;
-     }
- 
--    if (may_do_cert_auth(pctx, preq->pd) && preq->cert_user_objs != NULL) {
-+    if (may_do_cert_auth(pctx, preq->pd) && preq->cert_list != NULL) {
-         /* Check if user matches certificate user */
--        for (c = 0; c < preq->cert_user_objs->count; c++) {
--            cert_user = ldb_msg_find_attr_as_string(
--                                                  preq->cert_user_objs->msgs[c],
--                                                  SYSDB_NAME,
--                                                  NULL);
--            if (cert_user == NULL) {
--                /* Even if there might be other users mapped to the
--                 * certificate a missing SYSDB_NAME indicates some critical
--                 * condition which justifies that the whole request is aborted
--                 * */
--                DEBUG(SSSDBG_CRIT_FAILURE,
--                      "Certificate user object has no name.\n");
--                preq->pd->pam_status = PAM_USER_UNKNOWN;
--                pam_reply(preq);
--                return;
-+        found = false;
-+        for (preq->current_cert = preq->cert_list;
-+             preq->current_cert != NULL;
-+             preq->current_cert = sss_cai_get_next(preq->current_cert)) {
-+
-+            cert_user_objs = sss_cai_get_cert_user_objs(preq->current_cert);
-+            if (cert_user_objs == NULL) {
-+                DEBUG(SSSDBG_OP_FAILURE,
-+                      "Unexpteced missing certificate user, "
-+                      "trying next certificate.\n");
-+                continue;
-             }
- 
--            /* pam_check_user_search() calls pd_set_primary_name() is the search
--             * was successful, so pd->user contains the canonical sysdb name
--             * as well */
--            if (ldb_dn_compare(preq->cert_user_objs->msgs[c]->dn,
--                               preq->user_obj->dn) == 0) {
--
--                if (preq->pd->cmd == SSS_PAM_PREAUTH) {
--                    ret = sss_authtok_set_sc(preq->pd->authtok,
--                                             SSS_AUTHTOK_TYPE_SC_PIN, NULL, 0,
--                                             preq->token_name, 0,
--                                             preq->module_name, 0,
--                                             preq->key_id, 0);
--                    if (ret != EOK) {
--                        DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_set_sc failed, "
--                                                 "Smartcard authentication "
--                                                 "detection might fail in the "
--                                                 "backend.\n");
--                    }
--
--                    ret = add_pam_cert_response(preq->pd, cert_user,
--                                                preq->token_name,
--                                                preq->module_name,
--                                                preq->key_id,
--                                                SSS_PAM_CERT_INFO);
--                    if (ret != EOK) {
--                        DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n");
--                        preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
--                    }
--                }
--
--                /* We are done if we do not have to call the backend */
--                if (preq->pd->cmd == SSS_PAM_AUTHENTICATE
--                        && preq->cert_auth_local) {
--                    preq->pd->pam_status = PAM_SUCCESS;
--                    preq->callback = pam_reply;
-+            for (c = 0; c < cert_user_objs->count; c++) {
-+                cert_user = ldb_msg_find_attr_as_string(cert_user_objs->msgs[c],
-+                                                        SYSDB_NAME, NULL);
-+                if (cert_user == NULL) {
-+                    /* Even if there might be other users mapped to the
-+                     * certificate a missing SYSDB_NAME indicates some critical
-+                     * condition which justifies that the whole request is aborted
-+                     * */
-+                    DEBUG(SSSDBG_CRIT_FAILURE,
-+                          "Certificate user object has no name.\n");
-+                    preq->pd->pam_status = PAM_USER_UNKNOWN;
-                     pam_reply(preq);
-                     return;
-                 }
-+
-+                if (ldb_dn_compare(cert_user_objs->msgs[c]->dn,
-+                                   preq->user_obj->dn) == 0) {
-+                    found = true;
-+                    if (preq->pd->cmd == SSS_PAM_PREAUTH) {
-+                        ret = sss_authtok_set_sc(preq->pd->authtok,
-+                                 SSS_AUTHTOK_TYPE_SC_PIN, NULL, 0,
-+                                 sss_cai_get_token_name(preq->current_cert), 0,
-+                                 sss_cai_get_module_name(preq->current_cert), 0,
-+                                 sss_cai_get_key_id(preq->current_cert), 0);
-+                        if (ret != EOK) {
-+                            DEBUG(SSSDBG_OP_FAILURE,
-+                                  "sss_authtok_set_sc failed, Smartcard "
-+                                  "authentication detection might fail in "
-+                                  "the backend.\n");
-+                        }
-+
-+                        /* FIXME: use the right cert info */
-+                        ret = add_pam_cert_response(preq->pd, cert_user,
-+                                                    preq->current_cert,
-+                                                    SSS_PAM_CERT_INFO);
-+                        if (ret != EOK) {
-+                            DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n");
-+                            preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
-+                        }
-+                    }
-+
-+                }
-             }
-         }
- 
--        if (preq->pd->cmd == SSS_PAM_PREAUTH) {
--            DEBUG(SSSDBG_TRACE_FUNC,
--                  "User and certificate user do not match, "
--                  "continue with other authentication methods.\n");
-+        if (found) {
-+            /* We are done if we do not have to call the backend */
-+            if (preq->pd->cmd == SSS_PAM_AUTHENTICATE
-+                    && preq->cert_auth_local) {
-+                preq->pd->pam_status = PAM_SUCCESS;
-+                preq->callback = pam_reply;
-+                pam_reply(preq);
-+                return;
-+            }
-         } else {
--            DEBUG(SSSDBG_CRIT_FAILURE,
--                  "User and certificate user do not match.\n");
--            preq->pd->pam_status = PAM_AUTH_ERR;
--            pam_reply(preq);
--            return;
-+            if (preq->pd->cmd == SSS_PAM_PREAUTH) {
-+                DEBUG(SSSDBG_TRACE_FUNC,
-+                      "User and certificate user do not match, "
-+                      "continue with other authentication methods.\n");
-+            } else {
-+                DEBUG(SSSDBG_CRIT_FAILURE,
-+                      "User and certificate user do not match.\n");
-+                preq->pd->pam_status = PAM_AUTH_ERR;
-+                pam_reply(preq);
-+                return;
-+            }
-         }
-     }
- 
-diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
-index ff32d1e726808caa36ca7cca557220866ef1a9ab..57c8e1e464f4262f2d78f869c52ca48bd469d90a 100644
---- a/src/responder/pam/pamsrv_p11.c
-+++ b/src/responder/pam/pamsrv_p11.c
-@@ -40,10 +40,80 @@ struct cert_auth_info {
-     char *token_name;
-     char *module_name;
-     char *key_id;
-+    struct ldb_result *cert_user_objs;
-     struct cert_auth_info *prev;
-     struct cert_auth_info *next;
- };
- 
-+const char *sss_cai_get_cert(struct cert_auth_info *i)
-+{
-+    return i != NULL ? i->cert : NULL;
-+}
-+
-+const char *sss_cai_get_token_name(struct cert_auth_info *i)
-+{
-+    return i != NULL ? i->token_name : NULL;
-+}
-+
-+const char *sss_cai_get_module_name(struct cert_auth_info *i)
-+{
-+    return i != NULL ? i->module_name : NULL;
-+}
-+
-+const char *sss_cai_get_key_id(struct cert_auth_info *i)
-+{
-+    return i != NULL ? i->key_id : NULL;
-+}
-+
-+struct cert_auth_info *sss_cai_get_next(struct cert_auth_info *i)
-+{
-+    return i != NULL ? i->next : NULL;
-+}
-+
-+struct ldb_result *sss_cai_get_cert_user_objs(struct cert_auth_info *i)
-+{
-+    return i != NULL ? i->cert_user_objs : NULL;
-+}
-+
-+void sss_cai_set_cert_user_objs(struct cert_auth_info *i,
-+                                struct ldb_result *cert_user_objs)
-+{
-+    if (i->cert_user_objs != NULL) {
-+        talloc_free(i->cert_user_objs);
-+    }
-+    i->cert_user_objs = talloc_steal(i, cert_user_objs);
-+}
-+
-+void sss_cai_check_users(struct cert_auth_info **list, size_t *_cert_count,
-+                         size_t *_cert_user_count)
-+{
-+    struct cert_auth_info *c;
-+    struct cert_auth_info *tmp;
-+    size_t cert_count = 0;
-+    size_t cert_user_count = 0;
-+    struct ldb_result *user_objs;
-+
-+    DLIST_FOR_EACH_SAFE(c, tmp, *list) {
-+        user_objs = sss_cai_get_cert_user_objs(c);
-+        if (user_objs != NULL) {
-+            cert_count++;
-+            cert_user_count += user_objs->count;
-+        } else {
-+            DLIST_REMOVE(*list, c);
-+        }
-+    }
-+
-+    if (_cert_count != NULL) {
-+        *_cert_count = cert_count;
-+    }
-+
-+    if (_cert_user_count != NULL) {
-+        *_cert_user_count = cert_user_count;
-+    }
-+
-+    return;
-+}
-+
- errno_t p11_child_init(struct pam_ctx *pctx)
- {
-     return child_debug_init(P11_CHILD_LOG_FILE, &pctx->p11_child_debug_fd);
-@@ -566,39 +636,71 @@ static void p11_child_timeout(struct tevent_context *ev,
- }
- 
- errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
--                            char **cert, char **token_name, char **module_name,
--                            char **key_id)
-+                            struct cert_auth_info **cert_list)
- {
-+    struct cert_auth_info *tmp_cert_auth_info;
-     struct pam_check_cert_state *state =
-                               tevent_req_data(req, struct pam_check_cert_state);
- 
-     TEVENT_REQ_RETURN_ON_ERROR(req);
- 
--    if (state->cert_list == NULL) {
--        *token_name = NULL;
--        *cert = NULL;
--        *module_name = NULL;
--        *key_id = NULL;
-+    if (cert_list != NULL) {
-+        DLIST_FOR_EACH(tmp_cert_auth_info, state->cert_list) {
-+            talloc_steal(mem_ctx, tmp_cert_auth_info);
-+        }
-+
-+        *cert_list = state->cert_list;
-     }
- 
--    if (cert != NULL) {
--        *cert = (state->cert_list == NULL) ? NULL
--                                : talloc_steal(mem_ctx, state->cert_list->cert);
-+    return EOK;
-+}
-+
-+static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username,
-+                              struct cert_auth_info *cert_info,
-+                              uint8_t **_msg, size_t *_msg_len)
-+{
-+    uint8_t *msg = NULL;
-+    size_t msg_len;
-+    const char *token_name;
-+    const char *module_name;
-+    const char *key_id;
-+    size_t user_len;
-+    size_t token_len;
-+    size_t module_len;
-+    size_t key_id_len;
-+    const char *username = "";
-+
-+    if (sysdb_username != NULL) {
-+        username = sysdb_username;
-     }
- 
--    if (token_name != NULL) {
--        *token_name = (state->cert_list == NULL) ? NULL
--                          : talloc_steal(mem_ctx, state->cert_list->token_name);
-+    token_name = sss_cai_get_token_name(cert_info);
-+    module_name = sss_cai_get_module_name(cert_info);
-+    key_id = sss_cai_get_key_id(cert_info);
-+
-+    user_len = strlen(username) + 1;
-+    token_len = strlen(token_name) + 1;
-+    module_len = strlen(module_name) + 1;
-+    key_id_len = strlen(key_id) + 1;
-+    msg_len = user_len + token_len + module_len + key_id_len;
-+
-+    msg = talloc_zero_size(mem_ctx, msg_len);
-+    if (msg == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n");
-+        return ENOMEM;
-     }
- 
--    if (module_name != NULL) {
--        *module_name = (state->cert_list == NULL) ? NULL
--                         : talloc_steal(mem_ctx, state->cert_list->module_name);
-+    memcpy(msg, username, user_len);
-+    memcpy(msg + user_len, token_name, token_len);
-+    memcpy(msg + user_len + token_len, module_name, module_len);
-+    memcpy(msg + user_len + token_len + module_len, key_id, key_id_len);
-+
-+    if (_msg != NULL) {
-+        *_msg = msg;
-     }
- 
--    if (key_id != NULL) {
--        *key_id = (state->cert_list == NULL) ? NULL
--                              : talloc_steal(mem_ctx, state->cert_list->key_id);
-+    if (_msg_len != NULL) {
-+        *_msg_len = msg_len;
-     }
- 
-     return EOK;
-@@ -613,18 +715,13 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
- #define PKCS11_LOGIN_TOKEN_ENV_NAME "PKCS11_LOGIN_TOKEN_NAME"
- 
- errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username,
--                              const char *token_name, const char *module_name,
--                              const char *key_id, enum response_type type)
-+                              struct cert_auth_info *cert_info,
-+                              enum response_type type)
- {
-     uint8_t *msg = NULL;
-     char *env = NULL;
--    size_t user_len;
-     size_t msg_len;
--    size_t slot_len;
--    size_t module_len;
--    size_t key_id_len;
-     int ret;
--    const char *username = "";
- 
-     if (type != SSS_PAM_CERT_INFO && type != SSS_PAM_CERT_INFO_WITH_HINT) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid response type [%d].\n", type);
-@@ -632,26 +729,14 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username,
-     }
- 
-     if ((type == SSS_PAM_CERT_INFO && sysdb_username == NULL)
--            || token_name == NULL || module_name == NULL || key_id == NULL) {
-+            || cert_info == NULL
-+            || sss_cai_get_token_name(cert_info) == NULL
-+            || sss_cai_get_module_name(cert_info) == NULL
-+            || sss_cai_get_key_id(cert_info) == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Missing mandatory user or slot name.\n");
-         return EINVAL;
-     }
- 
--    if (sysdb_username != NULL) {
--        username = sysdb_username;
--    }
--    user_len = strlen(username) + 1;
--    slot_len = strlen(token_name) + 1;
--    module_len = strlen(module_name) + 1;
--    key_id_len = strlen(key_id) + 1;
--    msg_len = user_len + slot_len + module_len + key_id_len;
--
--    msg = talloc_zero_size(pd, msg_len);
--    if (msg == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n");
--        return ENOMEM;
--    }
--
-     /* sysdb_username is a fully-qualified name which is used by pam_sss when
-      * prompting the user for the PIN and as login name if it wasn't set by
-      * the PAM caller but has to be determined based on the inserted
-@@ -659,10 +744,12 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username,
-      * re_expression config option was set in a way that user@domain cannot be
-      * handled anymore some more logic has to be added here. But for the time
-      * being I think using sysdb_username is fine. */
--    memcpy(msg, username, user_len);
--    memcpy(msg + user_len, token_name, slot_len);
--    memcpy(msg + user_len + slot_len, module_name, module_len);
--    memcpy(msg + user_len + slot_len + module_len, key_id, key_id_len);
-+
-+    ret = pack_cert_data(pd, sysdb_username, cert_info, &msg, &msg_len);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "pack_cert_data failed.\n");
-+        return ret;
-+    }
- 
-     ret = pam_add_response(pd, type, msg_len, msg);
-     talloc_free(msg);
-@@ -674,7 +761,7 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username,
- 
-     if (strcmp(pd->service, "gdm-smartcard") == 0) {
-         env = talloc_asprintf(pd, "%s=%s", PKCS11_LOGIN_TOKEN_ENV_NAME,
--                              token_name);
-+                              sss_cai_get_token_name(cert_info));
-         if (env == NULL) {
-             DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
-             return ENOMEM;
-diff --git a/src/tests/cmocka/p11_nssdb_2certs/pkcs11.txt b/src/tests/cmocka/p11_nssdb_2certs/pkcs11.txt
-new file mode 100644
-index 0000000000000000000000000000000000000000..73f5279c338dffe25ad2fad8c9cafae2f3c4cdfe
---- /dev/null
-+++ b/src/tests/cmocka/p11_nssdb_2certs/pkcs11.txt
-@@ -0,0 +1,4 @@
-+library=
-+name=NSS Internal PKCS #11 Module
-+parameters=configdir='sql:../src/tests/cmocka/p11_nssdb' certPrefix='' keyPrefix='' secmod='secmod.db' flags= updatedir='' updateCertPrefix='' updateKeyPrefix='' updateid='' updateTokenDescription=''
-+NSS=Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={slotFlags=[RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,SHA256,SHA512] askpw=any timeout=30})
-diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
-index 351067eb664431cda159f73590de772920504380..7f0ed706512ffe0866c0e1fb7e6baa16bec942d8 100644
---- a/src/tests/cmocka/test_pam_srv.c
-+++ b/src/tests/cmocka/test_pam_srv.c
-@@ -47,6 +47,9 @@
- #define NSS_DB_PATH TESTS_PATH
- #define NSS_DB "sql:"NSS_DB_PATH
- 
-+#define NSS_DB_PATH_2CERTS TESTS_PATH "_2certs"
-+#define NSS_DB_2CERTS "sql:"NSS_DB_PATH_2CERTS
-+
- #define TEST_TOKEN_NAME "SSSD Test Token"
- #define TEST_MODULE_NAME "NSS-Internal"
- #define TEST_KEY_ID "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7"
-@@ -74,6 +77,28 @@
- "8Z+9gqZhCa7FEKJOPNR9RVtJs0qUUutMZrp1zpyx0GTmXQBA7LbgPxy8L68uymEQ" \
- "XyQBwOYRORlnfGyu+Yc9c3E0Wx8Tlznz0lqPR9g="
- 
-+#define TEST2_KEY_ID "C8D60E009EB195D01A7083EE1D5419251AA87C2C"
-+#define TEST_TOKEN_2ND_CERT \
-+"MIIDazCCAlOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \
-+"REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \
-+"NDEzMDFaFw0xODA1MTMxNDEzMDFaMCUxEjAQBgNVBAoMCUlQQS5ERVZFTDEPMA0G" \
-+"A1UEAwwGSVBBIFJBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3abE" \
-+"8LmIc6QN16VVxsMlN/rrCOoZKyyJolSzpP4+K66t+KZUiW/1j1MZogjyYyD39U1F" \
-+"zpa2H+pID74XYrdiqP7sp+uE9/k2XOv/nN3FobXDt+fSINLDriCmxNhUZqpgo2uq" \
-+"Mmka+yx2iJZwkntEoJTcd3aynoa2Sa2ZZbkMBy5p6/pUQKwnD6scOwe6mUDppIBK" \
-+"+ZZRm+u/NDdIRFI5wfKLRR1r/ONaJA9nz1TxSEsgLsjG/1m+Zbb6lGG4pePIFkQ9" \
-+"Iotpi64obBh93oIxzQR29lBG/FMjQVHlPIbx+xuGx11Vtp5pAomgFz0HRrj0leI7" \
-+"bROE+jnC/VGPLQD2aQIDAQABo4GWMIGTMB8GA1UdIwQYMBaAFPci/0Km5D/L5z7Y" \
-+"qwEc7E1/GwgcMEEGCCsGAQUFBwEBBDUwMzAxBggrBgEFBQcwAYYlaHR0cDovL2lw" \
-+"YS1kZXZlbC5pcGEuZGV2ZWw6ODAvY2Evb2NzcDAOBgNVHQ8BAf8EBAMCBPAwHQYD" \
-+"VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBg" \
-+"4Sppx2C3eXPJ4Pd9XElkQPOaBReXf1vV0uk/GlK+rG+aAqAkA2Lryx5PK/iAuzAU" \
-+"M6JUpELuQYgqugoCgBXMgsMlpAO/0C3CFq4ZH3KgIsRlRngKPrt6RG0UPMRD1CE2" \
-+"tSVkwUWvyK83lDiu2BbWDXyMyz5eZOlp7uHusf5BKvob8jEndHj1YzaNTmVSsDM5" \
-+"kiIwf8qgFhsO1HCq08PtAnbVHhqkcvnmIJN98eNWNfTKodDmFVbN8gB0wK+WB5ii" \
-+"WVOw7+3/zF1QgqnYX3t+kPLRryip/wvTZkzXWwMNj/W6UHgjNF/4gWGoBgCHu+u3" \
-+"EvjMmbVSrEkesibpGQS5"
-+
- 
- static char CACHED_AUTH_TIMEOUT_STR[] = "4";
- static const int CACHED_AUTH_TIMEOUT = 4;
-@@ -111,6 +136,13 @@ static errno_t setup_nss_db(void)
-         return ret;
-     }
- 
-+    ret = mkdir(NSS_DB_PATH_2CERTS, 0775);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_FATAL_FAILURE,
-+              "Failed to create " NSS_DB_PATH_2CERTS ".\n");
-+        return ret;
-+    }
-+
-     child_pid = fork();
-     if (child_pid == 0) { /* child */
-         ret = execlp("certutil", "certutil", "-N", "--empty-password", "-d",
-@@ -127,6 +159,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_2CERTS, 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");
-@@ -148,6 +196,27 @@ static errno_t setup_nss_db(void)
-         return ret;
-     }
- 
-+    fp = fopen(NSS_DB_PATH_2CERTS"/pkcs11.txt", "w");
-+    if (fp == NULL) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "fopen() failed.\n");
-+        return ret;
-+    }
-+    ret = fprintf(fp, "library=libsoftokn3.so\nname=soft\n");
-+    if (ret < 0) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "fprintf() failed.\n");
-+        return ret;
-+    }
-+    ret = fprintf(fp, "parameters=configdir='sql:%s/src/tests/cmocka/p11_nssdb_2certs' dbSlotDescription='SSSD Test Slot' dbTokenDescription='SSSD Test Token' secmod='secmod.db' flags=readOnly \n\n", ABS_SRC_DIR);
-+    if (ret < 0) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "fprintf() failed.\n");
-+        return ret;
-+    }
-+    ret = fclose(fp);
-+    if (ret != 0) {
-+        DEBUG(SSSDBG_FATAL_FAILURE, "fclose() failed.\n");
-+        return ret;
-+    }
-+
-     return EOK;
- }
- 
-@@ -174,6 +243,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_2CERTS"/cert9.db");
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Failed to remove cert9.db.\n");
-+    }
-+
-+    ret = unlink(NSS_DB_PATH_2CERTS"/key4.db");
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Failed to remove key4.db.\n");
-+    }
-+
-+    ret = unlink(NSS_DB_PATH_2CERTS"/pkcs11.txt");
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Failed to remove pkcs11.db.\n");
-+    }
-+
-+    ret = rmdir(NSS_DB_PATH_2CERTS);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Failed to remove " NSS_DB_PATH "\n");
-+    }
- }
- 
- struct pam_ctx *mock_pctx(TALLOC_CTX *mem_ctx)
-@@ -749,7 +838,8 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body,
- }
- 
- static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
--                                  enum response_type type, const char *name)
-+                                  enum response_type type, const char *name,
-+                                  const char *name2)
- {
-     size_t rp = 0;
-     uint32_t val;
-@@ -763,7 +853,11 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
-     if (name == NULL || *name == '\0') {
-         assert_int_equal(val, 1);
-     } else {
--        assert_int_equal(val, 2);
-+        if (name2 == NULL || *name2 == '\0') {
-+            assert_int_equal(val, 2);
-+        } else {
-+            assert_int_equal(val, 3);
-+        }
- 
-         SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-         assert_int_equal(val, SSS_PAM_DOMAIN_NAME);
-@@ -801,6 +895,33 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
-     assert_string_equal(body + rp, TEST_KEY_ID);
-     rp += sizeof(TEST_KEY_ID);
- 
-+    if (name2 != NULL && *name2 != '\0') {
-+        SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+        assert_int_equal(val, type);
-+
-+        SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-+        assert_int_equal(val, (strlen(name) + 1
-+                                    + sizeof(TEST_TOKEN_NAME)
-+                                    + sizeof(TEST_MODULE_NAME)
-+                                    + sizeof(TEST2_KEY_ID)));
-+
-+        assert_int_equal(*(body + rp + strlen(name)), 0);
-+        assert_string_equal(body + rp, name);
-+        rp += strlen(name) + 1;
-+
-+        assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0);
-+        assert_string_equal(body + rp, TEST_TOKEN_NAME);
-+        rp += sizeof(TEST_TOKEN_NAME);
-+
-+        assert_int_equal(*(body + rp + sizeof(TEST_MODULE_NAME) - 1), 0);
-+        assert_string_equal(body + rp, TEST_MODULE_NAME);
-+        rp += sizeof(TEST_MODULE_NAME);
-+
-+        assert_int_equal(*(body + rp + sizeof(TEST2_KEY_ID) - 1), 0);
-+        assert_string_equal(body + rp, TEST2_KEY_ID);
-+        rp += sizeof(TEST2_KEY_ID);
-+    }
-+
-     assert_int_equal(rp, blen);
- 
-     return EOK;
-@@ -809,7 +930,8 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
- static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen)
- {
-     return test_pam_cert_check_ex(status, body, blen,
--                                  SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME);
-+                                  SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME,
-+                                  NULL);
- }
- 
- static int test_pam_cert_check_with_hint(uint32_t status, uint8_t *body,
-@@ -817,14 +939,22 @@ static int test_pam_cert_check_with_hint(uint32_t status, uint8_t *body,
- {
-     return test_pam_cert_check_ex(status, body, blen,
-                                   SSS_PAM_CERT_INFO_WITH_HINT,
--                                  "pamuser@"TEST_DOM_NAME);
-+                                  "pamuser@"TEST_DOM_NAME, NULL);
- }
- 
- static int test_pam_cert_check_with_hint_no_user(uint32_t status, uint8_t *body,
-                                                  size_t blen)
- {
-     return test_pam_cert_check_ex(status, body, blen,
--                                  SSS_PAM_CERT_INFO_WITH_HINT, "");
-+                                  SSS_PAM_CERT_INFO_WITH_HINT, "", NULL);
-+}
-+
-+static int test_pam_cert_check_2certs(uint32_t status, uint8_t *body,
-+                                      size_t blen)
-+{
-+    return test_pam_cert_check_ex(status, body, blen,
-+                                  SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME,
-+                                  "pamuser@"TEST_DOM_NAME);
- }
- 
- static int test_pam_offline_chauthtok_check(uint32_t status,
-@@ -1737,6 +1867,33 @@ static int test_lookup_by_cert_cb(void *pvt)
- 
-     return EOK;
- }
-+static int test_lookup_by_cert_cb_2nd_cert_same_user(void *pvt)
-+{
-+    int ret;
-+    struct sysdb_attrs *attrs;
-+    unsigned char *der = NULL;
-+    size_t der_size;
-+
-+    test_lookup_by_cert_cb(pvt);
-+
-+    attrs = sysdb_new_attrs(pam_test_ctx);
-+    assert_non_null(attrs);
-+
-+    der = sss_base64_decode(pam_test_ctx, TEST_TOKEN_2ND_CERT, &der_size);
-+    assert_non_null(der);
-+
-+    ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size);
-+    talloc_free(der);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = sysdb_set_user_attr(pam_test_ctx->tctx->dom,
-+                              pam_test_ctx->pam_user_fqdn,
-+                              attrs,
-+                              LDB_FLAG_MOD_ADD);
-+    assert_int_equal(ret, EOK);
-+
-+    return EOK;
-+}
- 
- static int test_lookup_by_cert_double_cb(void *pvt)
- {
-@@ -2094,6 +2251,51 @@ void test_pam_cert_auth_double_cert(void **state)
-     assert_int_equal(ret, EOK);
- }
- 
-+void test_pam_cert_preauth_2certs_one_mapping(void **state)
-+{
-+    int ret;
-+
-+    set_cert_auth_param(pam_test_ctx->pctx, NSS_DB_2CERTS);
-+
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL,
-+                        test_lookup_by_cert_cb, TEST_TOKEN_CERT, 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_2certs_two_mappings(void **state)
-+{
-+    int ret;
-+
-+    set_cert_auth_param(pam_test_ctx->pctx, NSS_DB_2CERTS);
-+
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL,
-+                        test_lookup_by_cert_cb_2nd_cert_same_user,
-+                        TEST_TOKEN_CERT, 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_2certs);
-+    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)
- {
-     int ret;
-@@ -2523,6 +2725,10 @@ int main(int argc, const char *argv[])
-                                         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,
-+                                        pam_test_setup, pam_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_pam_cert_preauth_2certs_two_mappings,
-+                                        pam_test_setup, pam_test_teardown),
- #endif /* HAVE_NSS */
- 
-         cmocka_unit_test_setup_teardown(test_filter_response,
-diff --git a/src/tests/whitespace_test b/src/tests/whitespace_test
-index 799e35358b1d5ae4b10c4405068fb507cb234b6f..f055ed4c255db4001194844f45a9df7cda774b38 100755
---- a/src/tests/whitespace_test
-+++ b/src/tests/whitespace_test
-@@ -39,7 +39,7 @@ fi
- declare found_file=false
- while read file; do
-     [[ $file == "src/config/testconfigs/noparse.api.conf" ]] && continue
--    [[ $file =~ ^src/tests/cmocka/p11_nssdb/.*db ]] && continue
-+    [[ $file =~ ^src/tests/cmocka/p11_nssdb.*/.*db ]] && continue
-     test `tail -c 1 $ABS_TOP_SRCDIR/$file` && \
-         echo "Missing new line at the eof: $file" && \
-         found_file=true
--- 
-2.13.6
-
diff --git a/SOURCES/0037-SUDO-Fix-running-in-unprivileged-responder.patch b/SOURCES/0037-SUDO-Fix-running-in-unprivileged-responder.patch
new file mode 100644
index 0000000..5ac4676
--- /dev/null
+++ b/SOURCES/0037-SUDO-Fix-running-in-unprivileged-responder.patch
@@ -0,0 +1,95 @@
+From 261ff6442294b11261c11262d2a6acf379803e36 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Tue, 24 Jul 2018 18:52:08 +0000
+Subject: [PATCH] SUDO: Fix running in unprivileged responder
+
+There are strict checks for private sockets which does not work with
+unprivileged responder
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3778
+
+Merges: https://pagure.io/SSSD/sssd/pull-request/3784
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 4900b8e59bdbb89fbc1c9718969aabe26f3db34a)
+
+DOWNSTREAM:
+Resolves: rhbz#1607313 - When sssd is running as non-root user, the sudo pipe is created as sssd:sssd but then the private pipe ownership fails
+---
+ src/responder/sudo/sudosrv.c | 31 +++++++++++++++++++++++++++----
+ 1 file changed, 27 insertions(+), 4 deletions(-)
+
+diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c
+index e87a24499c2d82fafaa8e1f9b386e44332394266..82315e0a8f7879595e02458a9aa79e7332b04734 100644
+--- a/src/responder/sudo/sudosrv.c
++++ b/src/responder/sudo/sudosrv.c
+@@ -67,7 +67,8 @@ static void sudo_dp_reconnect_init(struct sbus_connection *conn,
+ 
+ int sudo_process_init(TALLOC_CTX *mem_ctx,
+                       struct tevent_context *ev,
+-                      struct confdb_ctx *cdb)
++                      struct confdb_ctx *cdb,
++                      int pipe_fd)
+ {
+     struct resp_ctx *rctx;
+     struct sss_cmd_table *sudo_cmds;
+@@ -79,8 +80,8 @@ int sudo_process_init(TALLOC_CTX *mem_ctx,
+     sudo_cmds = get_sudo_cmds();
+     ret = sss_process_init(mem_ctx, ev, cdb,
+                            sudo_cmds,
+-                           NULL, -1,                   /* No public socket */
+-                           SSS_SUDO_SOCKET_NAME, -1,   /* Private socket only */
++                           SSS_SUDO_SOCKET_NAME, pipe_fd,   /* custom permissions on socket */
++                           NULL, -1,                   /* No private socket */
+                            CONFDB_SUDO_CONF_ENTRY,
+                            SSS_SUDO_SBUS_SERVICE_NAME,
+                            SSS_SUDO_SBUS_SERVICE_VERSION,
+@@ -182,6 +183,7 @@ int main(int argc, const char *argv[])
+     char *opt_logger = NULL;
+     struct main_context *main_ctx;
+     int ret;
++    int pipe_fd = -1;
+     uid_t uid;
+     gid_t gid;
+ 
+@@ -219,6 +221,27 @@ int main(int argc, const char *argv[])
+ 
+     sss_set_logger(opt_logger);
+ 
++    if (!is_socket_activated()) {
++        /* Create pipe file descriptors here with right ownerschip */
++        ret = create_pipe_fd(SSS_SUDO_SOCKET_NAME, &pipe_fd, SSS_DFL_UMASK);
++        if (ret != EOK) {
++            DEBUG(SSSDBG_FATAL_FAILURE,
++                  "create_pipe_fd failed [%d]: %s.\n",
++                  ret, sss_strerror(ret));
++            return 4;
++        }
++
++        ret = chown(SSS_SUDO_SOCKET_NAME, uid, 0);
++        if (ret != 0) {
++            ret = errno;
++            close(pipe_fd);
++            DEBUG(SSSDBG_FATAL_FAILURE,
++                  "create_pipe_fd failed [%d]: %s.\n",
++                  ret, sss_strerror(ret));
++            return 5;
++        }
++    }
++
+     ret = server_setup("sssd[sudo]", 0, uid, gid, CONFDB_SUDO_CONF_ENTRY,
+                        &main_ctx);
+     if (ret != EOK) {
+@@ -234,7 +257,7 @@ int main(int argc, const char *argv[])
+ 
+     ret = sudo_process_init(main_ctx,
+                             main_ctx->event_ctx,
+-                            main_ctx->confdb_ctx);
++                            main_ctx->confdb_ctx, pipe_fd);
+     if (ret != EOK) {
+         return 3;
+     }
+-- 
+2.14.4
+
diff --git a/SOURCES/0038-SUDO-Root-should-be-able-to-read-write-sssd-sudo-soc.patch b/SOURCES/0038-SUDO-Root-should-be-able-to-read-write-sssd-sudo-soc.patch
new file mode 100644
index 0000000..607eabb
--- /dev/null
+++ b/SOURCES/0038-SUDO-Root-should-be-able-to-read-write-sssd-sudo-soc.patch
@@ -0,0 +1,39 @@
+From 2708fb488277209a60a5daf5217502c029c196c1 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Tue, 24 Jul 2018 18:52:08 +0000
+Subject: [PATCH] SUDO: Root should be able to read/write sssd-sudo socket
+
+There is not any reason to require additional capabilities from root
+when sssd is running as unprivileged user.
+
+Sudo UNIX socket is not a real private socket. It just cannot
+be used by others. Just owner(sssd) and root should be able to use it.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3778
+
+Merges: https://pagure.io/SSSD/sssd/pull-request/3784
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 21ea8204a0bd8ea4451f420713e909d3cfee34ef)
+---
+ src/sysv/systemd/sssd-sudo.socket.in | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/src/sysv/systemd/sssd-sudo.socket.in b/src/sysv/systemd/sssd-sudo.socket.in
+index 96a8b0327ddb4d331c9b2e97ece3453f8f76872d..e94a2f6151e3d69edc304776b72a81db22762503 100644
+--- a/src/sysv/systemd/sssd-sudo.socket.in
++++ b/src/sysv/systemd/sssd-sudo.socket.in
+@@ -10,8 +10,7 @@ Conflicts=shutdown.target
+ ExecStartPre=@libexecdir@/sssd/sssd_check_socket_activated_responders -r sudo
+ ListenStream=@pipepath@/sudo
+ SocketUser=@SSSD_USER@
+-SocketGroup=@SSSD_USER@
+-SocketMode=0600
++SocketMode=0660
+ 
+ [Install]
+ WantedBy=sssd.service
+-- 
+2.14.4
+
diff --git a/SOURCES/0038-pam_sss-refactoring-use-struct-cert_auth_info.patch b/SOURCES/0038-pam_sss-refactoring-use-struct-cert_auth_info.patch
deleted file mode 100644
index fc2b370..0000000
--- a/SOURCES/0038-pam_sss-refactoring-use-struct-cert_auth_info.patch
+++ /dev/null
@@ -1,680 +0,0 @@
-From cee84ed12721092bc40bc02dc66ce3efbb2bac74 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 16 Oct 2017 14:13:10 +0200
-Subject: [PATCH 38/46] pam_sss: refactoring, use struct cert_auth_info
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Similar as in the PAM responder this patch replaces the individual
-certificate authentication related attributes by a struct which can be
-used as a list. With the pam_sss can handle multiple SSS_PAM_CERT_INFO
-message and place the data in individual list items.
-
-If multiple certificates are returned before prompting for the PIN a
-dialog to select a certificate is shown to the users. If available a GDM
-PAM extension is used to let the user choose from a list. All coded
-needed at runtime to check if the extension is available and handle the
-data is provided by GDM as macros. This means that there are no
-additional run-time requirements.
-
-Related to https://pagure.io/SSSD/sssd/issue/3560
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Tested-by: Scott Poore <spoore@redhat.com>
-(cherry picked from commit 122830e67472390b41edc73f0cfcd5c5705b726b)
----
- contrib/sssd.spec.in         |   9 +
- src/external/pam.m4          |  12 ++
- src/sss_client/pam_message.h |   8 +-
- src/sss_client/pam_sss.c     | 439 ++++++++++++++++++++++++++++++++++---------
- 4 files changed, 370 insertions(+), 98 deletions(-)
-
-diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
-index 1ee64d5a2a64635984260fceced779f4804e8b31..d9323bf1a2d84f4219f8ab11886e5ce87b401c15 100644
---- a/contrib/sssd.spec.in
-+++ b/contrib/sssd.spec.in
-@@ -121,6 +121,12 @@
-     %global with_kcm_option --without-kcm
- %endif
- 
-+%if (0%{?fedora} >= 27 || (0%{?rhel} >= 7 && 0%{?rhel7_minor} > 4))
-+    %global with_gdm_pam_extensions 1
-+%else
-+    %global with_gdm_pam_extensions 0
-+%endif
-+
- Name: @PACKAGE_NAME@
- Version: @PACKAGE_VERSION@
- Release: 0@PRERELEASE_VERSION@%{?dist}
-@@ -233,6 +239,9 @@ BuildRequires: libuuid-devel
- BuildRequires: jansson-devel
- BuildRequires: libcurl-devel
- %endif
-+%if (0%{?with_gdm_pam_extensions} == 1)
-+BuildRequires: gdm-devel
-+%endif
- 
- %description
- Provides a set of daemons to manage access to remote directories and
-diff --git a/src/external/pam.m4 b/src/external/pam.m4
-index 4776b6ae338409f0a2729dfc4cf5962463a40dfd..0dc7f19d0df6a4588cf893ecff6e518111462433 100644
---- a/src/external/pam.m4
-+++ b/src/external/pam.m4
-@@ -27,3 +27,15 @@ AC_CHECK_FUNCS(pam_modutil_getlogin pam_vsyslog)
- 
- dnl restore LIBS
- LIBS="$save_LIBS"
-+
-+PKG_CHECK_MODULES([GDM_PAM_EXTENSIONS], [gdm-pam-extensions],
-+                  [found_gdm_pam_extensions=yes],
-+                  [AC_MSG_NOTICE([gdm-pam-extensions were not found. gdm support
-+for multiple certificates will not be build.
-+])])
-+
-+AC_SUBST(GDM_PAM_EXTENSIONS_CFLAGS)
-+
-+AS_IF([test x"$found_gdm_pam_extensions" = xyes],
-+      [AC_DEFINE_UNQUOTED(HAVE_GDM_PAM_EXTENSIONS, 1,
-+                          [Build with gdm-pam-extensions support])])
-diff --git a/src/sss_client/pam_message.h b/src/sss_client/pam_message.h
-index f215392f6879f01a0ca12abc8807bac5fc1f1cbb..11526a80a767ff5602b194d14765ff261e8f9707 100644
---- a/src/sss_client/pam_message.h
-+++ b/src/sss_client/pam_message.h
-@@ -29,6 +29,8 @@
- 
- #include "sss_client/sss_cli.h"
- 
-+struct cert_auth_info;
-+
- struct pam_items {
-     const char *pam_service;
-     const char *pam_user;
-@@ -59,11 +61,9 @@ struct pam_items {
-     char *first_factor;
-     bool password_prompting;
- 
--    char *cert_user;
--    char *token_name;
--    char *module_name;
--    char *key_id;
-     bool user_name_hint;
-+    struct cert_auth_info *cert_list;
-+    struct cert_auth_info *selected_cert;
- };
- 
- int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer);
-diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
-index 303809b9ea05b5a8709c05ae230d5f289b57de31..c147d4b3d76443d69e27eb2da042f8eebd1ae6ab 100644
---- a/src/sss_client/pam_sss.c
-+++ b/src/sss_client/pam_sss.c
-@@ -36,6 +36,10 @@
- #include <security/pam_modules.h>
- #include <security/pam_appl.h>
- 
-+#ifdef HAVE_GDM_PAM_EXTENSIONS
-+#include <gdm/gdm-pam-extensions.h>
-+#endif
-+
- #include "sss_pam_compat.h"
- #include "sss_pam_macros.h"
- 
-@@ -43,6 +47,7 @@
- #include "pam_message.h"
- #include "util/atomic_io.h"
- #include "util/authtok-utils.h"
-+#include "util/dlinklist.h"
- 
- #include <libintl.h>
- #define _(STRING) dgettext (PACKAGE, STRING)
-@@ -118,6 +123,40 @@ static void close_fd(pam_handle_t *pamh, void *ptr, int err)
-     sss_pam_close_fd();
- }
- 
-+struct cert_auth_info {
-+    char *cert_user;
-+    char *cert;
-+    char *token_name;
-+    char *module_name;
-+    char *key_id;
-+    struct cert_auth_info *prev;
-+    struct cert_auth_info *next;
-+};
-+
-+static void free_cai(struct cert_auth_info *cai)
-+{
-+    if (cai != NULL) {
-+        free(cai->cert_user);
-+        free(cai->cert);
-+        free(cai->token_name);
-+        free(cai->key_id);
-+        free(cai);
-+    }
-+}
-+
-+static void free_cert_list(struct cert_auth_info *list)
-+{
-+    struct cert_auth_info *cai;
-+    struct cert_auth_info *cai_next;
-+
-+    if (list != NULL) {
-+        DLIST_FOR_EACH_SAFE(cai, cai_next, list) {
-+            DLIST_REMOVE(list, cai);
-+            free_cai(cai);
-+        }
-+    }
-+}
-+
- static void overwrite_and_free_authtoks(struct pam_items *pi)
- {
-     if (pi->pam_authtok != NULL) {
-@@ -158,17 +197,9 @@ static void overwrite_and_free_pam_items(struct pam_items *pi)
-     free(pi->otp_challenge);
-     pi->otp_challenge = NULL;
- 
--    free(pi->cert_user);
--    pi->cert_user = NULL;
--
--    free(pi->token_name);
--    pi->token_name = NULL;
--
--    free(pi->module_name);
--    pi->module_name = NULL;
--
--    free(pi->key_id);
--    pi->key_id = NULL;
-+    free_cert_list(pi->cert_list);
-+    pi->cert_list = NULL;
-+    pi->selected_cert = NULL;
- }
- 
- static int null_strcmp(const char *s1, const char *s2) {
-@@ -821,6 +852,90 @@ static int eval_user_info_response(pam_handle_t *pamh, size_t buflen,
-     return ret;
- }
- 
-+static int parse_cert_info(struct pam_items *pi, uint8_t *buf, size_t len,
-+                           size_t *p, const char **cert_user)
-+{
-+    struct cert_auth_info *cai = NULL;
-+    size_t offset;
-+    int ret;
-+
-+    if (buf[*p + (len - 1)] != '\0') {
-+        D(("cert info does not end with \\0."));
-+        return EINVAL;
-+    }
-+
-+    cai = calloc(1, sizeof(struct cert_auth_info));
-+    if (cai == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    cai->cert_user = strdup((char *) &buf[*p]);
-+    if (cai->cert_user == NULL) {
-+        D(("strdup failed"));
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+    if (cert_user != NULL) {
-+        *cert_user = cai->cert_user;
-+    }
-+
-+    offset = strlen(cai->cert_user) + 1;
-+    if (offset >= len) {
-+        D(("Cert message size mismatch"));
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    cai->token_name = strdup((char *) &buf[*p + offset]);
-+    if (cai->token_name == NULL) {
-+        D(("strdup failed"));
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    offset += strlen(cai->token_name) + 1;
-+    if (offset >= len) {
-+        D(("Cert message size mismatch"));
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    cai->module_name = strdup((char *) &buf[*p + offset]);
-+    if (cai->module_name == NULL) {
-+        D(("strdup failed"));
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    offset += strlen(cai->module_name) + 1;
-+    if (offset >= len) {
-+        D(("Cert message size mismatch"));
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    cai->key_id = strdup((char *) &buf[*p + offset]);
-+    if (cai->key_id == NULL) {
-+        D(("strdup failed"));
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    D(("cert user: [%s] token name: [%s] module: [%s] key id: [%s]",
-+       cai->cert_user, cai->token_name, cai->module_name,
-+       cai->key_id));
-+
-+    DLIST_ADD(pi->cert_list, cai);
-+    ret = 0;
-+
-+done:
-+    if (ret != 0) {
-+        free_cai(cai);
-+    }
-+
-+    return ret;
-+}
-+
- static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
-                          struct pam_items *pi)
- {
-@@ -832,6 +947,7 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
-     int32_t len;
-     int32_t pam_status;
-     size_t offset;
-+    const char *cert_user;
- 
-     if (buflen < (2*sizeof(int32_t))) {
-         D(("response buffer is too small"));
-@@ -988,27 +1104,21 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
-                     break;
-                 }
- 
--                free(pi->cert_user);
--                pi->cert_user = strdup((char *) &buf[p]);
--                if (pi->cert_user == NULL) {
--                    D(("strdup failed"));
--                    break;
--                }
--
--                if (type == SSS_PAM_CERT_INFO && *pi->cert_user == '\0') {
--                    D(("Invalid CERT message"));
--                    break;
--                }
--
-                 if (type == SSS_PAM_CERT_INFO_WITH_HINT) {
-                     pi->user_name_hint = true;
-                 } else {
-                     pi->user_name_hint = false;
-                 }
- 
-+                ret = parse_cert_info(pi, buf, len, &p, &cert_user);
-+                if (ret != 0) {
-+                    D(("Failed to parse cert info"));
-+                    break;
-+                }
-+
-                 if ((pi->pam_user == NULL || *(pi->pam_user) == '\0')
--                        && *pi->cert_user != '\0') {
--                    ret = pam_set_item(pamh, PAM_USER, pi->cert_user);
-+                        && *cert_user != '\0') {
-+                    ret = pam_set_item(pamh, PAM_USER, cert_user);
-                     if (ret != PAM_SUCCESS) {
-                         D(("Failed to set PAM_USER during "
-                            "Smartcard authentication [%s]",
-@@ -1027,59 +1137,6 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
- 
-                     pi->pam_user_size = strlen(pi->pam_user) + 1;
-                 }
--
--                offset = strlen(pi->cert_user) + 1;
--                if (offset >= len) {
--                    D(("Cert message size mismatch"));
--                    free(pi->cert_user);
--                    pi->cert_user = NULL;
--                    break;
--                }
--                free(pi->token_name);
--                pi->token_name = strdup((char *) &buf[p + offset]);
--                if (pi->token_name == NULL) {
--                    D(("strdup failed"));
--                    free(pi->cert_user);
--                    pi->cert_user = NULL;
--                    break;
--                }
--
--                offset += strlen(pi->token_name) + 1;
--                if (offset >= len) {
--                    D(("Cert message size mismatch"));
--                    free(pi->cert_user);
--                    pi->cert_user = NULL;
--                    free(pi->token_name);
--                    pi->token_name = NULL;
--                    break;
--                }
--                free(pi->module_name);
--                pi->module_name = strdup((char *) &buf[p + offset]);
--                if (pi->module_name == NULL) {
--                    D(("strdup failed"));
--                    break;
--                }
--
--                offset += strlen(pi->module_name) + 1;
--                if (offset >= len) {
--                    D(("Cert message size mismatch"));
--                    free(pi->cert_user);
--                    pi->cert_user = NULL;
--                    free(pi->token_name);
--                    pi->token_name = NULL;
--                    free(pi->module_name);
--                    pi->module_name = NULL;
--                    break;
--                }
--                free(pi->key_id);
--                pi->key_id = strdup((char *) &buf[p + offset]);
--                if (pi->key_id == NULL) {
--                    D(("strdup failed"));
--                    break;
--                }
--                D(("cert user: [%s] token name: [%s] module: [%s] key id: [%s]",
--                    pi->cert_user, pi->token_name, pi->module_name,
--                    pi->key_id));
-                 break;
-             case SSS_PASSWORD_PROMPTING:
-                 D(("Password prompting available."));
-@@ -1175,10 +1232,8 @@ static int get_pam_items(pam_handle_t *pamh, uint32_t flags,
-     pi->otp_challenge = NULL;
-     pi->password_prompting = false;
- 
--    pi->cert_user = NULL;
--    pi->token_name = NULL;
--    pi->module_name = NULL;
--    pi->key_id = NULL;
-+    pi->cert_list = NULL;
-+    pi->selected_cert = NULL;
- 
-     return PAM_SUCCESS;
- }
-@@ -1484,6 +1539,184 @@ done:
- 
- #define SC_PROMPT_FMT "PIN for %s"
- 
-+#ifndef discard_const
-+#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
-+#endif
-+
-+#define CERT_SEL_PROMPT_FMT "Certificate: %s"
-+#define SEL_TITLE discard_const("Please select a certificate")
-+
-+static int prompt_multi_cert_gdm(pam_handle_t *pamh, struct pam_items *pi)
-+{
-+#ifdef HAVE_GDM_PAM_EXTENSIONS
-+    int ret;
-+    size_t cert_count = 0;
-+    size_t c;
-+    const struct pam_conv *conv;
-+    struct cert_auth_info *cai;
-+    GdmPamExtensionChoiceListRequest *request = NULL;
-+    GdmPamExtensionChoiceListResponse *response = NULL;
-+    struct pam_message prompt_message;
-+    const struct pam_message *prompt_messages[1];
-+    struct pam_response *reply = NULL;
-+    char *prompt;
-+
-+    if (!GDM_PAM_EXTENSION_SUPPORTED(GDM_PAM_EXTENSION_CHOICE_LIST)) {
-+        return ENOTSUP;
-+    }
-+
-+    if (pi->cert_list == NULL) {
-+        return EINVAL;
-+    }
-+
-+    DLIST_FOR_EACH(cai, pi->cert_list) {
-+        cert_count++;
-+    }
-+
-+    ret = pam_get_item(pamh, PAM_CONV, (const void **)&conv);
-+    if (ret != PAM_SUCCESS) {
-+        ret = EIO;
-+        return ret;
-+    }
-+
-+    request = calloc(1, GDM_PAM_EXTENSION_CHOICE_LIST_REQUEST_SIZE(cert_count));
-+    if (request == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+    GDM_PAM_EXTENSION_CHOICE_LIST_REQUEST_INIT(request, SEL_TITLE, cert_count);
-+
-+    c = 0;
-+    DLIST_FOR_EACH(cai, pi->cert_list) {
-+        ret = asprintf(&prompt, CERT_SEL_PROMPT_FMT, cai->key_id);
-+        if (ret == -1) {
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+        request->list.items[c].key = cai->key_id;
-+        request->list.items[c++].text = prompt;
-+    }
-+
-+    GDM_PAM_EXTENSION_MESSAGE_TO_BINARY_PROMPT_MESSAGE(request,
-+                                                       &prompt_message);
-+    prompt_messages[0] = &prompt_message;
-+
-+    ret = conv->conv(1, prompt_messages, &reply, conv->appdata_ptr);
-+    if (ret != PAM_SUCCESS) {
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    ret = EIO;
-+    response = GDM_PAM_EXTENSION_REPLY_TO_CHOICE_LIST_RESPONSE(reply);
-+    if (response->key == NULL) {
-+        goto done;
-+    }
-+
-+    DLIST_FOR_EACH(cai, pi->cert_list) {
-+        if (strcmp(response->key, cai->key_id) == 0) {
-+            pam_info(pamh, "Certificate ‘%s’ selected", cai->key_id);
-+            pi->selected_cert = cai;
-+            ret = 0;
-+            break;
-+        }
-+    }
-+
-+done:
-+    if (request != NULL) {
-+        for (c = 0; c < cert_count; c++) {
-+            free(discard_const(request->list.items[c++].text));
-+        }
-+        free(request);
-+    }
-+    free(response);
-+
-+    return ret;
-+#else
-+    return ENOTSUP;
-+#endif
-+}
-+
-+#define TEXT_CERT_SEL_PROMPT_FMT "%s[%zu] Certificate: %s\n"
-+#define TEXT_SEL_TITLE discard_const("Please select a certificate by typing " \
-+                                     "the corresponding number\n")
-+static int prompt_multi_cert(pam_handle_t *pamh, struct pam_items *pi)
-+{
-+    int ret;
-+    size_t cert_count = 0;
-+    size_t tries = 0;
-+    long int resp = -1;
-+    struct cert_auth_info *cai;
-+    char *prompt;
-+    char *tmp;
-+    char *answer;
-+    char *ep;
-+
-+    /* First check if gdm extension is supported */
-+    ret = prompt_multi_cert_gdm(pamh, pi);
-+    if (ret != ENOTSUP) {
-+        return ret;
-+    }
-+
-+    if (pi->cert_list == NULL) {
-+        return EINVAL;
-+    }
-+
-+    prompt = strdup(TEXT_SEL_TITLE);
-+    if (prompt == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    DLIST_FOR_EACH(cai, pi->cert_list) {
-+        cert_count++;
-+        ret = asprintf(&tmp, TEXT_CERT_SEL_PROMPT_FMT, prompt, cert_count,
-+                                                       cai->key_id);
-+        free(prompt);
-+        if (ret == -1) {
-+            return ENOMEM;
-+        }
-+
-+        prompt = tmp;
-+    }
-+
-+    do {
-+        ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_ON, prompt, NULL,
-+                                  &answer);
-+        if (ret != PAM_SUCCESS) {
-+            D(("do_pam_conversation failed."));
-+            break;
-+        }
-+
-+        errno = 0;
-+        resp = strtol(answer, &ep, 10);
-+        if (errno == 0 && *ep == '\0' && resp > 0 && resp <= cert_count) {
-+            /* do not free answer ealier because ep is pointing to it */
-+            free(answer);
-+            break;
-+        }
-+        free(answer);
-+        resp = -1;
-+    } while (++tries < 5);
-+    free(prompt);
-+
-+    pi->selected_cert = NULL;
-+    ret = ENOENT;
-+    if (resp > 0 && resp <= cert_count) {
-+        cert_count = 0;
-+        DLIST_FOR_EACH(cai, pi->cert_list) {
-+            cert_count++;
-+            if (resp == cert_count) {
-+                pam_info(pamh, "Certificate ‘%s’ selected", cai->key_id);
-+                pi->selected_cert = cai;
-+                ret = 0;
-+                break;
-+            }
-+        }
-+    }
-+
-+    return ret;
-+}
-+
- static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi)
- {
-     int ret;
-@@ -1495,19 +1728,20 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi)
-     const struct pam_message *mesg[2] = { NULL, NULL };
-     struct pam_message m[2] = { { 0 }, { 0 } };
-     struct pam_response *resp = NULL;
-+    struct cert_auth_info *cai = pi->selected_cert;
- 
--    if (pi->token_name == NULL || *pi->token_name == '\0') {
-+    if (cai == NULL || cai->token_name == NULL || *cai->token_name == '\0') {
-         return EINVAL;
-     }
- 
--    size = sizeof(SC_PROMPT_FMT) + strlen(pi->token_name);
-+    size = sizeof(SC_PROMPT_FMT) + strlen(cai->token_name);
-     prompt = malloc(size);
-     if (prompt == NULL) {
-         D(("malloc failed."));
-         return ENOMEM;
-     }
- 
--    ret = snprintf(prompt, size, SC_PROMPT_FMT, pi->token_name);
-+    ret = snprintf(prompt, size, SC_PROMPT_FMT, cai->token_name);
-     if (ret < 0 || ret >= size) {
-         D(("snprintf failed."));
-         free(prompt);
-@@ -1604,9 +1838,9 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi)
-         pi->pam_authtok_size=0;
-     } else {
- 
--        ret = sss_auth_pack_sc_blob(answer, 0, pi->token_name, 0,
--                                    pi->module_name, 0,
--                                    pi->key_id, 0,
-+        ret = sss_auth_pack_sc_blob(answer, 0, cai->token_name, 0,
-+                                    cai->module_name, 0,
-+                                    cai->key_id, 0,
-                                     NULL, 0, &needed_size);
-         if (ret != EAGAIN) {
-             D(("sss_auth_pack_sc_blob failed."));
-@@ -1621,9 +1855,9 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi)
-             goto done;
-         }
- 
--        ret = sss_auth_pack_sc_blob(answer, 0, pi->token_name, 0,
--                                    pi->module_name, 0,
--                                    pi->key_id, 0,
-+        ret = sss_auth_pack_sc_blob(answer, 0, cai->token_name, 0,
-+                                    cai->module_name, 0,
-+                                    cai->key_id, 0,
-                                     (uint8_t *) pi->pam_authtok, needed_size,
-                                     &needed_size);
-         if (ret != EOK) {
-@@ -1786,7 +2020,17 @@ static int get_authtok_for_authentication(pam_handle_t *pamh,
-                 ret = prompt_2fa(pamh, pi, _("First Factor: "),
-                                  _("Second Factor: "));
-             }
--        } else if (pi->token_name != NULL && *(pi->token_name) != '\0') {
-+        } else if (pi->cert_list != NULL) {
-+            if (pi->cert_list->next == NULL) {
-+                /* Only one certificate */
-+                pi->selected_cert = pi->cert_list;
-+            } else {
-+                ret = prompt_multi_cert(pamh, pi);
-+                if (ret != 0) {
-+                    D(("Failed to select certificate"));
-+                    return PAM_AUTHTOK_ERR;
-+                }
-+            }
-             ret = prompt_sc_pin(pamh, pi);
-         } else {
-             ret = prompt_password(pamh, pi, _("Password: "));
-@@ -1905,14 +2149,21 @@ static int check_login_token_name(pam_handle_t *pamh, struct pam_items *pi,
-     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;
-+    }
- 
-     login_token_name = getenv("PKCS11_LOGIN_TOKEN_NAME");
-     if (login_token_name == NULL) {
-         return PAM_SUCCESS;
-     }
- 
--    while (pi->token_name == NULL
--            || strcmp(login_token_name, pi->token_name) != 0) {
-+    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) {
--- 
-2.13.6
-
diff --git a/SOURCES/0039-p11_child-use-options-to-select-certificate-for-auth.patch b/SOURCES/0039-p11_child-use-options-to-select-certificate-for-auth.patch
deleted file mode 100644
index 4b476fc..0000000
--- a/SOURCES/0039-p11_child-use-options-to-select-certificate-for-auth.patch
+++ /dev/null
@@ -1,609 +0,0 @@
-From e857005c207e514c487ba75daf20ca4be5321c38 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 27 Oct 2017 10:13:36 +0200
-Subject: [PATCH 39/46] p11_child: use options to select certificate for
- authentication
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-New options are added to p11_child to select a specific certificate
-during authentication.
-
-The related unit tests are updated by adding the needed attributes to
-the requests. The was not necessary before because although the
-attribute were already send by pam_sss they were not used in the PAM
-responder but only forwarded to the back where they were used by the
-PKINIT code to select the expected certificate.
-
-Related to https://pagure.io/SSSD/sssd/issue/3560
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Tested-by: Scott Poore <spoore@redhat.com>
-(cherry picked from commit 0a8024af282b271ad2185f68703d9f4e766d2bdc)
----
- src/p11_child/p11_child_nss.c   | 213 ++++++++++++++++++++++++++--------------
- src/responder/pam/pamsrv_p11.c  |  30 +++++-
- src/tests/cmocka/test_pam_srv.c |  64 ++++++++----
- 3 files changed, 210 insertions(+), 97 deletions(-)
-
-diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
-index 50bde2f4f91f6c00260b0db383d0962112686ebc..c676375cf7f6677a1d7f38f09b9bb5fd820d60c5 100644
---- a/src/p11_child/p11_child_nss.c
-+++ b/src/p11_child/p11_child_nss.c
-@@ -67,12 +67,34 @@ static char *password_passthrough(PK11SlotInfo *slot, PRBool retry, void *arg)
-   return PL_strdup((char *)arg);
- }
- 
-+static char *get_key_id_str(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].\n",
-+              PR_GetError());
-+        return NULL;
-+    }
- 
--int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in,
-+    key_id_str = CERT_Hexify(key_id, PR_FALSE);
-+    SECITEM_FreeItem(key_id, PR_TRUE);
-+    if (key_id_str == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d].\n", PR_GetError());
-+        return NULL;
-+    }
-+
-+    return key_id_str;
-+}
-+
-+int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-             enum op_mode mode, const char *pin,
-             struct cert_verify_opts *cert_verify_opts,
--            char **_multi)
-+            const char *module_name_in, const char *token_name_in,
-+            const char *key_id_in, char **_multi)
- {
-     int ret;
-     SECStatus rv;
-@@ -153,42 +175,31 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in,
-                                 mod_list_item->module->dllName);
-     }
- 
--    if (slot_name_in != NULL) {
--        slot = PK11_FindSlotByName(slot_name_in);
--        if (slot == NULL) {
--            DEBUG(SSSDBG_OP_FAILURE, "PK11_FindSlotByName failed for [%s]: [%d].\n",
--                                     slot_name_in, PR_GetError());
--            return EIO;
--        }
--    } else {
--
--        list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE,
--                                 NULL);
--        if (list == NULL) {
--            DEBUG(SSSDBG_OP_FAILURE, "PK11_GetAllTokens failed.\n");
--            return EIO;
--        }
-+    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE,
-+                             NULL);
-+    if (list == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "PK11_GetAllTokens failed.\n");
-+        return EIO;
-+    }
- 
--        for (le = list->head; le; le = le->next) {
--            CK_SLOT_INFO slInfo;
-+    for (le = list->head; le; le = le->next) {
-+        CK_SLOT_INFO slInfo;
- 
--            slInfo.flags = 0;
--            rv = PK11_GetSlotInfo(le->slot, &slInfo);
--            DEBUG(SSSDBG_TRACE_ALL,
--                  "Description [%s] Manufacturer [%s] flags [%lu].\n",
--                  slInfo.slotDescription, slInfo.manufacturerID, slInfo.flags);
--            if (rv == SECSuccess && (slInfo.flags & CKF_REMOVABLE_DEVICE)) {
--                slot = PK11_ReferenceSlot(le->slot);
--                break;
--           }
--        }
--        PK11_FreeSlotList(list);
--        if (slot == NULL) {
--            DEBUG(SSSDBG_OP_FAILURE, "No removable slots found.\n");
--            return EIO;
-+        slInfo.flags = 0;
-+        rv = PK11_GetSlotInfo(le->slot, &slInfo);
-+        DEBUG(SSSDBG_TRACE_ALL,
-+              "Description [%s] Manufacturer [%s] flags [%lu].\n",
-+              slInfo.slotDescription, slInfo.manufacturerID, slInfo.flags);
-+        if (rv == SECSuccess && (slInfo.flags & CKF_REMOVABLE_DEVICE)) {
-+            slot = PK11_ReferenceSlot(le->slot);
-+            break;
-         }
-     }
--
-+    PK11_FreeSlotList(list);
-+    if (slot == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "No removable slots found.\n");
-+        return EIO;
-+    }
- 
-     slot_id = PK11_GetSlotID(slot);
-     module_id = PK11_GetModuleID(slot);
-@@ -317,24 +328,60 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in,
-     for (cert_list_node = CERT_LIST_HEAD(cert_list);
-                 !CERT_LIST_END(cert_list_node, cert_list);
-                 cert_list_node = CERT_LIST_NEXT(cert_list_node)) {
--        if (cert_list_node->cert) {
--            DEBUG(SSSDBG_TRACE_ALL, "found cert[%s][%s]\n",
--                             cert_list_node->cert->nickname,
--                             cert_list_node->cert->subjectName);
-+        if (cert_list_node->cert == NULL) {
-+            DEBUG(SSSDBG_TRACE_ALL, "--- empty cert list node ---\n");
-+            continue;
-+        }
- 
--            if (cert_verify_opts->do_verification) {
--                rv = CERT_VerifyCertificateNow(handle, cert_list_node->cert,
--                                               PR_TRUE,
--                                               certificateUsageSSLClient,
--                                               NULL, NULL);
--                if (rv != SECSuccess) {
--                    DEBUG(SSSDBG_OP_FAILURE,
--                          "Certificate [%s][%s] not valid [%d], skipping.\n",
--                          cert_list_node->cert->nickname,
--                          cert_list_node->cert->subjectName, PR_GetError());
--                    continue;
--                }
-+        DEBUG(SSSDBG_TRACE_ALL,
-+              "found cert[%s][%s]\n",
-+              cert_list_node->cert->nickname,
-+              cert_list_node->cert->subjectName);
-+
-+        if (cert_verify_opts->do_verification) {
-+            rv = CERT_VerifyCertificateNow(handle, cert_list_node->cert,
-+                                           PR_TRUE,
-+                                           certificateUsageSSLClient,
-+                                           NULL, NULL);
-+            if (rv != SECSuccess) {
-+                DEBUG(SSSDBG_OP_FAILURE,
-+                      "Certificate [%s][%s] not valid [%d], skipping.\n",
-+                      cert_list_node->cert->nickname,
-+                      cert_list_node->cert->subjectName, PR_GetError());
-+                continue;
-             }
-+        }
-+
-+        if (key_id_in != NULL) {
-+            PORT_Free(key_id_str);
-+            key_id_str = NULL;
-+            key_id_str = get_key_id_str(slot, cert_list_node->cert);
-+        }
-+        /* 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_name, token_name_in, token_name,
-+              key_id_in, key_id_str);
-+        if ((mode == OP_AUTH
-+                && module_name_in != NULL
-+                && token_name_in != NULL
-+                && key_id_in != NULL
-+                && key_id_str != NULL
-+                && strcmp(key_id_in, key_id_str) == 0
-+                && strcmp(token_name_in, token_name) == 0
-+                && strcmp(module_name_in, module_name) == 0)
-+            || (mode == OP_PREAUTH
-+                && (module_name_in == NULL
-+                    || (module_name_in != NULL
-+                        && strcmp(module_name_in, module_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 && key_id_str != NULL
-+                        && strcmp(key_id_in, key_id_str) == 0)))) {
- 
-             rv = CERT_AddCertToListTail(valid_certs, cert_list_node->cert);
-             if (rv != SECSuccess) {
-@@ -343,15 +390,6 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in,
-                 ret = EIO;
-                 goto done;
-             }
--
--            if (found_cert == NULL) {
--                found_cert = cert_list_node->cert;
--            } else {
--                DEBUG(SSSDBG_TRACE_ALL, "More than one certificate found, " \
--                                        "using just the first one.\n");
--            }
--        } else {
--            DEBUG(SSSDBG_TRACE_ALL, "--- empty cert list node ---\n");
-         }
-     }
- 
-@@ -367,7 +405,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in,
-         }
-     }
- 
--    if (found_cert == NULL) {
-+    if (CERT_LIST_EMPTY(valid_certs)) {
-         DEBUG(SSSDBG_TRACE_ALL, "No certificate found.\n");
-         *_multi = NULL;
-         ret = EOK;
-@@ -375,6 +413,23 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in,
-     }
- 
-     if (mode == OP_AUTH) {
-+        cert_list_node = CERT_LIST_HEAD(valid_certs);
-+        if (!CERT_LIST_END(CERT_LIST_NEXT(cert_list_node), valid_certs)) {
-+            DEBUG(SSSDBG_FATAL_FAILURE,
-+                  "More than one certificate found for authentication, "
-+                  "aborting!\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
-+
-+        found_cert = cert_list_node->cert;
-+        if (found_cert == NULL) {
-+            DEBUG(SSSDBG_FATAL_FAILURE,
-+                  "No certificate found for authentication, aborting!\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
-+
-         rv = PK11_GenerateRandom(random_value, sizeof(random_value));
-         if (rv != SECSuccess) {
-             DEBUG(SSSDBG_OP_FAILURE,
-@@ -449,21 +504,10 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in,
- 
-         found_cert = cert_list_node->cert;
- 
--        SECITEM_FreeItem(key_id, PR_TRUE);
-         PORT_Free(key_id_str);
--        key_id = PK11_GetLowLevelKeyIDForCert(slot, found_cert, NULL);
--        if (key_id == NULL) {
--            DEBUG(SSSDBG_OP_FAILURE,
--                  "PK11_GetLowLevelKeyIDForCert failed [%d].\n",
--                  PR_GetError());
--            ret = EINVAL;
--            goto done;
--        }
--
--        key_id_str = CERT_Hexify(key_id, PR_FALSE);
-+        key_id_str = get_key_id_str(slot, found_cert);
-         if (key_id_str == NULL) {
--            DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d].\n",
--                  PR_GetError());
-+            DEBUG(SSSDBG_OP_FAILURE, "get_key_id_str [%d].\n", PR_GetError());
-             ret = ENOMEM;
-             goto done;
-         }
-@@ -576,11 +620,13 @@ int main(int argc, const char *argv[])
-     enum op_mode mode = OP_NONE;
-     enum pin_mode pin_mode = PIN_NONE;
-     char *pin = NULL;
--    char *slot_name_in = NULL;
-     char *nss_db = NULL;
-     struct cert_verify_opts *cert_verify_opts;
-     char *verify_opts = NULL;
-     char *multi = NULL;
-+    char *module_name = NULL;
-+    char *token_name = NULL;
-+    char *key_id = NULL;
- 
-     struct poptOption long_options[] = {
-         POPT_AUTOHELP
-@@ -605,6 +651,12 @@ int main(int argc, const char *argv[])
-          NULL},
-         {"nssdb", 0, POPT_ARG_STRING, &nss_db, 0, _("NSS DB to use"),
-          NULL},
-+        {"module_name", 0, POPT_ARG_STRING, &module_name, 0,
-+         _("Module name for authentication"), NULL},
-+        {"token_name", 0, POPT_ARG_STRING, &token_name, 0,
-+         _("Token name for authentication"), NULL},
-+        {"key_id", 0, POPT_ARG_STRING, &key_id, 0,
-+         _("Key ID for authentication"), NULL},
-         POPT_TABLEEND
-     };
- 
-@@ -730,6 +782,15 @@ int main(int argc, const char *argv[])
-     }
-     talloc_steal(main_ctx, debug_prg_name);
- 
-+    if (mode == OP_AUTH && (module_name == NULL || token_name == NULL
-+                                || key_id == NULL)) {
-+        DEBUG(SSSDBG_FATAL_FAILURE,
-+              "--module_name, --token_name and --key_id must be for "
-+              "authentication");
-+        ret = EINVAL;
-+        goto fail;
-+    }
-+
-     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");
-@@ -744,8 +805,8 @@ int main(int argc, const char *argv[])
-         }
-     }
- 
--    ret = do_work(main_ctx, nss_db, slot_name_in, mode, pin, cert_verify_opts,
--                  &multi);
-+    ret = do_work(main_ctx, nss_db, mode, pin, cert_verify_opts, module_name,
-+                  token_name, key_id, &multi);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "do_work failed.\n");
-         goto fail;
-diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
-index 57c8e1e464f4262f2d78f869c52ca48bd469d90a..4d5572164763ed0b3a842019f820680a4dc2dfdc 100644
---- a/src/responder/pam/pamsrv_p11.c
-+++ b/src/responder/pam/pamsrv_p11.c
-@@ -399,10 +399,13 @@ 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[7] = { NULL };
-+    const char *extra_args[13] = { NULL };
-     uint8_t *write_buf = NULL;
-     size_t write_buf_len = 0;
-     size_t arg_c;
-+    const char *module_name = NULL;
-+    const char *token_name = NULL;
-+    const char *key_id = NULL;
- 
-     req = tevent_req_create(mem_ctx, &state, struct pam_check_cert_state);
-     if (req == NULL) {
-@@ -423,6 +426,30 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
-         extra_args[arg_c++] = verify_opts;
-         extra_args[arg_c++] = "--verify";
-     }
-+
-+    if (sss_authtok_get_type(pd->authtok) == SSS_AUTHTOK_TYPE_SC_PIN
-+            || sss_authtok_get_type(pd->authtok) == SSS_AUTHTOK_TYPE_SC_KEYPAD) {
-+        ret = sss_authtok_get_sc(pd->authtok, NULL, NULL, &token_name, NULL,
-+                                 &module_name, NULL, &key_id, NULL);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_sc failed.\n");
-+            goto done;
-+        }
-+
-+        if (module_name != NULL && *module_name != '\0') {
-+            extra_args[arg_c++] = module_name;
-+            extra_args[arg_c++] = "--module_name";
-+        }
-+        if (token_name != NULL && *token_name != '\0') {
-+            extra_args[arg_c++] = token_name;
-+            extra_args[arg_c++] = "--token_name";
-+        }
-+        if (key_id != NULL && *key_id != '\0') {
-+            extra_args[arg_c++] = key_id;
-+            extra_args[arg_c++] = "--key_id";
-+        }
-+    }
-+
-     if (pd->cmd == SSS_PAM_AUTHENTICATE) {
-         extra_args[arg_c++] = "--auth";
-         switch (sss_authtok_get_type(pd->authtok)) {
-@@ -437,6 +464,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
-             ret = EINVAL;
-             goto done;
-         }
-+
-     } else if (pd->cmd == SSS_PAM_PREAUTH) {
-         extra_args[arg_c++] = "--pre";
-     } else {
-diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
-index 7f0ed706512ffe0866c0e1fb7e6baa16bec942d8..5c1f621ccead75717d1721714d953d7d4d415d7b 100644
---- a/src/tests/cmocka/test_pam_srv.c
-+++ b/src/tests/cmocka/test_pam_srv.c
-@@ -687,7 +687,9 @@ static void mock_input_pam(TALLOC_CTX *mem_ctx,
- }
- 
- static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name,
--                                const char *pin, const char *service,
-+                                const char *pin, const char *token_name,
-+                                const char *module_name, const char *key_id,
-+                                const char *service,
-                                 acct_cb_t acct_cb, const char *cert,
-                                 bool only_one_provider_call)
- {
-@@ -697,6 +699,7 @@ static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name,
-     struct pam_items pi = { 0 };
-     int ret;
-     bool already_mocked = false;
-+    size_t needed_size;
- 
-     if (name != NULL) {
-         pi.pam_user = name;
-@@ -707,9 +710,21 @@ static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name,
-     }
- 
-     if (pin != NULL) {
--        pi.pam_authtok = discard_const(pin);
--        pi.pam_authtok_size = strlen(pi.pam_authtok) + 1;
-+        ret = sss_auth_pack_sc_blob(pin, 0, token_name, 0, module_name, 0,
-+                                    key_id, 0, NULL, 0, &needed_size);
-+        assert_int_equal(ret, EAGAIN);
-+
-+        pi.pam_authtok = malloc(needed_size);
-+        assert_non_null(pi.pam_authtok);
-+
-+        ret = sss_auth_pack_sc_blob(pin, 0, token_name, 0, module_name, 0,
-+                                    key_id, 0,
-+                                    (uint8_t *)pi.pam_authtok, needed_size,
-+                                    &needed_size);
-+        assert_int_equal(ret, EOK);
-+
-         pi.pam_authtok_type = SSS_AUTHTOK_TYPE_SC_PIN;
-+        pi.pam_authtok_size = needed_size;
-     }
- 
-     pi.pam_service = service == NULL ? "login" : service;
-@@ -724,6 +739,7 @@ static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name,
-     pi.cli_pid = 12345;
- 
-     ret = pack_message_v3(&pi, &buf_size, &m_buf);
-+    free(pi.pam_authtok);
-     assert_int_equal(ret, 0);
- 
-     buf = talloc_memdup(mem_ctx, m_buf, buf_size);
-@@ -1732,7 +1748,8 @@ void test_pam_preauth_no_logon_name(void **state)
- {
-     int ret;
- 
--    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, false);
-+    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-+                        NULL, false);
- 
-     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-     will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-@@ -1824,7 +1841,8 @@ void test_pam_preauth_cert_nocert(void **state)
- 
-     set_cert_auth_param(pam_test_ctx->pctx, "/no/path");
- 
--    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, false);
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL,
-+                        NULL, NULL, false);
- 
-     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-     will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-@@ -1962,7 +1980,7 @@ void test_pam_preauth_cert_nomatch(void **state)
- 
-     set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
- 
--    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL,
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL,
-                         test_lookup_by_cert_cb, NULL, false);
- 
-     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-@@ -1984,7 +2002,7 @@ void test_pam_preauth_cert_match(void **state)
- 
-     set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
- 
--    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL,
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL,
-                         test_lookup_by_cert_cb, TEST_TOKEN_CERT, false);
- 
-     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-@@ -2007,8 +2025,9 @@ void test_pam_preauth_cert_match_gdm_smartcard(void **state)
- 
-     set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
- 
--    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, "gdm-smartcard",
--                        test_lookup_by_cert_cb, TEST_TOKEN_CERT, false);
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL,
-+                        "gdm-smartcard", test_lookup_by_cert_cb,
-+                        TEST_TOKEN_CERT, false);
- 
-     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-     will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-@@ -2029,7 +2048,7 @@ void test_pam_preauth_cert_match_wrong_user(void **state)
- 
-     set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
- 
--    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL,
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL,
-                         test_lookup_by_cert_wrong_user_cb,
-                         TEST_TOKEN_CERT, false);
- 
-@@ -2061,7 +2080,7 @@ void test_pam_preauth_cert_no_logon_name(void **state)
-      * Additionally sss_parse_inp_recv() must be mocked because the cache
-      * request will be done with the username found by the certificate
-      * lookup. */
--    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL,
-+    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL,
-                         test_lookup_by_cert_cb, TEST_TOKEN_CERT, false);
-     mock_account_recv_simple();
-     mock_parse_inp("pamuser", NULL, EOK);
-@@ -2090,7 +2109,7 @@ void test_pam_preauth_cert_no_logon_name_with_hint(void **state)
-      * Since user name hint is enabled we do not have to search the user
-      * during pre-auth and there is no need for an extra mocked response as in
-      * test_pam_preauth_cert_no_logon_name. */
--    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL,
-+    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL,
-                         test_lookup_by_cert_cb, TEST_TOKEN_CERT, false);
- 
-     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-@@ -2112,7 +2131,7 @@ void test_pam_preauth_cert_no_logon_name_double_cert(void **state)
- 
-     set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
- 
--    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL,
-+    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL,
-                         test_lookup_by_cert_double_cb, TEST_TOKEN_CERT, false);
- 
-     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-@@ -2135,7 +2154,7 @@ void test_pam_preauth_cert_no_logon_name_double_cert_with_hint(void **state)
-     set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
-     pam_test_ctx->rctx->domains->user_name_hint = true;
- 
--    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL,
-+    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL,
-                         test_lookup_by_cert_double_cb, TEST_TOKEN_CERT, false);
- 
-     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-@@ -2157,7 +2176,8 @@ void test_pam_preauth_no_cert_no_logon_name(void **state)
- 
-     set_cert_auth_param(pam_test_ctx->pctx, "/no/path");
- 
--    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, false);
-+    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-+                        NULL, false);
- 
-     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-     will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
-@@ -2178,7 +2198,7 @@ void test_pam_preauth_cert_no_logon_name_no_match(void **state)
- 
-     set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
- 
--    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL,
-+    mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL,
-                         test_lookup_by_cert_cb, NULL, false);
- 
-     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-@@ -2206,7 +2226,9 @@ void test_pam_cert_auth(void **state)
-      * 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", NULL,
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", "SSSD Test Token",
-+                        "NSS-Internal",
-+                        "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7", NULL,
-                         test_lookup_by_cert_cb, TEST_TOKEN_CERT, true);
- 
-     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE);
-@@ -2232,7 +2254,9 @@ void test_pam_cert_auth_double_cert(void **state)
- 
-     set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
- 
--    mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", NULL,
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", "SSSD Test Token",
-+                        "NSS-Internal",
-+                        "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7", NULL,
-                         test_lookup_by_cert_double_cb, TEST_TOKEN_CERT, true);
- 
-     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE);
-@@ -2257,7 +2281,7 @@ void test_pam_cert_preauth_2certs_one_mapping(void **state)
- 
-     set_cert_auth_param(pam_test_ctx->pctx, NSS_DB_2CERTS);
- 
--    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL,
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL,
-                         test_lookup_by_cert_cb, TEST_TOKEN_CERT, false);
- 
-     will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
-@@ -2279,7 +2303,7 @@ void test_pam_cert_preauth_2certs_two_mappings(void **state)
- 
-     set_cert_auth_param(pam_test_ctx->pctx, NSS_DB_2CERTS);
- 
--    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL,
-+    mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL,
-                         test_lookup_by_cert_cb_2nd_cert_same_user,
-                         TEST_TOKEN_CERT, false);
- 
--- 
-2.13.6
-
diff --git a/SOURCES/0039-sdap-respect-passwordGracelimit.patch b/SOURCES/0039-sdap-respect-passwordGracelimit.patch
new file mode 100644
index 0000000..4150d92
--- /dev/null
+++ b/SOURCES/0039-sdap-respect-passwordGracelimit.patch
@@ -0,0 +1,93 @@
+From bfafa12ae83bcdec53bb306f68eff9e6acfbb4a6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
+Date: Fri, 20 Jul 2018 12:15:18 +0200
+Subject: [PATCH] sdap: respect passwordGracelimit
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Since recent changes in 389-ds two response controls are end when
+passwordGracelimit is set and about to expire:
+- [1.3.6.1.4.1.42.2.27.8.5.1] for the GraceLimit itself
+- [2.16.840.1.113730.3.4.4] for the PasswordExpired
+
+Whenever the former is returned and the GraceLimit is still valid, we
+shouldn't report the latter to the users.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3597
+
+Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit 954bf82b60b7cfd93b865a6618f155d042b15729)
+
+DOWNSTREAM:
+Resolves: rhbz#1522928 - sssd doesn't allow user with expired password
+to login when PasswordgraceLimit set
+---
+ src/providers/ldap/sdap_async_connection.c | 21 ++++++++++++++++++++-
+ 1 file changed, 20 insertions(+), 1 deletion(-)
+
+diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c
+index a8d4262b52c4b2d2810450d68794f00558ea5c2d..8aacd6705a1f82be8c14f97996786ac9b47396d5 100644
+--- a/src/providers/ldap/sdap_async_connection.c
++++ b/src/providers/ldap/sdap_async_connection.c
+@@ -734,6 +734,7 @@ static void simple_bind_done(struct sdap_op *op,
+     ber_int_t pp_expire;
+     LDAPPasswordPolicyError pp_error;
+     int result = LDAP_OTHER;
++    bool on_grace_login_limit = false;
+ 
+     if (error) {
+         tevent_req_error(req, error);
+@@ -772,6 +773,7 @@ static void simple_bind_done(struct sdap_op *op,
+             DEBUG(SSSDBG_TRACE_INTERNAL,
+                   "Server returned control [%s].\n",
+                    response_controls[c]->ldctl_oid);
++
+             if (strcmp(response_controls[c]->ldctl_oid,
+                        LDAP_CONTROL_PASSWORDPOLICYRESPONSE) == 0) {
+                 lret = ldap_parse_passwordpolicy_control(state->sh->ldap,
+@@ -799,13 +801,26 @@ static void simple_bind_done(struct sdap_op *op,
+                 state->ppolicy->grace = pp_grace;
+                 state->ppolicy->expire = pp_expire;
+                 if (result == LDAP_SUCCESS) {
+-
++                    /* We have to set the on_grace_login_limit as when going
++                     * through the response controls 389-ds may return both
++                     * an warning and an error (and the order is not ensured)
++                     * for the GraceLimit:
++                     * - [1.3.6.1.4.1.42.2.27.8.5.1] for the GraceLimit itself
++                     * - [2.16.840.1.113730.3.4.4] for the PasswordExpired
++                     *
++                     * So, in order to avoid bulldozing the GraceLimit, let's
++                     * set it to true when pp_grace >= 0 and, in the end of
++                     * this function, just return EOK when LDAP returns the
++                     * PasswordExpired error but the GraceLimit is still valid.
++                     */
++                    on_grace_login_limit = false;
+                     if (pp_error == PP_changeAfterReset) {
+                         DEBUG(SSSDBG_TRACE_LIBS,
+                               "Password was reset. "
+                                "User must set a new password.\n");
+                         ret = ERR_PASSWORD_EXPIRED;
+                     } else if (pp_grace >= 0) {
++                        on_grace_login_limit = true;
+                         DEBUG(SSSDBG_TRACE_LIBS,
+                               "Password expired. "
+                                "[%d] grace logins remaining.\n",
+@@ -875,6 +890,10 @@ static void simple_bind_done(struct sdap_op *op,
+         ret = ERR_AUTH_FAILED;
+     }
+ 
++    if (ret == ERR_PASSWORD_EXPIRED && on_grace_login_limit) {
++        ret = EOK;
++    }
++
+ done:
+     ldap_controls_free(response_controls);
+     ldap_memfree(errmsg);
+-- 
+2.14.4
+
diff --git a/SOURCES/0040-MC-Remove-check-if-record-is-in-the-mapped-address-s.patch b/SOURCES/0040-MC-Remove-check-if-record-is-in-the-mapped-address-s.patch
new file mode 100644
index 0000000..5e9d331
--- /dev/null
+++ b/SOURCES/0040-MC-Remove-check-if-record-is-in-the-mapped-address-s.patch
@@ -0,0 +1,93 @@
+From 64085ac9dbc95bc7b227f24a9a8ec78952c68227 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 11 Jul 2018 22:18:41 +0200
+Subject: [PATCH] MC: Remove check if record is in the mapped address space
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There is a check in the memory cache code that checks if a record pointer
+points to the mmapped region . But since some time ago, we return not
+a pointer to the mmapped region itself, but a copy to avoid issues with
+invalidating an entry while the same entry is being returned.
+
+In most cases, the check is correct, simply because of how memory is laid
+out on Linux, but in some cases the check was failing and causing a high
+load of SSSD.
+
+Signed-off-by: Jakub Hrozek <jhrozek@redhat.com>
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3776
+
+Reviewed-by: Michal Židek <mzidek@redhat.com>
+(cherry picked from commit f1c2d4139b6107ee3e9bec0cbe5bf8c2ea8428b2)
+
+DOWNSTREAM:
+Resolves: rhbz#1586127 - Spurious check in the sssd nss memcache can cause the memory cache to be skipped
+---
+ src/sss_client/nss_mc_group.c  | 4 +---
+ src/sss_client/nss_mc_initgr.c | 5 +----
+ src/sss_client/nss_mc_passwd.c | 4 +---
+ 3 files changed, 3 insertions(+), 10 deletions(-)
+
+diff --git a/src/sss_client/nss_mc_group.c b/src/sss_client/nss_mc_group.c
+index 6a2336b6116f198adea94f9eda9d9632f9fc8268..3371e0ffc274cd55dad4e7cdb74456f9f4b92d8b 100644
+--- a/src/sss_client/nss_mc_group.c
++++ b/src/sss_client/nss_mc_group.c
+@@ -152,12 +152,10 @@ errno_t sss_nss_mc_getgrnam(const char *name, size_t name_len,
+         /* Integrity check
+          * - data->name cannot point outside strings
+          * - all strings must be within copy of record
+-         * - record must not end outside data table
+          * - rec_name is a zero-terminated string */
+         if (data->name < strs_offset
+             || data->name >= strs_offset + data->strs_len
+-            || data->strs_len > rec->len
+-            || (uint8_t *) rec + rec->len > gr_mc_ctx.data_table + data_size) {
++            || data->strs_len > rec->len) {
+             ret = ENOENT;
+             goto done;
+         }
+diff --git a/src/sss_client/nss_mc_initgr.c b/src/sss_client/nss_mc_initgr.c
+index 5a8c661c7e15a085e9662297f62a6a84e70b669e..331930cef357d17c74892f67d5743ebc6a818631 100644
+--- a/src/sss_client/nss_mc_initgr.c
++++ b/src/sss_client/nss_mc_initgr.c
+@@ -133,15 +133,12 @@ errno_t sss_nss_mc_initgroups_dyn(const char *name, size_t name_len,
+         /* Integrity check
+          * - data->name cannot point outside all strings or data
+          * - all data must be within copy of record
+-         * - size of record must be lower that data table size
+          * - data->strs cannot point outside strings
+          * - rec_name is a zero-terminated string */
+         if (data->name < data_offset
+             || data->name >= data_offset + data->data_len
+             || data->strs_len > data->data_len
+-            || data->data_len > rec->len
+-            || (uint8_t *) rec + rec->len
+-                                      > initgr_mc_ctx.data_table + data_size) {
++            || data->data_len > rec->len) {
+             ret = ENOENT;
+             goto done;
+         }
+diff --git a/src/sss_client/nss_mc_passwd.c b/src/sss_client/nss_mc_passwd.c
+index 3c62481778788173227f8a241953e421316e248d..ac44b711d8614ac0daa841a7a9dd5894f1a1eb08 100644
+--- a/src/sss_client/nss_mc_passwd.c
++++ b/src/sss_client/nss_mc_passwd.c
+@@ -145,12 +145,10 @@ errno_t sss_nss_mc_getpwnam(const char *name, size_t name_len,
+         /* Integrity check
+          * - data->name cannot point outside strings
+          * - all strings must be within copy of record
+-         * - record must not end outside data table
+          * - rec_name is a zero-terminated string */
+         if (data->name < strs_offset
+             || data->name >= strs_offset + data->strs_len
+-            || data->strs_len > rec->len
+-            || (uint8_t *) rec + rec->len > pw_mc_ctx.data_table + data_size) {
++            || data->strs_len > rec->len) {
+             ret = ENOENT;
+             goto done;
+         }
+-- 
+2.14.4
+
diff --git a/SOURCES/0040-pam-add-prompt-string-for-certificate-authentication.patch b/SOURCES/0040-pam-add-prompt-string-for-certificate-authentication.patch
deleted file mode 100644
index 8d94ce2..0000000
--- a/SOURCES/0040-pam-add-prompt-string-for-certificate-authentication.patch
+++ /dev/null
@@ -1,337 +0,0 @@
-From 4f09838b50cc771d52c7b00cc47fb3362d8ecda2 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 30 Oct 2017 08:03:42 +0100
-Subject: [PATCH 40/46] pam: add prompt string for certificate authentication
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-A new certificate attribute is added which contains a string which is
-used in the certificate selection list displayed to the user. The
-Subject-DN of the certificate is used here because it is present in all
-certificate and in general differs for certificate with different usage.
-libsss_certmap is used to extract the subject-DN from the certificate
-and convert it into a string.
-
-Related to https://pagure.io/SSSD/sssd/issue/3560
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Tested-by: Scott Poore <spoore@redhat.com>
-(cherry picked from commit 06c2300353faf3983e38fecb1d6afe1f6cc8fe32)
----
- Makefile.am                     |  2 ++
- src/responder/pam/pamsrv_p11.c  | 65 ++++++++++++++++++++++++++++++++++++++++-
- src/sss_client/pam_sss.c        | 31 ++++++++++++++++----
- src/tests/cmocka/test_pam_srv.c | 23 +++++++++++++--
- 4 files changed, 111 insertions(+), 10 deletions(-)
-
-diff --git a/Makefile.am b/Makefile.am
-index 4ed872a532daf9b934537cc5f64ce77778121e2a..16bcb4efc028b05c1196249245f4f3091b9366af 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -1400,6 +1400,7 @@ sssd_pam_LDADD = \
-     $(SELINUX_LIBS) \
-     $(PAM_LIBS) \
-     $(SYSTEMD_DAEMON_LIBS) \
-+    libsss_certmap.la \
-     $(SSSD_INTERNAL_LTLIBS) \
-     $(NULL)
- 
-@@ -2423,6 +2424,7 @@ pam_srv_tests_LDADD = \
-     $(SYSTEMD_DAEMON_LIBS) \
-     libsss_test_common.la \
-     libsss_idmap.la \
-+    libsss_certmap.la \
-     $(NULL)
- 
- EXTRA_responder_get_domains_tests_DEPENDENCIES = \
-diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
-index 4d5572164763ed0b3a842019f820680a4dc2dfdc..5a3eeff0ec977829a9ad8c80b4fc6b2e06857097 100644
---- a/src/responder/pam/pamsrv_p11.c
-+++ b/src/responder/pam/pamsrv_p11.c
-@@ -26,6 +26,8 @@
- #include "util/child_common.h"
- #include "util/strtonum.h"
- #include "responder/pam/pamsrv.h"
-+#include "lib/certmap/sss_certmap.h"
-+#include "util/crypto/sss_crypto.h"
- 
- 
- #ifndef SSSD_LIBEXEC_PATH
-@@ -683,6 +685,54 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-     return EOK;
- }
- 
-+static char *get_cert_prompt(TALLOC_CTX *mem_ctx, const char *cert)
-+{
-+    int ret;
-+    struct sss_certmap_ctx *ctx = NULL;
-+    unsigned char *der = NULL;
-+    size_t der_size;
-+    char *prompt = NULL;
-+    char *filter = NULL;
-+    char **domains = NULL;
-+
-+    ret = sss_certmap_init(mem_ctx, NULL, NULL, &ctx);
-+    if (ret != 0) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_init failed.\n");
-+        return NULL;
-+    }
-+
-+    ret = sss_certmap_add_rule(ctx, 10, "KRB5:<ISSUER>.*",
-+                               "LDAP:{subject_dn!nss}", NULL);
-+    if (ret != 0) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_add_rule failed.\n");
-+        goto done;
-+    }
-+
-+    der = sss_base64_decode(mem_ctx, cert, &der_size);
-+    if (der == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n");
-+        goto done;
-+    }
-+
-+    ret = sss_certmap_get_search_filter(ctx, der, der_size, &filter, &domains);
-+    if (ret != 0) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_get_search_filter failed.\n");
-+        goto done;
-+    }
-+
-+    prompt = talloc_strdup(mem_ctx, filter);
-+    if (prompt == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
-+    }
-+
-+done:
-+    sss_certmap_free_filter_and_domains(filter, domains);
-+    sss_certmap_free_ctx(ctx);
-+    talloc_free(der);
-+
-+    return prompt;
-+}
-+
- static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username,
-                               struct cert_auth_info *cert_info,
-                               uint8_t **_msg, size_t *_msg_len)
-@@ -692,16 +742,24 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username,
-     const char *token_name;
-     const char *module_name;
-     const char *key_id;
-+    char *prompt;
-     size_t user_len;
-     size_t token_len;
-     size_t module_len;
-     size_t key_id_len;
-+    size_t prompt_len;
-     const char *username = "";
- 
-     if (sysdb_username != NULL) {
-         username = sysdb_username;
-     }
- 
-+    prompt = get_cert_prompt(mem_ctx, sss_cai_get_cert(cert_info));
-+    if (prompt == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "get_cert_prompt failed.\n");
-+        return EIO;
-+    }
-+
-     token_name = sss_cai_get_token_name(cert_info);
-     module_name = sss_cai_get_module_name(cert_info);
-     key_id = sss_cai_get_key_id(cert_info);
-@@ -710,10 +768,12 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username,
-     token_len = strlen(token_name) + 1;
-     module_len = strlen(module_name) + 1;
-     key_id_len = strlen(key_id) + 1;
--    msg_len = user_len + token_len + module_len + key_id_len;
-+    prompt_len = strlen(prompt) + 1;
-+    msg_len = user_len + token_len + module_len + key_id_len + prompt_len;
- 
-     msg = talloc_zero_size(mem_ctx, msg_len);
-     if (msg == NULL) {
-+        talloc_free(prompt);
-         DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n");
-         return ENOMEM;
-     }
-@@ -722,6 +782,9 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username,
-     memcpy(msg + user_len, token_name, token_len);
-     memcpy(msg + user_len + token_len, module_name, module_len);
-     memcpy(msg + user_len + token_len + module_len, key_id, key_id_len);
-+    memcpy(msg + user_len + token_len + module_len + key_id_len,
-+           prompt, prompt_len);
-+    talloc_free(prompt);
- 
-     if (_msg != NULL) {
-         *_msg = msg;
-diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
-index c147d4b3d76443d69e27eb2da042f8eebd1ae6ab..1dc51ea0536a92a63ec2f4d97f65dbb02604dbb3 100644
---- a/src/sss_client/pam_sss.c
-+++ b/src/sss_client/pam_sss.c
-@@ -129,6 +129,7 @@ struct cert_auth_info {
-     char *token_name;
-     char *module_name;
-     char *key_id;
-+    char *prompt_str;
-     struct cert_auth_info *prev;
-     struct cert_auth_info *next;
- };
-@@ -140,6 +141,7 @@ static void free_cai(struct cert_auth_info *cai)
-         free(cai->cert);
-         free(cai->token_name);
-         free(cai->key_id);
-+        free(cai->prompt_str);
-         free(cai);
-     }
- }
-@@ -921,9 +923,25 @@ static int parse_cert_info(struct pam_items *pi, uint8_t *buf, size_t len,
-         goto done;
-     }
- 
--    D(("cert user: [%s] token name: [%s] module: [%s] key id: [%s]",
-+    offset += strlen(cai->key_id) + 1;
-+    if (offset >= len) {
-+        D(("Cert message size mismatch"));
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    cai->prompt_str = strdup((char *) &buf[*p + offset]);
-+    if (cai->prompt_str == NULL) {
-+        D(("strdup failed"));
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+
-+    D(("cert user: [%s] token name: [%s] module: [%s] key id: [%s] "
-+       "prompt: [%s]",
-        cai->cert_user, cai->token_name, cai->module_name,
--       cai->key_id));
-+       cai->key_id, cai->prompt_str));
- 
-     DLIST_ADD(pi->cert_list, cai);
-     ret = 0;
-@@ -1543,7 +1561,7 @@ done:
- #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
- #endif
- 
--#define CERT_SEL_PROMPT_FMT "Certificate: %s"
-+#define CERT_SEL_PROMPT_FMT "%s"
- #define SEL_TITLE discard_const("Please select a certificate")
- 
- static int prompt_multi_cert_gdm(pam_handle_t *pamh, struct pam_items *pi)
-@@ -1588,7 +1606,7 @@ static int prompt_multi_cert_gdm(pam_handle_t *pamh, struct pam_items *pi)
- 
-     c = 0;
-     DLIST_FOR_EACH(cai, pi->cert_list) {
--        ret = asprintf(&prompt, CERT_SEL_PROMPT_FMT, cai->key_id);
-+        ret = asprintf(&prompt, CERT_SEL_PROMPT_FMT, cai->prompt_str);
-         if (ret == -1) {
-             ret = ENOMEM;
-             goto done;
-@@ -1637,9 +1655,10 @@ done:
- #endif
- }
- 
--#define TEXT_CERT_SEL_PROMPT_FMT "%s[%zu] Certificate: %s\n"
-+#define TEXT_CERT_SEL_PROMPT_FMT "%s\n[%zu]:\n%s\n"
- #define TEXT_SEL_TITLE discard_const("Please select a certificate by typing " \
-                                      "the corresponding number\n")
-+
- static int prompt_multi_cert(pam_handle_t *pamh, struct pam_items *pi)
- {
-     int ret;
-@@ -1670,7 +1689,7 @@ static int prompt_multi_cert(pam_handle_t *pamh, struct pam_items *pi)
-     DLIST_FOR_EACH(cai, pi->cert_list) {
-         cert_count++;
-         ret = asprintf(&tmp, TEXT_CERT_SEL_PROMPT_FMT, prompt, cert_count,
--                                                       cai->key_id);
-+                                                       cai->prompt_str);
-         free(prompt);
-         if (ret == -1) {
-             return ENOMEM;
-diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
-index 5c1f621ccead75717d1721714d953d7d4d415d7b..50d3ed005468375ff02c60bebd1c61047ca1c6d4 100644
---- a/src/tests/cmocka/test_pam_srv.c
-+++ b/src/tests/cmocka/test_pam_srv.c
-@@ -53,6 +53,7 @@
- #define TEST_TOKEN_NAME "SSSD Test Token"
- #define TEST_MODULE_NAME "NSS-Internal"
- #define TEST_KEY_ID "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7"
-+#define TEST_SUBJECT_DN "CN=ipa-devel.ipa.devel,O=IPA.DEVEL"
- #define TEST_TOKEN_CERT \
- "MIIECTCCAvGgAwIBAgIBCTANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \
- "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \
-@@ -78,6 +79,7 @@
- "XyQBwOYRORlnfGyu+Yc9c3E0Wx8Tlznz0lqPR9g="
- 
- #define TEST2_KEY_ID "C8D60E009EB195D01A7083EE1D5419251AA87C2C"
-+#define TEST2_SUBJECT_DN "CN=IPA RA,O=IPA.DEVEL"
- #define TEST_TOKEN_2ND_CERT \
- "MIIDazCCAlOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \
- "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \
-@@ -831,7 +833,8 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body,
-     assert_int_equal(val, (sizeof("pamuser@"TEST_DOM_NAME)
-                                 + sizeof(TEST_TOKEN_NAME)
-                                 + sizeof(TEST_MODULE_NAME)
--                                + sizeof(TEST_KEY_ID)));
-+                                + sizeof(TEST_KEY_ID)
-+                                + sizeof(TEST_SUBJECT_DN)));
- 
-     assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0);
-     assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME);
-@@ -849,6 +852,10 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body,
-     assert_string_equal(body + rp, TEST_KEY_ID);
-     rp += sizeof(TEST_KEY_ID);
- 
-+    assert_int_equal(*(body + rp + sizeof(TEST_SUBJECT_DN) - 1), 0);
-+    assert_string_equal(body + rp, TEST_SUBJECT_DN);
-+    rp += sizeof(TEST_SUBJECT_DN);
-+
-     assert_int_equal(rp, blen);
-     return EOK;
- }
-@@ -893,7 +900,8 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
-     assert_int_equal(val, (strlen(name) + 1
-                                 + sizeof(TEST_TOKEN_NAME)
-                                 + sizeof(TEST_MODULE_NAME)
--                                + sizeof(TEST_KEY_ID)));
-+                                + sizeof(TEST_KEY_ID)
-+                                + sizeof(TEST_SUBJECT_DN)));
- 
-     assert_int_equal(*(body + rp + strlen(name)), 0);
-     assert_string_equal(body + rp, name);
-@@ -911,6 +919,10 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
-     assert_string_equal(body + rp, TEST_KEY_ID);
-     rp += sizeof(TEST_KEY_ID);
- 
-+    assert_int_equal(*(body + rp + sizeof(TEST_SUBJECT_DN) - 1), 0);
-+    assert_string_equal(body + rp, TEST_SUBJECT_DN);
-+    rp += sizeof(TEST_SUBJECT_DN);
-+
-     if (name2 != NULL && *name2 != '\0') {
-         SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-         assert_int_equal(val, type);
-@@ -919,7 +931,8 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
-         assert_int_equal(val, (strlen(name) + 1
-                                     + sizeof(TEST_TOKEN_NAME)
-                                     + sizeof(TEST_MODULE_NAME)
--                                    + sizeof(TEST2_KEY_ID)));
-+                                    + sizeof(TEST2_KEY_ID)
-+                                    + sizeof(TEST2_SUBJECT_DN)));
- 
-         assert_int_equal(*(body + rp + strlen(name)), 0);
-         assert_string_equal(body + rp, name);
-@@ -936,6 +949,10 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
-         assert_int_equal(*(body + rp + sizeof(TEST2_KEY_ID) - 1), 0);
-         assert_string_equal(body + rp, TEST2_KEY_ID);
-         rp += sizeof(TEST2_KEY_ID);
-+
-+        assert_int_equal(*(body + rp + sizeof(TEST2_SUBJECT_DN) - 1), 0);
-+        assert_string_equal(body + rp, TEST2_SUBJECT_DN);
-+        rp += sizeof(TEST2_SUBJECT_DN);
-     }
- 
-     assert_int_equal(rp, blen);
--- 
-2.13.6
-
diff --git a/SOURCES/0041-PAM-allow-missing-logon_name-during-certificate-auth.patch b/SOURCES/0041-PAM-allow-missing-logon_name-during-certificate-auth.patch
deleted file mode 100644
index 669c063..0000000
--- a/SOURCES/0041-PAM-allow-missing-logon_name-during-certificate-auth.patch
+++ /dev/null
@@ -1,256 +0,0 @@
-From f6e57537cbeaf6e3f313e700f08e0022a32a7d6c Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 30 Oct 2017 17:11:56 +0100
-Subject: [PATCH 41/46] PAM: allow missing logon_name during certificate
- authentication
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-If only one certificate is available and the logon_name is the user is
-not given the PAM responder already tried to find the name during the
-pre-auth step. With multiple certificates this might cause useless extra
-effort and the name should be determined after the certificate is
-selected in the authentication step. This might currently only happen
-with GDM because all other PAM clients will prompt for the user name
-unconditionally.
-
-New unit tests are added to cover this new case.
-
-Related to https://pagure.io/SSSD/sssd/issue/3560
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Tested-by: Scott Poore <spoore@redhat.com>
-(cherry picked from commit fd6f4047b58686bd4057c9859c3c804a77b136d8)
----
- src/responder/pam/pamsrv_cmd.c  | 63 ++++++++++++++++++++++++++-----
- src/tests/cmocka/test_pam_srv.c | 82 +++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 135 insertions(+), 10 deletions(-)
-
-diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
-index 8b2c086e206796ad4c977495be957c56b3255e7f..caf6c99489b8378d2e850473191223709920cd79 100644
---- a/src/responder/pam/pamsrv_cmd.c
-+++ b/src/responder/pam/pamsrv_cmd.c
-@@ -1151,6 +1151,7 @@ static errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *p
-     size_t blen;
-     errno_t ret;
-     uint32_t terminator;
-+    const char *key_id;
- 
-     prctx = talloc_get_type(cctx->protocol_ctx, struct cli_protocol);
- 
-@@ -1191,9 +1192,33 @@ static errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *p
-                                          pd->logon_name,
-                                          &pd->domain, &pd->user);
-     } else {
--        /* Only SSS_PAM_PREAUTH request may have a missing name, e.g. if the
--         * name is determined with the help of a certificate */
--        if (pd->cmd == SSS_PAM_PREAUTH
-+        /* SSS_PAM_PREAUTH request may have a missing name, e.g. if the
-+         * name is determined with the help of a certificate. During
-+         * SSS_PAM_AUTHENTICATE at least a key ID is needed to identify the
-+         * selected certificate. */
-+        if (pd->cmd == SSS_PAM_AUTHENTICATE
-+                && may_do_cert_auth(talloc_get_type(cctx->rctx->pvt_ctx,
-+                                                    struct pam_ctx), pd)
-+                && (sss_authtok_get_type(pd->authtok) == SSS_AUTHTOK_TYPE_SC_PIN
-+                    || sss_authtok_get_type(pd->authtok)
-+                                               == SSS_AUTHTOK_TYPE_SC_KEYPAD)) {
-+            ret = sss_authtok_get_sc(pd->authtok, NULL, NULL, NULL, NULL, NULL,
-+                                     NULL, &key_id, NULL);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_sc failed.\n");
-+                goto done;
-+            }
-+
-+            if (key_id == NULL || *key_id == '\0') {
-+                DEBUG(SSSDBG_CRIT_FAILURE,
-+                      "Missing logon and Smartcard key ID during "
-+                      "authentication.\n");
-+                ret = ERR_NO_CREDS;
-+                goto done;
-+            }
-+
-+            ret = EOK;
-+        } else if (pd->cmd == SSS_PAM_PREAUTH
-                 && may_do_cert_auth(talloc_get_type(cctx->rctx->pvt_ctx,
-                                                     struct pam_ctx), pd)) {
-             ret = EOK;
-@@ -1375,9 +1400,12 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
-     /* Determine what domain type to contact */
-     preq->req_dom_type = get_domain_request_type(preq, pctx);
- 
--    /* try backend first for authentication before doing local Smartcard
--     * authentication */
--    if (pd->cmd != SSS_PAM_AUTHENTICATE && may_do_cert_auth(pctx, pd)) {
-+    /* Try backend first for authentication before doing local Smartcard
-+     * authentication if a logon name is available. Otherwise try to derive
-+     * the logon name from the certificate first. */
-+    if ((pd->cmd != SSS_PAM_AUTHENTICATE
-+                || (pd->cmd == SSS_PAM_AUTHENTICATE && pd->logon_name == NULL))
-+            && may_do_cert_auth(pctx, pd)) {
-         ret = check_cert(cctx, cctx->ev, pctx, preq, pd);
-         /* Finish here */
-         goto done;
-@@ -1577,9 +1605,10 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
-     } else {
- 
-         if (preq->pd->logon_name == NULL) {
--            if (preq->pd->cmd != SSS_PAM_PREAUTH) {
-+            if (preq->pd->cmd != SSS_PAM_PREAUTH
-+                    && preq->pd->cmd != SSS_PAM_AUTHENTICATE) {
-                 DEBUG(SSSDBG_CRIT_FAILURE,
--                      "Missing logon name only allowed during pre-auth.\n");
-+                      "Missing logon name only allowed during (pre-)auth.\n");
-                 ret = ENOENT;
-                 goto done;
-             }
-@@ -1641,7 +1670,8 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
-                 }
-             }
- 
--            if (preq->cctx->rctx->domains->user_name_hint) {
-+            if (preq->cctx->rctx->domains->user_name_hint
-+                    && preq->pd->cmd == SSS_PAM_PREAUTH) {
-                 ret = add_pam_cert_response(preq->pd, cert_user,
-                                             preq->cert_list,
-                                             SSS_PAM_CERT_INFO_WITH_HINT);
-@@ -1664,6 +1694,20 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
-                 goto done;
-             }
- 
-+            /* If logon_name was not given during authentication add a
-+             * 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,
-+                                            preq->cert_list,
-+                                            SSS_PAM_CERT_INFO);
-+                if (ret != EOK) {
-+                    DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n");
-+                    preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
-+                    goto done;
-+                }
-+            }
-+
-             /* cert_user will be returned to the PAM client as user name, so
-              * we can use it here already e.g. to set in initgroups timeout */
-             preq->pd->logon_name = talloc_strdup(preq->pd, cert_user);
-@@ -2039,7 +2083,6 @@ static void pam_dom_forwarder(struct pam_auth_req *preq)
-                                   "the backend.\n");
-                         }
- 
--                        /* FIXME: use the right cert info */
-                         ret = add_pam_cert_response(preq->pd, cert_user,
-                                                     preq->current_cert,
-                                                     SSS_PAM_CERT_INFO);
-diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
-index 50d3ed005468375ff02c60bebd1c61047ca1c6d4..b6845320ca41d6933280aa2836a3d984dacfcc5e 100644
---- a/src/tests/cmocka/test_pam_srv.c
-+++ b/src/tests/cmocka/test_pam_srv.c
-@@ -967,6 +967,16 @@ static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen)
-                                   NULL);
- }
- 
-+static int test_pam_cert_check_auth_success(uint32_t status, uint8_t *body,
-+                                            size_t blen)
-+{
-+    assert_int_equal(pam_test_ctx->exp_pam_status, PAM_BAD_ITEM);
-+    pam_test_ctx->exp_pam_status = PAM_SUCCESS;
-+    return test_pam_cert_check_ex(status, body, blen,
-+                                  SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME,
-+                                  NULL);
-+}
-+
- static int test_pam_cert_check_with_hint(uint32_t status, uint8_t *body,
-                                          size_t blen)
- {
-@@ -2265,6 +2275,74 @@ void test_pam_cert_auth(void **state)
-     assert_int_equal(ret, EOK);
- }
- 
-+void test_pam_cert_auth_no_logon_name(void **state)
-+{
-+    int ret;
-+
-+    set_cert_auth_param(pam_test_ctx->pctx, NSS_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, NULL, "123456", "SSSD Test Token",
-+                        "NSS-Internal",
-+                        "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7", NULL,
-+                        test_lookup_by_cert_cb, TEST_TOKEN_CERT, true);
-+
-+    mock_account_recv_simple();
-+    mock_parse_inp("pamuser", NULL, EOK);
-+
-+    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_cert_check_auth_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_no_key_id(void **state)
-+{
-+    int ret;
-+
-+    set_cert_auth_param(pam_test_ctx->pctx, NSS_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, NULL, "123456", "SSSD Test Token",
-+                        "NSS-Internal", NULL, NULL,
-+                        NULL, NULL, false);
-+
-+    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_creds_insufficient_check);
-+    ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE,
-+                          pam_test_ctx->pam_cmds);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Wait until the test finishes with EOK */
-+    ret = test_ev_loop(pam_test_ctx->tctx);
-+    assert_int_equal(ret, EOK);
-+}
-+
- void test_pam_cert_auth_double_cert(void **state)
- {
-     int ret;
-@@ -2770,6 +2848,10 @@ 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_no_logon_name,
-+                                        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),
- #endif /* HAVE_NSS */
- 
-         cmocka_unit_test_setup_teardown(test_filter_response,
--- 
-2.13.6
-
diff --git a/SOURCES/0041-Revert-CRYPTO-Suppress-warning-Wstringop-truncation.patch b/SOURCES/0041-Revert-CRYPTO-Suppress-warning-Wstringop-truncation.patch
new file mode 100644
index 0000000..83f3206
--- /dev/null
+++ b/SOURCES/0041-Revert-CRYPTO-Suppress-warning-Wstringop-truncation.patch
@@ -0,0 +1,54 @@
+From 61227cf82d01ee42300ad7054bfd683536e15acb Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
+Date: Fri, 27 Jul 2018 11:37:20 +0200
+Subject: [PATCH] Revert "CRYPTO: Suppress warning Wstringop-truncation"
+
+This reverts commit 2951a9a84bd85f384213a3e071ffc167907df2d7.
+
+The original use stpncpy was correct. Changing it to memcpy
+changed the resulting hash. This resulted in users from
+local domain to not be able to authenticate (offline
+authentication was also probably broken) if their hash was
+created before this change.
+
+https://pagure.io/SSSD/sssd/issue/3791
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+
+DOWNSTREAM:
+Resolves: rhbz#1602781 - Local users failed to login with same password
+after upgrading to RHEL7.6
+---
+ src/util/crypto/libcrypto/crypto_sha512crypt.c | 2 +-
+ src/util/crypto/nss/nss_sha512crypt.c          | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/util/crypto/libcrypto/crypto_sha512crypt.c b/src/util/crypto/libcrypto/crypto_sha512crypt.c
+index 5861f34b9325f7552491a07e8b85fe35ca5ae607..b074eee555fafac6e486bfdf9efb9ddf4964a990 100644
+--- a/src/util/crypto/libcrypto/crypto_sha512crypt.c
++++ b/src/util/crypto/libcrypto/crypto_sha512crypt.c
+@@ -277,7 +277,7 @@ static int sha512_crypt_r(const char *key,
+         goto done;
+     }
+ 
+-    cp = memcpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
++    cp = stpncpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
+     buflen -= SALT_PREF_SIZE;
+ 
+     if (rounds_custom) {
+diff --git a/src/util/crypto/nss/nss_sha512crypt.c b/src/util/crypto/nss/nss_sha512crypt.c
+index 709cf51961bb7069ddebf3d636aa29b020756f0a..2f1624e6396c40f539a4e2034ab545cad8f05434 100644
+--- a/src/util/crypto/nss/nss_sha512crypt.c
++++ b/src/util/crypto/nss/nss_sha512crypt.c
+@@ -267,7 +267,7 @@ static int sha512_crypt_r(const char *key,
+         goto done;
+     }
+ 
+-    cp = memcpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
++    cp = stpncpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
+     buflen -= SALT_PREF_SIZE;
+ 
+     if (rounds_custom) {
+-- 
+2.14.4
+
diff --git a/SOURCES/0042-Revert-Revert-CRYPTO-Suppress-warning-Wstringop-trun.patch b/SOURCES/0042-Revert-Revert-CRYPTO-Suppress-warning-Wstringop-trun.patch
new file mode 100644
index 0000000..c9e72ef
--- /dev/null
+++ b/SOURCES/0042-Revert-Revert-CRYPTO-Suppress-warning-Wstringop-trun.patch
@@ -0,0 +1,52 @@
+From 503172f46360b33170063b3bf75047990c644ed5 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Tue, 31 Jul 2018 20:43:37 +0000
+Subject: [PATCH] Revert "Revert "CRYPTO: Suppress warning
+ Wstringop-truncation""
+
+This reverts commit bb20d5160faed5e0076887ac4a83e550be15a8b2.
+
+The patch introduced compile time warning
+src/util/crypto/libcrypto/crypto_sha512crypt.c:280:10: error: 'stpncpy'
+    output truncated before terminating nul copying 3 bytes from a string
+    of the same length [-Werror=stringop-truncation]
+     cp = stpncpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
+          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Merges: https://pagure.io/SSSD/sssd/pull-request/3792
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/util/crypto/libcrypto/crypto_sha512crypt.c | 2 +-
+ src/util/crypto/nss/nss_sha512crypt.c          | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/util/crypto/libcrypto/crypto_sha512crypt.c b/src/util/crypto/libcrypto/crypto_sha512crypt.c
+index b074eee555fafac6e486bfdf9efb9ddf4964a990..5861f34b9325f7552491a07e8b85fe35ca5ae607 100644
+--- a/src/util/crypto/libcrypto/crypto_sha512crypt.c
++++ b/src/util/crypto/libcrypto/crypto_sha512crypt.c
+@@ -277,7 +277,7 @@ static int sha512_crypt_r(const char *key,
+         goto done;
+     }
+ 
+-    cp = stpncpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
++    cp = memcpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
+     buflen -= SALT_PREF_SIZE;
+ 
+     if (rounds_custom) {
+diff --git a/src/util/crypto/nss/nss_sha512crypt.c b/src/util/crypto/nss/nss_sha512crypt.c
+index 2f1624e6396c40f539a4e2034ab545cad8f05434..709cf51961bb7069ddebf3d636aa29b020756f0a 100644
+--- a/src/util/crypto/nss/nss_sha512crypt.c
++++ b/src/util/crypto/nss/nss_sha512crypt.c
+@@ -267,7 +267,7 @@ static int sha512_crypt_r(const char *key,
+         goto done;
+     }
+ 
+-    cp = stpncpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
++    cp = memcpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
+     buflen -= SALT_PREF_SIZE;
+ 
+     if (rounds_custom) {
+-- 
+2.14.4
+
diff --git a/SOURCES/0042-p11_child-add-descriptions-for-error-codes-to-debug-.patch b/SOURCES/0042-p11_child-add-descriptions-for-error-codes-to-debug-.patch
deleted file mode 100644
index 37350b5..0000000
--- a/SOURCES/0042-p11_child-add-descriptions-for-error-codes-to-debug-.patch
+++ /dev/null
@@ -1,276 +0,0 @@
-From aa476a78b67a60d4ca2433091268a7790b4d62f7 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 30 Oct 2017 10:22:33 +0100
-Subject: [PATCH 42/46] p11_child: add descriptions for error codes to debug
- messages
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Additionally to the NSS erro code a text message describing the error is
-added. This will help to see why p11_child ignores specific
-certificates. For example it would be more obvious why the certificate
-is not valid (expired, missing CA cert, failed OCSP etc).
-
-Related to https://pagure.io/SSSD/sssd/issue/3560
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Tested-by: Scott Poore <spoore@redhat.com>
-(cherry picked from commit 08d1f8c0d6eece6a48201d7f8824b282eac3458d)
----
- src/p11_child/p11_child_nss.c | 91 ++++++++++++++++++++++++-------------------
- 1 file changed, 50 insertions(+), 41 deletions(-)
-
-diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
-index c676375cf7f6677a1d7f38f09b9bb5fd820d60c5..5f289688e41f4ea610292b907036e05cf95eb29d 100644
---- a/src/p11_child/p11_child_nss.c
-+++ b/src/p11_child/p11_child_nss.c
-@@ -75,15 +75,16 @@ static char *get_key_id_str(PK11SlotInfo *slot, CERTCertificate *cert)
-     key_id = PK11_GetLowLevelKeyIDForCert(slot, cert, NULL);
-     if (key_id == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE,
--              "PK11_GetLowLevelKeyIDForCert failed [%d].\n",
--              PR_GetError());
-+              "PK11_GetLowLevelKeyIDForCert failed [%d][%s].\n",
-+              PR_GetError(), PORT_ErrorToString(PR_GetError()));
-         return NULL;
-     }
- 
-     key_id_str = CERT_Hexify(key_id, PR_FALSE);
-     SECITEM_FreeItem(key_id, PR_TRUE);
-     if (key_id_str == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d].\n", PR_GetError());
-+        DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d][%s].\n",
-+              PR_GetError(), PORT_ErrorToString(PR_GetError()));
-         return NULL;
-     }
- 
-@@ -138,8 +139,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
- 
-     nss_ctx = NSS_InitContext(nss_db, "", "", SECMOD_DB, &parameters, flags);
-     if (nss_ctx == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "NSS_InitContext failed [%d].\n",
--                                 PR_GetError());
-+        DEBUG(SSSDBG_OP_FAILURE, "NSS_InitContext failed [%d][%s].\n",
-+              PR_GetError(), PORT_ErrorToString(PR_GetError()));
-         return EIO;
-     }
- 
-@@ -232,8 +233,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-         if (pin != NULL) {
-             rv = PK11_Authenticate(slot, PR_FALSE, discard_const(pin));
-             if (rv !=  SECSuccess) {
--                DEBUG(SSSDBG_OP_FAILURE, "PK11_Authenticate failed: [%d].\n",
--                                         PR_GetError());
-+                DEBUG(SSSDBG_OP_FAILURE, "PK11_Authenticate failed: [%d][%s].\n",
-+                      PR_GetError(), PORT_ErrorToString(PR_GetError()));
-                 return EIO;
-             }
-         } else {
-@@ -246,8 +247,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
- 
-     cert_list = PK11_ListCertsInSlot(slot);
-     if (cert_list == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "PK11_ListCertsInSlot failed: [%d].\n",
--                                 PR_GetError());
-+        DEBUG(SSSDBG_OP_FAILURE, "PK11_ListCertsInSlot failed: [%d][%s].\n",
-+              PR_GetError(), PORT_ErrorToString(PR_GetError()));
-         return EIO;
-     }
- 
-@@ -265,31 +266,33 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
- 
-     rv = CERT_FilterCertListByUsage(cert_list, certUsageSSLClient, PR_FALSE);
-     if (rv != SECSuccess) {
--        DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListByUsage failed: [%d].\n",
--                                 PR_GetError());
-+        DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListByUsage failed: [%d][%s].\n",
-+              PR_GetError(), PORT_ErrorToString(PR_GetError()));
-         return EIO;
-     }
- 
-     rv = CERT_FilterCertListForUserCerts(cert_list);
-     if (rv != SECSuccess) {
--        DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListForUserCerts failed: [%d].\n",
--                                 PR_GetError());
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "CERT_FilterCertListForUserCerts failed: [%d][%s].\n",
-+              PR_GetError(), PORT_ErrorToString(PR_GetError()));
-         return EIO;
-     }
- 
- 
-     handle = CERT_GetDefaultCertDB();
-     if (handle == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "CERT_GetDefaultCertDB failed: [%d].\n",
--                                 PR_GetError());
-+        DEBUG(SSSDBG_OP_FAILURE, "CERT_GetDefaultCertDB failed: [%d][%s].\n",
-+              PR_GetError(), PORT_ErrorToString(PR_GetError()));
-         return EIO;
-     }
- 
-     if (cert_verify_opts->do_ocsp) {
-         rv = CERT_EnableOCSPChecking(handle);
-         if (rv != SECSuccess) {
--            DEBUG(SSSDBG_OP_FAILURE, "CERT_EnableOCSPChecking failed: [%d].\n",
--                                     PR_GetError());
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "CERT_EnableOCSPChecking failed: [%d][%s].\n",
-+                  PR_GetError(), PORT_ErrorToString(PR_GetError()));
-             return EIO;
-         }
- 
-@@ -300,16 +303,16 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-                          cert_verify_opts->ocsp_default_responder_signing_cert);
-             if (rv != SECSuccess) {
-                 DEBUG(SSSDBG_OP_FAILURE,
--                      "CERT_SetOCSPDefaultResponder failed: [%d].\n",
--                      PR_GetError());
-+                      "CERT_SetOCSPDefaultResponder failed: [%d][%s].\n",
-+                      PR_GetError(), PORT_ErrorToString(PR_GetError()));
-                 return EIO;
-             }
- 
-             rv = CERT_EnableOCSPDefaultResponder(handle);
-             if (rv != SECSuccess) {
-                 DEBUG(SSSDBG_OP_FAILURE,
--                      "CERT_EnableOCSPDefaultResponder failed: [%d].\n",
--                      PR_GetError());
-+                      "CERT_EnableOCSPDefaultResponder failed: [%d][%s].\n",
-+                      PR_GetError(), PORT_ErrorToString(PR_GetError()));
-                 return EIO;
-             }
-         }
-@@ -318,8 +321,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-     found_cert = NULL;
-     valid_certs = CERT_NewCertList();
-     if (valid_certs == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "CERT_NewCertList failed [%d].\n",
--                                 PR_GetError());
-+        DEBUG(SSSDBG_OP_FAILURE, "CERT_NewCertList failed [%d][%s].\n",
-+              PR_GetError(), PORT_ErrorToString(PR_GetError()));
-         ret = ENOMEM;
-         goto done;
-     }
-@@ -345,9 +348,10 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-                                            NULL, NULL);
-             if (rv != SECSuccess) {
-                 DEBUG(SSSDBG_OP_FAILURE,
--                      "Certificate [%s][%s] not valid [%d], skipping.\n",
-+                      "Certificate [%s][%s] not valid [%d][%s], skipping.\n",
-                       cert_list_node->cert->nickname,
--                      cert_list_node->cert->subjectName, PR_GetError());
-+                      cert_list_node->cert->subjectName,
-+                      PR_GetError(), PORT_ErrorToString(PR_GetError()));
-                 continue;
-             }
-         }
-@@ -386,7 +390,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-             rv = CERT_AddCertToListTail(valid_certs, cert_list_node->cert);
-             if (rv != SECSuccess) {
-                 DEBUG(SSSDBG_OP_FAILURE,
--                      "CERT_AddCertToListTail failed [%d].\n", PR_GetError());
-+                      "CERT_AddCertToListTail failed [%d][%s].\n",
-+                      PR_GetError(), PORT_ErrorToString(PR_GetError()));
-                 ret = EIO;
-                 goto done;
-             }
-@@ -400,8 +405,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-         rv = CERT_DisableOCSPDefaultResponder(handle);
-         if (rv != SECSuccess) {
-             DEBUG(SSSDBG_OP_FAILURE,
--                  "CERT_DisableOCSPDefaultResponder failed: [%d].\n",
--                  PR_GetError());
-+                  "CERT_DisableOCSPDefaultResponder failed: [%d][%s].\n",
-+                  PR_GetError(), PORT_ErrorToString(PR_GetError()));
-         }
-     }
- 
-@@ -433,15 +438,17 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-         rv = PK11_GenerateRandom(random_value, sizeof(random_value));
-         if (rv != SECSuccess) {
-             DEBUG(SSSDBG_OP_FAILURE,
--                  "PK11_GenerateRandom failed [%d].\n", PR_GetError());
-+                  "PK11_GenerateRandom failed [%d][%s].\n",
-+                  PR_GetError(), PORT_ErrorToString(PR_GetError()));
-             return EIO;
-         }
- 
-         priv_key = PK11_FindPrivateKeyFromCert(slot, found_cert, NULL);
-         if (priv_key == NULL) {
-             DEBUG(SSSDBG_OP_FAILURE,
--                  "PK11_FindPrivateKeyFromCert failed [%d]." \
--                  "Maybe pin is missing.\n", PR_GetError());
-+                  "PK11_FindPrivateKeyFromCert failed [%d][%s]."
-+                  "Maybe pin is missing.\n",
-+                  PR_GetError(), PORT_ErrorToString(PR_GetError()));
-             ret = EIO;
-             goto done;
-         }
-@@ -451,8 +458,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-         if (algtag == SEC_OID_UNKNOWN) {
-             SECKEY_DestroyPrivateKey(priv_key);
-             DEBUG(SSSDBG_OP_FAILURE,
--                  "SEC_GetSignatureAlgorithmOidTag failed [%d].\n",
--                  PR_GetError());
-+                  "SEC_GetSignatureAlgorithmOidTag failed [%d][%s].\n",
-+                  PR_GetError(), PORT_ErrorToString(PR_GetError()));
-             ret = EIO;
-             goto done;
-         }
-@@ -462,8 +469,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-                           priv_key, algtag);
-         SECKEY_DestroyPrivateKey(priv_key);
-         if (rv != SECSuccess) {
--            DEBUG(SSSDBG_OP_FAILURE, "SEC_SignData failed [%d].\n",
--                                     PR_GetError());
-+            DEBUG(SSSDBG_OP_FAILURE, "SEC_SignData failed [%d][%s].\n",
-+                  PR_GetError(), PORT_ErrorToString(PR_GetError()));
-             ret = EIO;
-             goto done;
-         }
-@@ -471,7 +478,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-         pub_key = CERT_ExtractPublicKey(found_cert);
-         if (pub_key == NULL) {
-             DEBUG(SSSDBG_OP_FAILURE,
--                  "CERT_ExtractPublicKey failed [%d].\n", PR_GetError());
-+                  "CERT_ExtractPublicKey failed [%d][%s].\n",
-+                  PR_GetError(), PORT_ErrorToString(PR_GetError()));
-             ret = EIO;
-             goto done;
-         }
-@@ -481,8 +489,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-                             NULL);
-         SECKEY_DestroyPublicKey(pub_key);
-         if (rv != SECSuccess) {
--            DEBUG(SSSDBG_OP_FAILURE, "VFY_VerifyData failed [%d].\n",
--                                     PR_GetError());
-+            DEBUG(SSSDBG_OP_FAILURE, "VFY_VerifyData failed [%d][%s].\n",
-+                  PR_GetError(), PORT_ErrorToString(PR_GetError()));
-             ret = EACCES;
-             goto done;
-         }
-@@ -507,7 +515,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-         PORT_Free(key_id_str);
-         key_id_str = get_key_id_str(slot, found_cert);
-         if (key_id_str == NULL) {
--            DEBUG(SSSDBG_OP_FAILURE, "get_key_id_str [%d].\n", PR_GetError());
-+            DEBUG(SSSDBG_OP_FAILURE, "get_key_id_str [%d][%s].\n",
-+                  PR_GetError(), PORT_ErrorToString(PR_GetError()));
-             ret = ENOMEM;
-             goto done;
-         }
-@@ -562,8 +571,8 @@ done:
- 
-     rv = NSS_ShutdownContext(nss_ctx);
-     if (rv != SECSuccess) {
--        DEBUG(SSSDBG_OP_FAILURE, "NSS_ShutdownContext failed [%d].\n",
--                                 PR_GetError());
-+        DEBUG(SSSDBG_OP_FAILURE, "NSS_ShutdownContext failed [%d][%s].\n",
-+              PR_GetError(), PORT_ErrorToString(PR_GetError()));
-     }
- 
-     return ret;
--- 
-2.13.6
-
diff --git a/SOURCES/0043-CRYPTO-Save-prefix-in-s3crypt_sha512.patch b/SOURCES/0043-CRYPTO-Save-prefix-in-s3crypt_sha512.patch
new file mode 100644
index 0000000..fea39ee
--- /dev/null
+++ b/SOURCES/0043-CRYPTO-Save-prefix-in-s3crypt_sha512.patch
@@ -0,0 +1,48 @@
+From 62cfc6d28b770f56fcb103eeed32e961d3531f3d Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Tue, 31 Jul 2018 20:44:06 +0000
+Subject: [PATCH] CRYPTO: Save prefix in s3crypt_sha512
+
+Since commit 2951a9a84bd85f384213a3e071ffc167907df2d7 where we switched from
+stpncpy to memcpy the salt prefix "$6$" is not stored at all.
+This broke offline authentication if someone upgraded from old version
+that stored the prefix to one that doesn't store it.
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3791
+
+Merges: https://pagure.io/SSSD/sssd/pull-request/3792
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/util/crypto/libcrypto/crypto_sha512crypt.c | 1 +
+ src/util/crypto/nss/nss_sha512crypt.c          | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/src/util/crypto/libcrypto/crypto_sha512crypt.c b/src/util/crypto/libcrypto/crypto_sha512crypt.c
+index 5861f34b9325f7552491a07e8b85fe35ca5ae607..2275ccd96212b28984e47c128ba2acb233b865d0 100644
+--- a/src/util/crypto/libcrypto/crypto_sha512crypt.c
++++ b/src/util/crypto/libcrypto/crypto_sha512crypt.c
+@@ -278,6 +278,7 @@ static int sha512_crypt_r(const char *key,
+     }
+ 
+     cp = memcpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
++    cp += SALT_PREF_SIZE;
+     buflen -= SALT_PREF_SIZE;
+ 
+     if (rounds_custom) {
+diff --git a/src/util/crypto/nss/nss_sha512crypt.c b/src/util/crypto/nss/nss_sha512crypt.c
+index 709cf51961bb7069ddebf3d636aa29b020756f0a..4d0594d9f21f0fe4228037901c6792625bd4f7c6 100644
+--- a/src/util/crypto/nss/nss_sha512crypt.c
++++ b/src/util/crypto/nss/nss_sha512crypt.c
+@@ -268,6 +268,7 @@ static int sha512_crypt_r(const char *key,
+     }
+ 
+     cp = memcpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
++    cp += SALT_PREF_SIZE;
+     buflen -= SALT_PREF_SIZE;
+ 
+     if (rounds_custom) {
+-- 
+2.14.4
+
diff --git a/SOURCES/0043-pam-filter-certificates-in-the-responder-not-in-the-.patch b/SOURCES/0043-pam-filter-certificates-in-the-responder-not-in-the-.patch
deleted file mode 100644
index ac52d99..0000000
--- a/SOURCES/0043-pam-filter-certificates-in-the-responder-not-in-the-.patch
+++ /dev/null
@@ -1,357 +0,0 @@
-From 69c820abacd963a3699fc9ea84a17bb99f9eaf3a Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 6 Nov 2017 15:26:38 +0100
-Subject: [PATCH 43/46] pam: filter certificates in the responder not in the
- child
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-With the new selection option and the handling of multiple certificates
-in the PAM responder it is not needed anymore to filter the certificates
-in p11_child but the matching rules can be applied by the PAM responder
-directly.
-
-Related to https://pagure.io/SSSD/sssd/issue/3560
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Tested-by: Scott Poore <spoore@redhat.com>
-(cherry picked from commit 177ab84f0e336b75289a3ac0b2df25bd5ab5198b)
----
- src/p11_child/p11_child_nss.c   |  18 +-----
- src/responder/pam/pamsrv.h      |   6 ++
- src/responder/pam/pamsrv_cmd.c  |  10 ++-
- src/responder/pam/pamsrv_p11.c  | 135 +++++++++++++++++++++++++++++++++++++++-
- src/tests/cmocka/test_pam_srv.c |   3 +
- 5 files changed, 152 insertions(+), 20 deletions(-)
-
-diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
-index 5f289688e41f4ea610292b907036e05cf95eb29d..e59aba0d1561f58206252f7251ecd88315836b1b 100644
---- a/src/p11_child/p11_child_nss.c
-+++ b/src/p11_child/p11_child_nss.c
-@@ -264,22 +264,6 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-         }
-     }
- 
--    rv = CERT_FilterCertListByUsage(cert_list, certUsageSSLClient, PR_FALSE);
--    if (rv != SECSuccess) {
--        DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListByUsage failed: [%d][%s].\n",
--              PR_GetError(), PORT_ErrorToString(PR_GetError()));
--        return EIO;
--    }
--
--    rv = CERT_FilterCertListForUserCerts(cert_list);
--    if (rv != SECSuccess) {
--        DEBUG(SSSDBG_OP_FAILURE,
--              "CERT_FilterCertListForUserCerts failed: [%d][%s].\n",
--              PR_GetError(), PORT_ErrorToString(PR_GetError()));
--        return EIO;
--    }
--
--
-     handle = CERT_GetDefaultCertDB();
-     if (handle == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE, "CERT_GetDefaultCertDB failed: [%d][%s].\n",
-@@ -344,7 +328,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-         if (cert_verify_opts->do_verification) {
-             rv = CERT_VerifyCertificateNow(handle, cert_list_node->cert,
-                                            PR_TRUE,
--                                           certificateUsageSSLClient,
-+                                           certificateUsageCheckAllUsages,
-                                            NULL, NULL);
-             if (rv != SECSuccess) {
-                 DEBUG(SSSDBG_OP_FAILURE,
-diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
-index f15f7f19f1f38626288416c9f2038371c6f58b47..0bc229212844602ed461d1c7db48bf51ac2e2194 100644
---- a/src/responder/pam/pamsrv.h
-+++ b/src/responder/pam/pamsrv.h
-@@ -27,6 +27,7 @@
- #include "sbus/sssd_dbus.h"
- #include "responder/common/responder.h"
- #include "responder/common/cache_req/cache_req.h"
-+#include "lib/certmap/sss_certmap.h"
- 
- struct pam_auth_req;
- 
-@@ -49,6 +50,7 @@ struct pam_ctx {
-     bool cert_auth;
-     int p11_child_debug_fd;
-     char *nss_db;
-+    struct sss_certmap_ctx *sss_certmap_ctx;
- };
- 
- struct pam_auth_dp_req {
-@@ -104,6 +106,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
-                                        const char *nss_db,
-                                        time_t timeout,
-                                        const char *verify_opts,
-+                                       struct sss_certmap_ctx *sss_certmap_ctx,
-                                        struct pam_data *pd);
- errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-                             struct cert_auth_info **cert_list);
-@@ -114,6 +117,9 @@ 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);
-+
- errno_t
- pam_set_last_online_auth_with_curr_token(struct sss_domain_info *domain,
-                                          const char *username,
-diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
-index caf6c99489b8378d2e850473191223709920cd79..0e76c9e772f1775635677f35b870e9613b2faf64 100644
---- a/src/responder/pam/pamsrv_cmd.c
-+++ b/src/responder/pam/pamsrv_cmd.c
-@@ -1336,7 +1336,8 @@ static errno_t check_cert(TALLOC_CTX *mctx,
- 
-     req = pam_check_cert_send(mctx, ev, pctx->p11_child_debug_fd,
-                               pctx->nss_db, p11_child_timeout,
--                              cert_verification_opts, pd);
-+                              cert_verification_opts, pctx->sss_certmap_ctx,
-+                              pd);
-     if (req == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE, "pam_check_cert_send failed.\n");
-         return ENOMEM;
-@@ -1749,6 +1750,13 @@ static void pam_forwarder_cb(struct tevent_req *req)
-         goto done;
-     }
- 
-+    ret = p11_refresh_certmap_ctx(pctx, pctx->rctx->domains->certmaps);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "p11_refresh_certmap_ctx failed, "
-+              "certificate matching might not work as expected");
-+    }
-+
-     pd = preq->pd;
- 
-     ret = pam_forwarder_parse_data(cctx, pd);
-diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
-index 5a3eeff0ec977829a9ad8c80b4fc6b2e06857097..ec52c5ae7163d41144fe082643a201b766a1e201 100644
---- a/src/responder/pam/pamsrv_p11.c
-+++ b/src/responder/pam/pamsrv_p11.c
-@@ -36,6 +36,7 @@
- 
- #define P11_CHILD_LOG_FILE "p11_child"
- #define P11_CHILD_PATH SSSD_LIBEXEC_PATH"/p11_child"
-+#define CERT_AUTH_DEFAULT_MATCHING_RULE "KRB5:<EKU>clientAuth"
- 
- struct cert_auth_info {
-     char *cert;
-@@ -116,8 +117,110 @@ void sss_cai_check_users(struct cert_auth_info **list, size_t *_cert_count,
-     return;
- }
- 
-+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 p11_refresh_certmap_ctx(struct pam_ctx *pctx,
-+                                struct certmap_info **certmap_list)
-+{
-+    int ret;
-+    struct sss_certmap_ctx *sss_certmap_ctx = NULL;
-+    size_t c;
-+
-+    ret = sss_certmap_init(pctx, ext_debug, NULL, &sss_certmap_ctx);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_init failed.\n");
-+        goto done;
-+    }
-+
-+    if (certmap_list == NULL || *certmap_list == NULL) {
-+        /* 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);
-+        if (ret != 0) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Failed to add default matching rule.\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(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:
-+    if (ret == EOK) {
-+        sss_certmap_free_ctx(pctx->sss_certmap_ctx);
-+        pctx->sss_certmap_ctx = sss_certmap_ctx;
-+    } else {
-+        sss_certmap_free_ctx(sss_certmap_ctx);
-+    }
-+
-+    return ret;
-+}
-+
- 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;
-+
-+    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;
-+
-+    ret = p11_refresh_certmap_ctx(pctx, dom->certmaps);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "p11_refresh_certmap_ctx failed.\n");
-+        return ret;
-+    }
-+
-     return child_debug_init(P11_CHILD_LOG_FILE, &pctx->p11_child_debug_fd);
- }
- 
-@@ -214,6 +317,7 @@ static errno_t get_p11_child_write_buffer(TALLOC_CTX *mem_ctx,
- 
- static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf,
-                                         ssize_t buf_len,
-+                                        struct sss_certmap_ctx *sss_certmap_ctx,
-                                         struct cert_auth_info **_cert_list)
- {
-     int ret;
-@@ -222,6 +326,8 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf,
-     uint8_t *pn;
-     struct cert_auth_info *cert_list = NULL;
-     struct cert_auth_info *cert_auth_info;
-+    unsigned char *der = NULL;
-+    size_t der_size;
- 
-     if (buf_len < 0) {
-         DEBUG(SSSDBG_CRIT_FAILURE,
-@@ -347,7 +453,22 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf,
-         }
-         DEBUG(SSSDBG_TRACE_ALL, "Found cert [%s].\n", cert_auth_info->cert);
- 
--        DLIST_ADD(cert_list, cert_auth_info);
-+        der = sss_base64_decode(tmp_ctx, cert_auth_info->cert, &der_size);
-+        if (der == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n");
-+            ret = EIO;
-+            goto done;
-+        }
-+
-+        ret = sss_certmap_match_cert(sss_certmap_ctx, der, der_size);
-+        if (ret == 0) {
-+            DLIST_ADD(cert_list, cert_auth_info);
-+        } else {
-+            DEBUG(SSSDBG_TRACE_LIBS,
-+                  "Cert [%s] does not match matching rules and is ignored.\n",
-+                  cert_auth_info->cert);
-+            talloc_free(cert_auth_info);
-+        }
- 
-         p = ++pn;
-     } while ((pn - buf) < buf_len);
-@@ -373,6 +494,7 @@ struct pam_check_cert_state {
-     struct sss_child_ctx_old *child_ctx;
-     struct tevent_timer *timeout_handler;
-     struct tevent_context *ev;
-+    struct sss_certmap_ctx *sss_certmap_ctx;
- 
-     struct child_io_fds *io;
- 
-@@ -391,6 +513,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
-                                        const char *nss_db,
-                                        time_t timeout,
-                                        const char *verify_opts,
-+                                       struct sss_certmap_ctx *sss_certmap_ctx,
-                                        struct pam_data *pd)
- {
-     errno_t ret;
-@@ -420,6 +543,12 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
-+    if (sss_certmap_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Missing certificate matching context.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-     /* extra_args are added in revers order */
-     arg_c = 0;
-     extra_args[arg_c++] = nss_db;
-@@ -476,6 +605,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
-     }
- 
-     state->ev = ev;
-+    state->sss_certmap_ctx = sss_certmap_ctx;
-     state->child_status = EFAULT;
-     state->io = talloc(state, struct child_io_fds);
-     if (state->io == NULL) {
-@@ -639,7 +769,8 @@ static void p11_child_done(struct tevent_req *subreq)
- 
-     PIPE_FD_CLOSE(state->io->read_from_child_fd);
- 
--    ret = parse_p11_child_response(state, buf, buf_len, &state->cert_list);
-+    ret = parse_p11_child_response(state, buf, buf_len, state->sss_certmap_ctx,
-+                                   &state->cert_list);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "parse_p11_child_response failed.\n");
-         tevent_req_error(req, ret);
-diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
-index b6845320ca41d6933280aa2836a3d984dacfcc5e..bccf9972dacbb414076904a783772198620fd73c 100644
---- a/src/tests/cmocka/test_pam_srv.c
-+++ b/src/tests/cmocka/test_pam_srv.c
-@@ -287,6 +287,9 @@ struct pam_ctx *mock_pctx(TALLOC_CTX *mem_ctx)
-         return NULL;
-     }
- 
-+    ret = p11_refresh_certmap_ctx(pctx, NULL);
-+    assert_int_equal(ret, 0);
-+
-     return pctx;
- }
- 
--- 
-2.13.6
-
diff --git a/SOURCES/0044-PAM-add-certificate-s-label-to-the-selection-prompt.patch b/SOURCES/0044-PAM-add-certificate-s-label-to-the-selection-prompt.patch
deleted file mode 100644
index 4ec3f7b..0000000
--- a/SOURCES/0044-PAM-add-certificate-s-label-to-the-selection-prompt.patch
+++ /dev/null
@@ -1,274 +0,0 @@
-From 35790511fd43b0c33f3b410b20a31e007b3e5d20 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 7 Nov 2017 09:52:56 +0100
-Subject: [PATCH 44/46] PAM: add certificate's label to the selection prompt
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Some types of Smartcards contain multiple certificate with the same
-subject-DN for different usages. To make it easier to choose between
-them in case the matching rules allow more than one of them for
-authentication the label assigned to the certificate on the Smartcard is
-shown in the selection prompt as well.
-
-Related to https://pagure.io/SSSD/sssd/issue/3560
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Tested-by: Scott Poore <spoore@redhat.com>
-(cherry picked from commit 57cefea8305a57c1c0491afb739813b7f17d5a25)
----
- src/p11_child/p11_child_nss.c   | 18 ++++++++++++++----
- src/responder/pam/pamsrv.h      |  1 +
- src/responder/pam/pamsrv_p11.c  | 41 +++++++++++++++++++++++++++++++++++++----
- src/tests/cmocka/test_pam_srv.c | 28 ++++++++++++++--------------
- 4 files changed, 66 insertions(+), 22 deletions(-)
-
-diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
-index e59aba0d1561f58206252f7251ecd88315836b1b..21c508eb1b1b68b3606d0a5eed36573b01f27a19 100644
---- a/src/p11_child/p11_child_nss.c
-+++ b/src/p11_child/p11_child_nss.c
-@@ -130,7 +130,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-     CERTCertificate *found_cert = NULL;
-     PK11SlotList *list = NULL;
-     PK11SlotListElement *le;
--    SECItem *key_id = NULL;
-+    const char *label;
-     char *key_id_str = NULL;
-     CERTCertList *valid_certs = NULL;
-     char *cert_b64 = NULL;
-@@ -505,6 +505,17 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-             goto done;
-         }
- 
-+        /* The NSS nickname is typically token_name:label, so the label starts
-+         * after the ':'. */
-+        if (found_cert->nickname != NULL) {
-+            if ((label = strchr(found_cert->nickname, ':')) == NULL) {
-+                label = found_cert->nickname;
-+            } else {
-+                label++;
-+            }
-+        } else {
-+            label = "- no label found -";
-+        }
-         talloc_free(cert_b64);
-         cert_b64 = sss_base64_encode(mem_ctx, found_cert->derCert.data,
-                                      found_cert->derCert.len);
-@@ -517,9 +528,9 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-         DEBUG(SSSDBG_TRACE_ALL, "Found certificate has key id [%s].\n",
-               key_id_str);
- 
--        multi = talloc_asprintf_append(multi, "%s\n%s\n%s\n%s\n",
-+        multi = talloc_asprintf_append(multi, "%s\n%s\n%s\n%s\n%s\n",
-                                        token_name, module_name, key_id_str,
--                                       cert_b64);
-+                                       label, cert_b64);
-     }
-     *_multi = multi;
- 
-@@ -546,7 +557,6 @@ done:
-         CERT_DestroyCertList(cert_list);
-     }
- 
--    SECITEM_FreeItem(key_id, PR_TRUE);
-     PORT_Free(key_id_str);
- 
-     PORT_Free(signed_random_value.data);
-diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h
-index 0bc229212844602ed461d1c7db48bf51ac2e2194..dfd982178446d6327e09afc652018886c08fd88a 100644
---- a/src/responder/pam/pamsrv.h
-+++ b/src/responder/pam/pamsrv.h
-@@ -93,6 +93,7 @@ const char *sss_cai_get_cert(struct cert_auth_info *i);
- const char *sss_cai_get_token_name(struct cert_auth_info *i);
- const char *sss_cai_get_module_name(struct cert_auth_info *i);
- const char *sss_cai_get_key_id(struct cert_auth_info *i);
-+const char *sss_cai_get_label(struct cert_auth_info *i);
- struct cert_auth_info *sss_cai_get_next(struct cert_auth_info *i);
- struct ldb_result *sss_cai_get_cert_user_objs(struct cert_auth_info *i);
- void sss_cai_set_cert_user_objs(struct cert_auth_info *i,
-diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
-index ec52c5ae7163d41144fe082643a201b766a1e201..fa2435543ea305f7cdb1e18753525beb373eaf4c 100644
---- a/src/responder/pam/pamsrv_p11.c
-+++ b/src/responder/pam/pamsrv_p11.c
-@@ -43,6 +43,7 @@ struct cert_auth_info {
-     char *token_name;
-     char *module_name;
-     char *key_id;
-+    char *label;
-     struct ldb_result *cert_user_objs;
-     struct cert_auth_info *prev;
-     struct cert_auth_info *next;
-@@ -68,6 +69,11 @@ const char *sss_cai_get_key_id(struct cert_auth_info *i)
-     return i != NULL ? i->key_id : NULL;
- }
- 
-+const char *sss_cai_get_label(struct cert_auth_info *i)
-+{
-+    return i != NULL ? i->label : NULL;
-+}
-+
- struct cert_auth_info *sss_cai_get_next(struct cert_auth_info *i)
- {
-     return i != NULL ? i->next : NULL;
-@@ -439,6 +445,31 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf,
-         }
- 
-         if (pn == p) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Missing label in p11_child response.\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
-+
-+        cert_auth_info->label = talloc_strndup(cert_auth_info, (char *) p,
-+                                               (pn - p));
-+        if (cert_auth_info->label == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+        DEBUG(SSSDBG_TRACE_ALL, "Found label [%s].\n", cert_auth_info->label);
-+
-+        p = ++pn;
-+        pn = memchr(p, '\n', buf_len - (p - buf));
-+        if (pn == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Missing new-line in p11_child response.\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
-+
-+        if (pn == p) {
-             DEBUG(SSSDBG_OP_FAILURE, "Missing cert in p11_child response.\n");
-             ret = EINVAL;
-             goto done;
-@@ -816,7 +847,8 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-     return EOK;
- }
- 
--static char *get_cert_prompt(TALLOC_CTX *mem_ctx, const char *cert)
-+static char *get_cert_prompt(TALLOC_CTX *mem_ctx,
-+                             struct cert_auth_info *cert_info)
- {
-     int ret;
-     struct sss_certmap_ctx *ctx = NULL;
-@@ -839,7 +871,7 @@ static char *get_cert_prompt(TALLOC_CTX *mem_ctx, const char *cert)
-         goto done;
-     }
- 
--    der = sss_base64_decode(mem_ctx, cert, &der_size);
-+    der = sss_base64_decode(mem_ctx, sss_cai_get_cert(cert_info), &der_size);
-     if (der == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n");
-         goto done;
-@@ -851,7 +883,8 @@ static char *get_cert_prompt(TALLOC_CTX *mem_ctx, const char *cert)
-         goto done;
-     }
- 
--    prompt = talloc_strdup(mem_ctx, filter);
-+    prompt = talloc_asprintf(mem_ctx, "%s\n%s", sss_cai_get_label(cert_info),
-+                                                filter);
-     if (prompt == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
-     }
-@@ -885,7 +918,7 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username,
-         username = sysdb_username;
-     }
- 
--    prompt = get_cert_prompt(mem_ctx, sss_cai_get_cert(cert_info));
-+    prompt = get_cert_prompt(mem_ctx, cert_info);
-     if (prompt == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE, "get_cert_prompt failed.\n");
-         return EIO;
-diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c
-index bccf9972dacbb414076904a783772198620fd73c..4752648796ab4c863706780a2f470853cddbcc11 100644
---- a/src/tests/cmocka/test_pam_srv.c
-+++ b/src/tests/cmocka/test_pam_srv.c
-@@ -53,7 +53,7 @@
- #define TEST_TOKEN_NAME "SSSD Test Token"
- #define TEST_MODULE_NAME "NSS-Internal"
- #define TEST_KEY_ID "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7"
--#define TEST_SUBJECT_DN "CN=ipa-devel.ipa.devel,O=IPA.DEVEL"
-+#define TEST_PROMPT "Server-Cert\nCN=ipa-devel.ipa.devel,O=IPA.DEVEL"
- #define TEST_TOKEN_CERT \
- "MIIECTCCAvGgAwIBAgIBCTANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \
- "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \
-@@ -79,7 +79,7 @@
- "XyQBwOYRORlnfGyu+Yc9c3E0Wx8Tlznz0lqPR9g="
- 
- #define TEST2_KEY_ID "C8D60E009EB195D01A7083EE1D5419251AA87C2C"
--#define TEST2_SUBJECT_DN "CN=IPA RA,O=IPA.DEVEL"
-+#define TEST2_PROMPT "ipaCert\nCN=IPA RA,O=IPA.DEVEL"
- #define TEST_TOKEN_2ND_CERT \
- "MIIDazCCAlOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \
- "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \
-@@ -837,7 +837,7 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body,
-                                 + sizeof(TEST_TOKEN_NAME)
-                                 + sizeof(TEST_MODULE_NAME)
-                                 + sizeof(TEST_KEY_ID)
--                                + sizeof(TEST_SUBJECT_DN)));
-+                                + sizeof(TEST_PROMPT)));
- 
-     assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0);
-     assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME);
-@@ -855,9 +855,9 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body,
-     assert_string_equal(body + rp, TEST_KEY_ID);
-     rp += sizeof(TEST_KEY_ID);
- 
--    assert_int_equal(*(body + rp + sizeof(TEST_SUBJECT_DN) - 1), 0);
--    assert_string_equal(body + rp, TEST_SUBJECT_DN);
--    rp += sizeof(TEST_SUBJECT_DN);
-+    assert_int_equal(*(body + rp + sizeof(TEST_PROMPT) - 1), 0);
-+    assert_string_equal(body + rp, TEST_PROMPT);
-+    rp += sizeof(TEST_PROMPT);
- 
-     assert_int_equal(rp, blen);
-     return EOK;
-@@ -904,7 +904,7 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
-                                 + sizeof(TEST_TOKEN_NAME)
-                                 + sizeof(TEST_MODULE_NAME)
-                                 + sizeof(TEST_KEY_ID)
--                                + sizeof(TEST_SUBJECT_DN)));
-+                                + sizeof(TEST_PROMPT)));
- 
-     assert_int_equal(*(body + rp + strlen(name)), 0);
-     assert_string_equal(body + rp, name);
-@@ -922,9 +922,9 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
-     assert_string_equal(body + rp, TEST_KEY_ID);
-     rp += sizeof(TEST_KEY_ID);
- 
--    assert_int_equal(*(body + rp + sizeof(TEST_SUBJECT_DN) - 1), 0);
--    assert_string_equal(body + rp, TEST_SUBJECT_DN);
--    rp += sizeof(TEST_SUBJECT_DN);
-+    assert_int_equal(*(body + rp + sizeof(TEST_PROMPT) - 1), 0);
-+    assert_string_equal(body + rp, TEST_PROMPT);
-+    rp += sizeof(TEST_PROMPT);
- 
-     if (name2 != NULL && *name2 != '\0') {
-         SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
-@@ -935,7 +935,7 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
-                                     + sizeof(TEST_TOKEN_NAME)
-                                     + sizeof(TEST_MODULE_NAME)
-                                     + sizeof(TEST2_KEY_ID)
--                                    + sizeof(TEST2_SUBJECT_DN)));
-+                                    + sizeof(TEST2_PROMPT)));
- 
-         assert_int_equal(*(body + rp + strlen(name)), 0);
-         assert_string_equal(body + rp, name);
-@@ -953,9 +953,9 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen,
-         assert_string_equal(body + rp, TEST2_KEY_ID);
-         rp += sizeof(TEST2_KEY_ID);
- 
--        assert_int_equal(*(body + rp + sizeof(TEST2_SUBJECT_DN) - 1), 0);
--        assert_string_equal(body + rp, TEST2_SUBJECT_DN);
--        rp += sizeof(TEST2_SUBJECT_DN);
-+        assert_int_equal(*(body + rp + sizeof(TEST2_PROMPT) - 1), 0);
-+        assert_string_equal(body + rp, TEST2_PROMPT);
-+        rp += sizeof(TEST2_PROMPT);
-     }
- 
-     assert_int_equal(rp, blen);
--- 
-2.13.6
-
diff --git a/SOURCES/0044-crypto-tests-Add-unit-test-for-s3crypt_sha512.patch b/SOURCES/0044-crypto-tests-Add-unit-test-for-s3crypt_sha512.patch
new file mode 100644
index 0000000..b88bc1a
--- /dev/null
+++ b/SOURCES/0044-crypto-tests-Add-unit-test-for-s3crypt_sha512.patch
@@ -0,0 +1,68 @@
+From f0d437220d5c76f6b09dee5c5744397549fc3813 Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Tue, 31 Jul 2018 20:44:16 +0000
+Subject: [PATCH] crypto-tests: Add unit test for s3crypt_sha512
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3791
+
+Merges: https://pagure.io/SSSD/sssd/pull-request/3792
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ src/tests/crypto-tests.c | 32 ++++++++++++++++++++++++++++++++
+ 1 file changed, 32 insertions(+)
+
+diff --git a/src/tests/crypto-tests.c b/src/tests/crypto-tests.c
+index 2e826a41b3c1302b87c7136cc37b7c4df02a0584..6f5e22a878ad9e40b73b23915d08395b3f6f2e3d 100644
+--- a/src/tests/crypto-tests.c
++++ b/src/tests/crypto-tests.c
+@@ -201,6 +201,37 @@ START_TEST(test_sss_encrypt_decrypt)
+ }
+ END_TEST
+ 
++START_TEST(test_s3crypt_sha512)
++{
++    int ret;
++    char *salt;
++    char *userhash;
++    char *comphash;
++    const char *password = "password123";
++    const char *expected_hash = "$6$tU67Q/9h3tm5WJ.U$aL9gjCfiSZQewHTI6A4/MHCVWrMCiJZ.gNXEIw6HO39XGbg.s2nTyGlYXeoQyQtDll3XSbIZN41fJEC3v7ELy0";
++
++    test_ctx = talloc_new(NULL);
++    fail_if(test_ctx == NULL);
++
++    ret = s3crypt_gen_salt(test_ctx, &salt);
++    fail_if(ret != 0);
++
++    ret = s3crypt_sha512(test_ctx, password, salt, &userhash);
++    fail_if(ret != 0);
++
++    ret = s3crypt_sha512(test_ctx, password, userhash, &comphash);
++    fail_if(ret != 0);
++    ck_assert_str_eq(userhash, comphash);
++    talloc_free(comphash);
++
++    ret = s3crypt_sha512(test_ctx, password, expected_hash, &comphash);
++    fail_if(ret != 0);
++    ck_assert_str_eq(expected_hash, comphash);
++
++    talloc_free(test_ctx);
++}
++END_TEST
++
+ Suite *crypto_suite(void)
+ {
+     Suite *s = suite_create("sss_crypto");
+@@ -216,6 +247,7 @@ Suite *crypto_suite(void)
+     tcase_add_test(tc, test_base64_encode);
+     tcase_add_test(tc, test_base64_decode);
+     tcase_add_test(tc, test_sss_encrypt_decrypt);
++    tcase_add_test(tc, test_s3crypt_sha512);
+     /* Add all test cases to the test suite */
+     suite_add_tcase(s, tc);
+ 
+-- 
+2.14.4
+
diff --git a/SOURCES/0045-SSS_CERT-Close-file-descriptors-after-executing-p11_.patch b/SOURCES/0045-SSS_CERT-Close-file-descriptors-after-executing-p11_.patch
new file mode 100644
index 0000000..8eb4a97
--- /dev/null
+++ b/SOURCES/0045-SSS_CERT-Close-file-descriptors-after-executing-p11_.patch
@@ -0,0 +1,44 @@
+From a195869e527df27451bee8b68108abd005976b2d Mon Sep 17 00:00:00 2001
+From: Lukas Slebodnik <lslebodn@redhat.com>
+Date: Tue, 31 Jul 2018 21:03:38 +0000
+Subject: [PATCH] SSS_CERT: Close file descriptors after executing p11_child
+
+We can call cert_to_ssh_key_step from cert_to_ssh_key_done and thus
+p11_child can be executed more time. We created pipes for each call
+but destructor for state->io can close just last one.
+
+It's better to manually close pipes with macro PIPE_FD_CLOSE.
+that macro set file descriptor to -1 and destructor will not try
+to close them 2nd time. Destructor will cover just edge cases.
+
+Merges: https://pagure.io/SSSD/sssd/pull-request/3793
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3794
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+(cherry picked from commit a76f96ac143128c11bdb975293d667aca861cd91)
+
+DOWNSTREAM:
+Resolves: rhbz#1610667 - sssd_ssh leaks file descriptors when more than one certificate is converted into an SSH key
+---
+ src/util/cert/cert_common_p11_child.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/util/cert/cert_common_p11_child.c b/src/util/cert/cert_common_p11_child.c
+index 17e97eeeeb1956ca6d2bbf048445117029b10dde..aacdb5c475274234fd18d5eca23ee5f9c9288c3e 100644
+--- a/src/util/cert/cert_common_p11_child.c
++++ b/src/util/cert/cert_common_p11_child.c
+@@ -255,6 +255,9 @@ static void cert_to_ssh_key_done(int child_status,
+     int ret;
+     bool valid = false;
+ 
++    PIPE_FD_CLOSE(state->io->read_from_child_fd);
++    PIPE_FD_CLOSE(state->io->write_to_child_fd);
++
+     if (WIFEXITED(child_status)) {
+         if (WEXITSTATUS(child_status) != 0) {
+             DEBUG(SSSDBG_OP_FAILURE,
+-- 
+2.17.1
+
diff --git a/SOURCES/0045-SYSDB-Remove-code-causing-a-covscan-warning.patch b/SOURCES/0045-SYSDB-Remove-code-causing-a-covscan-warning.patch
deleted file mode 100644
index c2e1d8c..0000000
--- a/SOURCES/0045-SYSDB-Remove-code-causing-a-covscan-warning.patch
+++ /dev/null
@@ -1,128 +0,0 @@
-From 075f45980ea004201b2d13a3ecfe3bfb1478046d Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
-Date: Mon, 13 Nov 2017 08:29:53 +0100
-Subject: [PATCH 45/46] SYSDB: Remove code causing a covscan warning
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-There's no reason to check for both ret != EOK and sanitized == NULL, as
-the second should never ever happen.
-
-This check is causing a clang warning in our code:
-
- Defect type: CLANG_WARNING
- 1. sssd-1.16.0/src/db/sysdb_ops.c:4223:9: warning: Dereference of undefined pointer value
- #     if (res->count > 1) {
- #         ^~~~~~~~~~
- 4. sssd-1.16.0/src/db/sysdb_ops.c:4199:5: note: 'res' declared without an initial value
- #     struct ldb_result *res;
- #     ^~~~~~~~~~~~~~~~~~~~~~
- 7. sssd-1.16.0/src/db/sysdb_ops.c:4202:9: note: Assuming 'sid_str' is non-null
- #     if (!sid_str) return EINVAL;
- #         ^~~~~~~~
- 10. sssd-1.16.0/src/db/sysdb_ops.c:4202:5: note: Taking false branch
- #     if (!sid_str) return EINVAL;
- #     ^
- 13. sssd-1.16.0/src/db/sysdb_ops.c:4205:9: note: Assuming 'tmp_ctx' is non-null
- #     if (!tmp_ctx) {
- #         ^~~~~~~~
- 16. sssd-1.16.0/src/db/sysdb_ops.c:4205:5: note: Taking false branch
- #     if (!tmp_ctx) {
- #     ^
- 19. sssd-1.16.0/src/db/sysdb_ops.c:4209:11: note: Calling 'sysdb_search_object_by_sid'
- #     ret = sysdb_search_object_by_sid(tmp_ctx, domain, sid_str, NULL, &res);
- #           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 22. sssd-1.16.0/src/db/sysdb_ops.c:4960:12: note: Calling 'sysdb_search_object_by_str_attr'
- #     return sysdb_search_object_by_str_attr(mem_ctx, domain, SYSDB_SID_FILTER,
- #            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 25. sssd-1.16.0/src/db/sysdb_ops.c:4872:5: note: Taking false branch
- #     if (str == NULL) {
- #     ^
- 28. sssd-1.16.0/src/db/sysdb_ops.c:4877:9: note: Assuming 'ret' is equal to 0
- #     if (ret != EOK || sanitized == NULL) {
- #         ^~~~~~~~~~
- 31. sssd-1.16.0/src/db/sysdb_ops.c:4877:9: note: Left side of '||' is false
- 32. sssd-1.16.0/src/db/sysdb_ops.c:4877:23: note: Assuming 'sanitized' is equal to null
- #     if (ret != EOK || sanitized == NULL) {
- #                       ^~~~~~~~~~~~~~~~~
- 35. sssd-1.16.0/src/db/sysdb_ops.c:4877:5: note: Taking true branch
- #     if (ret != EOK || sanitized == NULL) {
- #     ^
- 38. sssd-1.16.0/src/db/sysdb_ops.c:4878:9: note: Left side of '||' is false
- #         DEBUG(SSSDBG_OP_FAILURE, "sss_filter_sanitize failed.\n");
- #         ^
- 41. sssd-1.16.0/src/util/debug.h:123:9: note: expanded from macro 'DEBUG'
- #     if (DEBUG_IS_SET(__debug_macro_level)) { \
- #         ^
- 44. sssd-1.16.0/src/util/debug.h:135:30: note: expanded from macro 'DEBUG_IS_SET'
- # #define DEBUG_IS_SET(level) (debug_level & (level) || \
- #                              ^
- 47. sssd-1.16.0/src/db/sysdb_ops.c:4878:9: note: Assuming 'debug_level' is not equal to 0
- #         DEBUG(SSSDBG_OP_FAILURE, "sss_filter_sanitize failed.\n");
- #         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 50. sssd-1.16.0/src/util/debug.h:123:9: note: expanded from macro 'DEBUG'
- #     if (DEBUG_IS_SET(__debug_macro_level)) { \
- #         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 53. sssd-1.16.0/src/util/debug.h:136:30: note: expanded from macro 'DEBUG_IS_SET'
- #                             (debug_level == SSSDBG_UNRESOLVED && \
- #                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 56. sssd-1.16.0/src/db/sysdb_ops.c:4878:9: note: Left side of '&&' is false
- 57. sssd-1.16.0/src/util/debug.h:123:9: note: expanded from macro 'DEBUG'
- #     if (DEBUG_IS_SET(__debug_macro_level)) { \
- #         ^
- 60. sssd-1.16.0/src/util/debug.h:136:63: note: expanded from macro 'DEBUG_IS_SET'
- #                             (debug_level == SSSDBG_UNRESOLVED && \
- #                                                               ^
- 63. sssd-1.16.0/src/db/sysdb_ops.c:4878:9: note: Loop condition is false. Exiting loop
- 64. sssd-1.16.0/src/util/debug.h:121:35: note: expanded from macro 'DEBUG'
- # #define DEBUG(level, format, ...) do { \
- #                                   ^
- 67. sssd-1.16.0/src/db/sysdb_ops.c:4879:9: note: Control jumps to line 4892
- #         goto done;
- #         ^
- 70. sssd-1.16.0/src/db/sysdb_ops.c:4960:12: note: Returning from 'sysdb_search_object_by_str_attr'
- #     return sysdb_search_object_by_str_attr(mem_ctx, domain, SYSDB_SID_FILTER,
- #            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 73. sssd-1.16.0/src/db/sysdb_ops.c:4209:11: note: Returning from 'sysdb_search_object_by_sid'
- #     ret = sysdb_search_object_by_sid(tmp_ctx, domain, sid_str, NULL, &res);
- #           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 76. sssd-1.16.0/src/db/sysdb_ops.c:4211:5: note: Taking false branch
- #     if (ret == ENOENT) {
- #     ^
- 79. sssd-1.16.0/src/db/sysdb_ops.c:4217:12: note: Taking false branch
- #     } else if (ret != EOK) {
- #            ^
- 82. sssd-1.16.0/src/db/sysdb_ops.c:4223:9: note: Dereference of undefined pointer value
- #     if (res->count > 1) {
- #         ^~~~~~~~~~
- #  4221|       }
- #  4222|
- #  4223|->     if (res->count > 1) {
- #  4224|           DEBUG(SSSDBG_FATAL_FAILURE, "getbysid call returned more than one " \
- #  4225|                                        "result !?!\n");
-
-Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit b739b3e767c053bb3a7e6651514896b30502d838)
----
- src/db/sysdb_ops.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
-index 2f8e36c6c9a2c2cefe4af5fb78957763304d989a..635c7db51f516e2217c93016409499e49289004c 100644
---- a/src/db/sysdb_ops.c
-+++ b/src/db/sysdb_ops.c
-@@ -4874,7 +4874,7 @@ static errno_t sysdb_search_object_by_str_attr(TALLOC_CTX *mem_ctx,
-     }
- 
-     ret = sss_filter_sanitize(NULL, str, &sanitized);
--    if (ret != EOK || sanitized == NULL) {
-+    if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "sss_filter_sanitize failed.\n");
-         goto done;
-     }
--- 
-2.13.6
-
diff --git a/SOURCES/0046-SELINUX-Also-call-is_selinux_enabled-as-a-check-for-.patch b/SOURCES/0046-SELINUX-Also-call-is_selinux_enabled-as-a-check-for-.patch
new file mode 100644
index 0000000..7665629
--- /dev/null
+++ b/SOURCES/0046-SELINUX-Also-call-is_selinux_enabled-as-a-check-for-.patch
@@ -0,0 +1,60 @@
+From 663fdd3897c5da1a54fcb51613bd71660ef9b19a Mon Sep 17 00:00:00 2001
+From: Jakub Hrozek <jhrozek@redhat.com>
+Date: Wed, 20 Jun 2018 22:02:57 +0200
+Subject: [PATCH] SELINUX: Also call is_selinux_enabled as a check for selinux
+ child
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Resolves:
+https://pagure.io/SSSD/sssd/issue/3796
+
+The SSSD selinux management routines were only checking if SELinux is
+managed on the system. If it is managed, the code tries to proceed and
+set the login context, otherwise an error is returned which SSSD handles
+gracefully.
+
+But this is not enough, in some cases SELinux might be disabled, but
+managed and in these cases SSSD was returning strange errors, which
+might have prevented login with selinux provider in effect.
+
+We got this hint form the RH SELinux maintainer:
+"""
+libsemanage is for managing SELinux infrastructure. generally if there's
+/etc/selinux/config where libsemanage can read SELINUXTYPE and SELinux
+module store - /etc/selinux/<SELINUXTYPE>/active (or
+/var/lib/selinux/<SELINUXTYPE>/active) - is available, libsemanage can
+manage it even when SELinux is disabled.
+
+I'm not sure if selinux_child doesn any is_selinux_enabled() checks but
+it could help to avoid such situations.
+"""
+
+Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
+(cherry picked from commit 1e81d040c75b2b15cab48fb7df1041138747e6c3)
+
+DOWNSTREAM:
+Resolves: rhbz#1583360 - The IPA selinux provider can return an error if SELinux is completely disabled
+---
+ src/util/sss_semanage.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c
+index 7b0eef22330db8df6ab8f46da5fb76c68f6adabc..bcce57b603bd1c4d5c6465dbb5cc7a3fbe72412d 100644
+--- a/src/util/sss_semanage.c
++++ b/src/util/sss_semanage.c
+@@ -82,6 +82,10 @@ static int sss_is_selinux_managed(semanage_handle_t *handle)
+         return EINVAL;
+     }
+ 
++    if (!is_selinux_enabled()) {
++        return ERR_SELINUX_NOT_MANAGED;
++    }
++
+     ret = semanage_is_managed(handle);
+     if (ret == 0) {
+         DEBUG(SSSDBG_TRACE_FUNC, "SELinux policy not managed via libsemanage\n");
+-- 
+2.17.1
+
diff --git a/SOURCES/0046-SYSDB-Better-debugging-for-email-conflicts.patch b/SOURCES/0046-SYSDB-Better-debugging-for-email-conflicts.patch
deleted file mode 100644
index 283ef2a..0000000
--- a/SOURCES/0046-SYSDB-Better-debugging-for-email-conflicts.patch
+++ /dev/null
@@ -1,94 +0,0 @@
-From de3b178ada423c10c8f14194a64c299ad96e7bf1 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
-Date: Thu, 26 Oct 2017 18:38:42 +0200
-Subject: [PATCH 46/46] SYSDB: Better debugging for email conflicts
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Add DEBUG message when conflicts in FQ names or emails
-are detected.
-
-Also improve man page to hint on how to work around issue
-with conflicting emails.
-
-Note: We store emails in two different attributes in sysdb:
-- SYSDB_USER_EMAIL
-- SYSDB_NAME_ALIAS - this one is lowercased and used in getpwnam
-                     searches.
-
-Resolves:
-https://fedorahosted.org/sssd/ticket/3293
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 39d6a3be119b050b0690152b6b443117c8617b1c)
----
- src/db/sysdb_ops.c      |  4 +++-
- src/db/sysdb_search.c   | 15 +++++++++++++++
- src/man/sssd-ldap.5.xml |  9 +++++++++
- 3 files changed, 27 insertions(+), 1 deletion(-)
-
-diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
-index 635c7db51f516e2217c93016409499e49289004c..1539c41c93e7d6ebd1e544abbb1707df5578cd72 100644
---- a/src/db/sysdb_ops.c
-+++ b/src/db/sysdb_ops.c
-@@ -640,7 +640,9 @@ int sysdb_search_user_by_upn_res(TALLOC_CTX *mem_ctx,
-         goto done;
-     } else if (res->count > 1) {
-         DEBUG(SSSDBG_OP_FAILURE,
--              "Search for upn [%s] returns more than one result.\n", upn);
-+              "Search for upn [%s] returns more than one result. One of the "
-+              "possible reasons can be that several users share the same "
-+              "email address.\n", upn);
-         ret = EINVAL;
-         goto done;
-     }
-diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
-index f488442afcc6eef114437a7110722759f86fe19e..8083966900429b268a3b984f1cad3d47d1099198 100644
---- a/src/db/sysdb_search.c
-+++ b/src/db/sysdb_search.c
-@@ -218,6 +218,21 @@ int sysdb_getpwnam(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
-+    if (res->count > 1) {
-+        /* We expected either 0 or 1 result for search with
-+         * SYSDB_PWNAM_FILTER, but we got more. This error
-+         * is handled individually depending on what function
-+         * called sysdb_getpwnam, so we just print a message
-+         * here and let the caller decide what error code to
-+         * propagate based on res->count > 1. */
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Search for [%s] returned multiple results. It can be an email "
-+              "address shared among multiple users or an email address of a "
-+              "user that conflicts with another user's fully qualified name. "
-+              "SSSD will not be able to handle those users properly.\n",
-+              sanitized_name);
-+    }
-+
-     /* Merge in the timestamps from the fast ts db */
-     ret = sysdb_merge_res_ts_attrs(domain->sysdb, res, attrs);
-     if (ret != EOK) {
-diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
-index d38bac3607d294c53ea692130a6b93ced9b0ab82..de596f0da62be9eb61b880b6e1d4a0f33689e25a 100644
---- a/src/man/sssd-ldap.5.xml
-+++ b/src/man/sssd-ldap.5.xml
-@@ -878,6 +878,15 @@
-                             address of the user.
-                         </para>
-                         <para>
-+                            Note: If an email address of a user conflicts with
-+                            an email address or fully qualified name of another
-+                            user, then SSSD will not be able to serve those
-+                            users properly. If for some reason several users
-+                            need to share the same email address then set
-+                            this option to a nonexistent attribute name in
-+                            order to disable user lookup/login by email.
-+                        </para>
-+                        <para>
-                             Default: mail
-                         </para>
-                     </listitem>
--- 
-2.13.6
-
diff --git a/SOURCES/0047-NSS-Use-enum_ctx-as-memory_context-in-_setnetgrent_s.patch b/SOURCES/0047-NSS-Use-enum_ctx-as-memory_context-in-_setnetgrent_s.patch
deleted file mode 100644
index 28b8715..0000000
--- a/SOURCES/0047-NSS-Use-enum_ctx-as-memory_context-in-_setnetgrent_s.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From 3b4479b63ae812c1ef355c1c697caddd882b1b8f Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 6 Nov 2017 17:03:19 +0100
-Subject: [PATCH 47/47] NSS: Use enum_ctx as memory_context in
- _setnetgrent_set_timeout()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-We've noticed some crashes that happened because enum_ctx is already
-freed, but the timeout handler is still called. In order to avoid that,
-let's remove the timeout handler when enum_ctx is freed at other places.
-
-Resolves: https://pagure.io/SSSD/sssd/issue/3523
-
-Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit f6a1cef87abdd983d6b5349cd341c9a249826577)
----
- src/responder/nss/nss_enum.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/responder/nss/nss_enum.c b/src/responder/nss/nss_enum.c
-index aa7d8428f37e943a6b5904495c40ad4b8011b767..da844fbced529f606a3e98669fb7b95e0696ce00 100644
---- a/src/responder/nss/nss_enum.c
-+++ b/src/responder/nss/nss_enum.c
-@@ -283,7 +283,7 @@ nss_setnetgrent_set_timeout(struct tevent_context *ev,
-     timeout = enum_ctx->result[0]->domain->netgroup_timeout;
- 
-     tv = tevent_timeval_current_ofs(timeout, 0);
--    te = tevent_add_timer(ev, nss_ctx, tv, nss_setnetgrent_timeout, enum_ctx);
-+    te = tevent_add_timer(ev, enum_ctx, tv, nss_setnetgrent_timeout, enum_ctx);
-     if (te == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE,
-               "Could not set up life timer for enumeration object.\n");
--- 
-2.13.6
-
diff --git a/SOURCES/0048-TOOLS-Add-a-new-sssctl-command-access-report.patch b/SOURCES/0048-TOOLS-Add-a-new-sssctl-command-access-report.patch
deleted file mode 100644
index 5788df9..0000000
--- a/SOURCES/0048-TOOLS-Add-a-new-sssctl-command-access-report.patch
+++ /dev/null
@@ -1,504 +0,0 @@
-From 73a04a5c53c0e7701aa7753fd459ffbea52e28b8 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 23 Oct 2017 18:08:12 +0200
-Subject: [PATCH 48/57] TOOLS: Add a new sssctl command access-report
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/2840
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 3ee8659bc6a77a78bc6c61b9650a36bd18ea95c8)
----
- Makefile.am                             |   1 +
- src/tools/sssctl/sssctl.c               |   1 +
- src/tools/sssctl/sssctl.h               |   5 +
- src/tools/sssctl/sssctl_access_report.c | 435 ++++++++++++++++++++++++++++++++
- 4 files changed, 442 insertions(+)
- create mode 100644 src/tools/sssctl/sssctl_access_report.c
-
-diff --git a/Makefile.am b/Makefile.am
-index 16bcb4efc028b05c1196249245f4f3091b9366af..5917bd904054055a259eb69217282e4fb914c700 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -1754,6 +1754,7 @@ sssctl_SOURCES = \
-     src/tools/sssctl/sssctl_sifp.c \
-     src/tools/sssctl/sssctl_config.c \
-     src/tools/sssctl/sssctl_user_checks.c \
-+    src/tools/sssctl/sssctl_access_report.c \
-     $(SSSD_TOOLS_OBJ) \
-     $(NULL)
- sssctl_LDADD = \
-diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c
-index 1e061c00d2238bf34adff4183e560dc127dd62c7..eee2d613966a5dda81627d2e225bfdc9bade4041 100644
---- a/src/tools/sssctl/sssctl.c
-+++ b/src/tools/sssctl/sssctl.c
-@@ -264,6 +264,7 @@ int main(int argc, const char **argv)
-         SSS_TOOL_COMMAND("domain-list", "List available domains", 0, sssctl_domain_list),
-         SSS_TOOL_COMMAND("domain-status", "Print information about domain", 0, sssctl_domain_status),
-         SSS_TOOL_COMMAND("user-checks", "Print information about a user and check authentication", 0, sssctl_user_checks),
-+        SSS_TOOL_COMMAND("access-report", "Generate access report for a domain", 0, sssctl_access_report),
-         SSS_TOOL_DELIMITER("Information about cached content:"),
-         SSS_TOOL_COMMAND("user-show", "Information about cached user", 0, sssctl_user_show),
-         SSS_TOOL_COMMAND("group-show", "Information about cached group", 0, sssctl_group_show),
-diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h
-index 22ca5d41e2c084e64b58bc5aa066414b002e7e8b..70fc19eff07317c264978a1ecb9159ae3acdfced 100644
---- a/src/tools/sssctl/sssctl.h
-+++ b/src/tools/sssctl/sssctl.h
-@@ -133,4 +133,9 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline,
- errno_t sssctl_user_checks(struct sss_cmdline *cmdline,
-                            struct sss_tool_ctx *tool_ctx,
-                            void *pvt);
-+
-+errno_t sssctl_access_report(struct sss_cmdline *cmdline,
-+                             struct sss_tool_ctx *tool_ctx,
-+                             void *pvt);
-+
- #endif /* _SSSCTL_H_ */
-diff --git a/src/tools/sssctl/sssctl_access_report.c b/src/tools/sssctl/sssctl_access_report.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..11172329817b4dedaca480ab8a4537149853c330
---- /dev/null
-+++ b/src/tools/sssctl/sssctl_access_report.c
-@@ -0,0 +1,435 @@
-+/*
-+    Copyright (C) 2017 Red Hat
-+
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU Lesser General Public License as published by
-+    the Free Software Foundation; either version 3 of the License, or
-+    (at your option) any later version.
-+
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU Lesser General Public License for more details.
-+
-+    You should have received a copy of the GNU Lesser General Public License
-+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+*/
-+
-+#include <security/pam_appl.h>
-+
-+#include "util/util.h"
-+#include "tools/common/sss_tools.h"
-+#include "tools/sssctl/sssctl.h"
-+
-+/*
-+ * We're searching the cache directly..
-+ */
-+#include "providers/ipa/ipa_hbac_private.h"
-+#include "providers/ipa/ipa_rules_common.h"
-+
-+#ifdef HAVE_SECURITY_PAM_MISC_H
-+# include <security/pam_misc.h>
-+#elif defined(HAVE_SECURITY_OPENPAM_H)
-+# include <security/openpam.h>
-+#endif
-+
-+#ifdef HAVE_SECURITY_PAM_MISC_H
-+static struct pam_conv conv = {
-+    misc_conv,
-+    NULL
-+};
-+#elif defined(HAVE_SECURITY_OPENPAM_H)
-+static struct pam_conv conv = {
-+    openpam_ttyconv,
-+    NULL
-+};
-+#else
-+# error "Missing text based pam conversation function"
-+#endif
-+
-+#ifndef DEFAULT_SERVICE
-+#define DEFAULT_SERVICE "system-auth"
-+#endif /* DEFAULT_SERVICE */
-+
-+#ifndef DEFAULT_USER
-+#define DEFAULT_USER "admin"
-+#endif /* DEFAULT_USER */
-+
-+typedef errno_t (*sssctl_dom_access_reporter_fn)(struct sss_tool_ctx *tool_ctx,
-+                                                 const char *user,
-+                                                 const char *service,
-+                                                 struct sss_domain_info *domain);
-+
-+static errno_t run_pam_acct(struct sss_tool_ctx *tool_ctx,
-+                            const char *user,
-+                            const char *service,
-+                            struct sss_domain_info *domain)
-+{
-+    errno_t ret;
-+    pam_handle_t *pamh;
-+
-+    ret = pam_start(service, user, &conv, &pamh);
-+    if (ret != PAM_SUCCESS) {
-+        ERROR("pam_start failed: %s\n", pam_strerror(pamh, ret));
-+        return EIO;
-+    }
-+
-+    ret = pam_acct_mgmt(pamh, 0);
-+    pam_end(pamh, ret);
-+    return ret;
-+}
-+
-+static errno_t get_rdn_value(TALLOC_CTX *mem_ctx,
-+                             struct sss_domain_info *dom,
-+                             const char *dn_attr,
-+                             const char **_rdn_value)
-+{
-+    errno_t ret;
-+    TALLOC_CTX *tmp_ctx;
-+    struct ldb_dn *dn = NULL;
-+    const struct ldb_val *rdn_val;
-+    const char *rdn_str;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    dn = ldb_dn_new(tmp_ctx, sysdb_ctx_get_ldb(dom->sysdb), dn_attr);
-+    if (dn == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    rdn_val = ldb_dn_get_rdn_val(dn);
-+    if (rdn_val == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "No RDN value?\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    rdn_str = talloc_strndup(tmp_ctx,
-+                               (const char *)rdn_val->data,
-+                               rdn_val->length);
-+    if (rdn_str == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = EOK;
-+    *_rdn_value = talloc_steal(mem_ctx, rdn_str);
-+done:
-+    talloc_zfree(tmp_ctx);
-+    return ret;
-+}
-+
-+static errno_t is_member_group(struct sss_domain_info *dom,
-+                               const char *dn_attr,
-+                               const char *group_rdn,
-+                               bool *_is_group)
-+{
-+    const char *comp_name;
-+    const struct ldb_val *comp_val;
-+    TALLOC_CTX *tmp_ctx;
-+    bool is_group = false;
-+    errno_t ret;
-+    struct ldb_dn *dn = NULL;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    dn = ldb_dn_new(tmp_ctx, sysdb_ctx_get_ldb(dom->sysdb), dn_attr);
-+    if (dn == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    comp_name = ldb_dn_get_component_name(dn, 1);
-+    comp_val = ldb_dn_get_component_val(dn, 1);
-+    if (strcasecmp("cn", comp_name) == 0
-+            && strncasecmp(group_rdn,
-+                           (const char *) comp_val->data,
-+                           comp_val->length) == 0) {
-+        is_group = true;
-+    }
-+
-+    ret = EOK;
-+done:
-+    *_is_group = is_group;
-+    talloc_zfree(tmp_ctx);
-+    return ret;
-+}
-+
-+static void print_category(struct sss_domain_info *domain,
-+                           struct ldb_message *rule_msg,
-+                           const char *category_attr_name,
-+                           const char *category_label)
-+{
-+    struct ldb_message_element *category_attr;
-+
-+    category_attr = ldb_msg_find_element(rule_msg, category_attr_name);
-+    if (category_attr == NULL) {
-+        DEBUG(SSSDBG_MINOR_FAILURE, "Cannot find %s\n", category_attr_name);
-+        return;
-+    }
-+
-+    if (category_attr->num_values > 0) {
-+        PRINT("\t%s: ", category_label);
-+        for (unsigned i = 0; i < category_attr->num_values; i++) {
-+            PRINT("%s%s",
-+                  i > 0 ? ", " : "",
-+                  (const char *) category_attr->values[i].data);
-+        }
-+        PRINT("\n");
-+    }
-+}
-+
-+static void print_member_attr(struct sss_domain_info *domain,
-+                              struct ldb_message *rule_msg,
-+                              const char *member_attr_name,
-+                              const char *group_rdn,
-+                              const char *object_label,
-+                              const char *group_label)
-+{
-+    errno_t ret;
-+    TALLOC_CTX *tmp_ctx = NULL;
-+    const char **member_names = NULL;
-+    size_t name_count = 0;
-+    const char **member_group_names = NULL;
-+    size_t group_count = 0;
-+    struct ldb_message_element *member_attr = NULL;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        return;
-+    }
-+
-+    member_attr = ldb_msg_find_element(rule_msg, member_attr_name);
-+    if (member_attr == NULL) {
-+        DEBUG(SSSDBG_MINOR_FAILURE, "Cannot find %s\n", member_attr_name);
-+        goto done;
-+    }
-+
-+    member_names = talloc_zero_array(tmp_ctx,
-+                                      const char *,
-+                                      member_attr->num_values + 1);
-+    member_group_names = talloc_zero_array(tmp_ctx,
-+                                           const char *,
-+                                           member_attr->num_values + 1);
-+    if (member_names == NULL || member_group_names == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "OOM?\n");
-+        goto done;
-+    }
-+
-+    for (size_t i = 0; i < member_attr->num_values; i++) {
-+        bool is_group;
-+        const char *rdn_string;
-+        const char *dn_attr;
-+
-+        dn_attr = (const char *) member_attr->values[i].data;
-+
-+        ret = is_member_group(domain, dn_attr, group_rdn, &is_group);
-+        if (ret != EOK) {
-+            continue;
-+        }
-+
-+        ret = get_rdn_value(tmp_ctx, domain, dn_attr, &rdn_string);
-+        if (ret != EOK) {
-+            continue;
-+        }
-+
-+        if (is_group == false) {
-+            member_names[name_count] = talloc_steal(member_names,
-+                                                    rdn_string);
-+            if (member_names[name_count] == NULL) {
-+                goto done;
-+            }
-+            name_count++;
-+        } else {
-+            member_group_names[group_count] = talloc_strdup(member_group_names,
-+                                                            rdn_string);
-+            if (member_group_names[group_count] == NULL) {
-+                goto done;
-+            }
-+            group_count++;
-+        }
-+    }
-+
-+    if (member_names[0] != NULL) {
-+        PRINT("\t%s: ", object_label);
-+        for (int i = 0; member_names[i]; i++) {
-+            PRINT("%s%s", i > 0 ? ", " : "", member_names[i]);
-+        }
-+        PRINT("\n");
-+    }
-+
-+    if (member_group_names[0] != NULL) {
-+        PRINT("\t%s: ", group_label);
-+        for (int i = 0; member_group_names[i]; i++) {
-+            PRINT("%s%s", i > 0 ? ", " : "", member_group_names[i]);
-+        }
-+        PRINT("\n");
-+    }
-+
-+done:
-+    talloc_free(tmp_ctx);
-+}
-+
-+static void print_ipa_hbac_rule(struct sss_domain_info *domain,
-+                                struct ldb_message *rule_msg)
-+{
-+    struct ldb_message_element *el;
-+
-+    el = ldb_msg_find_element(rule_msg, IPA_CN);
-+    if (el == NULL || el->num_values < 1) {
-+        DEBUG(SSSDBG_MINOR_FAILURE, "A rule with no name\n");
-+        return;
-+    }
-+
-+    PRINT("Rule name: %1$s\n", el->values[0].data);
-+
-+    print_member_attr(domain,
-+                      rule_msg,
-+                      IPA_MEMBER_USER,
-+                      "groups",
-+                      _("Member users"),
-+                      _("Member groups"));
-+    print_category(domain,
-+                   rule_msg,
-+                   IPA_USER_CATEGORY,
-+                   _("User category"));
-+
-+    print_member_attr(domain,
-+                      rule_msg,
-+                      IPA_MEMBER_SERVICE,
-+                      "hbacservicegroups",
-+                      _("Member services"),
-+                      _("Member service groups"));
-+    print_category(domain,
-+                   rule_msg,
-+                   IPA_SERVICE_CATEGORY,
-+                   _("Service category"));
-+
-+    PRINT("\n");
-+}
-+
-+static errno_t sssctl_ipa_access_report(struct sss_tool_ctx *tool_ctx,
-+                                        const char *user,
-+                                        const char *service,
-+                                        struct sss_domain_info *domain)
-+{
-+    TALLOC_CTX *tmp_ctx = NULL;
-+    const char *filter = NULL;
-+    errno_t ret;
-+    const char *attrs[] = {
-+        OBJECTCLASS,
-+        IPA_CN,
-+        IPA_MEMBER_USER,
-+        IPA_USER_CATEGORY,
-+        IPA_MEMBER_SERVICE,
-+        IPA_SERVICE_CATEGORY,
-+        IPA_MEMBER_HOST,
-+        IPA_HOST_CATEGORY,
-+        NULL,
-+    };
-+    size_t rule_count;
-+    struct ldb_message **msgs = NULL;
-+
-+    /* Run the pam account phase to make sure the rules are fetched by SSSD */
-+    ret = run_pam_acct(tool_ctx, user, service, domain);
-+    if (ret != PAM_SUCCESS && ret != PAM_PERM_DENIED) {
-+        ERROR("Cannot run the PAM account phase, reporting stale rules\n");
-+        /* Non-fatal */
-+    }
-+
-+    tmp_ctx = talloc_new(tool_ctx);
-+    if (tmp_ctx == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    filter = talloc_asprintf(tmp_ctx, "(objectClass=%s)", IPA_HBAC_RULE);
-+    if (filter == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = sysdb_search_custom(tmp_ctx, domain, filter,
-+                              HBAC_RULES_SUBDIR, attrs,
-+                              &rule_count, &msgs);
-+    if (ret != EOK && ret != ENOENT) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Error looking up HBAC rules\n");
-+        goto done;
-+    }
-+
-+    if (ret == ENOENT) {
-+        PRINT("No cached rules. All users will be denied access\n");
-+        ret = EOK;
-+        goto done;
-+    }
-+
-+    PRINT("%1$zu rules cached\n\n", rule_count);
-+
-+    for (size_t i = 0; i < rule_count; i++) {
-+        print_ipa_hbac_rule(domain, msgs[i]);
-+    }
-+
-+    ret = EOK;
-+done:
-+    talloc_zfree(tmp_ctx);
-+    return ret;
-+}
-+
-+sssctl_dom_access_reporter_fn get_report_fn(const char *provider)
-+{
-+    if (strcmp(provider, "ipa") == 0) {
-+        return sssctl_ipa_access_report;
-+    }
-+
-+    return NULL;
-+}
-+
-+errno_t sssctl_access_report(struct sss_cmdline *cmdline,
-+                             struct sss_tool_ctx *tool_ctx,
-+                             void *pvt)
-+{
-+    errno_t ret;
-+    const char *domname = NULL;
-+    sssctl_dom_access_reporter_fn reporter;
-+    struct sss_domain_info *dom;
-+    const char *user = DEFAULT_USER;
-+    const char *service = DEFAULT_SERVICE;
-+
-+    /* Parse command line. */
-+    struct poptOption options[] = {
-+        { "user", 'u', POPT_ARG_STRING, &user, 0,
-+          _("PAM user, default: " DEFAULT_USER), NULL },
-+        { "service", 's', POPT_ARG_STRING, &service, 0,
-+          _("PAM service, default: " DEFAULT_SERVICE), NULL },
-+        POPT_TABLEEND
-+    };
-+
-+    ret = sss_tool_popt_ex(cmdline, options, SSS_TOOL_OPT_OPTIONAL,
-+                           NULL, NULL, "DOMAIN", _("Specify domain name."),
-+                           &domname, NULL);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n");
-+        return ret;
-+    }
-+
-+    dom = find_domain_by_name(tool_ctx->domains, domname, true);
-+    if (dom == NULL) {
-+        ERROR("Cannot find domain %1$s\n", domname);
-+        return ERR_DOMAIN_NOT_FOUND;
-+    }
-+
-+    reporter = get_report_fn(dom->provider);
-+    if (reporter == NULL) {
-+        ERROR("Access report not implemented for domains of type %1$s\n",
-+              dom->provider);
-+        return ret;
-+    }
-+
-+    return reporter(tool_ctx, user, service, dom);
-+}
--- 
-2.14.3
-
diff --git a/SOURCES/0049-dp-use-void-to-express-empty-output-argument-list.patch b/SOURCES/0049-dp-use-void-to-express-empty-output-argument-list.patch
deleted file mode 100644
index 8d23c72..0000000
--- a/SOURCES/0049-dp-use-void-to-express-empty-output-argument-list.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From ae4435d84bae06c592d7bed16ce7aa2b07823be9 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 2 Nov 2017 14:58:05 +0100
-Subject: [PATCH 49/57] dp: use void * to express empty output argument list
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Since we cannot use plain void type is function definition.
-
-Related:
-https://pagure.io/SSSD/sssd/issue/2840
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 6211a202301e6f61d46cdb2bf0be332a70c7fdea)
----
- src/providers/data_provider/dp_private.h       | 2 +-
- src/providers/data_provider/dp_request_reply.c | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/providers/data_provider/dp_private.h b/src/providers/data_provider/dp_private.h
-index 2e71a373fdc8886fccb23bfb8283dc5bc341b1b0..028070f7f1866854c145a148e44c2cb108d2fc58 100644
---- a/src/providers/data_provider/dp_private.h
-+++ b/src/providers/data_provider/dp_private.h
-@@ -136,7 +136,7 @@ typedef void (*dp_req_reply_fn)(const char *req_name,
- 
- void dp_req_reply_default(const char *req_name,
-                           struct sbus_request *sbus_req,
--                          void *data);
-+                          void **data);
- 
- /* Data provider request table. */
- 
-diff --git a/src/providers/data_provider/dp_request_reply.c b/src/providers/data_provider/dp_request_reply.c
-index 27d9654bad76a099b004846463f035bf2e6d1243..34440fda7f28f0026d63af1af9958dcea3c6aaec 100644
---- a/src/providers/data_provider/dp_request_reply.c
-+++ b/src/providers/data_provider/dp_request_reply.c
-@@ -31,7 +31,7 @@
- 
- void dp_req_reply_default(const char *req_name,
-                           struct sbus_request *sbus_req,
--                          void *data)
-+                          void **data)
- {
-     DP_REQ_DEBUG(SSSDBG_TRACE_FUNC, req_name, "Replying with empty message");
- 
--- 
-2.14.3
-
diff --git a/SOURCES/0050-dp-add-method-to-refresh-access-control-rules.patch b/SOURCES/0050-dp-add-method-to-refresh-access-control-rules.patch
deleted file mode 100644
index cb7b567..0000000
--- a/SOURCES/0050-dp-add-method-to-refresh-access-control-rules.patch
+++ /dev/null
@@ -1,192 +0,0 @@
-From 7de7fd7a9378461ce57f9b5174938af9440381ca Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 2 Nov 2017 14:58:38 +0100
-Subject: [PATCH 50/57] dp: add method to refresh access control rules
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-https://pagure.io/SSSD/sssd/issue/2840
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit e737cdfa225e0d455c0e574bcb82c2cc16a17d9d)
----
- src/providers/data_provider/dp.h                 |  2 ++
- src/providers/data_provider/dp_iface.c           |  6 ++++++
- src/providers/data_provider/dp_iface.h           |  4 ++++
- src/providers/data_provider/dp_iface.xml         |  6 ++++++
- src/providers/data_provider/dp_iface_generated.c | 27 ++++++++++++++++++++++++
- src/providers/data_provider/dp_iface_generated.h | 16 ++++++++++++++
- src/providers/data_provider/dp_target_auth.c     | 14 ++++++++++++
- 7 files changed, 75 insertions(+)
-
-diff --git a/src/providers/data_provider/dp.h b/src/providers/data_provider/dp.h
-index 9cdbe5b3a56ba159f9a10df6e010e616e4aefcac..aa5b781158c54545b26034602bb25db46b189e87 100644
---- a/src/providers/data_provider/dp.h
-+++ b/src/providers/data_provider/dp.h
-@@ -83,6 +83,8 @@ enum dp_methods {
-     DPM_DOMAINS_HANDLER,
-     DPM_SESSION_HANDLER,
- 
-+    DPM_REFRESH_ACCESS_RULES,
-+
-     DP_METHOD_SENTINEL
- };
- 
-diff --git a/src/providers/data_provider/dp_iface.c b/src/providers/data_provider/dp_iface.c
-index 4b2b0ddca68be8899f7285b4d881a91444b99362..28d70e686f63a3572ac595f493aa1d59436c563f 100644
---- a/src/providers/data_provider/dp_iface.c
-+++ b/src/providers/data_provider/dp_iface.c
-@@ -48,10 +48,16 @@ struct iface_dp_failover iface_dp_failover = {
-     .ListServers = dp_failover_list_servers
- };
- 
-+struct iface_dp_access_control iface_dp_access_control = {
-+    { &iface_dp_access_control_meta, 0 },
-+    .RefreshRules = dp_access_control_refresh_rules_handler
-+};
-+
- static struct sbus_iface_map dp_map[] = {
-     { DP_PATH, &iface_dp.vtable },
-     { DP_PATH, &iface_dp_backend.vtable },
-     { DP_PATH, &iface_dp_failover.vtable },
-+    { DP_PATH, &iface_dp_access_control.vtable },
-     { NULL, NULL }
- };
- 
-diff --git a/src/providers/data_provider/dp_iface.h b/src/providers/data_provider/dp_iface.h
-index 8ae7a2ad7a61f82b000493f3309926cd932211f6..759b9e6c9eb7f53836ae0b641b34e6c31e65779f 100644
---- a/src/providers/data_provider/dp_iface.h
-+++ b/src/providers/data_provider/dp_iface.h
-@@ -76,4 +76,8 @@ errno_t dp_failover_list_servers(struct sbus_request *sbus_req,
-                                  void *dp_cli,
-                                  const char *service_name);
- 
-+/* org.freedesktop.sssd.DataProvider.AccessControl */
-+errno_t dp_access_control_refresh_rules_handler(struct sbus_request *sbus_req,
-+                                                void *dp_cli);
-+
- #endif /* DP_IFACE_H_ */
-diff --git a/src/providers/data_provider/dp_iface.xml b/src/providers/data_provider/dp_iface.xml
-index a3969873ad1660c71ebdcae7a951757f5254c865..2bfa9dfa7e9d02d2d12c3358967f6969438a97a2 100644
---- a/src/providers/data_provider/dp_iface.xml
-+++ b/src/providers/data_provider/dp_iface.xml
-@@ -32,6 +32,12 @@
-         </method>
-     </interface>
- 
-+    <interface name="org.freedesktop.sssd.DataProvider.AccessControl">
-+        <annotation value="iface_dp_access_control" name="org.freedesktop.DBus.GLib.CSymbol"/>
-+        <method name="RefreshRules">
-+        </method>
-+    </interface>
-+
-     <interface name="org.freedesktop.sssd.dataprovider">
-         <annotation value="iface_dp" name="org.freedesktop.DBus.GLib.CSymbol"/>
-         <method name="pamHandler">
-diff --git a/src/providers/data_provider/dp_iface_generated.c b/src/providers/data_provider/dp_iface_generated.c
-index e2e0216bd98c498b2b34c524ba615b70564420a2..11ee2e24a69cc8d4d19fdbeed613e76081aef15d 100644
---- a/src/providers/data_provider/dp_iface_generated.c
-+++ b/src/providers/data_provider/dp_iface_generated.c
-@@ -187,6 +187,33 @@ const struct sbus_interface_meta iface_dp_failover_meta = {
-     sbus_invoke_get_all, /* GetAll invoker */
- };
- 
-+int iface_dp_access_control_RefreshRules_finish(struct sbus_request *req)
-+{
-+   return sbus_request_return_and_finish(req,
-+                                         DBUS_TYPE_INVALID);
-+}
-+
-+/* methods for org.freedesktop.sssd.DataProvider.AccessControl */
-+const struct sbus_method_meta iface_dp_access_control__methods[] = {
-+    {
-+        "RefreshRules", /* name */
-+        NULL, /* no in_args */
-+        NULL, /* no out_args */
-+        offsetof(struct iface_dp_access_control, RefreshRules),
-+        NULL, /* no invoker */
-+    },
-+    { NULL, }
-+};
-+
-+/* interface info for org.freedesktop.sssd.DataProvider.AccessControl */
-+const struct sbus_interface_meta iface_dp_access_control_meta = {
-+    "org.freedesktop.sssd.DataProvider.AccessControl", /* name */
-+    iface_dp_access_control__methods,
-+    NULL, /* no signals */
-+    NULL, /* no properties */
-+    sbus_invoke_get_all, /* GetAll invoker */
-+};
-+
- /* arguments for org.freedesktop.sssd.dataprovider.autofsHandler */
- const struct sbus_arg_meta iface_dp_autofsHandler__in[] = {
-     { "dp_flags", "u" },
-diff --git a/src/providers/data_provider/dp_iface_generated.h b/src/providers/data_provider/dp_iface_generated.h
-index b7f63fb438d7b3024a0f66de0a5d15cc3d426f44..541a90b0b5a5bc0a346cbd04974d33c8bb0983c5 100644
---- a/src/providers/data_provider/dp_iface_generated.h
-+++ b/src/providers/data_provider/dp_iface_generated.h
-@@ -26,6 +26,10 @@
- #define IFACE_DP_FAILOVER_ACTIVESERVER "ActiveServer"
- #define IFACE_DP_FAILOVER_LISTSERVERS "ListServers"
- 
-+/* constants for org.freedesktop.sssd.DataProvider.AccessControl */
-+#define IFACE_DP_ACCESS_CONTROL "org.freedesktop.sssd.DataProvider.AccessControl"
-+#define IFACE_DP_ACCESS_CONTROL_REFRESHRULES "RefreshRules"
-+
- /* constants for org.freedesktop.sssd.dataprovider */
- #define IFACE_DP "org.freedesktop.sssd.dataprovider"
- #define IFACE_DP_PAMHANDLER "pamHandler"
-@@ -88,6 +92,15 @@ int iface_dp_failover_ActiveServer_finish(struct sbus_request *req, const char *
- /* finish function for ListServers */
- int iface_dp_failover_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers);
- 
-+/* vtable for org.freedesktop.sssd.DataProvider.AccessControl */
-+struct iface_dp_access_control {
-+    struct sbus_vtable vtable; /* derive from sbus_vtable */
-+    int (*RefreshRules)(struct sbus_request *req, void *data);
-+};
-+
-+/* finish function for RefreshRules */
-+int iface_dp_access_control_RefreshRules_finish(struct sbus_request *req);
-+
- /* vtable for org.freedesktop.sssd.dataprovider */
- struct iface_dp {
-     struct sbus_vtable vtable; /* derive from sbus_vtable */
-@@ -130,6 +143,9 @@ extern const struct sbus_interface_meta iface_dp_backend_meta;
- /* interface info for org.freedesktop.sssd.DataProvider.Failover */
- extern const struct sbus_interface_meta iface_dp_failover_meta;
- 
-+/* interface info for org.freedesktop.sssd.DataProvider.AccessControl */
-+extern const struct sbus_interface_meta iface_dp_access_control_meta;
-+
- /* interface info for org.freedesktop.sssd.dataprovider */
- extern const struct sbus_interface_meta iface_dp_meta;
- 
-diff --git a/src/providers/data_provider/dp_target_auth.c b/src/providers/data_provider/dp_target_auth.c
-index 6bb3313b2de002466e5ca84464c962acd2412bfa..4b47975569a04a4d79aef4c16fcacf92c295de25 100644
---- a/src/providers/data_provider/dp_target_auth.c
-+++ b/src/providers/data_provider/dp_target_auth.c
-@@ -306,3 +306,17 @@ void dp_pam_handler_selinux_done(struct tevent_req *req)
-     dp_pam_reply(state->sbus_req, state->request_name, pd);
-     return;
- }
-+
-+errno_t dp_access_control_refresh_rules_handler(struct sbus_request *sbus_req,
-+                                                void *dp_cli)
-+{
-+    const char *key;
-+
-+    key = "RefreshRules";
-+
-+    dp_req_with_reply(dp_cli, NULL, "Refresh Access Control Rules", key,
-+                      sbus_req, DPT_ACCESS, DPM_REFRESH_ACCESS_RULES, 0, NULL,
-+                      dp_req_reply_default, void *);
-+
-+    return EOK;
-+}
--- 
-2.14.3
-
diff --git a/SOURCES/0051-ipa-implement-method-to-refresh-HBAC-rules.patch b/SOURCES/0051-ipa-implement-method-to-refresh-HBAC-rules.patch
deleted file mode 100644
index 5ccb7fd..0000000
--- a/SOURCES/0051-ipa-implement-method-to-refresh-HBAC-rules.patch
+++ /dev/null
@@ -1,140 +0,0 @@
-From 42f16ffa434de2efcdb9010df39dfe7cc619dfb0 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 2 Nov 2017 14:59:19 +0100
-Subject: [PATCH 51/57] ipa: implement method to refresh HBAC rules
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-https://pagure.io/SSSD/sssd/issue/2840
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 2754a8dcfa937d45b024a2e57419248bfd4c4919)
----
- src/providers/ipa/ipa_access.c | 68 ++++++++++++++++++++++++++++++++++++++++--
- src/providers/ipa/ipa_access.h | 10 +++++++
- src/providers/ipa/ipa_init.c   |  4 +++
- 3 files changed, 80 insertions(+), 2 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c
-index 32ccf541c9436b633e7724b2c44ee545810a7fb8..de9f68170b6e9c38fd8b6d23f1d565250bbf78d2 100644
---- a/src/providers/ipa/ipa_access.c
-+++ b/src/providers/ipa/ipa_access.c
-@@ -682,8 +682,8 @@ done:
- 
- errno_t
- ipa_pam_access_handler_recv(TALLOC_CTX *mem_ctx,
--                             struct tevent_req *req,
--                             struct pam_data **_data)
-+                            struct tevent_req *req,
-+                            struct pam_data **_data)
- {
-     struct ipa_pam_access_handler_state *state = NULL;
- 
-@@ -695,3 +695,67 @@ ipa_pam_access_handler_recv(TALLOC_CTX *mem_ctx,
- 
-     return EOK;
- }
-+
-+struct ipa_refresh_access_rules_state {
-+    int dummy;
-+};
-+
-+static void ipa_refresh_access_rules_done(struct tevent_req *subreq);
-+
-+struct tevent_req *
-+ipa_refresh_access_rules_send(TALLOC_CTX *mem_ctx,
-+                              struct ipa_access_ctx *access_ctx,
-+                              void *no_input_data,
-+                              struct dp_req_params *params)
-+{
-+    struct ipa_refresh_access_rules_state *state;
-+    struct tevent_req *subreq;
-+    struct tevent_req *req;
-+
-+    DEBUG(SSSDBG_TRACE_FUNC, "Refreshing HBAC rules\n");
-+
-+    req = tevent_req_create(mem_ctx, &state,
-+                            struct ipa_refresh_access_rules_state);
-+    if (req == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
-+        return NULL;
-+    }
-+
-+    subreq = ipa_fetch_hbac_send(state, params->ev, params->be_ctx, access_ctx);
-+    if (subreq == NULL) {
-+        tevent_req_error(req, ENOMEM);
-+        tevent_req_post(req, params->ev);
-+        return req;
-+    }
-+
-+    tevent_req_set_callback(subreq, ipa_refresh_access_rules_done, req);
-+
-+    return req;
-+}
-+
-+static void ipa_refresh_access_rules_done(struct tevent_req *subreq)
-+{
-+    struct tevent_req *req;
-+    errno_t ret;
-+
-+    req = tevent_req_callback_data(subreq, struct tevent_req);
-+
-+    ret = ipa_fetch_hbac_recv(subreq);
-+    talloc_zfree(subreq);
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    tevent_req_done(req);
-+    return;
-+}
-+
-+errno_t ipa_refresh_access_rules_recv(TALLOC_CTX *mem_ctx,
-+                                      struct tevent_req *req,
-+                                      void **_no_output_data)
-+{
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    return EOK;
-+}
-diff --git a/src/providers/ipa/ipa_access.h b/src/providers/ipa/ipa_access.h
-index de690350218bd47165a2b48c10059b8de96b718a..9cec0d1063fd39380a77093526e3240523752075 100644
---- a/src/providers/ipa/ipa_access.h
-+++ b/src/providers/ipa/ipa_access.h
-@@ -63,4 +63,14 @@ ipa_pam_access_handler_recv(TALLOC_CTX *mem_ctx,
-                              struct tevent_req *req,
-                              struct pam_data **_data);
- 
-+struct tevent_req *
-+ipa_refresh_access_rules_send(TALLOC_CTX *mem_ctx,
-+                              struct ipa_access_ctx *access_ctx,
-+                              void *no_input_data,
-+                              struct dp_req_params *params);
-+
-+errno_t ipa_refresh_access_rules_recv(TALLOC_CTX *mem_ctx,
-+                                      struct tevent_req *req,
-+                                      void **_no_output_data);
-+
- #endif /* _IPA_ACCESS_H_ */
-diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
-index 5b7c8e1348f561901782c872078a0e7391d4ff75..f335d51fd65959d256c54a5d92c594a24e895b7c 100644
---- a/src/providers/ipa/ipa_init.c
-+++ b/src/providers/ipa/ipa_init.c
-@@ -831,6 +831,10 @@ errno_t sssm_ipa_access_init(TALLOC_CTX *mem_ctx,
-                   ipa_pam_access_handler_send, ipa_pam_access_handler_recv, access_ctx,
-                   struct ipa_access_ctx, struct pam_data, struct pam_data *);
- 
-+    dp_set_method(dp_methods, DPM_REFRESH_ACCESS_RULES,
-+                      ipa_refresh_access_rules_send, ipa_refresh_access_rules_recv, access_ctx,
-+                      struct ipa_access_ctx, void, void *);
-+
-     ret = EOK;
- 
- done:
--- 
-2.14.3
-
diff --git a/SOURCES/0052-ifp-add-method-to-refresh-access-control-rules-in-do.patch b/SOURCES/0052-ifp-add-method-to-refresh-access-control-rules-in-do.patch
deleted file mode 100644
index 55e224d..0000000
--- a/SOURCES/0052-ifp-add-method-to-refresh-access-control-rules-in-do.patch
+++ /dev/null
@@ -1,158 +0,0 @@
-From c6e02c84a567127b37b1c036abf7952f1d36783a Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 2 Nov 2017 14:59:57 +0100
-Subject: [PATCH 52/57] ifp: add method to refresh access control rules in
- domain
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-https://pagure.io/SSSD/sssd/issue/2840
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit c6cf752337f5977ce3753b7113dc1a2342c86319)
----
- src/responder/ifp/ifp_domains.c         | 22 ++++++++++++++++++++++
- src/responder/ifp/ifp_domains.h         |  3 +++
- src/responder/ifp/ifp_iface.c           |  3 ++-
- src/responder/ifp/ifp_iface.xml         |  3 +++
- src/responder/ifp/ifp_iface_generated.c | 13 +++++++++++++
- src/responder/ifp/ifp_iface_generated.h |  5 +++++
- 6 files changed, 48 insertions(+), 1 deletion(-)
-
-diff --git a/src/responder/ifp/ifp_domains.c b/src/responder/ifp/ifp_domains.c
-index 977bbfcbe818f08873ce072d34fdcf900cabf52f..cd7e2fc7aeff5467514269e5b078b0da88ab4f50 100644
---- a/src/responder/ifp/ifp_domains.c
-+++ b/src/responder/ifp/ifp_domains.c
-@@ -630,3 +630,25 @@ int ifp_domains_domain_list_servers(struct sbus_request *sbus_req,
- 
-     return EOK;
- }
-+
-+int ifp_domains_domain_refresh_access_rules(struct sbus_request *sbus_req,
-+                                            void *data)
-+{
-+    struct ifp_ctx *ifp_ctx;
-+    struct sss_domain_info *dom;
-+
-+    ifp_ctx = talloc_get_type(data, struct ifp_ctx);
-+
-+    dom = get_domain_info_from_req(sbus_req, data);
-+    if (dom == NULL) {
-+        sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN,
-+                                 "Unknown domain");
-+        return EOK;
-+    }
-+
-+    rdp_message_send_and_reply(sbus_req, ifp_ctx->rctx, dom, DP_PATH,
-+                               IFACE_DP_ACCESS_CONTROL,
-+                               IFACE_DP_ACCESS_CONTROL_REFRESHRULES);
-+
-+    return EOK;
-+}
-diff --git a/src/responder/ifp/ifp_domains.h b/src/responder/ifp/ifp_domains.h
-index 621ba6158e285911cb8298cef212219dfd3afec8..d8cc9d34c92cd04b6db432c1fc0e179a717001da 100644
---- a/src/responder/ifp/ifp_domains.h
-+++ b/src/responder/ifp/ifp_domains.h
-@@ -108,4 +108,7 @@ int ifp_domains_domain_list_servers(struct sbus_request *sbus_req,
-                                     void *data,
-                                     const char *service);
- 
-+int ifp_domains_domain_refresh_access_rules(struct sbus_request *sbus_req,
-+                                            void *data);
-+
- #endif /* IFP_DOMAINS_H_ */
-diff --git a/src/responder/ifp/ifp_iface.c b/src/responder/ifp/ifp_iface.c
-index 3293b92d750d33b2ecf77a03098c5169d052c924..f995e28f99f9489ca17fbc51fa6894d458f9e21f 100644
---- a/src/responder/ifp/ifp_iface.c
-+++ b/src/responder/ifp/ifp_iface.c
-@@ -79,7 +79,8 @@ struct iface_ifp_domains_domain iface_ifp_domains_domain = {
-     .IsOnline = ifp_domains_domain_is_online,
-     .ListServices = ifp_domains_domain_list_services,
-     .ActiveServer = ifp_domains_domain_active_server,
--    .ListServers = ifp_domains_domain_list_servers
-+    .ListServers = ifp_domains_domain_list_servers,
-+    .RefreshAccessRules = ifp_domains_domain_refresh_access_rules
- };
- 
- struct iface_ifp_users iface_ifp_users = {
-diff --git a/src/responder/ifp/ifp_iface.xml b/src/responder/ifp/ifp_iface.xml
-index 39385e866f31131c7860001ae4d6e6b51105aa52..1aa7eac03f0a3dc86f1d25883ac37f2fabf6b9e8 100644
---- a/src/responder/ifp/ifp_iface.xml
-+++ b/src/responder/ifp/ifp_iface.xml
-@@ -112,6 +112,9 @@
-             <arg name="service_name" type="s" direction="in" />
-             <arg name="servers" type="as" direction="out" />
-         </method>
-+
-+        <method name="RefreshAccessRules">
-+        </method>
-     </interface>
- 
-     <interface name="org.freedesktop.sssd.infopipe.Cache">
-diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c
-index 6943e38e3b6d2fc9e09ade1a863905c8d81a39ba..c2cdbf5b0ef3d59068aeed7a8f45099c14c4a94a 100644
---- a/src/responder/ifp/ifp_iface_generated.c
-+++ b/src/responder/ifp/ifp_iface_generated.c
-@@ -552,6 +552,12 @@ int iface_ifp_domains_domain_ListServers_finish(struct sbus_request *req, const
-                                          DBUS_TYPE_INVALID);
- }
- 
-+int iface_ifp_domains_domain_RefreshAccessRules_finish(struct sbus_request *req)
-+{
-+   return sbus_request_return_and_finish(req,
-+                                         DBUS_TYPE_INVALID);
-+}
-+
- /* methods for org.freedesktop.sssd.infopipe.Domains.Domain */
- const struct sbus_method_meta iface_ifp_domains_domain__methods[] = {
-     {
-@@ -582,6 +588,13 @@ const struct sbus_method_meta iface_ifp_domains_domain__methods[] = {
-         offsetof(struct iface_ifp_domains_domain, ListServers),
-         invoke_s_method,
-     },
-+    {
-+        "RefreshAccessRules", /* name */
-+        NULL, /* no in_args */
-+        NULL, /* no out_args */
-+        offsetof(struct iface_ifp_domains_domain, RefreshAccessRules),
-+        NULL, /* no invoker */
-+    },
-     { NULL, }
- };
- 
-diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h
-index 30752bf063de1f2530c7451f01cc22ad3e863185..f1e6c80bab27d0ed581abc566a178e6857794805 100644
---- a/src/responder/ifp/ifp_iface_generated.h
-+++ b/src/responder/ifp/ifp_iface_generated.h
-@@ -57,6 +57,7 @@
- #define IFACE_IFP_DOMAINS_DOMAIN_LISTSERVICES "ListServices"
- #define IFACE_IFP_DOMAINS_DOMAIN_ACTIVESERVER "ActiveServer"
- #define IFACE_IFP_DOMAINS_DOMAIN_LISTSERVERS "ListServers"
-+#define IFACE_IFP_DOMAINS_DOMAIN_REFRESHACCESSRULES "RefreshAccessRules"
- 
- /* constants for org.freedesktop.sssd.infopipe.Cache */
- #define IFACE_IFP_CACHE "org.freedesktop.sssd.infopipe.Cache"
-@@ -209,6 +210,7 @@ struct iface_ifp_domains_domain {
-     int (*ListServices)(struct sbus_request *req, void *data);
-     int (*ActiveServer)(struct sbus_request *req, void *data, const char *arg_service);
-     int (*ListServers)(struct sbus_request *req, void *data, const char *arg_service_name);
-+    int (*RefreshAccessRules)(struct sbus_request *req, void *data);
- };
- 
- /* finish function for IsOnline */
-@@ -223,6 +225,9 @@ int iface_ifp_domains_domain_ActiveServer_finish(struct sbus_request *req, const
- /* finish function for ListServers */
- int iface_ifp_domains_domain_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers);
- 
-+/* finish function for RefreshAccessRules */
-+int iface_ifp_domains_domain_RefreshAccessRules_finish(struct sbus_request *req);
-+
- /* vtable for org.freedesktop.sssd.infopipe.Cache */
- struct iface_ifp_cache {
-     struct sbus_vtable vtable; /* derive from sbus_vtable */
--- 
-2.14.3
-
diff --git a/SOURCES/0053-sssctl-call-dbus-instead-of-pam-to-refresh-HBAC-rule.patch b/SOURCES/0053-sssctl-call-dbus-instead-of-pam-to-refresh-HBAC-rule.patch
deleted file mode 100644
index 4c2404e..0000000
--- a/SOURCES/0053-sssctl-call-dbus-instead-of-pam-to-refresh-HBAC-rule.patch
+++ /dev/null
@@ -1,200 +0,0 @@
-From cbe1f1f8fa207eded53260a0fb288c5b31b18c96 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
-Date: Thu, 2 Nov 2017 15:00:17 +0100
-Subject: [PATCH 53/57] sssctl: call dbus instead of pam to refresh HBAC rules
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related:
-https://pagure.io/SSSD/sssd/issue/2840
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit be804178d5e5fee64be2b080e73f4ce7b0074f76)
----
- src/tools/sssctl/sssctl_access_report.c | 127 +++++++++++++++-----------------
- 1 file changed, 58 insertions(+), 69 deletions(-)
-
-diff --git a/src/tools/sssctl/sssctl_access_report.c b/src/tools/sssctl/sssctl_access_report.c
-index 11172329817b4dedaca480ab8a4537149853c330..8cf1a8a871b27827c317d658c0f93f34773c4841 100644
---- a/src/tools/sssctl/sssctl_access_report.c
-+++ b/src/tools/sssctl/sssctl_access_report.c
-@@ -15,11 +15,11 @@
-     along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
- 
--#include <security/pam_appl.h>
--
- #include "util/util.h"
- #include "tools/common/sss_tools.h"
- #include "tools/sssctl/sssctl.h"
-+#include "sbus/sssd_dbus.h"
-+#include "responder/ifp/ifp_iface.h"
- 
- /*
-  * We're searching the cache directly..
-@@ -27,58 +27,9 @@
- #include "providers/ipa/ipa_hbac_private.h"
- #include "providers/ipa/ipa_rules_common.h"
- 
--#ifdef HAVE_SECURITY_PAM_MISC_H
--# include <security/pam_misc.h>
--#elif defined(HAVE_SECURITY_OPENPAM_H)
--# include <security/openpam.h>
--#endif
--
--#ifdef HAVE_SECURITY_PAM_MISC_H
--static struct pam_conv conv = {
--    misc_conv,
--    NULL
--};
--#elif defined(HAVE_SECURITY_OPENPAM_H)
--static struct pam_conv conv = {
--    openpam_ttyconv,
--    NULL
--};
--#else
--# error "Missing text based pam conversation function"
--#endif
--
--#ifndef DEFAULT_SERVICE
--#define DEFAULT_SERVICE "system-auth"
--#endif /* DEFAULT_SERVICE */
--
--#ifndef DEFAULT_USER
--#define DEFAULT_USER "admin"
--#endif /* DEFAULT_USER */
--
- typedef errno_t (*sssctl_dom_access_reporter_fn)(struct sss_tool_ctx *tool_ctx,
--                                                 const char *user,
--                                                 const char *service,
-                                                  struct sss_domain_info *domain);
- 
--static errno_t run_pam_acct(struct sss_tool_ctx *tool_ctx,
--                            const char *user,
--                            const char *service,
--                            struct sss_domain_info *domain)
--{
--    errno_t ret;
--    pam_handle_t *pamh;
--
--    ret = pam_start(service, user, &conv, &pamh);
--    if (ret != PAM_SUCCESS) {
--        ERROR("pam_start failed: %s\n", pam_strerror(pamh, ret));
--        return EIO;
--    }
--
--    ret = pam_acct_mgmt(pamh, 0);
--    pam_end(pamh, ret);
--    return ret;
--}
--
- static errno_t get_rdn_value(TALLOC_CTX *mem_ctx,
-                              struct sss_domain_info *dom,
-                              const char *dn_attr,
-@@ -315,9 +266,58 @@ static void print_ipa_hbac_rule(struct sss_domain_info *domain,
-     PRINT("\n");
- }
- 
-+static errno_t refresh_hbac_rules(struct sss_tool_ctx *tool_ctx,
-+                                  struct sss_domain_info *domain)
-+{
-+    TALLOC_CTX *tmp_ctx;
-+    sss_sifp_error error;
-+    sss_sifp_ctx *sifp;
-+    DBusMessage *reply;
-+    const char *path;
-+    errno_t ret;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
-+        return ENOMEM;
-+    }
-+
-+    path = sbus_opath_compose(tmp_ctx, IFP_PATH_DOMAINS, domain->name);
-+    if (path == NULL) {
-+        printf(_("Out of memory!\n"));
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    error = sssctl_sifp_init(tool_ctx, &sifp);
-+    if (error != SSS_SIFP_OK) {
-+        sssctl_sifp_error(sifp, error, "Unable to connect to the InfoPipe");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    error = sssctl_sifp_send(tmp_ctx, sifp, &reply, path,
-+                             IFACE_IFP_DOMAINS_DOMAIN,
-+                             IFACE_IFP_DOMAINS_DOMAIN_REFRESHACCESSRULES);
-+    if (error != SSS_SIFP_OK) {
-+        sssctl_sifp_error(sifp, error, "Unable to refresh HBAC rules");
-+        ret = EIO;
-+        goto done;
-+    }
-+
-+    ret = sbus_parse_reply(reply);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-+    ret = EOK;
-+
-+done:
-+    talloc_free(tmp_ctx);
-+    return ret;
-+}
-+
- static errno_t sssctl_ipa_access_report(struct sss_tool_ctx *tool_ctx,
--                                        const char *user,
--                                        const char *service,
-                                         struct sss_domain_info *domain)
- {
-     TALLOC_CTX *tmp_ctx = NULL;
-@@ -338,9 +338,9 @@ static errno_t sssctl_ipa_access_report(struct sss_tool_ctx *tool_ctx,
-     struct ldb_message **msgs = NULL;
- 
-     /* Run the pam account phase to make sure the rules are fetched by SSSD */
--    ret = run_pam_acct(tool_ctx, user, service, domain);
--    if (ret != PAM_SUCCESS && ret != PAM_PERM_DENIED) {
--        ERROR("Cannot run the PAM account phase, reporting stale rules\n");
-+    ret = refresh_hbac_rules(tool_ctx, domain);
-+    if (ret != EOK) {
-+        ERROR("Unable to refresh HBAC rules, using cached content\n");
-         /* Non-fatal */
-     }
- 
-@@ -398,19 +398,8 @@ errno_t sssctl_access_report(struct sss_cmdline *cmdline,
-     const char *domname = NULL;
-     sssctl_dom_access_reporter_fn reporter;
-     struct sss_domain_info *dom;
--    const char *user = DEFAULT_USER;
--    const char *service = DEFAULT_SERVICE;
- 
--    /* Parse command line. */
--    struct poptOption options[] = {
--        { "user", 'u', POPT_ARG_STRING, &user, 0,
--          _("PAM user, default: " DEFAULT_USER), NULL },
--        { "service", 's', POPT_ARG_STRING, &service, 0,
--          _("PAM service, default: " DEFAULT_SERVICE), NULL },
--        POPT_TABLEEND
--    };
--
--    ret = sss_tool_popt_ex(cmdline, options, SSS_TOOL_OPT_OPTIONAL,
-+    ret = sss_tool_popt_ex(cmdline, NULL, SSS_TOOL_OPT_OPTIONAL,
-                            NULL, NULL, "DOMAIN", _("Specify domain name."),
-                            &domname, NULL);
-     if (ret != EOK) {
-@@ -431,5 +420,5 @@ errno_t sssctl_access_report(struct sss_cmdline *cmdline,
-         return ret;
-     }
- 
--    return reporter(tool_ctx, user, service, dom);
-+    return reporter(tool_ctx, dom);
- }
--- 
-2.14.3
-
diff --git a/SOURCES/0054-sysdb-be_refresh_get_values_ex-remove-unused-option.patch b/SOURCES/0054-sysdb-be_refresh_get_values_ex-remove-unused-option.patch
deleted file mode 100644
index a4f566f..0000000
--- a/SOURCES/0054-sysdb-be_refresh_get_values_ex-remove-unused-option.patch
+++ /dev/null
@@ -1,66 +0,0 @@
-From e32a5bd6fa76c7146a7024d42efeb26895337048 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Wed, 8 Nov 2017 14:04:40 +0100
-Subject: [PATCH 54/57] sysdb: be_refresh_get_values_ex() remove unused option
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The objectclass argument is not used in be_refresh_get_values_ex()
-anymore.
-
-Related to https://pagure.io/SSSD/sssd/issue/3503
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 0cce3d3ad14caf406303cf2ce6bf80171b708a93)
----
- src/providers/be_refresh.c | 7 +------
- 1 file changed, 1 insertion(+), 6 deletions(-)
-
-diff --git a/src/providers/be_refresh.c b/src/providers/be_refresh.c
-index 81f2c5d1d368987bf9135fce730d917a32c1e24f..e8cf5da75847cd6ab647e91865b36ec6e4e59822 100644
---- a/src/providers/be_refresh.c
-+++ b/src/providers/be_refresh.c
-@@ -32,7 +32,6 @@
- static errno_t be_refresh_get_values_ex(TALLOC_CTX *mem_ctx,
-                                         struct sss_domain_info *domain,
-                                         time_t period,
--                                        const char *objectclass,
-                                         struct ldb_dn *base_dn,
-                                         const char *attr,
-                                         char ***_values)
-@@ -96,21 +95,17 @@ static errno_t be_refresh_get_values(TALLOC_CTX *mem_ctx,
-                                      char ***_values)
- {
-     struct ldb_dn *base_dn = NULL;
--    const char *class = NULL;
-     errno_t ret;
- 
-     switch (type) {
-     case BE_REFRESH_TYPE_USERS:
-         base_dn = sysdb_user_base_dn(mem_ctx, domain);
--        class = SYSDB_USER_CLASS;
-         break;
-     case BE_REFRESH_TYPE_GROUPS:
-         base_dn = sysdb_group_base_dn(mem_ctx, domain);
--        class = SYSDB_GROUP_CLASS;
-         break;
-     case BE_REFRESH_TYPE_NETGROUPS:
-         base_dn = sysdb_netgroup_base_dn(mem_ctx, domain);
--        class = SYSDB_NETGROUP_CLASS;
-         break;
-     case BE_REFRESH_TYPE_SENTINEL:
-         return ERR_INTERNAL;
-@@ -121,7 +116,7 @@ static errno_t be_refresh_get_values(TALLOC_CTX *mem_ctx,
-         return ENOMEM;
-     }
- 
--    ret = be_refresh_get_values_ex(mem_ctx, domain, period, class,
-+    ret = be_refresh_get_values_ex(mem_ctx, domain, period,
-                                    base_dn, SYSDB_NAME, _values);
- 
-     talloc_free(base_dn);
--- 
-2.14.3
-
diff --git a/SOURCES/0055-sysdb-do-not-use-objectClass-for-users-and-groups.patch b/SOURCES/0055-sysdb-do-not-use-objectClass-for-users-and-groups.patch
deleted file mode 100644
index 4d94916..0000000
--- a/SOURCES/0055-sysdb-do-not-use-objectClass-for-users-and-groups.patch
+++ /dev/null
@@ -1,758 +0,0 @@
-From e4ba8c5c6c08f86d51485d49c27635d7079efe13 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Wed, 8 Nov 2017 15:14:58 +0100
-Subject: [PATCH 55/57] sysdb: do not use objectClass for users and groups
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The majority of the object in the SSSD cache are users and groups. If
-there are many user and groups in the cache the index objects of the
-objectclass attributes 'user' and 'group' become  large because the
-must hold references to all objects of those object classes.
-
-As a result the management of these index objects becomes costly because
-they must be parsed and split apart quite often. Additionally they are
-mostly useless because user and groups are lookup up by more specific
-attributes in general.
-
-Only when enumerating all user or groups this kind of index might be
-useful.
-
-There are two way of removing this kind of index from the user and group
-objects. Either by removing objectClass from the list of indexes and add
-a new attribute to all other type of object we want and index for. Or by
-replacing objectClass with a different attribute for the user and group
-objects. After some testing I think the latter one is the more reliable
-one and implemented it in this patch.
-
-Related to https://pagure.io/SSSD/sssd/issue/3503
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 0e238c259c066cf997aaa940d33d6bda96c15925)
----
- src/db/sysdb.h                                     | 10 ++--
- src/db/sysdb_init.c                                |  5 +-
- src/db/sysdb_ops.c                                 |  6 +--
- src/db/sysdb_search.c                              | 11 +++--
- src/db/sysdb_upgrade.c                             |  4 ++
- src/ldb_modules/memberof.c                         |  6 +--
- src/providers/ad/ad_pac.c                          |  2 +-
- src/providers/ipa/ipa_id.c                         |  9 ++--
- src/providers/ipa/ipa_subdomains_ext_groups.c      |  2 +-
- src/providers/ipa/ipa_subdomains_id.c              |  2 +-
- src/providers/krb5/krb5_renew_tgt.c                |  3 +-
- src/providers/ldap/ldap_id_cleanup.c               |  2 +-
- src/providers/ldap/sdap_async_groups.c             |  8 ++--
- src/providers/ldap/sdap_async_initgroups.c         |  2 +-
- src/providers/ldap/sdap_async_initgroups_ad.c      |  2 +-
- src/providers/ldap/sdap_async_nested_groups.c      |  2 +-
- .../common/cache_req/plugins/cache_req_common.c    |  2 +-
- src/responder/ifp/ifp_cache.c                      |  4 +-
- src/responder/ifp/ifp_groups.c                     |  4 +-
- src/responder/ifp/ifp_users.c                      |  2 +-
- src/responder/nss/nss_cmd.c                        |  2 +-
- src/responder/nss/nss_protocol_grent.c             |  2 +-
- src/responder/nss/nss_protocol_sid.c               |  4 +-
- src/tests/cmocka/test_ad_common.c                  |  2 +-
- src/tests/cmocka/test_ipa_subdomains_server.c      | 54 ++++++++++++++++------
- src/tests/sysdb-tests.c                            | 20 +++++---
- src/tools/sssctl/sssctl_cache.c                    |  3 +-
- 27 files changed, 110 insertions(+), 65 deletions(-)
-
-diff --git a/src/db/sysdb.h b/src/db/sysdb.h
-index 4192f9085d941814eccd2ac60ce8fb6d4e1bfa67..fd18ecefed2b2c5f35060fa47fd160a8968e073b 100644
---- a/src/db/sysdb.h
-+++ b/src/db/sysdb.h
-@@ -192,9 +192,10 @@
- 
- #define SYSDB_NEXTID_FILTER "("SYSDB_NEXTID"=*)"
- 
--#define SYSDB_UC "objectclass="SYSDB_USER_CLASS
--#define SYSDB_GC "objectclass="SYSDB_GROUP_CLASS
--#define SYSDB_NC "objectclass="SYSDB_NETGROUP_CLASS
-+#define SYSDB_OBJECTCATEGORY "objectCategory"
-+#define SYSDB_UC SYSDB_OBJECTCATEGORY"="SYSDB_USER_CLASS
-+#define SYSDB_GC SYSDB_OBJECTCATEGORY"="SYSDB_GROUP_CLASS
-+#define SYSDB_NC SYSDB_OBJECTCLASS"="SYSDB_NETGROUP_CLASS
- #define SYSDB_MPGC "|("SYSDB_UC")("SYSDB_GC")"
- 
- #define SYSDB_PWNAM_FILTER "(&("SYSDB_UC")(|("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME_ALIAS"=%s)("SYSDB_NAME"=%s)))"
-@@ -227,7 +228,8 @@
- #define SYSDB_DEFAULT_ATTRS SYSDB_LAST_UPDATE, \
-                             SYSDB_CACHE_EXPIRE, \
-                             SYSDB_INITGR_EXPIRE, \
--                            SYSDB_OBJECTCLASS
-+                            SYSDB_OBJECTCLASS, \
-+                            SYSDB_OBJECTCATEGORY
- 
- #define SYSDB_PW_ATTRS {SYSDB_NAME, SYSDB_UIDNUM, \
-                         SYSDB_GIDNUM, SYSDB_GECOS, \
-diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c
-index e246a165ec1d654dba19aa771ed97bfc3a07f245..44a7918f603fe1368b7d81738666de6bb47b83d0 100644
---- a/src/db/sysdb_init.c
-+++ b/src/db/sysdb_init.c
-@@ -31,11 +31,12 @@
- #define LDB_MODULES_PATH "LDB_MODULES_PATH"
- 
- /* If an entry differs only in these attributes, they are written to
-- * the timestamp cache only. In addition, objectclass is added so that
-- * we can distinguish between users and groups.
-+ * the timestamp cache only. In addition, objectclass/objectcategory is added
-+ * so that we can distinguish between users and groups.
-  */
- const char *sysdb_ts_cache_attrs[] = {
-     SYSDB_OBJECTCLASS,
-+    SYSDB_OBJECTCATEGORY,
-     SYSDB_LAST_UPDATE,
-     SYSDB_CACHE_EXPIRE,
-     SYSDB_ORIG_MODSTAMP,
-diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
-index 1539c41c93e7d6ebd1e544abbb1707df5578cd72..024683317cab99743681db804f7026c8dbb33a38 100644
---- a/src/db/sysdb_ops.c
-+++ b/src/db/sysdb_ops.c
-@@ -958,7 +958,7 @@ static struct sysdb_attrs *ts_obj_attrs(TALLOC_CTX *mem_ctx,
-         return NULL;
-     }
- 
--    ret = sysdb_attrs_add_string(attrs, SYSDB_OBJECTCLASS, oc);
-+    ret = sysdb_attrs_add_string(attrs, SYSDB_OBJECTCATEGORY, oc);
-     if (ret != EOK) {
-         talloc_free(attrs);
-         return NULL;
-@@ -1667,7 +1667,7 @@ int sysdb_add_basic_user(struct sss_domain_info *domain,
-         ERROR_OUT(ret, ENOMEM, done);
-     }
- 
--    ret = sysdb_add_string(msg, SYSDB_OBJECTCLASS, SYSDB_USER_CLASS);
-+    ret = sysdb_add_string(msg, SYSDB_OBJECTCATEGORY, SYSDB_USER_CLASS);
-     if (ret) goto done;
- 
-     ret = sysdb_add_string(msg, SYSDB_NAME, name);
-@@ -2120,7 +2120,7 @@ int sysdb_add_basic_group(struct sss_domain_info *domain,
-         ERROR_OUT(ret, ENOMEM, done);
-     }
- 
--    ret = sysdb_add_string(msg, SYSDB_OBJECTCLASS, SYSDB_GROUP_CLASS);
-+    ret = sysdb_add_string(msg, SYSDB_OBJECTCATEGORY, SYSDB_GROUP_CLASS);
-     if (ret) goto done;
- 
-     ret = sysdb_add_string(msg, SYSDB_NAME, name);
-diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
-index 8083966900429b268a3b984f1cad3d47d1099198..a6a81e23d257331614085403b4dca8ded860600b 100644
---- a/src/db/sysdb_search.c
-+++ b/src/db/sysdb_search.c
-@@ -114,10 +114,11 @@ static errno_t merge_msg_ts_attrs(struct sysdb_ctx *sysdb,
-         return EIO;
-     }
- 
--    /* Deliberately start from 1 in order to not merge objectclass and avoid
--     * breaking MPGs where the OC might be made up
-+    /* Deliberately start from 2 in order to not merge
-+     * objectclass/objectcategory and avoid breaking MPGs where the OC might
-+     * be made up
-      */
--    for (size_t c = 1; sysdb_ts_cache_attrs[c]; c++) {
-+    for (size_t c = 2; sysdb_ts_cache_attrs[c]; c++) {
-         ret = merge_ts_attr(ts_msgs[0], sysdb_msg,
-                             sysdb_ts_cache_attrs[c], attrs);
-         if (ret != EOK) {
-@@ -751,7 +752,7 @@ static int mpg_convert(struct ldb_message *msg)
-     struct ldb_val *val = NULL;
-     int i;
- 
--    el = ldb_msg_find_element(msg, "objectClass");
-+    el = ldb_msg_find_element(msg, SYSDB_OBJECTCATEGORY);
-     if (!el) return EINVAL;
- 
-     /* see if this is a user to convert to a group */
-@@ -2088,7 +2089,7 @@ errno_t sysdb_get_direct_parents(TALLOC_CTX *mem_ctx,
-     }
- 
-     member_filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(%s=%s))",
--                                    SYSDB_OBJECTCLASS, SYSDB_GROUP_CLASS,
-+                                    SYSDB_OBJECTCATEGORY, SYSDB_GROUP_CLASS,
-                                     SYSDB_MEMBER, sanitized_dn);
-     if (!member_filter) {
-         ret = ENOMEM;
-diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c
-index 040c91ca6276e7c51a126eefe034aa5fe9d0433f..365d45f7ebd78523ca9ec4b9c2158cc09acb5489 100644
---- a/src/db/sysdb_upgrade.c
-+++ b/src/db/sysdb_upgrade.c
-@@ -149,6 +149,7 @@ int sysdb_upgrade_01(struct ldb_context *ldb, const char **ver)
-     struct ldb_dn *mem_dn;
-     struct ldb_message *msg;
-     const struct ldb_val *val;
-+    /* No change needed because this version has objectclass group */
-     const char *filter = "(&(memberUid=*)(objectclass=group))";
-     const char *attrs[] = { "memberUid", NULL };
-     const char *mdn;
-@@ -1041,6 +1042,7 @@ int sysdb_upgrade_10(struct sysdb_ctx *sysdb, struct sss_domain_info *domain,
-     struct ldb_message_element *memberof_el;
-     const char *name;
-     struct ldb_dn *basedn;
-+    /* No change needed because version 10 has objectclass user */
-     const char *filter = "(&(objectClass=user)(!(uidNumber=*))(memberOf=*))";
-     const char *attrs[] = { "name", "memberof", NULL };
-     struct upgrade_ctx *ctx;
-@@ -2082,6 +2084,7 @@ static void qualify_users(struct upgrade_ctx *ctx,
-                           struct sss_names_ctx *names,
-                           struct ldb_dn *base_dn)
- {
-+    /* No change needed because this version has objectclass user */
-     const char *user_filter = "objectclass=user";
-     const char *user_name_attrs[] = { SYSDB_NAME,
-                                       SYSDB_NAME_ALIAS,
-@@ -2107,6 +2110,7 @@ static void qualify_groups(struct upgrade_ctx *ctx,
-                            struct sss_names_ctx *names,
-                            struct ldb_dn *base_dn)
- {
-+    /* No change needed because this version has objectclass group */
-     const char *group_filter = "objectclass=group";
-     const char *group_name_attrs[] = { SYSDB_NAME,
-                                        SYSDB_NAME_ALIAS,
-diff --git a/src/ldb_modules/memberof.c b/src/ldb_modules/memberof.c
-index af7147ee7cc9299d4040d63a637373842dcee02a..327a38c5f75afcde1b997796afd1217d45acbde2 100644
---- a/src/ldb_modules/memberof.c
-+++ b/src/ldb_modules/memberof.c
-@@ -31,7 +31,7 @@
- #define DB_USER_CLASS "user"
- #define DB_GROUP_CLASS "group"
- #define DB_CACHE_EXPIRE "dataExpireTimestamp"
--#define DB_OC "objectClass"
-+#define DB_OC "objectCategory"
- 
- #ifndef MAX
- #define MAX(a,b) (((a) > (b)) ? (a) : (b))
-@@ -3928,7 +3928,7 @@ static int memberof_recompute_task(struct ldb_module *module,
- {
-     struct ldb_context *ldb = ldb_module_get_ctx(module);
-     static const char *attrs[] = { DB_NAME, DB_MEMBEROF, NULL };
--    static const char *filter = "(objectclass=user)";
-+    static const char *filter = "("DB_OC"="DB_USER_CLASS")";
-     struct mbof_rcmp_context *ctx;
-     struct ldb_request *src_req;
-     int ret;
-@@ -4035,7 +4035,7 @@ static int mbof_rcmp_search_groups(struct mbof_rcmp_context *ctx)
-     struct ldb_context *ldb = ldb_module_get_ctx(ctx->module);
-     static const char *attrs[] = { DB_MEMBEROF, DB_MEMBERUID,
-                                    DB_NAME, DB_MEMBER, NULL };
--    static const char *filter = "(objectclass=group)";
-+    static const char *filter = "("DB_OC"="DB_GROUP_CLASS")";
-     struct ldb_request *req;
-     int ret;
- 
-diff --git a/src/providers/ad/ad_pac.c b/src/providers/ad/ad_pac.c
-index ed002e1f9bf8f15d5b5d4b1c55392a34d18575e4..6b47462cf79a81b9258e3508914c043432edfed3 100644
---- a/src/providers/ad/ad_pac.c
-+++ b/src/providers/ad/ad_pac.c
-@@ -31,7 +31,7 @@ static errno_t find_user_entry(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
-                                struct dp_id_data *ar,
-                                struct ldb_message **_msg)
- {
--    const char *user_attrs[] = { SYSDB_NAME, SYSDB_OBJECTCLASS,
-+    const char *user_attrs[] = { SYSDB_NAME, SYSDB_OBJECTCATEGORY,
-                                  SYSDB_PAC_BLOB, SYSDB_PAC_BLOB_EXPIRE,
-                                  NULL };
-     struct ldb_message *msg;
-diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
-index 5044577f0faa95b19de9233240e92aa60f029774..8f8759f64b758aae7e45c88588e97a1bcf16ad79 100644
---- a/src/providers/ipa/ipa_id.c
-+++ b/src/providers/ipa/ipa_id.c
-@@ -431,7 +431,8 @@ static errno_t ipa_id_get_group_uuids(TALLOC_CTX *mem_ctx,
-     }
- 
-     filter = talloc_asprintf(tmp_ctx,
--                             "(&(objectclass=%s)(!(%s=*))(%s=*))",
-+                             "(&(%s=%s)(!(%s=*))(%s=*))",
-+                             SYSDB_OBJECTCATEGORY,
-                              SYSDB_GROUP_CLASS, SYSDB_OVERRIDE_DN,
-                              SYSDB_UUID);
-     if (filter == NULL) {
-@@ -733,7 +734,7 @@ static void ipa_id_get_account_info_orig_done(struct tevent_req *subreq)
-     const char *attrs[] = { SYSDB_NAME,
-                             SYSDB_UIDNUM,
-                             SYSDB_SID_STR,
--                            SYSDB_OBJECTCLASS,
-+                            SYSDB_OBJECTCATEGORY,
-                             SYSDB_UUID,
-                             SYSDB_GHOST,
-                             SYSDB_HOMEDIR,
-@@ -819,7 +820,7 @@ static int ipa_id_get_account_info_post_proc_step(struct tevent_req *req)
-     struct ipa_id_get_account_info_state *state = tevent_req_data(req,
-                                           struct ipa_id_get_account_info_state);
- 
--    class = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_OBJECTCLASS,
-+    class = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_OBJECTCATEGORY,
-                                         NULL);
-     if (class == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find an objectclass.\n");
-@@ -957,7 +958,7 @@ static void ipa_id_get_account_info_done(struct tevent_req *subreq)
-         goto fail;
-     }
- 
--    class = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_OBJECTCLASS,
-+    class = ldb_msg_find_attr_as_string(state->obj_msg, SYSDB_OBJECTCATEGORY,
-                                         NULL);
-     if (class == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find an objectclass.\n");
-diff --git a/src/providers/ipa/ipa_subdomains_ext_groups.c b/src/providers/ipa/ipa_subdomains_ext_groups.c
-index 0359e0dedeef8db0da71d16a6f0044e43a7a9840..9e1d6c3a9bdeda56b421a2dc9198dff0b84c54ce 100644
---- a/src/providers/ipa/ipa_subdomains_ext_groups.c
-+++ b/src/providers/ipa/ipa_subdomains_ext_groups.c
-@@ -940,7 +940,7 @@ search_user_or_group_by_sid_str(TALLOC_CTX *mem_ctx,
-     const char *attrs[] = { SYSDB_NAME,
-                             SYSDB_SID_STR,
-                             SYSDB_ORIG_DN,
--                            SYSDB_OBJECTCLASS,
-+                            SYSDB_OBJECTCATEGORY,
-                             SYSDB_CACHE_EXPIRE,
-                             NULL };
-     TALLOC_CTX *tmp_ctx = NULL;
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index 3530af94ef59397db72465fcb0c4a03117a4d8bd..2ba9813a44b4d914d9c2ef7a1a7504546f52954c 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -888,7 +888,7 @@ apply_subdomain_homedir(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
-     struct ldb_message_element *msg_el = NULL;
-     size_t c;
- 
--    msg_el = ldb_msg_find_element(msg, SYSDB_OBJECTCLASS);
-+    msg_el = ldb_msg_find_element(msg, SYSDB_OBJECTCATEGORY);
-     if (msg_el == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_find_element failed.\n");
-         ret = ENOENT;
-diff --git a/src/providers/krb5/krb5_renew_tgt.c b/src/providers/krb5/krb5_renew_tgt.c
-index ea6b39deb8dacdfa9211058a54a57b6e9f6b7d9d..549c08c6f105276fa9913568c228d3ff627623ae 100644
---- a/src/providers/krb5/krb5_renew_tgt.c
-+++ b/src/providers/krb5/krb5_renew_tgt.c
-@@ -385,8 +385,7 @@ static errno_t check_ccache_files(struct renew_tgt_ctx *renew_tgt_ctx)
- {
-     TALLOC_CTX *tmp_ctx;
-     int ret;
--    const char *ccache_filter = "(&("SYSDB_CCACHE_FILE"=*)" \
--                                  "("SYSDB_OBJECTCLASS"="SYSDB_USER_CLASS"))";
-+    const char *ccache_filter = "(&("SYSDB_CCACHE_FILE"=*)("SYSDB_UC"))";
-     const char *ccache_attrs[] = { SYSDB_CCACHE_FILE, SYSDB_UPN, SYSDB_NAME,
-                                    SYSDB_CANONICAL_UPN, NULL };
-     size_t msgs_count = 0;
-diff --git a/src/providers/ldap/ldap_id_cleanup.c b/src/providers/ldap/ldap_id_cleanup.c
-index c85ce45918cf938a95ff85c31bfe0541f9ddd052..8c0f0c18ba587e9bbfec144abe9c172cd5e0465b 100644
---- a/src/providers/ldap/ldap_id_cleanup.c
-+++ b/src/providers/ldap/ldap_id_cleanup.c
-@@ -438,7 +438,7 @@ static int cleanup_groups(TALLOC_CTX *memctx,
-              */
-             gid = (gid_t) ldb_msg_find_attr_as_uint(msgs[i], SYSDB_GIDNUM, 0);
-             subfilter = talloc_asprintf(tmpctx, "(&(%s=%s)(|(%s=%s)(%s=%lu)))",
--                                        SYSDB_OBJECTCLASS, SYSDB_USER_CLASS,
-+                                        SYSDB_OBJECTCATEGORY, SYSDB_USER_CLASS,
-                                         SYSDB_MEMBEROF, sanitized_dn,
-                                         SYSDB_GIDNUM, (long unsigned) gid);
-         } else {
-diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
-index 536e3f13744c5350eed518c9bd35fd89e0899dc6..b1cfb7e4a4c054e5d365da5fca65da27c9ef5461 100644
---- a/src/providers/ldap/sdap_async_groups.c
-+++ b/src/providers/ldap/sdap_async_groups.c
-@@ -39,7 +39,7 @@ static int sdap_find_entry_by_origDN(TALLOC_CTX *memctx,
-                                      bool *_is_group)
- {
-     TALLOC_CTX *tmpctx;
--    const char *attrs[] = {SYSDB_OBJECTCLASS,  NULL};
-+    const char *attrs[] = {SYSDB_OBJECTCLASS, SYSDB_OBJECTCATEGORY, NULL};
-     struct ldb_dn *base_dn;
-     char *filter;
-     struct ldb_message **msgs;
-@@ -90,11 +90,11 @@ static int sdap_find_entry_by_origDN(TALLOC_CTX *memctx,
-     }
- 
-     if (_is_group != NULL) {
--        objectclass = ldb_msg_find_attr_as_string(msgs[0], SYSDB_OBJECTCLASS,
-+        objectclass = ldb_msg_find_attr_as_string(msgs[0], SYSDB_OBJECTCATEGORY,
-                                                   NULL);
-         if (objectclass == NULL) {
--            DEBUG(SSSDBG_OP_FAILURE, "An antry without a %s?\n",
--                  SYSDB_OBJECTCLASS);
-+            DEBUG(SSSDBG_OP_FAILURE, "An entry without a %s?\n",
-+                  SYSDB_OBJECTCATEGORY);
-             ret = EINVAL;
-             goto done;
-         }
-diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
-index a33975cde4bc359cfe8395c0de04fd1774b8763d..f8a84474749e08349b539c774d68c876167cfdf1 100644
---- a/src/providers/ldap/sdap_async_initgroups.c
-+++ b/src/providers/ldap/sdap_async_initgroups.c
-@@ -2341,7 +2341,7 @@ static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req)
-     }
- 
-     ret = sysdb_attrs_get_string(state->groups[state->group_iter],
--                                 SYSDB_OBJECTCLASS, &class);
-+                                 SYSDB_OBJECTCATEGORY, &class);
-     if (ret == EOK) {
-         /* If there is a objectClass attribute the object is coming from the
-          * cache and the name attribute of the object already has the primary
-diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
-index 2831be9776293260aeec0e2ff85160f1938bdb32..61aa69a2dfbe22cac37a5b7fddc07473527e5de5 100644
---- a/src/providers/ldap/sdap_async_initgroups_ad.c
-+++ b/src/providers/ldap/sdap_async_initgroups_ad.c
-@@ -1606,7 +1606,7 @@ sdap_ad_get_domain_local_groups_parse_parents(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    ret = sysdb_attrs_get_string(gr->group, SYSDB_OBJECTCLASS, &class);
-+    ret = sysdb_attrs_get_string(gr->group, SYSDB_OBJECTCATEGORY, &class);
-     if (ret != EOK) {
-         /* If objectclass is missing gr->group is a nested parent found during
-          * the nested group lookup. It might not already stored in the cache.
-diff --git a/src/providers/ldap/sdap_async_nested_groups.c b/src/providers/ldap/sdap_async_nested_groups.c
-index 9271d8cfe38d11fb1ea14960a997f0deee175b27..b1f9753d7cdf5f6e278c54394d4f306cc21a42ab 100644
---- a/src/providers/ldap/sdap_async_nested_groups.c
-+++ b/src/providers/ldap/sdap_async_nested_groups.c
-@@ -1686,7 +1686,7 @@ static errno_t sdap_nested_group_get_ipa_user(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    ret = sysdb_attrs_add_string(user, SYSDB_OBJECTCLASS, SYSDB_USER_CLASS);
-+    ret = sysdb_attrs_add_string(user, SYSDB_OBJECTCATEGORY, SYSDB_USER_CLASS);
-     if (ret != EOK) {
-         goto done;
-     }
-diff --git a/src/responder/common/cache_req/plugins/cache_req_common.c b/src/responder/common/cache_req/plugins/cache_req_common.c
-index b80f310feeebbdbc824db441ff5313632585d3fb..1f86258bc14c7a382712959f24a4ec4c153572d4 100644
---- a/src/responder/common/cache_req/plugins/cache_req_common.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_common.c
-@@ -53,7 +53,7 @@ cache_req_well_known_sid_msg(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    ldberr = ldb_msg_add_string(msg, SYSDB_OBJECTCLASS, SYSDB_GROUP_CLASS);
-+    ldberr = ldb_msg_add_string(msg, SYSDB_OBJECTCATEGORY, SYSDB_GROUP_CLASS);
-     if (ldberr != LDB_SUCCESS) {
-         goto done;
-     }
-diff --git a/src/responder/ifp/ifp_cache.c b/src/responder/ifp/ifp_cache.c
-index 8ea2d8008d40bc0a28f3871b511690af677c5c5e..f84cb14de48b5c86acb027f275edded4eb73e192 100644
---- a/src/responder/ifp/ifp_cache.c
-+++ b/src/responder/ifp/ifp_cache.c
-@@ -100,7 +100,7 @@ ifp_cache_get_cached_objects(TALLOC_CTX *mem_ctx,
-     errno_t ret;
-     int ldb_ret;
-     int i;
--    const char *attrs[] = {SYSDB_OBJECTCLASS, SYSDB_UIDNUM,
-+    const char *attrs[] = {SYSDB_OBJECTCATEGORY, SYSDB_UIDNUM,
-                            SYSDB_GIDNUM, NULL};
- 
-     tmp_ctx = talloc_new(NULL);
-@@ -117,7 +117,7 @@ ifp_cache_get_cached_objects(TALLOC_CTX *mem_ctx,
- 
-     ldb_ret = ldb_search(sysdb_ctx_get_ldb(domain->sysdb), tmp_ctx, &result,
-                          base_dn, LDB_SCOPE_SUBTREE, attrs,
--                         "(&(objectClass=%s)(%s=TRUE))", class,
-+                         "(&(%s=%s)(%s=TRUE))", SYSDB_OBJECTCATEGORY, class,
-                          SYSDB_IFP_CACHED);
-     if (ldb_ret != LDB_SUCCESS) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to search the cache\n");
-diff --git a/src/responder/ifp/ifp_groups.c b/src/responder/ifp/ifp_groups.c
-index 7503254238eafdafbe2d90fbf7416587be49e1b7..b274b8f52d7908165acc10b91a7d6afe638f1a82 100644
---- a/src/responder/ifp/ifp_groups.c
-+++ b/src/responder/ifp/ifp_groups.c
-@@ -841,7 +841,7 @@ ifp_groups_group_get_members(TALLOC_CTX *mem_ctx,
-     int num_groups;
-     int i;
-     errno_t ret;
--    const char *attrs[] = {SYSDB_OBJECTCLASS, SYSDB_UIDNUM,
-+    const char *attrs[] = {SYSDB_OBJECTCATEGORY, SYSDB_UIDNUM,
-                            SYSDB_GIDNUM, NULL};
- 
-     tmp_ctx = talloc_new(NULL);
-@@ -888,7 +888,7 @@ ifp_groups_group_get_members(TALLOC_CTX *mem_ctx,
-     num_users = 0;
-     num_groups = 0;
-     for (i = 0; i < num_members; i++) {
--        class = ldb_msg_find_attr_as_string(members[i], SYSDB_OBJECTCLASS,
-+        class = ldb_msg_find_attr_as_string(members[i], SYSDB_OBJECTCATEGORY,
-                                             NULL);
-         if (class == NULL) {
-             ret = ERR_INTERNAL;
-diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c
-index 86a1f43a2c6e7d785c9d34e350c71f242ff7182f..cb342a245ef6545168a7a60c252505f50576fdf7 100644
---- a/src/responder/ifp/ifp_users.c
-+++ b/src/responder/ifp/ifp_users.c
-@@ -1441,7 +1441,7 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req,
-     }
- 
-     filter = talloc_asprintf(sbus_req, "(&(%s=%s)(%s=%s))",
--                             SYSDB_OBJECTCLASS, SYSDB_USER_CLASS,
-+                             SYSDB_OBJECTCATEGORY, SYSDB_USER_CLASS,
-                              SYSDB_NAME, name);
-     if (filter == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf() failed\n");
-diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c
-index 545257a0be7e91e9de767a57848bb77c5791db4e..956ee53cb88dd24faaa95ac39c8d9540af66cfb2 100644
---- a/src/responder/nss/nss_cmd.c
-+++ b/src/responder/nss/nss_cmd.c
-@@ -1148,7 +1148,7 @@ static errno_t nss_cmd_getorigbyname(struct cli_ctx *cli_ctx)
-     errno_t ret;
-     struct nss_ctx *nss_ctx;
-     const char **attrs;
--    static const char *defattrs[] = { SYSDB_NAME, SYSDB_OBJECTCLASS,
-+    static const char *defattrs[] = { SYSDB_NAME, SYSDB_OBJECTCATEGORY,
-                                       SYSDB_SID_STR,
-                                       ORIGINALAD_PREFIX SYSDB_NAME,
-                                       ORIGINALAD_PREFIX SYSDB_UIDNUM,
-diff --git a/src/responder/nss/nss_protocol_grent.c b/src/responder/nss/nss_protocol_grent.c
-index 6f6ae57dd97b000ad3cf174b0f649d46981563e2..3550c3f0d375b305d4dbdf3ea19613696448da35 100644
---- a/src/responder/nss/nss_protocol_grent.c
-+++ b/src/responder/nss/nss_protocol_grent.c
-@@ -33,7 +33,7 @@ nss_get_grent(TALLOC_CTX *mem_ctx,
-     errno_t ret;
- 
-     /* Check object class. */
--    if (!ldb_msg_check_string_attribute(msg, "objectClass",
-+    if (!ldb_msg_check_string_attribute(msg, SYSDB_OBJECTCATEGORY,
-                                         SYSDB_GROUP_CLASS)) {
-         DEBUG(SSSDBG_MINOR_FAILURE, "Wrong object (%s) found on stack!\n",
-               ldb_dn_get_linearized(msg->dn));
-diff --git a/src/responder/nss/nss_protocol_sid.c b/src/responder/nss/nss_protocol_sid.c
-index 61357c2bf92e2f15d978b64a15ad5bd5aa354445..3f60967d750eea3135257ccb597efaa5aa1e2de3 100644
---- a/src/responder/nss/nss_protocol_sid.c
-+++ b/src/responder/nss/nss_protocol_sid.c
-@@ -30,9 +30,9 @@ find_sss_id_type(struct ldb_message *msg,
-     struct ldb_message_element *el;
-     struct ldb_val *val = NULL;
- 
--    el = ldb_msg_find_element(msg, SYSDB_OBJECTCLASS);
-+    el = ldb_msg_find_element(msg, SYSDB_OBJECTCATEGORY);
-     if (el == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "Objectclass attribute not found.\n");
-+        DEBUG(SSSDBG_OP_FAILURE, "Objectcategory attribute not found.\n");
-         return EINVAL;
-     }
- 
-diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c
-index 3187af1b004cf3d1ffc1746950faa842f3a05fbc..80b3bb5599a95578b7734d5dfcd20a2a7428a084 100644
---- a/src/tests/cmocka/test_ad_common.c
-+++ b/src/tests/cmocka/test_ad_common.c
-@@ -336,7 +336,7 @@ static void test_ad_get_pac_data_from_user_entry(void **state)
- 
-     ret = ldb_msg_add_string(user_msg, SYSDB_NAME, "username");
-     assert_int_equal(ret, EOK);
--    ret = ldb_msg_add_string(user_msg, SYSDB_OBJECTCLASS, "user");
-+    ret = ldb_msg_add_string(user_msg, SYSDB_OBJECTCATEGORY, SYSDB_USER_CLASS);
-     assert_int_equal(ret, EOK);
-     ret = ldb_msg_add_string(user_msg, SYSDB_PAC_BLOB_EXPIRE, "12345");
-     assert_int_equal(ret, EOK);
-diff --git a/src/tests/cmocka/test_ipa_subdomains_server.c b/src/tests/cmocka/test_ipa_subdomains_server.c
-index eccfc2fe1e2a224b2cec8ea3184796a23d32febe..1e492e86c1caf26d8890bfa37ebb21321afca366 100644
---- a/src/tests/cmocka/test_ipa_subdomains_server.c
-+++ b/src/tests/cmocka/test_ipa_subdomains_server.c
-@@ -455,6 +455,8 @@ static void test_ipa_server_create_trusts_twoway(struct tevent_req *req)
-         tevent_req_callback_data(req, struct trust_test_ctx);
-     errno_t ret;
-     struct sss_domain_info *child_dom;
-+    struct ipa_ad_server_ctx *s_trust;
-+    struct ipa_ad_server_ctx *c_trust;
- 
-     ret = ipa_server_create_trusts_recv(req);
-     talloc_zfree(req);
-@@ -462,9 +464,18 @@ static void test_ipa_server_create_trusts_twoway(struct tevent_req *req)
- 
-     /* Trust object should be around now */
-     assert_non_null(test_ctx->ipa_ctx->server_mode->trusts);
-+    assert_non_null(test_ctx->ipa_ctx->server_mode->trusts->next);
- 
-+    if (strcmp(test_ctx->ipa_ctx->server_mode->trusts->dom->name,
-+               SUBDOM_NAME) == 0) {
-+        s_trust = test_ctx->ipa_ctx->server_mode->trusts;
-+        c_trust = test_ctx->ipa_ctx->server_mode->trusts->next;
-+    } else {
-+        s_trust = test_ctx->ipa_ctx->server_mode->trusts->next;
-+        c_trust = test_ctx->ipa_ctx->server_mode->trusts;
-+    }
-     /* Two-way trusts should use the system realm */
--    assert_trust_object(test_ctx->ipa_ctx->server_mode->trusts,
-+    assert_trust_object(c_trust,
-                         CHILD_NAME,
-                         DOM_REALM,
-                         CHILD_SID,
-@@ -472,9 +483,8 @@ static void test_ipa_server_create_trusts_twoway(struct tevent_req *req)
-                         TEST_AUTHID,
-                         DOM_REALM);
- 
--    assert_non_null(test_ctx->ipa_ctx->server_mode->trusts->next);
- 
--    assert_trust_object(test_ctx->ipa_ctx->server_mode->trusts->next,
-+    assert_trust_object(s_trust,
-                         SUBDOM_NAME,
-                         DOM_REALM,
-                         SUBDOM_SID,
-@@ -523,6 +533,8 @@ static void test_ipa_server_trust_init(void **state)
-     errno_t ret;
-     struct tevent_timer *timeout_handler;
-     struct timeval tv;
-+    struct ipa_ad_server_ctx *s_trust;
-+    struct ipa_ad_server_ctx *c_trust;
- 
-     add_test_2way_subdomains(test_ctx);
- 
-@@ -537,13 +549,21 @@ static void test_ipa_server_trust_init(void **state)
-     ret = test_ev_loop(test_ctx->tctx);
-     assert_int_equal(ret, ERR_OK);
- 
--    assert_non_null(test_ctx->ipa_ctx->server_mode->trusts);
--
-     /* Trust object should be around now */
-     assert_non_null(test_ctx->ipa_ctx->server_mode->trusts);
-+    assert_non_null(test_ctx->ipa_ctx->server_mode->trusts->next);
-+
-+    if (strcmp(test_ctx->ipa_ctx->server_mode->trusts->dom->name,
-+               SUBDOM_NAME) == 0) {
-+        s_trust = test_ctx->ipa_ctx->server_mode->trusts;
-+        c_trust = test_ctx->ipa_ctx->server_mode->trusts->next;
-+    } else {
-+        s_trust = test_ctx->ipa_ctx->server_mode->trusts->next;
-+        c_trust = test_ctx->ipa_ctx->server_mode->trusts;
-+    }
- 
-     /* Two-way trusts should use the system realm */
--    assert_trust_object(test_ctx->ipa_ctx->server_mode->trusts,
-+    assert_trust_object(c_trust,
-                         CHILD_NAME,
-                         DOM_REALM,
-                         CHILD_SID,
-@@ -551,9 +571,7 @@ static void test_ipa_server_trust_init(void **state)
-                         TEST_AUTHID,
-                         DOM_REALM);
- 
--    assert_non_null(test_ctx->ipa_ctx->server_mode->trusts->next);
--
--    assert_trust_object(test_ctx->ipa_ctx->server_mode->trusts->next,
-+    assert_trust_object(s_trust,
-                         SUBDOM_NAME,
-                         DOM_REALM,
-                         SUBDOM_SID,
-@@ -708,6 +726,8 @@ static void test_ipa_server_create_trusts_oneway(struct tevent_req *req)
-     struct trust_test_ctx *test_ctx = \
-         tevent_req_callback_data(req, struct trust_test_ctx);
-     errno_t ret;
-+    struct ipa_ad_server_ctx *s_trust;
-+    struct ipa_ad_server_ctx *c_trust;
- 
-     ret = ipa_server_create_trusts_recv(req);
-     talloc_zfree(req);
-@@ -720,9 +740,19 @@ static void test_ipa_server_create_trusts_oneway(struct tevent_req *req)
- 
-     /* Trust object should be around now */
-     assert_non_null(test_ctx->ipa_ctx->server_mode->trusts);
-+    assert_non_null(test_ctx->ipa_ctx->server_mode->trusts->next);
-+
-+    if (strcmp(test_ctx->ipa_ctx->server_mode->trusts->dom->name,
-+               SUBDOM_NAME) == 0) {
-+        s_trust = test_ctx->ipa_ctx->server_mode->trusts;
-+        c_trust = test_ctx->ipa_ctx->server_mode->trusts->next;
-+    } else {
-+        s_trust = test_ctx->ipa_ctx->server_mode->trusts->next;
-+        c_trust = test_ctx->ipa_ctx->server_mode->trusts;
-+    }
- 
-     assert_trust_object(
--        test_ctx->ipa_ctx->server_mode->trusts,
-+        c_trust,
-         CHILD_NAME,    /* AD domain name */
-         CHILD_REALM,   /* AD realm can be child if SDAP realm is parent's */
-         CHILD_SID,
-@@ -730,10 +760,8 @@ static void test_ipa_server_create_trusts_oneway(struct tevent_req *req)
-         ONEWAY_PRINC,     /* Principal shared with parent AD dom */
-         SUBDOM_REALM); /* SDAP realm must be AD root domain */
- 
--    assert_non_null(test_ctx->ipa_ctx->server_mode->trusts->next);
--
-     /* Here all properties point to the AD domain */
--    assert_trust_object(test_ctx->ipa_ctx->server_mode->trusts->next,
-+    assert_trust_object(s_trust,
-                         SUBDOM_NAME,
-                         SUBDOM_REALM,
-                         SUBDOM_SID,
-diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
-index 4652661087238c18f7fabb398d054db99f77d6cf..fc9936968bcde8370c7054ba303de4463b35e15a 100644
---- a/src/tests/sysdb-tests.c
-+++ b/src/tests/sysdb-tests.c
-@@ -503,7 +503,7 @@ static int test_search_all_users(struct test_data *data)
-     }
- 
-     ret = sysdb_search_entry(data, data->ctx->sysdb, base_dn,
--                             LDB_SCOPE_SUBTREE, "objectClass=user",
-+                             LDB_SCOPE_SUBTREE, SYSDB_UC,
-                              data->attrlist, &data->msgs_count, &data->msgs);
-     return ret;
- }
-@@ -2219,6 +2219,7 @@ START_TEST (test_sysdb_search_all_users)
-     struct test_data *data;
-     int ret;
-     int i;
-+    int j;
-     char *uid_str;
- 
-     /* Setup */
-@@ -2253,8 +2254,15 @@ START_TEST (test_sysdb_search_all_users)
-                     "wrong number of values, found [%d] expected [1]",
-                     data->msgs[i]->elements[0].num_values);
- 
--        uid_str = talloc_asprintf(data, "%d", 27010 + i);
--        fail_unless(uid_str != NULL, "talloc_asprintf failed.");
-+        for (j = 0; j < data->msgs_count; j++) {
-+            uid_str = talloc_asprintf(data, "%d", 27010 + j);
-+            fail_unless(uid_str != NULL, "talloc_asprintf failed.");
-+            if (strncmp(uid_str,
-+                        (char *) data->msgs[i]->elements[0].values[0].data,
-+                        data->msgs[i]->elements[0].values[0].length)  == 0) {
-+                break;
-+            }
-+        }
-         fail_unless(strncmp(uid_str,
-                             (char *) data->msgs[i]->elements[0].values[0].data,
-                             data->msgs[i]->elements[0].values[0].length)  == 0,
-@@ -4411,7 +4419,7 @@ START_TEST(test_SSS_LDB_SEARCH)
- 
-     /* Non-empty filter */
-     SSS_LDB_SEARCH(ret, test_ctx->sysdb->ldb, test_ctx, &res, group_dn,
--                   LDB_SCOPE_BASE, NULL, "objectClass=group");
-+                   LDB_SCOPE_BASE, NULL, SYSDB_GC);
- 
-     fail_unless(ret == EOK, "SSS_LDB_SEARCH error [%d][%s]",
-                 ret, strerror(ret));
-@@ -5203,7 +5211,7 @@ START_TEST (test_sysdb_search_return_ENOENT)
- 
-     ret = sysdb_search_entry(test_ctx, test_ctx->sysdb,
-                              user_dn, LDB_SCOPE_SUBTREE,
--                             "objectClass=user", NULL,
-+                             SYSDB_UC, NULL,
-                              &count, &msgs);
-     fail_unless(ret == ENOENT, "sysdb_search_entry failed: %d, %s",
-                                ret, strerror(ret));
-@@ -5215,7 +5223,7 @@ START_TEST (test_sysdb_search_return_ENOENT)
-                             data->username);
-     fail_if(user_dn == NULL, "sysdb_user_dn failed");
-     SSS_LDB_SEARCH(ret, test_ctx->sysdb->ldb, test_ctx, &res, user_dn,
--                   LDB_SCOPE_BASE, NULL, "objectClass=user");
-+                   LDB_SCOPE_BASE, NULL, SYSDB_UC);
- 
-     fail_unless(ret == ENOENT, "SSS_LDB_SEARCH failed: %d, %s",
-                                ret, strerror(ret));
-diff --git a/src/tools/sssctl/sssctl_cache.c b/src/tools/sssctl/sssctl_cache.c
-index 80f65bb55df42d0b123023bb9b1efdb2353b8e20..42a2a60fd31631b3c86d17ddbdd8027a8468366d 100644
---- a/src/tools/sssctl/sssctl_cache.c
-+++ b/src/tools/sssctl/sssctl_cache.c
-@@ -335,7 +335,8 @@ static const char *sssctl_create_filter(TALLOC_CTX *mem_ctx,
-         talloc_free(filter_value_old);
-     }
- 
--    filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(|(%s=%s)(%s=%s)))",
-+    filter = talloc_asprintf(mem_ctx, "(&(%s=%s)(|(%s=%s)(%s=%s)))",
-+                             obj_type == CACHED_NETGROUP ? SYSDB_OBJECTCLASS : SYSDB_OBJECTCATEGORY,
-                              class, attr_name, filter_value,
-                              SYSDB_NAME_ALIAS, filter_value);
- 
--- 
-2.14.3
-
diff --git a/SOURCES/0056-sysdb-do-not-use-LDB_SCOPE_ONELEVEL.patch b/SOURCES/0056-sysdb-do-not-use-LDB_SCOPE_ONELEVEL.patch
deleted file mode 100644
index e0f0758..0000000
--- a/SOURCES/0056-sysdb-do-not-use-LDB_SCOPE_ONELEVEL.patch
+++ /dev/null
@@ -1,83 +0,0 @@
-From c36d5d56e62f879dbc1c58155097dfc26746a7f4 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 14 Nov 2017 13:09:18 +0100
-Subject: [PATCH 56/57] sysdb: do not use LDB_SCOPE_ONELEVEL
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Currently the index for one-level searches is a huge blob which maps all
-parents with all it children. Handling this blob is costly and since all
-searches using LDB_SCOPE_ONELEVEL also have a filter with indexed
-attributes a sub-tree search would be more efficient. But since libldb
-currently first looks at the scope and hence use the one-level index
-blob we have to explicitly use LDB_SCOPE_SUBTREE in the callers to use
-the more efficient attribute based inxed.
-
-Related to https://pagure.io/SSSD/sssd/issue/3503
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 98195e591c4d97caa6125e8214879660b740973f)
----
- src/db/sysdb_autofs.c         | 2 +-
- src/db/sysdb_ranges.c         | 2 +-
- src/db/sysdb_subdomains.c     | 2 +-
- src/responder/ifp/ifp_users.c | 2 +-
- 4 files changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/src/db/sysdb_autofs.c b/src/db/sysdb_autofs.c
-index b3e9b4ec83b66ec65a72ab7a3180106e2293d8a5..89803a778c370c899611ee5e15b7ae1a48e82cb9 100644
---- a/src/db/sysdb_autofs.c
-+++ b/src/db/sysdb_autofs.c
-@@ -384,7 +384,7 @@ sysdb_autofs_entries_by_map(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    ret = sysdb_search_entry(tmp_ctx, domain->sysdb, mapdn, LDB_SCOPE_ONELEVEL,
-+    ret = sysdb_search_entry(tmp_ctx, domain->sysdb, mapdn, LDB_SCOPE_SUBTREE,
-                              filter, attrs, &count, &msgs);
-     if (ret != EOK && ret != ENOENT) {
-         DEBUG(SSSDBG_OP_FAILURE, "sysdb search failed: %d\n", ret);
-diff --git a/src/db/sysdb_ranges.c b/src/db/sysdb_ranges.c
-index 511e4785d9aa68b2a33b440e1c5ee62e5ccf7ce4..be3a0d37220f833d27417808ddfef0e74c0ba9b2 100644
---- a/src/db/sysdb_ranges.c
-+++ b/src/db/sysdb_ranges.c
-@@ -71,7 +71,7 @@ errno_t sysdb_get_ranges(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
-         goto done;
-     }
-     ret = ldb_search(sysdb->ldb, tmp_ctx, &res,
--                     basedn, LDB_SCOPE_ONELEVEL,
-+                     basedn, LDB_SCOPE_SUBTREE,
-                      attrs, "objectclass=%s", SYSDB_ID_RANGE_CLASS);
-     if (ret != LDB_SUCCESS) {
-         ret = EIO;
-diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
-index 353561765904efe4bd698c38949a1b290ecf0b80..0dd05c24c963f12a28ef6f6b64dc40faa7fcc649 100644
---- a/src/db/sysdb_subdomains.c
-+++ b/src/db/sysdb_subdomains.c
-@@ -338,7 +338,7 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain,
-         goto done;
-     }
-     ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res,
--                     basedn, LDB_SCOPE_ONELEVEL,
-+                     basedn, LDB_SCOPE_SUBTREE,
-                      attrs, "objectclass=%s", SYSDB_SUBDOMAIN_CLASS);
-     if (ret != LDB_SUCCESS) {
-         ret = EIO;
-diff --git a/src/responder/ifp/ifp_users.c b/src/responder/ifp/ifp_users.c
-index cb342a245ef6545168a7a60c252505f50576fdf7..f66587b8cf81a555dd1cb7aff12e0c8347c250b1 100644
---- a/src/responder/ifp/ifp_users.c
-+++ b/src/responder/ifp/ifp_users.c
-@@ -1449,7 +1449,7 @@ void ifp_users_user_get_extra_attributes(struct sbus_request *sbus_req,
-     }
- 
-     ret = sysdb_search_entry(sbus_req, domain->sysdb, basedn,
--                             LDB_SCOPE_ONELEVEL, filter,
-+                             LDB_SCOPE_SUBTREE, filter,
-                              extra, &count, &user);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to lookup user [%d]: %s\n",
--- 
-2.14.3
-
diff --git a/SOURCES/0057-sysdb-remove-IDXONE-and-objectClass-from-users-and-g.patch b/SOURCES/0057-sysdb-remove-IDXONE-and-objectClass-from-users-and-g.patch
deleted file mode 100644
index 278541e..0000000
--- a/SOURCES/0057-sysdb-remove-IDXONE-and-objectClass-from-users-and-g.patch
+++ /dev/null
@@ -1,384 +0,0 @@
-From 0f907d8501387ec32dbb00e1c38d5da25e698f90 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 14 Nov 2017 13:14:14 +0100
-Subject: [PATCH 57/57] sysdb: remove IDXONE and objectClass from users and
- groups
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This patch does the needed sysdb update for the previous to patches. It
-removes the one-level search index IDXONE and replaces objectClass with
-objectCategory in the user and group objects.
-
-Related to https://pagure.io/SSSD/sssd/issue/3503
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 2927da49dd8a16fff6312d89ad43cc355655800c)
----
- src/db/sysdb_init.c    |  52 +++++++++++-
- src/db/sysdb_private.h |  11 ++-
- src/db/sysdb_upgrade.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 274 insertions(+), 6 deletions(-)
-
-diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c
-index 44a7918f603fe1368b7d81738666de6bb47b83d0..74ad23f3050da0ae14fa495d2302f4a858fcd3c5 100644
---- a/src/db/sysdb_init.c
-+++ b/src/db/sysdb_init.c
-@@ -359,8 +359,48 @@ static errno_t sysdb_ts_cache_upgrade(TALLOC_CTX *mem_ctx,
-                                       const char *cur_version,
-                                       const char **_new_version)
- {
--    /* Currently the sysdb cache only has one version */
--    return EFAULT;
-+    errno_t ret;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *version;
-+    struct ldb_context *save_ldb;
-+
-+    tmp_ctx = talloc_new(NULL);
-+    if (tmp_ctx == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    /* The upgrade process depends on having ldb around, yet the upgrade
-+     * function shouldn't set the ldb pointer, only the connect function
-+     * should after it's successful. To avoid hard refactoring, save the
-+     * ldb pointer here and restore in the 'done' handler
-+     */
-+    save_ldb = sysdb->ldb;
-+    sysdb->ldb = ldb;
-+
-+    version = talloc_strdup(tmp_ctx, cur_version);
-+    if (version == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    DEBUG(SSSDBG_CONF_SETTINGS,
-+          "Upgrading timstamp cache of DB [%s] from version: %s\n",
-+          domain->name, version);
-+
-+    if (strcmp(version, SYSDB_TS_VERSION_0_1) == 0) {
-+        ret = sysdb_ts_upgrade_01(sysdb, &version);
-+        if (ret != EOK) {
-+            goto done;
-+        }
-+    }
-+
-+    ret = EOK;
-+
-+done:
-+    sysdb->ldb = save_ldb;
-+    *_new_version = version;
-+    talloc_free(tmp_ctx);
-+    return ret;
- }
- 
- static errno_t sysdb_domain_cache_upgrade(TALLOC_CTX *mem_ctx,
-@@ -511,6 +551,14 @@ static errno_t sysdb_domain_cache_upgrade(TALLOC_CTX *mem_ctx,
-         }
-     }
- 
-+    if (strcmp(version, SYSDB_VERSION_0_19) == 0) {
-+        ret = sysdb_upgrade_19(sysdb, &version);
-+        if (ret != EOK) {
-+            goto done;
-+        }
-+    }
-+
-+
-     ret = EOK;
- done:
-     sysdb->ldb = save_ldb;
-diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h
-index dbd75615bc212e73c4338a76dceaa68a5889ed1d..cac06ba46da23080d1ab661502d0792bd37b9291 100644
---- a/src/db/sysdb_private.h
-+++ b/src/db/sysdb_private.h
-@@ -23,6 +23,7 @@
- #ifndef __INT_SYS_DB_H__
- #define __INT_SYS_DB_H__
- 
-+#define SYSDB_VERSION_0_20 "0.20"
- #define SYSDB_VERSION_0_19 "0.19"
- #define SYSDB_VERSION_0_18 "0.18"
- #define SYSDB_VERSION_0_17 "0.17"
-@@ -43,7 +44,7 @@
- #define SYSDB_VERSION_0_2 "0.2"
- #define SYSDB_VERSION_0_1 "0.1"
- 
--#define SYSDB_VERSION SYSDB_VERSION_0_19
-+#define SYSDB_VERSION SYSDB_VERSION_0_20
- 
- #define SYSDB_BASE_LDIF \
-      "dn: @ATTRIBUTES\n" \
-@@ -72,7 +73,6 @@
-      "@IDXATTR: sudoUser\n" \
-      "@IDXATTR: sshKnownHostsExpire\n" \
-      "@IDXATTR: objectSIDString\n" \
--     "@IDXONE: 1\n" \
-      "@IDXATTR: ghost\n" \
-      "@IDXATTR: userPrincipalName\n" \
-      "@IDXATTR: canonicalUserPrincipalName\n" \
-@@ -92,9 +92,10 @@
-      "\n"
- 
- /* The timestamp cache has its own versioning */
-+#define SYSDB_TS_VERSION_0_2 "0.2"
- #define SYSDB_TS_VERSION_0_1 "0.1"
- 
--#define SYSDB_TS_VERSION SYSDB_TS_VERSION_0_1
-+#define SYSDB_TS_VERSION SYSDB_TS_VERSION_0_2
- 
- #define SYSDB_TS_BASE_LDIF \
-      "dn: @ATTRIBUTES\n" \
-@@ -103,7 +104,6 @@
-      "dn: @INDEXLIST\n" \
-      "@IDXATTR: lastUpdate\n" \
-      "@IDXATTR: dataExpireTimestamp\n" \
--     "@IDXONE: 1\n" \
-      "\n" \
-      "dn: cn=sysdb\n" \
-      "cn: sysdb\n" \
-@@ -169,6 +169,9 @@ int sysdb_upgrade_17(struct sysdb_ctx *sysdb,
-                      struct sysdb_dom_upgrade_ctx *upgrade_ctx,
-                      const char **ver);
- int sysdb_upgrade_18(struct sysdb_ctx *sysdb, const char **ver);
-+int sysdb_upgrade_19(struct sysdb_ctx *sysdb, const char **ver);
-+
-+int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver);
- 
- int sysdb_add_string(struct ldb_message *msg,
-                      const char *attr, const char *value);
-diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c
-index 365d45f7ebd78523ca9ec4b9c2158cc09acb5489..bc157a24664239bc1255e49a1825243a07acc90f 100644
---- a/src/db/sysdb_upgrade.c
-+++ b/src/db/sysdb_upgrade.c
-@@ -2317,6 +2317,223 @@ done:
-     return ret;
- }
- 
-+static errno_t add_object_category(struct ldb_context *ldb,
-+                                   struct upgrade_ctx *ctx)
-+{
-+    errno_t ret;
-+    struct ldb_result *objects = NULL;
-+    const char *attrs[] = { SYSDB_OBJECTCLASS, NULL };
-+    struct ldb_dn *base_dn;
-+    size_t c;
-+    const char *class_name;
-+    struct ldb_message *msg = NULL;
-+    struct ldb_message *del_msg = NULL;
-+
-+    base_dn = ldb_dn_new(ctx, ldb, SYSDB_BASE);
-+    if (base_dn == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed create base dn.\n");
-+        return ENOMEM;
-+    }
-+
-+    ret = ldb_search(ldb, ctx, &objects, base_dn,
-+                     LDB_SCOPE_SUBTREE, attrs,
-+                     "(|("SYSDB_OBJECTCLASS"="SYSDB_USER_CLASS")"
-+                       "("SYSDB_OBJECTCLASS"="SYSDB_GROUP_CLASS"))");
-+    talloc_free(base_dn);
-+    if (ret != LDB_SUCCESS) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to search objects: %d\n", ret);
-+        ret = sysdb_error_to_errno(ret);
-+        goto done;
-+    }
-+
-+    if (objects == NULL || objects->count == 0) {
-+        DEBUG(SSSDBG_TRACE_LIBS, "No objects found, nothing to do.");
-+        ret = EOK;
-+        goto done;
-+    }
-+
-+    del_msg = ldb_msg_new(ctx);
-+    if (del_msg == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+    ret = ldb_msg_add_empty(del_msg, SYSDB_OBJECTCLASS, LDB_FLAG_MOD_DELETE,
-+                            NULL);
-+    if (ret != LDB_SUCCESS) {
-+        DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n");
-+        ret = sysdb_error_to_errno(ret);
-+        goto done;
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_ALL, "Found [%d] objects.\n", objects->count);
-+    for (c = 0; c < objects->count; c++) {
-+        DEBUG(SSSDBG_TRACE_ALL, "Updating [%s].\n",
-+              ldb_dn_get_linearized(objects->msgs[c]->dn));
-+
-+        class_name = ldb_msg_find_attr_as_string(objects->msgs[c],
-+                                                 SYSDB_OBJECTCLASS, NULL);
-+        if (class_name == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "Searched objects by objectClass, "
-+                                     "but result does not have one.\n");
-+            ret = EINVAL;
-+            goto done;
-+        }
-+
-+        talloc_free(msg);
-+        msg = ldb_msg_new(ctx);
-+        if (msg == NULL) {
-+            DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+
-+        msg->dn = objects->msgs[c]->dn;
-+        del_msg->dn = objects->msgs[c]->dn;
-+
-+        ret = ldb_msg_add_empty(msg, SYSDB_OBJECTCATEGORY, LDB_FLAG_MOD_ADD,
-+                                NULL);
-+        if (ret != LDB_SUCCESS) {
-+            DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n");
-+            ret = sysdb_error_to_errno(ret);
-+            goto done;
-+        }
-+
-+        ret = ldb_msg_add_string(msg, SYSDB_OBJECTCATEGORY, class_name);
-+        if (ret != LDB_SUCCESS) {
-+            DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_string failed.\n");
-+            ret = sysdb_error_to_errno(ret);
-+            goto done;
-+        }
-+
-+        DEBUG(SSSDBG_TRACE_ALL, "Adding [%s] to [%s].\n", class_name,
-+              ldb_dn_get_linearized(objects->msgs[c]->dn));
-+        ret = ldb_modify(ldb, msg);
-+        if (ret != LDB_SUCCESS) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Failed to add objectCategory to %s: %d.\n",
-+                  ldb_dn_get_linearized(objects->msgs[c]->dn),
-+                  sysdb_error_to_errno(ret));
-+            ret = sysdb_error_to_errno(ret);
-+            goto done;
-+        }
-+
-+        ret = ldb_modify(ldb, del_msg);
-+        if (ret != LDB_SUCCESS) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "Failed to remove objectClass from %s: %d.\n",
-+                  ldb_dn_get_linearized(objects->msgs[c]->dn),
-+                  sysdb_error_to_errno(ret));
-+            ret = sysdb_error_to_errno(ret);
-+            goto done;
-+        }
-+    }
-+
-+    ret = EOK;
-+
-+done:
-+    talloc_free(msg);
-+    talloc_free(del_msg);
-+    talloc_free(objects);
-+
-+    return ret;
-+}
-+
-+int sysdb_upgrade_19(struct sysdb_ctx *sysdb, const char **ver)
-+{
-+    struct upgrade_ctx *ctx;
-+    errno_t ret;
-+    struct ldb_message *msg = NULL;
-+
-+    ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_20, &ctx);
-+    if (ret) {
-+        return ret;
-+    }
-+
-+    ret = add_object_category(sysdb->ldb, ctx);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "add_object_category failed.\n");
-+        goto done;
-+    }
-+
-+    /* Remove @IDXONE from index */
-+    msg = ldb_msg_new(ctx);
-+    if (msg == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST");
-+    if (msg->dn == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = ldb_msg_add_empty(msg, "@IDXONE", LDB_FLAG_MOD_DELETE, NULL);
-+    if (ret != LDB_SUCCESS) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = ldb_modify(sysdb->ldb, msg);
-+    if (ret != LDB_SUCCESS) {
-+        ret = sysdb_error_to_errno(ret);
-+        goto done;
-+    }
-+
-+    /* conversion done, update version number */
-+    ret = update_version(ctx);
-+
-+done:
-+    ret = finish_upgrade(ret, &ctx, ver);
-+    return ret;
-+}
-+
-+int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver)
-+{
-+    struct upgrade_ctx *ctx;
-+    errno_t ret;
-+    struct ldb_message *msg = NULL;
-+
-+    ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_TS_VERSION_0_2, &ctx);
-+    if (ret) {
-+        return ret;
-+    }
-+
-+    /* Remove @IDXONE from index */
-+    talloc_free(msg);
-+    msg = ldb_msg_new(ctx);
-+    if (msg == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST");
-+    if (msg->dn == NULL) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = ldb_msg_add_empty(msg, "@IDXONE", LDB_FLAG_MOD_DELETE, NULL);
-+    if (ret != LDB_SUCCESS) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = ldb_modify(sysdb->ldb, msg);
-+    if (ret != LDB_SUCCESS) {
-+        ret = sysdb_error_to_errno(ret);
-+        goto done;
-+    }
-+
-+    /* conversion done, update version number */
-+    ret = update_version(ctx);
-+
-+done:
-+    ret = finish_upgrade(ret, &ctx, ver);
-+    return ret;
-+}
-+
- /*
-  * Example template for future upgrades.
-  * Copy and change version numbers as appropriate.
--- 
-2.14.3
-
diff --git a/SOURCES/0058-mmap_cache-make-checks-independent-of-input-size.patch b/SOURCES/0058-mmap_cache-make-checks-independent-of-input-size.patch
deleted file mode 100644
index cc91c58..0000000
--- a/SOURCES/0058-mmap_cache-make-checks-independent-of-input-size.patch
+++ /dev/null
@@ -1,175 +0,0 @@
-From 531c0ad3e13ddc1f5c31a620aa1f8b91aa8a4053 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 17 Nov 2017 10:51:44 +0100
-Subject: [PATCH 58/59] mmap_cache: make checks independent of input size
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Currently the consistency checks for the mmap_cache payload data on the
-client and the responder side include the length of the input string of
-the current request. Since there might be hash collisions which other
-much longer or much shorter names those checks might fail although there
-is no data corruption.
-
-This patch removes the checks using the length of the input and adds a
-check if the name found in the payload is zero-terminated inside of the
-payload data.
-
-Resolves https://pagure.io/SSSD/sssd/issue/3571
-
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
-(cherry picked from commit 4382047490dd4f80b407cc1e618da048f13e5f8f)
----
- src/responder/nss/nsssrv_mmap_cache.c | 34 ++++++++++++++++++++++++----------
- src/sss_client/nss_mc_group.c         | 14 ++++++++------
- src/sss_client/nss_mc_initgr.c        | 14 +++++++++-----
- src/sss_client/nss_mc_passwd.c        | 14 ++++++++------
- 4 files changed, 49 insertions(+), 27 deletions(-)
-
-diff --git a/src/responder/nss/nsssrv_mmap_cache.c b/src/responder/nss/nsssrv_mmap_cache.c
-index a87ad646f9b741db3eb18680678697032fc420ba..ad5adbce15e50c065d4d16e626be97fd23d06643 100644
---- a/src/responder/nss/nsssrv_mmap_cache.c
-+++ b/src/responder/nss/nsssrv_mmap_cache.c
-@@ -547,18 +547,32 @@ static struct sss_mc_rec *sss_mc_find_record(struct sss_mc_ctx *mcc,
-             return NULL;
-         }
- 
-+        if (key->len > strs_len) {
-+            /* The string cannot be in current record */
-+            slot = sss_mc_next_slot_with_hash(rec, hash);
-+            continue;
-+        }
-+
-         safealign_memcpy(&name_ptr, rec->data, sizeof(rel_ptr_t), NULL);
--        if (key->len > strs_len
--            || (name_ptr + key->len) > (strs_offset + strs_len)
--            || (uint8_t *)rec->data + strs_offset + strs_len > max_addr) {
--            DEBUG(SSSDBG_FATAL_FAILURE,
--                  "Corrupted fastcache. name_ptr value is %u.\n", name_ptr);
--            sss_mc_save_corrupted(mcc);
--            sss_mmap_cache_reset(mcc);
--            return NULL;
--        }
--
-         t_key = (char *)rec->data + name_ptr;
-+        /* name_ptr must point to some data in the strs/gids area of the data
-+         * payload. Since it is a pointer relative to rec->data it must larger
-+         * equal strs_offset and must be smaller then strs_offset + strs_len.
-+         * Additionally the area must not end outside of the data table and
-+         * t_key must be a zero-terminates string. */
-+        if (name_ptr < strs_offset
-+                || name_ptr >= strs_offset + strs_len
-+                || (uint8_t *)rec->data > max_addr
-+                || strs_offset > max_addr - (uint8_t *)rec->data
-+                || strs_len > max_addr - (uint8_t *)rec->data - strs_offset) {
-+            DEBUG(SSSDBG_FATAL_FAILURE,
-+                  "Corrupted fastcache entry at slot %u. "
-+                  "name_ptr value is %u.\n", slot, name_ptr);
-+            sss_mc_save_corrupted(mcc);
-+            sss_mmap_cache_reset(mcc);
-+            return NULL;
-+        }
-+
-         if (strcmp(key->str, t_key) == 0) {
-             break;
-         }
-diff --git a/src/sss_client/nss_mc_group.c b/src/sss_client/nss_mc_group.c
-index ce88d42fdaf4f19e78fc43e187bc28651cdc3c4e..4b1601a171a3af700b6f0d2bfedb3a6198e6df6d 100644
---- a/src/sss_client/nss_mc_group.c
-+++ b/src/sss_client/nss_mc_group.c
-@@ -148,20 +148,22 @@ errno_t sss_nss_mc_getgrnam(const char *name, size_t name_len,
-         }
- 
-         data = (struct sss_mc_grp_data *)rec->data;
-+        rec_name = (char *)data + data->name;
-         /* Integrity check
--         * - name_len cannot be longer than all strings
-          * - data->name cannot point outside strings
-          * - all strings must be within copy of record
--         * - size of record must be lower that data table size */
--        if (name_len > data->strs_len
--            || (data->name + name_len) > (strs_offset + data->strs_len)
-+         * - record must not end outside data table
-+         * - rec_name is a zero-terminated string */
-+        if (data->name < strs_offset
-+            || data->name >= strs_offset + data->strs_len
-             || data->strs_len > rec->len
--            || rec->len > data_size) {
-+            || (uint8_t *) rec + rec->len > gr_mc_ctx.data_table + data_size
-+            || memchr(rec_name, '\0',
-+                      (strs_offset + data->strs_len) - data->name) == NULL) {
-             ret = ENOENT;
-             goto done;
-         }
- 
--        rec_name = (char *)data + data->name;
-         if (strcmp(name, rec_name) == 0) {
-             break;
-         }
-diff --git a/src/sss_client/nss_mc_initgr.c b/src/sss_client/nss_mc_initgr.c
-index a77088d849ad3601cb3edb55fc5ea4ae4c52fe38..d8c01f52ea2d23515d0b462541657dc9416b0915 100644
---- a/src/sss_client/nss_mc_initgr.c
-+++ b/src/sss_client/nss_mc_initgr.c
-@@ -131,15 +131,19 @@ errno_t sss_nss_mc_initgroups_dyn(const char *name, size_t name_len,
-         data = (struct sss_mc_initgr_data *)rec->data;
-         rec_name = (char *)data + data->name;
-         /* Integrity check
--         * - name_len cannot be longer than all strings or data
-+         * - data->name cannot point outside all strings or data
-          * - all data must be within copy of record
-          * - size of record must be lower that data table size
--         * - data->strs cannot point outside strings */
--        if (name_len > data->strs_len
-+         * - data->strs cannot point outside strings
-+         * - rec_name is a zero-terminated string */
-+        if (data->name < data_offset
-+            || data->name >= data_offset + data->data_len
-             || data->strs_len > data->data_len
-             || data->data_len > rec->len
--            || rec->len > data_size
--            || (data->strs + name_len) > (data_offset + data->data_len)) {
-+            || (uint8_t *) rec + rec->len
-+                                       > initgr_mc_ctx.data_table + data_size
-+            || memchr(rec_name, '\0',
-+                      (data_offset + data->data_len) - data->name) == NULL) {
-             ret = ENOENT;
-             goto done;
-         }
-diff --git a/src/sss_client/nss_mc_passwd.c b/src/sss_client/nss_mc_passwd.c
-index 0da7ad0aeece7d38ca34bb3fde64adc898eaf0ae..868427f03a7ec0c8bd7401c8547a6f6bead7af28 100644
---- a/src/sss_client/nss_mc_passwd.c
-+++ b/src/sss_client/nss_mc_passwd.c
-@@ -141,20 +141,22 @@ errno_t sss_nss_mc_getpwnam(const char *name, size_t name_len,
-         }
- 
-         data = (struct sss_mc_pwd_data *)rec->data;
-+        rec_name = (char *)data + data->name;
-         /* Integrity check
--         * - name_len cannot be longer than all strings
-          * - data->name cannot point outside strings
-          * - all strings must be within copy of record
--         * - size of record must be lower that data table size */
--        if (name_len > data->strs_len
--            || (data->name + name_len) > (strs_offset + data->strs_len)
-+         * - record must not end outside data table
-+         * - rec_name is a zero-terminated string */
-+        if (data->name < strs_offset
-+            || data->name >= strs_offset + data->strs_len
-             || data->strs_len > rec->len
--            || rec->len > data_size) {
-+            || (uint8_t *) rec + rec->len > pw_mc_ctx.data_table + data_size
-+            || memchr(rec_name, '\0',
-+                      (strs_offset + data->strs_len) - data->name) == NULL ) {
-             ret = ENOENT;
-             goto done;
-         }
- 
--        rec_name = (char *)data + data->name;
-         if (strcmp(name, rec_name) == 0) {
-             break;
-         }
--- 
-2.14.3
-
diff --git a/SOURCES/0059-NSS-Fix-covscan-warning.patch b/SOURCES/0059-NSS-Fix-covscan-warning.patch
deleted file mode 100644
index 2dfd5be..0000000
--- a/SOURCES/0059-NSS-Fix-covscan-warning.patch
+++ /dev/null
@@ -1,54 +0,0 @@
-From 2fd201a6e8f263f30fb3aeb3d7f826a06321e58e Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
-Date: Tue, 21 Nov 2017 16:12:24 +0100
-Subject: [PATCH 59/59] NSS: Fix covscan warning
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
- Error: NULL_RETURNS (CWE-476): [#def1]
- sssd-1.16.1/src/responder/nss/nss_protocol.c:162: returned_null: "memchr" returns null (checked 7 out of 8 times).
- sssd-1.16.1/src/responder/nss/nsssrv_mmap_cache.c:557: example_checked: Example 1: "memchr(t_key, 0, strs_offset + strs_len - name_ptr)" has its value checked in "memchr(t_key, 0, strs_offset + strs_len - name_ptr) == NULL".
- sssd-1.16.1/src/sss_client/idmap/sss_nss_idmap.c:171: example_assign: Example 2: Assigning: "p" = return value from "memchr(p, 0, buf_len - (p - buf))".
- sssd-1.16.1/src/sss_client/idmap/sss_nss_idmap.c:172: example_checked: Example 2 (cont.): "p" has its value checked in "p == NULL".
- sssd-1.16.1/src/sss_client/nss_mc_group.c:157: example_checked: Example 3: "memchr(rec_name, 0, 16UL + data->strs_len - data->name)" has its value checked in "memchr(rec_name, 0, 16UL + data->strs_len - data->name) == NULL".
- sssd-1.16.1/src/sss_client/nss_mc_initgr.c:139: example_checked: Example 4: "memchr(rec_name, 0, 24UL + data->data_len - data->name)" has its value checked in "memchr(rec_name, 0, 24UL + data->data_len - data->name) == NULL".
- sssd-1.16.1/src/sss_client/nss_mc_passwd.c:150: example_checked: Example 5: "memchr(rec_name, 0, 16UL + data->strs_len - data->name)" has its value checked in "memchr(rec_name, 0, 16UL + data->strs_len - data->name) == NULL".
- sssd-1.16.1/src/responder/nss/nss_protocol.c:162: var_assigned: Assigning: "p" = null return value from "memchr".
- sssd-1.16.1/src/responder/nss/nss_protocol.c:176: dereference: Incrementing a pointer which might be null: "p".
- #  174|       }
- #  175|
- #  176|->     p++;
- #  177|       if ((p - body) + sizeof(uint32_t) != blen) {
- #  178|           DEBUG(SSSDBG_CRIT_FAILURE, "Body has unexpected size!\n");
-
-Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
-
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-(cherry picked from commit 1d88a0591ce8445ea3b6a88845a5997d61c915b4)
----
- src/responder/nss/nss_protocol.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
-diff --git a/src/responder/nss/nss_protocol.c b/src/responder/nss/nss_protocol.c
-index 2655386498754c46fbb363bdd1f976f9ded6a434..13f6d1541b79bf5494e1560841f027bf98bef72b 100644
---- a/src/responder/nss/nss_protocol.c
-+++ b/src/responder/nss/nss_protocol.c
-@@ -160,6 +160,13 @@ nss_protocol_parse_name_ex(struct cli_ctx *cli_ctx, const char **_rawname,
-     }
- 
-     p = memchr(body, '\0', blen);
-+    /* Although body for sure is null terminated, let's add this check here
-+     * so static analyzers are happier. */
-+    if (p == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "memchr() returned NULL, body is not null terminated!\n");
-+        return EINVAL;
-+    }
- 
-     /* If the body isn't valid UTF-8, fail */
-     if (!sss_utf8_check(body, (p - body))) {
--- 
-2.14.3
-
diff --git a/SOURCES/0060-responder-Fix-talloc-hierarchy-in-sized_output_name.patch b/SOURCES/0060-responder-Fix-talloc-hierarchy-in-sized_output_name.patch
deleted file mode 100644
index dc76425..0000000
--- a/SOURCES/0060-responder-Fix-talloc-hierarchy-in-sized_output_name.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From af95dd657586d3fc5680a7f8b493a5502640235e Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Tue, 28 Nov 2017 12:19:54 +0100
-Subject: [PATCH 60/67] responder: Fix talloc hierarchy in sized_output_name
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-sized_output_name was a called with NULL context in
-memcache_delete_entry but returned data from sized_output_name
-didn't have proper talloc hierarchy and we could not release all
-all returned data.
-
-==00:01:01:29.871 10088== 934,414 bytes in 8,731 blocks are definitely lost in loss record 121 of 121
-==00:01:01:29.871 10088==    at 0x4C29BE3: malloc (vg_replace_malloc.c:299)
-==00:01:01:29.871 10088==    by 0x8FF4EAB: talloc_strdup (in /usr/lib64/libtalloc.so.2.1.9)
-==00:01:01:29.871 10088==    by 0x52933B9: sss_output_name (usertools.c:808)
-==00:01:01:29.871 10088==    by 0x5293550: sss_output_fqname (usertools.c:863)
-==00:01:01:29.871 10088==    by 0x1211F9: sized_output_name (responder_common.c:1708)
-==00:01:01:29.871 10088==    by 0x1137E6: memcache_delete_entry (nss_get_object.c:112)
-==00:01:01:29.871 10088==    by 0x113BB6: nss_get_object_done (nss_get_object.c:245)
-==00:01:01:29.871 10088==    by 0x8DE5291: _tevent_req_error (in /usr/lib64/libtevent.so.0.9.31)
-==00:01:01:29.871 10088==    by 0x1276CE: cache_req_done (cache_req.c:1047)
-==00:01:01:29.871 10088==    by 0x8DE5291: _tevent_req_error (in /usr/lib64/libtevent.so.0.9.31)
-==00:01:01:29.871 10088==    by 0x126AF6: cache_req_search_domains_done (cache_req.c:607)
-==00:01:01:29.871 10088==    by 0x8DE4AB9: tevent_common_loop_immediate (in /usr/lib64/libtevent.so.0.9.31)
-==00:01:01:29.871 10088==    by 0x8DE9C9C: ??? (in /usr/lib64/libtevent.so.0.9.31)
-==00:01:01:29.871 10088==    by 0x8DE82A6: ??? (in /usr/lib64/libtevent.so.0.9.31)
-==00:01:01:29.871 10088==    by 0x8DE40CC: _tevent_loop_once (in /usr/lib64/libtevent.so.0.9.31)
-==00:01:01:29.871 10088==    by 0x8DE42FA: tevent_common_loop_wait (in /usr/lib64/libtevent.so.0.9.31)
-==00:01:01:29.871 10088==    by 0x8DE8246: ??? (in /usr/lib64/libtevent.so.0.9.31)
-==00:01:01:29.871 10088==    by 0x5291B32: server_loop (server.c:718)
-==00:01:01:29.871 10088==    by 0x11004C: main (nsssrv.c:560)
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3588
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 06e741a9bf23a18a998f366d9a8990b887a01638)
----
- src/responder/common/responder_common.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
-index 6b4d2d9e5936c79944b6f883e9fe46fd03ff32f6..e1100ce4b1eaae8bc561246699dc9bacc96133c8 100644
---- a/src/responder/common/responder_common.c
-+++ b/src/responder/common/responder_common.c
-@@ -1815,7 +1815,7 @@ int sized_output_name(TALLOC_CTX *mem_ctx,
-         goto done;
-     }
- 
--    ret = sss_output_fqname(mem_ctx, name_dom, orig_name,
-+    ret = sss_output_fqname(name, name_dom, orig_name,
-                             rctx->override_space, &name_str);
-     if (ret != EOK) {
-         goto done;
--- 
-2.14.3
-
diff --git a/SOURCES/0061-test_responder-Check-memory-leak-in-sized_output_nam.patch b/SOURCES/0061-test_responder-Check-memory-leak-in-sized_output_nam.patch
deleted file mode 100644
index 79da5fd..0000000
--- a/SOURCES/0061-test_responder-Check-memory-leak-in-sized_output_nam.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-From d624420972d061f72b08727bd7b2e227ce047272 Mon Sep 17 00:00:00 2001
-From: Lukas Slebodnik <lslebodn@redhat.com>
-Date: Tue, 28 Nov 2017 12:20:26 +0100
-Subject: [PATCH 61/67] test_responder: Check memory leak in sized_output_name
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3588
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 051e0fc7cc86fb4e4b3a9323a61684ad3a6fa589)
----
- src/tests/cmocka/test_responder_common.c | 20 ++++++++++++++++++++
- 1 file changed, 20 insertions(+)
-
-diff --git a/src/tests/cmocka/test_responder_common.c b/src/tests/cmocka/test_responder_common.c
-index fb7e4ee500570319999e6e85ee14a05cddea8de3..5441167caeb284982ee76926117da029966ec997 100644
---- a/src/tests/cmocka/test_responder_common.c
-+++ b/src/tests/cmocka/test_responder_common.c
-@@ -316,6 +316,23 @@ void test_schedule_get_domains_task(void **state)
-     talloc_free(dummy_ncache_ptr);
- }
- 
-+void test_sss_output_fqname(void **state)
-+{
-+    struct parse_inp_test_ctx *parse_inp_ctx = talloc_get_type(*state,
-+                                                   struct parse_inp_test_ctx);
-+    errno_t ret;
-+    struct sized_string *res = NULL;
-+
-+    ret = sized_output_name(parse_inp_ctx, parse_inp_ctx->rctx, "dummy",
-+                            parse_inp_ctx->tctx->dom, &res);
-+    assert_int_equal(ret, EOK);
-+    assert_non_null(res);
-+    assert_string_equal("dummy", res->str);
-+    assert_int_equal(6, res->len);
-+
-+    talloc_zfree(res);
-+}
-+
- int main(int argc, const char *argv[])
- {
-     int rv;
-@@ -346,6 +363,9 @@ int main(int argc, const char *argv[])
-         cmocka_unit_test_setup_teardown(test_schedule_get_domains_task,
-                                         parse_inp_test_setup,
-                                         parse_inp_test_teardown),
-+        cmocka_unit_test_setup_teardown(test_sss_output_fqname,
-+                                        parse_inp_test_setup,
-+                                        parse_inp_test_teardown),
-     };
- 
-     /* Set debug level to invalid value so we can deside if -d 0 was used. */
--- 
-2.14.3
-
diff --git a/SOURCES/0062-UTIL-add-find_domain_by_object_name_ex.patch b/SOURCES/0062-UTIL-add-find_domain_by_object_name_ex.patch
deleted file mode 100644
index 321cedc..0000000
--- a/SOURCES/0062-UTIL-add-find_domain_by_object_name_ex.patch
+++ /dev/null
@@ -1,82 +0,0 @@
-From ab9a8db7539bea30effe398d9bd82b1ecadd8a6f Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 20 Nov 2017 12:08:30 +0100
-Subject: [PATCH 62/67] UTIL: add find_domain_by_object_name_ex()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The _ex version of find_domain_by_object_name() has a additional option
-'strict'. If set to 'true' NULL is return instead to domain from the
-first argument. This way the caller can see if the provider object name
-really contains a known domain.
-
-Related to https://pagure.io/SSSD/sssd/issue/3579
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit b6d3da6cfe78c6d0ddb854088bc23e293b336401)
----
- src/util/domain_info_utils.c | 17 ++++++++++++++---
- src/util/util.h              |  4 ++++
- 2 files changed, 18 insertions(+), 3 deletions(-)
-
-diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
-index 3a3f5130a32e2c5fe4b81819bf2de697a4474111..66077092a40111967a98b0937506d9e4472f50d5 100644
---- a/src/util/domain_info_utils.c
-+++ b/src/util/domain_info_utils.c
-@@ -174,8 +174,8 @@ sss_get_domain_by_sid_ldap_fallback(struct sss_domain_info *domain,
- }
- 
- struct sss_domain_info *
--find_domain_by_object_name(struct sss_domain_info *domain,
--                           const char *object_name)
-+find_domain_by_object_name_ex(struct sss_domain_info *domain,
-+                              const char *object_name, bool strict)
- {
-     TALLOC_CTX *tmp_ctx;
-     struct sss_domain_info *dom = NULL;
-@@ -197,7 +197,11 @@ find_domain_by_object_name(struct sss_domain_info *domain,
-     }
- 
-     if (domainname == NULL) {
--        dom = domain;
-+        if (strict) {
-+            dom = NULL;
-+        } else {
-+            dom = domain;
-+        }
-     } else {
-         dom = find_domain_by_name(domain, domainname, true);
-     }
-@@ -207,6 +211,13 @@ done:
-     return dom;
- }
- 
-+struct sss_domain_info *
-+find_domain_by_object_name(struct sss_domain_info *domain,
-+                           const char *object_name)
-+{
-+    return find_domain_by_object_name_ex(domain, object_name, false);
-+}
-+
- errno_t sssd_domain_init(TALLOC_CTX *mem_ctx,
-                          struct confdb_ctx *cdb,
-                          const char *domain_name,
-diff --git a/src/util/util.h b/src/util/util.h
-index 37383011763a9a2a3c2c066215e3ed94aca77308..2521b1789b0b8701b1fbcce33890eedb7fe18d5e 100644
---- a/src/util/util.h
-+++ b/src/util/util.h
-@@ -551,6 +551,10 @@ struct sss_domain_info *
- find_domain_by_object_name(struct sss_domain_info *domain,
-                            const char *object_name);
- 
-+struct sss_domain_info *
-+find_domain_by_object_name_ex(struct sss_domain_info *domain,
-+                              const char *object_name, bool strict);
-+
- bool subdomain_enumerates(struct sss_domain_info *parent,
-                           const char *sd_name);
- 
--- 
-2.14.3
-
diff --git a/SOURCES/0063-ipa-handle-users-from-different-domains-in-ipa_resol.patch b/SOURCES/0063-ipa-handle-users-from-different-domains-in-ipa_resol.patch
deleted file mode 100644
index 68c09b2..0000000
--- a/SOURCES/0063-ipa-handle-users-from-different-domains-in-ipa_resol.patch
+++ /dev/null
@@ -1,76 +0,0 @@
-From d8d4e9fb842444eb3bd4e1a116fce00aba557707 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 20 Nov 2017 12:04:50 +0100
-Subject: [PATCH 63/67] ipa: handle users from different domains in
- ipa_resolve_user_list_send()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Instead of assuming that all users in the list can be found in the
-provided domain with this patch the domain name part of the user name is
-preferred. The provided domain name is used as a fallback.
-
-Related to https://pagure.io/SSSD/sssd/issue/3579
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 7988988aab5bd0249476671b850eb3909aa753f8)
----
- src/providers/ipa/ipa_id.c | 20 ++++++++++++++++----
- 1 file changed, 16 insertions(+), 4 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c
-index 8f8759f64b758aae7e45c88588e97a1bcf16ad79..2b4386584192d6b5ef0372099292ed73b77177bd 100644
---- a/src/providers/ipa/ipa_id.c
-+++ b/src/providers/ipa/ipa_id.c
-@@ -63,6 +63,8 @@ struct ipa_resolve_user_list_state {
-     struct ipa_id_ctx *ipa_ctx;
-     struct ldb_message_element *users;
-     const char *domain_name;
-+    struct sss_domain_info *domain;
-+    struct sss_domain_info *user_domain;
-     size_t user_idx;
- 
-     int dp_error;
-@@ -91,6 +93,8 @@ ipa_resolve_user_list_send(TALLOC_CTX *memctx, struct tevent_context *ev,
-     state->ev = ev;
-     state->ipa_ctx = ipa_ctx;
-     state->domain_name = domain_name;
-+    state->domain = find_domain_by_name(state->ipa_ctx->sdap_id_ctx->be->domain,
-+                                        state->domain_name, true);
-     state->users = users;
-     state->user_idx = 0;
-     state->dp_error = DP_ERR_FATAL;
-@@ -132,8 +136,17 @@ static errno_t ipa_resolve_user_list_get_user_step(struct tevent_req *req)
- 
-     DEBUG(SSSDBG_TRACE_ALL, "Trying to resolve user [%s].\n", ar->filter_value);
- 
--    if (strcasecmp(state->domain_name,
--                   state->ipa_ctx->sdap_id_ctx->be->domain->name) != 0) {
-+    state->user_domain = find_domain_by_object_name_ex(
-+                                        state->ipa_ctx->sdap_id_ctx->be->domain,
-+                                        ar->filter_value, true);
-+    /* Use provided domain as as fallback is no known domain was found in the
-+     * user name. */
-+    if (state->user_domain == NULL) {
-+        state->user_domain = state->domain;
-+    }
-+    ar->domain = state->user_domain->name;
-+
-+    if (state->user_domain != state->ipa_ctx->sdap_id_ctx->be->domain) {
-         subreq = ipa_subdomain_account_send(state, state->ev, state->ipa_ctx,
-                                             ar);
-     } else {
-@@ -158,8 +171,7 @@ static void ipa_resolve_user_list_get_user_done(struct tevent_req *subreq)
-                                             struct ipa_resolve_user_list_state);
-     int ret;
- 
--    if (strcasecmp(state->domain_name,
--                   state->ipa_ctx->sdap_id_ctx->be->domain->name) != 0) {
-+    if (state->user_domain != state->ipa_ctx->sdap_id_ctx->be->domain) {
-         ret = ipa_subdomain_account_recv(subreq, &state->dp_error);
-     } else {
-         ret = ipa_id_get_account_info_recv(subreq, &state->dp_error);
--- 
-2.14.3
-
diff --git a/SOURCES/0064-overrides-fixes-for-sysdb_invalidate_overrides.patch b/SOURCES/0064-overrides-fixes-for-sysdb_invalidate_overrides.patch
deleted file mode 100644
index c8d9de9..0000000
--- a/SOURCES/0064-overrides-fixes-for-sysdb_invalidate_overrides.patch
+++ /dev/null
@@ -1,203 +0,0 @@
-From c0263b48a3512d8b6984693c4b8e772844215f9e Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 20 Nov 2017 15:51:27 +0100
-Subject: [PATCH 64/67] overrides: fixes for sysdb_invalidate_overrides()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-There were two issues in sysdb_invalidate_overrides().
-
-First, SYSDB_CACHE_EXPIRE was only reset for the entry in the data cache
-but not in the timestamp cache.
-
-Second, if one of the steps in the combined replace and delete operation
-failed no change was committed to the cache. If, for whatever reasons,
-a user or group object didn't had SYSDB_OVERRIDE_DN set the delete
-failed and hence SYSDB_CACHE_EXPIRE wasn't reset as well. To make sure
-the cache is in a consistent state after a view change the replace and
-the delete operations are don in two steps.
-
-Related to https://pagure.io/SSSD/sssd/issue/3579
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 4671acb949c65c5c080532e03b1b6f1c9377a6a5)
----
- src/db/sysdb_views.c | 111 +++++++++++++++++++++++++++++++++++++--------------
- 1 file changed, 80 insertions(+), 31 deletions(-)
-
-diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c
-index afc7852ecf402ef144beca9c1b94fbe3cc4bbb6a..70082d8db9b25c11e8c0823d4e5da2ba0c0d10d1 100644
---- a/src/db/sysdb_views.c
-+++ b/src/db/sysdb_views.c
-@@ -279,6 +279,45 @@ done:
-     return ret;
- }
- 
-+static errno_t invalidate_entry_override(struct sysdb_ctx *sysdb,
-+                                         struct ldb_dn *dn,
-+                                         struct ldb_message *msg_del,
-+                                         struct ldb_message *msg_repl)
-+{
-+    int ret;
-+
-+    msg_del->dn = dn;
-+    msg_repl->dn = dn;
-+
-+    ret = ldb_modify(sysdb->ldb, msg_del);
-+    if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "ldb_modify failed: [%s](%d)[%s]\n",
-+              ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb));
-+        return sysdb_error_to_errno(ret);
-+    }
-+
-+    ret = ldb_modify(sysdb->ldb, msg_repl);
-+    if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "ldb_modify failed: [%s](%d)[%s]\n",
-+              ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb));
-+        return sysdb_error_to_errno(ret);
-+    }
-+
-+    if (sysdb->ldb_ts != NULL) {
-+        ret = ldb_modify(sysdb->ldb_ts, msg_repl);
-+        if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
-+            DEBUG(SSSDBG_OP_FAILURE,
-+                  "ldb_modify failed: [%s](%d)[%s]\n",
-+                  ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb_ts));
-+            return sysdb_error_to_errno(ret);
-+        }
-+    }
-+
-+    return EOK;
-+}
-+
- errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb)
- {
-     int ret;
-@@ -287,22 +326,23 @@ errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb)
-     bool in_transaction = false;
-     struct ldb_result *res;
-     size_t c;
--    struct ldb_message *msg;
-+    struct ldb_message *msg_del;
-+    struct ldb_message *msg_repl;
-     struct ldb_dn *base_dn;
- 
-+    if (sysdb->ldb_ts == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Timestamp cache context not available, cache might not be "
-+              "invalidated completely. Please call 'sss_cache -E' or remove "
-+              "the cache file if there are issues after a view name change.\n");
-+    }
-+
-     tmp_ctx = talloc_new(NULL);
-     if (tmp_ctx == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
-         return ENOMEM;
-     }
- 
--    msg = ldb_msg_new(tmp_ctx);
--    if (msg == NULL) {
--        DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n");
--        ret = ENOMEM;
--        goto done;
--    }
--
-     base_dn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_BASE);
-     if (base_dn == NULL) {
-         DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed\n");
-@@ -310,27 +350,40 @@ errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb)
-         goto done;
-     }
- 
--    ret = ldb_msg_add_empty(msg, SYSDB_CACHE_EXPIRE, LDB_FLAG_MOD_REPLACE,
-+    msg_del = ldb_msg_new(tmp_ctx);
-+    if (msg_del == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+    ret = ldb_msg_add_empty(msg_del, SYSDB_OVERRIDE_DN, LDB_FLAG_MOD_DELETE,
-                             NULL);
-     if (ret != LDB_SUCCESS) {
-         DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n");
-         ret = sysdb_error_to_errno(ret);
-         goto done;
-     }
--    ret = ldb_msg_add_string(msg, SYSDB_CACHE_EXPIRE, "1");
-+
-+    msg_repl = ldb_msg_new(tmp_ctx);
-+    if (msg_repl == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n");
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+    ret = ldb_msg_add_empty(msg_repl, SYSDB_CACHE_EXPIRE,
-+                            LDB_FLAG_MOD_REPLACE, NULL);
-+    if (ret != LDB_SUCCESS) {
-+        DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n");
-+        ret = sysdb_error_to_errno(ret);
-+        goto done;
-+    }
-+    ret = ldb_msg_add_string(msg_repl, SYSDB_CACHE_EXPIRE, "1");
-     if (ret != LDB_SUCCESS) {
-         DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_string failed.\n");
-         ret = sysdb_error_to_errno(ret);
-         goto done;
-     }
- 
--    ret = ldb_msg_add_empty(msg, SYSDB_OVERRIDE_DN, LDB_FLAG_MOD_DELETE, NULL);
--    if (ret != LDB_SUCCESS) {
--        DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n");
--        ret = sysdb_error_to_errno(ret);
--        goto done;
--    }
--
-     ret = sysdb_transaction_start(sysdb);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_start failed.\n");
-@@ -347,14 +400,12 @@ errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb)
-     }
- 
-     for (c = 0; c < res->count; c++) {
--        msg->dn = res->msgs[c]->dn;
--
--        ret = ldb_modify(sysdb->ldb, msg);
--        if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
-+        ret = invalidate_entry_override(sysdb, res->msgs[c]->dn, msg_del,
-+                                                                 msg_repl);
-+        if (ret != EOK) {
-             DEBUG(SSSDBG_OP_FAILURE,
--                  "ldb_modify failed: [%s](%d)[%s]\n",
--                  ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb));
--            ret = sysdb_error_to_errno(ret);
-+                  "invalidate_entry_override failed [%d][%s].\n",
-+                  ret, sss_strerror(ret));
-             goto done;
-         }
-     }
-@@ -370,14 +421,12 @@ errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb)
-     }
- 
-     for (c = 0; c < res->count; c++) {
--        msg->dn = res->msgs[c]->dn;
--
--        ret = ldb_modify(sysdb->ldb, msg);
--        if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
-+        ret = invalidate_entry_override(sysdb, res->msgs[c]->dn, msg_del,
-+                                                                 msg_repl);
-+        if (ret != EOK) {
-             DEBUG(SSSDBG_OP_FAILURE,
--                  "ldb_modify failed: [%s](%d)[%s]\n",
--                  ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb));
--            ret = sysdb_error_to_errno(ret);
-+                  "invalidate_entry_override failed [%d][%s].\n",
-+                  ret, sss_strerror(ret));
-             goto done;
-         }
-     }
--- 
-2.14.3
-
diff --git a/SOURCES/0065-ipa-check-for-SYSDB_OVERRIDE_DN-in-process_members-a.patch b/SOURCES/0065-ipa-check-for-SYSDB_OVERRIDE_DN-in-process_members-a.patch
deleted file mode 100644
index 74f5f5e..0000000
--- a/SOURCES/0065-ipa-check-for-SYSDB_OVERRIDE_DN-in-process_members-a.patch
+++ /dev/null
@@ -1,254 +0,0 @@
-From 53c6201539d24f8b929120565ca661977ecbb1a4 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 20 Nov 2017 16:12:58 +0100
-Subject: [PATCH 65/67] ipa: check for SYSDB_OVERRIDE_DN in process_members and
- get_group_dn_list
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-process_members() and get_group_dn_list() are used on an IPA client to
-determine a list of users or groups which are missing in the cache and
-are needed to properly add a group or user object to the cache
-respectively.
-
-If a non-default view is assigned to the client the SYSDB_OVERRIDE_DN
-must be set for all user and group objects to indicate that it was
-already checked if there is an id-override defined for the object or
-not. There a circumstances were SYSDB_OVERRIDE_DN is not set, e.g. after
-a view name change. To make sure the cache is in a consistent state with
-this patch  user and group entries without SYSDB_OVERRIDE_DN are
-considered as missing is a non-default view is assigned to the client.
-
-Related to https://pagure.io/SSSD/sssd/issue/3579
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 919b5d76057d31877e0c25ca495711ff76c713d6)
----
- src/providers/ipa/ipa_s2n_exop.c | 145 ++++++++++++++++++++++-----------------
- 1 file changed, 83 insertions(+), 62 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
-index 39ed17cbf0e8c523212084197e9f2963fed88dc8..c6132f509dcc8e7af84e03e8bfe20701107d1392 100644
---- a/src/providers/ipa/ipa_s2n_exop.c
-+++ b/src/providers/ipa/ipa_s2n_exop.c
-@@ -1523,6 +1523,7 @@ fail:
- }
- 
- static errno_t process_members(struct sss_domain_info *domain,
-+                               bool is_default_view,
-                                struct sysdb_attrs *group_attrs,
-                                char **members,
-                                TALLOC_CTX *mem_ctx, char ***_missing_members)
-@@ -1536,6 +1537,7 @@ static errno_t process_members(struct sss_domain_info *domain,
-     struct sss_domain_info *parent_domain;
-     char **missing_members = NULL;
-     size_t miss_count = 0;
-+    const char *attrs[] = {SYSDB_NAME, SYSDB_OVERRIDE_DN, NULL};
- 
-     if (members == NULL) {
-         DEBUG(SSSDBG_TRACE_INTERNAL, "No members\n");
-@@ -1572,53 +1574,59 @@ static errno_t process_members(struct sss_domain_info *domain,
-             goto done;
-         }
- 
--        ret = sysdb_search_user_by_name(tmp_ctx, obj_domain, members[c], NULL,
-+        ret = sysdb_search_user_by_name(tmp_ctx, obj_domain, members[c], attrs,
-                                         &msg);
--        if (ret == EOK) {
--            if (group_attrs != NULL) {
--                dn_str = ldb_dn_get_linearized(msg->dn);
--                if (dn_str == NULL) {
--                    DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_get_linearized failed.\n");
--                    ret = EINVAL;
--                    goto done;
--                }
--
--                DEBUG(SSSDBG_TRACE_ALL, "Adding member [%s][%s]\n",
--                                        members[c], dn_str);
-+        if (ret == EOK || ret == ENOENT) {
-+            if (ret == ENOENT
-+                    || (!is_default_view
-+                        && ldb_msg_find_attr_as_string(msg, SYSDB_OVERRIDE_DN,
-+                                                       NULL) == NULL)) {
-+                /* only add ghost if the member is really missing */
-+                if (group_attrs != NULL && ret == ENOENT) {
-+                    DEBUG(SSSDBG_TRACE_ALL, "Adding ghost member [%s]\n",
-+                                            members[c]);
- 
--                ret = sysdb_attrs_add_string_safe(group_attrs, SYSDB_MEMBER,
--                                                  dn_str);
--                if (ret != EOK) {
--                    DEBUG(SSSDBG_OP_FAILURE,
--                          "sysdb_attrs_add_string_safe failed.\n");
--                    goto done;
-+                    /* There were cases where the server returned the same user
-+                     * multiple times */
-+                    ret = sysdb_attrs_add_string_safe(group_attrs, SYSDB_GHOST,
-+                                                      members[c]);
-+                    if (ret != EOK) {
-+                        DEBUG(SSSDBG_OP_FAILURE,
-+                              "sysdb_attrs_add_string failed.\n");
-+                        goto done;
-+                    }
-                 }
--            }
--        } else if (ret == ENOENT) {
--            if (group_attrs != NULL) {
--                DEBUG(SSSDBG_TRACE_ALL, "Adding ghost member [%s]\n",
--                                        members[c]);
- 
--                /* There were cases where the server returned the same user
--                 * multiple times */
--                ret = sysdb_attrs_add_string_safe(group_attrs, SYSDB_GHOST,
--                                                  members[c]);
--                if (ret != EOK) {
--                    DEBUG(SSSDBG_OP_FAILURE,
--                          "sysdb_attrs_add_string failed.\n");
--                    goto done;
-+                if (missing_members != NULL) {
-+                    missing_members[miss_count] = talloc_strdup(missing_members,
-+                                                                members[c]);
-+                    if (missing_members[miss_count] == NULL) {
-+                        DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
-+                        ret = ENOMEM;
-+                        goto done;
-+                    }
-+                    miss_count++;
-                 }
--            }
-+            } else {
-+                if (group_attrs != NULL) {
-+                    dn_str = ldb_dn_get_linearized(msg->dn);
-+                    if (dn_str == NULL) {
-+                        DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_get_linearized failed.\n");
-+                        ret = EINVAL;
-+                        goto done;
-+                    }
-+
-+                    DEBUG(SSSDBG_TRACE_ALL, "Adding member [%s][%s]\n",
-+                                            members[c], dn_str);
- 
--            if (missing_members != NULL) {
--                missing_members[miss_count] = talloc_strdup(missing_members,
--                                                            members[c]);
--                if (missing_members[miss_count] == NULL) {
--                    DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
--                    ret = ENOMEM;
--                    goto done;
-+                    ret = sysdb_attrs_add_string_safe(group_attrs, SYSDB_MEMBER,
-+                                                      dn_str);
-+                    if (ret != EOK) {
-+                        DEBUG(SSSDBG_OP_FAILURE,
-+                              "sysdb_attrs_add_string_safe failed.\n");
-+                        goto done;
-+                    }
-                 }
--                miss_count++;
-             }
-         } else {
-             DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_user_by_name failed.\n");
-@@ -1649,6 +1657,7 @@ done:
- }
- 
- static errno_t get_group_dn_list(TALLOC_CTX *mem_ctx,
-+                                 bool is_default_view,
-                                  struct sss_domain_info *dom,
-                                  size_t ngroups, char **groups,
-                                  struct ldb_dn ***_dn_list,
-@@ -1664,6 +1673,7 @@ static errno_t get_group_dn_list(TALLOC_CTX *mem_ctx,
-     size_t n_missing = 0;
-     struct sss_domain_info *obj_domain;
-     struct sss_domain_info *parent_domain;
-+    const char *attrs[] = {SYSDB_NAME, SYSDB_OVERRIDE_DN, NULL};
- 
-     tmp_ctx = talloc_new(NULL);
-     if (tmp_ctx == NULL) {
-@@ -1689,25 +1699,31 @@ static errno_t get_group_dn_list(TALLOC_CTX *mem_ctx,
-             goto done;
-         }
- 
--        ret = sysdb_search_group_by_name(tmp_ctx, obj_domain, groups[c], NULL,
-+        ret = sysdb_search_group_by_name(tmp_ctx, obj_domain, groups[c], attrs,
-                                          &msg);
--        if (ret == EOK) {
--            dn_list[n_dns] = ldb_dn_copy(dn_list, msg->dn);
--            if (dn_list[n_dns] == NULL) {
--                DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_copy failed.\n");
--                ret = ENOMEM;
--                goto done;
-+        if (ret == EOK || ret == ENOENT) {
-+            if (ret == ENOENT
-+                    || (!is_default_view
-+                        && ldb_msg_find_attr_as_string(msg, SYSDB_OVERRIDE_DN,
-+                                                       NULL) == NULL)) {
-+                missing_groups[n_missing] = talloc_strdup(missing_groups,
-+                                                          groups[c]);
-+                if (missing_groups[n_missing] == NULL) {
-+                    DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
-+                    ret = ENOMEM;
-+                    goto done;
-+                }
-+                n_missing++;
-+
-+            } else {
-+                dn_list[n_dns] = ldb_dn_copy(dn_list, msg->dn);
-+                if (dn_list[n_dns] == NULL) {
-+                    DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_copy failed.\n");
-+                    ret = ENOMEM;
-+                    goto done;
-+                }
-+                n_dns++;
-             }
--            n_dns++;
--        } else if (ret == ENOENT) {
--            missing_groups[n_missing] = talloc_strdup(missing_groups,
--                                                      groups[c]);
--            if (missing_groups[n_missing] == NULL) {
--                DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
--                ret = ENOMEM;
--                goto done;
--            }
--            n_missing++;
-         } else {
-             DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_group_by_name failed.\n");
-             goto done;
-@@ -1803,7 +1819,9 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
-             }
- 
- 
--            ret = get_group_dn_list(state, state->dom,
-+            ret = get_group_dn_list(state,
-+                                    is_default_view(state->ipa_ctx->view_name),
-+                                    state->dom,
-                                     attrs->ngroups, attrs->groups,
-                                     &group_dn_list, &missing_list);
-             if (ret != EOK) {
-@@ -1832,8 +1850,10 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
-             }
-             break;
-         } else if (attrs->response_type == RESP_GROUP_MEMBERS) {
--            ret = process_members(state->dom, NULL, attrs->a.group.gr_mem,
--                                  state, &missing_list);
-+            ret = process_members(state->dom,
-+                                  is_default_view(state->ipa_ctx->view_name),
-+                                  NULL, attrs->a.group.gr_mem, state,
-+                                  &missing_list);
-             if (ret != EOK) {
-                 DEBUG(SSSDBG_OP_FAILURE, "process_members failed.\n");
-                 goto done;
-@@ -2572,8 +2592,9 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
-                 }
-             }
- 
--            ret = process_members(dom, attrs->sysdb_attrs,
--                                  attrs->a.group.gr_mem, NULL, NULL);
-+            ret = process_members(dom, is_default_view(view_name),
-+                                  attrs->sysdb_attrs, attrs->a.group.gr_mem,
-+                                  NULL, NULL);
-             if (ret != EOK) {
-                 DEBUG(SSSDBG_OP_FAILURE, "process_members failed.\n");
-                 goto done;
--- 
-2.14.3
-
diff --git a/SOURCES/0066-IPA-use-cache-searches-in-get_groups_dns.patch b/SOURCES/0066-IPA-use-cache-searches-in-get_groups_dns.patch
deleted file mode 100644
index 5268e1a..0000000
--- a/SOURCES/0066-IPA-use-cache-searches-in-get_groups_dns.patch
+++ /dev/null
@@ -1,70 +0,0 @@
-From 3500a7766f5443c9ec50f9c8de27e2dea8c0c234 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 20 Nov 2017 16:41:29 +0100
-Subject: [PATCH 66/67] IPA: use cache searches in get_groups_dns()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-If the group name is overridden in the default view we have to search
-for the name and cannot construct it because the extdom plugin will
-return the overridden name but the DN of the related group object in the
-cache will contain the original name.
-
-Related to https://pagure.io/SSSD/sssd/issue/3579
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit f29040342a6d69e170f4543662621f2e27221f91)
----
- src/providers/ipa/ipa_s2n_exop.c | 27 +++++++++++++++++++--------
- 1 file changed, 19 insertions(+), 8 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
-index c6132f509dcc8e7af84e03e8bfe20701107d1392..49c393e9a1eb19ab683949cf633a6838274bc0fe 100644
---- a/src/providers/ipa/ipa_s2n_exop.c
-+++ b/src/providers/ipa/ipa_s2n_exop.c
-@@ -2038,6 +2038,7 @@ static errno_t get_groups_dns(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
-     int c;
-     struct sss_domain_info *root_domain;
-     char **dn_list;
-+    struct ldb_message *msg;
- 
-     if (name_list == NULL) {
-         *_dn_list = NULL;
-@@ -2082,15 +2083,25 @@ static errno_t get_groups_dns(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
-             goto done;
-         }
- 
--        /* This might fail if some unexpected cases are used. But current
--         * sysdb code which handles group membership constructs DNs this way
--         * as well, IPA names are lowercased and AD names by default will be
--         * lowercased as well. If there are really use-cases which cause an
--         * issue here, sysdb_group_strdn() has to be replaced by a proper
--         * search. */
--        dn_list[c] = sysdb_group_strdn(dn_list, dom->name, name_list[c]);
-+        /* If the group name is overridden in the default view we have to
-+         * search for the name and cannot construct it because the extdom
-+         * plugin will return the overridden name but the DN of the related
-+         * group object in the cache will contain the original name. */
-+
-+        ret = sysdb_search_group_by_name(tmp_ctx, dom, name_list[c], NULL,
-+                                         &msg);
-+        if (ret == EOK) {
-+            dn_list[c] = ldb_dn_alloc_linearized(dn_list, msg->dn);
-+        } else {
-+            /* best effort, try to construct the DN */
-+            DEBUG(SSSDBG_TRACE_FUNC,
-+                  "sysdb_search_group_by_name failed with [%d], "
-+                  "generating DN for [%s] in domain [%s].\n",
-+                  ret, name_list[c], dom->name);
-+            dn_list[c] = sysdb_group_strdn(dn_list, dom->name, name_list[c]);
-+        }
-         if (dn_list[c] == NULL) {
--            DEBUG(SSSDBG_OP_FAILURE, "sysdb_group_strdn failed.\n");
-+            DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_alloc_linearized failed.\n");
-             ret = ENOMEM;
-             goto done;
-         }
--- 
-2.14.3
-
diff --git a/SOURCES/0067-ipa-compare-DNs-instead-of-group-names-in-ipa_s2n_sa.patch b/SOURCES/0067-ipa-compare-DNs-instead-of-group-names-in-ipa_s2n_sa.patch
deleted file mode 100644
index cc19a9e..0000000
--- a/SOURCES/0067-ipa-compare-DNs-instead-of-group-names-in-ipa_s2n_sa.patch
+++ /dev/null
@@ -1,86 +0,0 @@
-From 118860519777791368520f4e92ecbf2ef60cb7db Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 20 Nov 2017 16:45:45 +0100
-Subject: [PATCH 67/67] ipa: compare DNs instead of group names in
- ipa_s2n_save_objects()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-If group names are used to compare the current list of group memberships
-returned by the server with the one from the cache some groups might end
-up in the wrong result list if group names are overridden. This
-ambiguity can be resolved by using the DNs of the cached objects.
-
-Related to https://pagure.io/SSSD/sssd/issue/3579
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit a52226c651308a0a7732544b492eb4db56b84f1d)
----
- src/providers/ipa/ipa_s2n_exop.c | 31 ++++++++++++-------------------
- 1 file changed, 12 insertions(+), 19 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
-index 49c393e9a1eb19ab683949cf633a6838274bc0fe..8b97f78620f19b0708e8a480cb72fd7f12d96dfb 100644
---- a/src/providers/ipa/ipa_s2n_exop.c
-+++ b/src/providers/ipa/ipa_s2n_exop.c
-@@ -2185,10 +2185,9 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
-     struct ldb_result *res;
-     enum sysdb_member_type type;
-     char **sysdb_grouplist;
--    char **add_groups;
-     char **add_groups_dns;
--    char **del_groups;
-     char **del_groups_dns;
-+    char **groups_dns;
-     bool in_transaction = false;
-     int tret;
-     struct sysdb_attrs *gid_override_attrs = NULL;
-@@ -2514,33 +2513,27 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom,
-             }
- 
-             if (attrs->response_type == RESP_USER_GROUPLIST) {
--                ret = get_sysdb_grouplist(tmp_ctx, dom->sysdb, dom, name,
--                                          &sysdb_grouplist);
-+                ret = get_sysdb_grouplist_dn(tmp_ctx, dom->sysdb, dom, name,
-+                                             &sysdb_grouplist);
-                 if (ret != EOK) {
-                     DEBUG(SSSDBG_OP_FAILURE, "get_sysdb_grouplist failed.\n");
-                     goto done;
-                 }
- 
--                ret = diff_string_lists(tmp_ctx, attrs->groups,
--                                        sysdb_grouplist, &add_groups,
--                                        &del_groups, NULL);
-+                ret = get_groups_dns(tmp_ctx, dom, attrs->groups, &groups_dns);
-+                if (ret != EOK) {
-+                    DEBUG(SSSDBG_OP_FAILURE, "get_groups_dns failed.\n");
-+                    goto done;
-+                }
-+
-+                ret = diff_string_lists(tmp_ctx, groups_dns,
-+                                        sysdb_grouplist, &add_groups_dns,
-+                                        &del_groups_dns, NULL);
-                 if (ret != EOK) {
-                     DEBUG(SSSDBG_OP_FAILURE, "diff_string_lists failed.\n");
-                     goto done;
-                 }
- 
--                ret = get_groups_dns(tmp_ctx, dom, add_groups, &add_groups_dns);
--                if (ret != EOK) {
--                    DEBUG(SSSDBG_OP_FAILURE, "get_groups_dns failed.\n");
--                    goto done;
--                }
--
--                ret = get_groups_dns(tmp_ctx, dom, del_groups, &del_groups_dns);
--                if (ret != EOK) {
--                    DEBUG(SSSDBG_OP_FAILURE, "get_groups_dns failed.\n");
--                    goto done;
--                }
--
-                 DEBUG(SSSDBG_TRACE_INTERNAL, "Updating memberships for %s\n",
-                                              name);
-                 ret = sysdb_update_members_dn(dom, name, SYSDB_MEMBER_USER,
--- 
-2.14.3
-
diff --git a/SOURCES/0068-SDAP-Split-out-utility-function-sdap_get_object_doma.patch b/SOURCES/0068-SDAP-Split-out-utility-function-sdap_get_object_doma.patch
deleted file mode 100644
index 24ee010..0000000
--- a/SOURCES/0068-SDAP-Split-out-utility-function-sdap_get_object_doma.patch
+++ /dev/null
@@ -1,92 +0,0 @@
-From 0e5d9f481daeeaecefeb68cdc03e45a11dfd7091 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 7 Nov 2017 17:03:13 +0100
-Subject: [PATCH 68/83] SDAP: Split out utility function
- sdap_get_object_domain() from sdap_object_in_domain()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The DP request that returns a domain of an entry to responder will need
-this functionality in order to map the original DN of the entry found
-to a domain name.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 37fdd9dc1ad5968067f8e3c43a51ed2ac9f3b104)
----
- src/providers/ldap/sdap.c | 26 ++++++++++++++++++++------
- src/providers/ldap/sdap.h |  4 ++++
- 2 files changed, 24 insertions(+), 6 deletions(-)
-
-diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
-index b6b1c91cb7507ebb95cd559634a77ed44dfb5fc0..59d24fed53cc35751b5c24679e247a42f82e1d0a 100644
---- a/src/providers/ldap/sdap.c
-+++ b/src/providers/ldap/sdap.c
-@@ -1673,9 +1673,9 @@ char *sdap_make_oc_list(TALLOC_CTX *mem_ctx, struct sdap_attr_map *map)
-     }
- }
- 
--bool sdap_object_in_domain(struct sdap_options *opts,
--                           struct sysdb_attrs *obj,
--                           struct sss_domain_info *dom)
-+struct sss_domain_info *sdap_get_object_domain(struct sdap_options *opts,
-+                                               struct sysdb_attrs *obj,
-+                                               struct sss_domain_info *dom)
- {
-     errno_t ret;
-     const char *original_dn = NULL;
-@@ -1685,7 +1685,7 @@ bool sdap_object_in_domain(struct sdap_options *opts,
-     if (ret) {
-         DEBUG(SSSDBG_FUNC_DATA,
-               "The group has no original DN, assuming our domain\n");
--        return true;
-+        return dom;
-     }
- 
-     sdmatch = sdap_domain_get_by_dn(opts, original_dn);
-@@ -1693,10 +1693,24 @@ bool sdap_object_in_domain(struct sdap_options *opts,
-         DEBUG(SSSDBG_FUNC_DATA,
-               "The original DN of the group cannot "
-               "be related to any search base\n");
--        return true;
-+        return dom;
-     }
- 
--    return (sdmatch->dom == dom);
-+    return sdmatch->dom;
-+}
-+
-+bool sdap_object_in_domain(struct sdap_options *opts,
-+                           struct sysdb_attrs *obj,
-+                           struct sss_domain_info *dom)
-+{
-+    struct sss_domain_info *obj_dom;
-+
-+    obj_dom = sdap_get_object_domain(opts, obj, dom);
-+    if (obj_dom == NULL) {
-+        return false;
-+    }
-+
-+    return (obj_dom == dom);
- }
- 
- size_t sdap_steal_objects_in_dom(struct sdap_options *opts,
-diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
-index 2ba016ff52313198287ac5196e24517333882099..8b0f1f0ce0fef59554270f0f31cfd2d5f0aa57f5 100644
---- a/src/providers/ldap/sdap.h
-+++ b/src/providers/ldap/sdap.h
-@@ -644,6 +644,10 @@ size_t sdap_steal_objects_in_dom(struct sdap_options *opts,
-                                  size_t count,
-                                  bool filter);
- 
-+struct sss_domain_info *sdap_get_object_domain(struct sdap_options *opts,
-+                                               struct sysdb_attrs *obj,
-+                                               struct sss_domain_info *dom);
-+
- bool sdap_object_in_domain(struct sdap_options *opts,
-                            struct sysdb_attrs *obj,
-                            struct sss_domain_info *dom);
--- 
-2.14.3
-
diff --git a/SOURCES/0069-LDAP-Extract-the-check-whether-to-run-a-POSIX-check-.patch b/SOURCES/0069-LDAP-Extract-the-check-whether-to-run-a-POSIX-check-.patch
deleted file mode 100644
index 1b64e0d..0000000
--- a/SOURCES/0069-LDAP-Extract-the-check-whether-to-run-a-POSIX-check-.patch
+++ /dev/null
@@ -1,115 +0,0 @@
-From 880552cc45e55c7ef9f81423aff8fe867451d752 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Thu, 30 Nov 2017 11:47:30 +0100
-Subject: [PATCH 69/83] LDAP: Extract the check whether to run a POSIX check to
- a function
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This will reduce the code duplication in the following patches and will
-allow to keep all the logic on one place so that when/if we change the
-code in the future, we only have to change the single place.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 8e93ebb2a6f7644c389c1d1f4e92a21c4d0b2b45)
----
- src/providers/ldap/ldap_common.c     | 15 +++++++++++++++
- src/providers/ldap/ldap_common.h     |  4 ++++
- src/providers/ldap/ldap_id.c         | 15 ++++++---------
- src/providers/ldap/sdap_async_enum.c |  7 +++----
- 4 files changed, 28 insertions(+), 13 deletions(-)
-
-diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
-index 0597e91f7fade47aeb34565597c730ac406e0cfc..3eff3515d95043d4b59cb0d9953cf050355a0ca5 100644
---- a/src/providers/ldap/ldap_common.c
-+++ b/src/providers/ldap/ldap_common.c
-@@ -971,3 +971,18 @@ sdap_id_ctx_new(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
- 
-     return sdap_ctx;
- }
-+
-+bool should_run_posix_check(struct sdap_id_ctx *ctx,
-+                            bool use_id_mapping,
-+                            bool posix_request)
-+{
-+    if (use_id_mapping == false &&
-+            posix_request == true &&
-+            ctx->opts->schema_type == SDAP_SCHEMA_AD &&
-+            ctx->srv_opts &&
-+            ctx->srv_opts->posix_checked == false) {
-+        return true;
-+    }
-+
-+    return false;
-+}
-diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
-index 0510b7d5ab5121bd96f699e8e59520a2a18a604f..fa7cda4df9d7334f6f0f5baccae0cba0478bfbea 100644
---- a/src/providers/ldap/ldap_common.h
-+++ b/src/providers/ldap/ldap_common.h
-@@ -304,6 +304,10 @@ char *get_enterprise_principal_string_filter(TALLOC_CTX *mem_ctx,
-                                              const char *princ,
-                                              struct dp_option *sdap_basic_opts);
- 
-+bool should_run_posix_check(struct sdap_id_ctx *ctx,
-+                            bool id_mapping,
-+                            bool posix_request);
-+
- char *sdap_get_access_filter(TALLOC_CTX *mem_ctx,
-                              const char *base_filter);
- 
-diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
-index e89fc6133316f684810afe4c1a0731b8a04f2931..6ab9e0aa1db3eed32deb75211ded30a4cb48ca30 100644
---- a/src/providers/ldap/ldap_id.c
-+++ b/src/providers/ldap/ldap_id.c
-@@ -411,11 +411,9 @@ static void users_get_connect_done(struct tevent_req *subreq)
-     /* If POSIX attributes have been requested with an AD server and we
-      * have no idea about POSIX attributes support, run a one-time check
-      */
--    if (state->use_id_mapping == false &&
--            state->non_posix == false &&
--            state->ctx->opts->schema_type == SDAP_SCHEMA_AD &&
--            state->ctx->srv_opts &&
--            state->ctx->srv_opts->posix_checked == false) {
-+    if (should_run_posix_check(state->ctx,
-+                               state->use_id_mapping,
-+                               !state->non_posix)) {
-         subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
-                                        sdap_id_op_handle(state->op),
-                                        state->sdom->user_search_bases,
-@@ -958,10 +956,9 @@ static void groups_get_connect_done(struct tevent_req *subreq)
-     /* If POSIX attributes have been requested with an AD server and we
-      * have no idea about POSIX attributes support, run a one-time check
-      */
--    if (state->use_id_mapping == false &&
--            state->ctx->opts->schema_type == SDAP_SCHEMA_AD &&
--            state->ctx->srv_opts &&
--            state->ctx->srv_opts->posix_checked == false) {
-+    if (should_run_posix_check(state->ctx,
-+                               state->use_id_mapping,
-+                               !state->non_posix)) {
-         subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
-                                        sdap_id_op_handle(state->op),
-                                        state->sdom->user_search_bases,
-diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
-index 91e481c4e694126900c729e86d187fba355de0b8..2cef4eb886f982ba388a34955bdd38468fe68200 100644
---- a/src/providers/ldap/sdap_async_enum.c
-+++ b/src/providers/ldap/sdap_async_enum.c
-@@ -196,10 +196,9 @@ static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq)
-     /* If POSIX attributes have been requested with an AD server and we
-      * have no idea about POSIX attributes support, run a one-time check
-      */
--    if (use_id_mapping == false &&
--            state->ctx->opts->schema_type == SDAP_SCHEMA_AD &&
--            state->ctx->srv_opts &&
--            state->ctx->srv_opts->posix_checked == false) {
-+    if (should_run_posix_check(state->ctx,
-+                               use_id_mapping,
-+                               true)) {
-         subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
-                                        sdap_id_op_handle(state->user_op),
-                                        state->sdom->user_search_bases,
--- 
-2.14.3
-
diff --git a/SOURCES/0070-LDAP-Only-run-the-POSIX-check-with-a-GC-connection.patch b/SOURCES/0070-LDAP-Only-run-the-POSIX-check-with-a-GC-connection.patch
deleted file mode 100644
index f4be7e3..0000000
--- a/SOURCES/0070-LDAP-Only-run-the-POSIX-check-with-a-GC-connection.patch
+++ /dev/null
@@ -1,95 +0,0 @@
-From 405f08eabf5017cc00891fb2090be80306c8aeae Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Thu, 30 Nov 2017 12:01:51 +0100
-Subject: [PATCH 70/83] LDAP: Only run the POSIX check with a GC connection
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Previously, we used to run the POSIX check also with an LDAP connection.
-This was wasteful, but worked, so the waste wasn't the biggest problem
--- the approach would only cause problems with the following patch which
-uses a NULL search base to search the Global Catalog, because searching
-with a SUBTREE scope and a NULL base returns a referral with an LDAP
-connection.
-
-Instead, this patch uses a heuristics (whether the connection ignores
-the offline state) to check if the connection is a POSIX one and if it
-is NOT, then skips the POSIX check.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit dacfe74113dde62ddaaa7f9abf9d2b6448d89db6)
----
- src/providers/ldap/ldap_common.c     | 2 ++
- src/providers/ldap/ldap_common.h     | 1 +
- src/providers/ldap/ldap_id.c         | 2 ++
- src/providers/ldap/sdap_async_enum.c | 1 +
- 4 files changed, 6 insertions(+)
-
-diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
-index 3eff3515d95043d4b59cb0d9953cf050355a0ca5..36e79b9d6ca23ef5e21a8b0bedc7f05db8f4fc98 100644
---- a/src/providers/ldap/ldap_common.c
-+++ b/src/providers/ldap/ldap_common.c
-@@ -973,12 +973,14 @@ sdap_id_ctx_new(TALLOC_CTX *mem_ctx, struct be_ctx *bectx,
- }
- 
- bool should_run_posix_check(struct sdap_id_ctx *ctx,
-+                            struct sdap_id_conn_ctx *conn,
-                             bool use_id_mapping,
-                             bool posix_request)
- {
-     if (use_id_mapping == false &&
-             posix_request == true &&
-             ctx->opts->schema_type == SDAP_SCHEMA_AD &&
-+            conn->ignore_mark_offline == true &&
-             ctx->srv_opts &&
-             ctx->srv_opts->posix_checked == false) {
-         return true;
-diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
-index fa7cda4df9d7334f6f0f5baccae0cba0478bfbea..44dbc3fb0678412f46366321e0be836313380949 100644
---- a/src/providers/ldap/ldap_common.h
-+++ b/src/providers/ldap/ldap_common.h
-@@ -305,6 +305,7 @@ char *get_enterprise_principal_string_filter(TALLOC_CTX *mem_ctx,
-                                              struct dp_option *sdap_basic_opts);
- 
- bool should_run_posix_check(struct sdap_id_ctx *ctx,
-+                            struct sdap_id_conn_ctx *conn,
-                             bool id_mapping,
-                             bool posix_request);
- 
-diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
-index 6ab9e0aa1db3eed32deb75211ded30a4cb48ca30..47969a9749253721334a20f46230f7aecea64882 100644
---- a/src/providers/ldap/ldap_id.c
-+++ b/src/providers/ldap/ldap_id.c
-@@ -412,6 +412,7 @@ static void users_get_connect_done(struct tevent_req *subreq)
-      * have no idea about POSIX attributes support, run a one-time check
-      */
-     if (should_run_posix_check(state->ctx,
-+                               state->conn,
-                                state->use_id_mapping,
-                                !state->non_posix)) {
-         subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
-@@ -957,6 +958,7 @@ static void groups_get_connect_done(struct tevent_req *subreq)
-      * have no idea about POSIX attributes support, run a one-time check
-      */
-     if (should_run_posix_check(state->ctx,
-+                               state->conn,
-                                state->use_id_mapping,
-                                !state->non_posix)) {
-         subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
-diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
-index 2cef4eb886f982ba388a34955bdd38468fe68200..baa039d63c71cc5054e6af6538d34d04cde6b858 100644
---- a/src/providers/ldap/sdap_async_enum.c
-+++ b/src/providers/ldap/sdap_async_enum.c
-@@ -197,6 +197,7 @@ static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq)
-      * have no idea about POSIX attributes support, run a one-time check
-      */
-     if (should_run_posix_check(state->ctx,
-+                               state->user_conn,
-                                use_id_mapping,
-                                true)) {
-         subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
--- 
-2.14.3
-
diff --git a/SOURCES/0071-SDAP-Search-with-a-NULL-search-base-when-looking-up-.patch b/SOURCES/0071-SDAP-Search-with-a-NULL-search-base-when-looking-up-.patch
deleted file mode 100644
index 5be8736..0000000
--- a/SOURCES/0071-SDAP-Search-with-a-NULL-search-base-when-looking-up-.patch
+++ /dev/null
@@ -1,191 +0,0 @@
-From c7003e815aca1c28953c3dc55311ffc3f2d4ab28 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Sun, 12 Nov 2017 19:24:01 +0100
-Subject: [PATCH 71/83] SDAP: Search with a NULL search base when looking up an
- ID in the Global Catalog
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The posix_check request is used to determine whether domains in the forest
-replicate the POSIX attributes into the Global Catalog. And since the
-schema modification that replicates the attributes is not per-domain, but
-per-forest, we don't need to iterate over search bases when checking for
-the POSIX attribute presence. It is OK to just search with a NULL search
-base (and it's what Windows clients do, too).
-
-Additionally, searching over the whole GC will come handy when implementing
-the request that located an account's domain.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 6ae22d9adc0b075361defc99b8f14480ba8e7b46)
----
- src/providers/ldap/ldap_id.c         |  2 --
- src/providers/ldap/sdap_async.c      | 51 +++++++-----------------------------
- src/providers/ldap/sdap_async.h      |  1 -
- src/providers/ldap/sdap_async_enum.c |  1 -
- 4 files changed, 10 insertions(+), 45 deletions(-)
-
-diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
-index 47969a9749253721334a20f46230f7aecea64882..b5ac3a749113a281fe8a5564ac341ced0570eded 100644
---- a/src/providers/ldap/ldap_id.c
-+++ b/src/providers/ldap/ldap_id.c
-@@ -417,7 +417,6 @@ static void users_get_connect_done(struct tevent_req *subreq)
-                                !state->non_posix)) {
-         subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
-                                        sdap_id_op_handle(state->op),
--                                       state->sdom->user_search_bases,
-                                        dp_opt_get_int(state->ctx->opts->basic,
-                                                       SDAP_SEARCH_TIMEOUT));
-         if (subreq == NULL) {
-@@ -963,7 +962,6 @@ static void groups_get_connect_done(struct tevent_req *subreq)
-                                !state->non_posix)) {
-         subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
-                                        sdap_id_op_handle(state->op),
--                                       state->sdom->user_search_bases,
-                                        dp_opt_get_int(state->ctx->opts->basic,
-                                                       SDAP_SEARCH_TIMEOUT));
-         if (subreq == NULL) {
-diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
-index 246e12a1f386da1841963d5c1d1c4d2870cc1b6b..1df0b85f4bda6442d8da66784ad7424306b1f051 100644
---- a/src/providers/ldap/sdap_async.c
-+++ b/src/providers/ldap/sdap_async.c
-@@ -2573,7 +2573,6 @@ int sdap_asq_search_recv(struct tevent_req *req,
- }
- 
- /* ==Posix attribute presence test================================= */
--static errno_t sdap_posix_check_next(struct tevent_req *req);
- static void sdap_posix_check_done(struct tevent_req *subreq);
- static errno_t sdap_posix_check_parse(struct sdap_handle *sh,
-                                       struct sdap_msg *msg,
-@@ -2583,12 +2582,10 @@ struct sdap_posix_check_state {
-     struct tevent_context *ev;
-     struct sdap_options *opts;
-     struct sdap_handle *sh;
--    struct sdap_search_base **search_bases;
-     int timeout;
- 
-     const char **attrs;
-     const char *filter;
--    size_t base_iter;
- 
-     bool has_posix;
- };
-@@ -2596,10 +2593,10 @@ struct sdap_posix_check_state {
- struct tevent_req *
- sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
-                       struct sdap_options *opts, struct sdap_handle *sh,
--                      struct sdap_search_base **search_bases,
-                       int timeout)
- {
-     struct tevent_req *req = NULL;
-+    struct tevent_req *subreq = NULL;
-     struct sdap_posix_check_state *state;
-     errno_t ret;
- 
-@@ -2610,7 +2607,6 @@ sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
-     state->ev = ev;
-     state->sh = sh;
-     state->opts = opts;
--    state->search_bases = search_bases;
-     state->timeout = timeout;
- 
-     state->attrs = talloc_array(state, const char *, 4);
-@@ -2634,43 +2630,26 @@ sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
-         goto fail;
-     }
- 
--    ret = sdap_posix_check_next(req);
--    if (ret != EOK) {
--        goto fail;
--    }
--
--    return req;
--
--fail:
--    tevent_req_error(req, ret);
--    tevent_req_post(req, ev);
--    return req;
--}
--
--static errno_t sdap_posix_check_next(struct tevent_req *req)
--{
--    struct tevent_req *subreq = NULL;
--    struct sdap_posix_check_state *state =
--        tevent_req_data(req, struct sdap_posix_check_state);
--
--    DEBUG(SSSDBG_TRACE_FUNC,
--          "Searching for POSIX attributes with base [%s]\n",
--           state->search_bases[state->base_iter]->basedn);
--
-     subreq = sdap_get_generic_ext_send(state, state->ev, state->opts,
-                                  state->sh,
--                                 state->search_bases[state->base_iter]->basedn,
-+                                 "",
-                                  LDAP_SCOPE_SUBTREE, state->filter,
-                                  state->attrs,
-                                  NULL, NULL, 1, state->timeout,
-                                  sdap_posix_check_parse, state,
-                                  SDAP_SRCH_FLG_SIZELIMIT_SILENT);
-     if (subreq == NULL) {
--        return ENOMEM;
-+        ret = ENOMEM;
-+        goto fail;
-     }
-     tevent_req_set_callback(subreq, sdap_posix_check_done, req);
- 
--    return EOK;
-+    return req;
-+
-+fail:
-+    tevent_req_error(req, ret);
-+    tevent_req_post(req, ev);
-+    return req;
- }
- 
- static errno_t sdap_posix_check_parse(struct sdap_handle *sh,
-@@ -2746,16 +2725,6 @@ static void sdap_posix_check_done(struct tevent_req *subreq)
-         return;
-     }
- 
--    state->base_iter++;
--    if (state->search_bases[state->base_iter]) {
--        /* There are more search bases to try */
--        ret = sdap_posix_check_next(req);
--        if (ret != EOK) {
--            tevent_req_error(req, ret);
--        }
--        return;
--    }
--
-     /* All bases done! */
-     DEBUG(SSSDBG_TRACE_LIBS, "Cycled through all bases\n");
-     tevent_req_done(req);
-diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
-index 6e5800b42ba4a045fa7985b09a80b6b86b8c6055..7216ba032e551196cf5258b4e58fbfc8cfe417ea 100644
---- a/src/providers/ldap/sdap_async.h
-+++ b/src/providers/ldap/sdap_async.h
-@@ -269,7 +269,6 @@ int sdap_deref_search_recv(struct tevent_req *req,
- struct tevent_req *
- sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
-                       struct sdap_options *opts, struct sdap_handle *sh,
--                      struct sdap_search_base **search_bases,
-                       int timeout);
- 
- int sdap_posix_check_recv(struct tevent_req *req,
-diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
-index baa039d63c71cc5054e6af6538d34d04cde6b858..ec0c679823a8cd9820bb978f77799a3f86621271 100644
---- a/src/providers/ldap/sdap_async_enum.c
-+++ b/src/providers/ldap/sdap_async_enum.c
-@@ -202,7 +202,6 @@ static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq)
-                                true)) {
-         subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
-                                        sdap_id_op_handle(state->user_op),
--                                       state->sdom->user_search_bases,
-                                        dp_opt_get_int(state->ctx->opts->basic,
-                                                       SDAP_SEARCH_TIMEOUT));
-         if (subreq == NULL) {
--- 
-2.14.3
-
diff --git a/SOURCES/0072-SDAP-Rename-sdap_posix_check-to-sdap_gc_posix_check.patch b/SOURCES/0072-SDAP-Rename-sdap_posix_check-to-sdap_gc_posix_check.patch
deleted file mode 100644
index 3335d35..0000000
--- a/SOURCES/0072-SDAP-Rename-sdap_posix_check-to-sdap_gc_posix_check.patch
+++ /dev/null
@@ -1,251 +0,0 @@
-From ada45cd38a73b1b196db459849fcc19781bc06fc Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 6 Dec 2017 16:26:15 +0100
-Subject: [PATCH 72/83] SDAP: Rename sdap_posix_check to sdap_gc_posix_check
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Because searching the LDAP port of Active Directory server with a NULL
-search base yields an error:
-    https://technet.microsoft.com/en-us/library/cc755809(v=ws.10).aspx
-we changed the POSIX check request to only run against a GC connection
-in a previous patch. To make it clearer to the caller that this request
-should only be used with a GC connection, this patch renames the
-request.
-
-There are no functional changes in this patch.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit ba8a92bbd59f189bd1323dd0c4010cdfc694be35)
----
- src/providers/ldap/ldap_id.c         | 20 +++++++--------
- src/providers/ldap/sdap_async.c      | 48 ++++++++++++++++++------------------
- src/providers/ldap/sdap_async.h      | 16 ++++++++----
- src/providers/ldap/sdap_async_enum.c | 10 ++++----
- 4 files changed, 50 insertions(+), 44 deletions(-)
-
-diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
-index b5ac3a749113a281fe8a5564ac341ced0570eded..3824f8f9aa8d2892664f1182376bedf6fb8627f6 100644
---- a/src/providers/ldap/ldap_id.c
-+++ b/src/providers/ldap/ldap_id.c
-@@ -415,10 +415,10 @@ static void users_get_connect_done(struct tevent_req *subreq)
-                                state->conn,
-                                state->use_id_mapping,
-                                !state->non_posix)) {
--        subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
--                                       sdap_id_op_handle(state->op),
--                                       dp_opt_get_int(state->ctx->opts->basic,
--                                                      SDAP_SEARCH_TIMEOUT));
-+        subreq = sdap_gc_posix_check_send(state, state->ev, state->ctx->opts,
-+                                          sdap_id_op_handle(state->op),
-+                                          dp_opt_get_int(state->ctx->opts->basic,
-+                                                         SDAP_SEARCH_TIMEOUT));
-         if (subreq == NULL) {
-             tevent_req_error(req, ENOMEM);
-             return;
-@@ -441,7 +441,7 @@ static void users_get_posix_check_done(struct tevent_req *subreq)
-     struct users_get_state *state = tevent_req_data(req,
-                                                     struct users_get_state);
- 
--    ret = sdap_posix_check_recv(subreq, &has_posix);
-+    ret = sdap_gc_posix_check_recv(subreq, &has_posix);
-     talloc_zfree(subreq);
-     if (ret != EOK) {
-         /* We can only finish the id_op on error as the connection
-@@ -960,10 +960,10 @@ static void groups_get_connect_done(struct tevent_req *subreq)
-                                state->conn,
-                                state->use_id_mapping,
-                                !state->non_posix)) {
--        subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
--                                       sdap_id_op_handle(state->op),
--                                       dp_opt_get_int(state->ctx->opts->basic,
--                                                      SDAP_SEARCH_TIMEOUT));
-+        subreq = sdap_gc_posix_check_send(state, state->ev, state->ctx->opts,
-+                                          sdap_id_op_handle(state->op),
-+                                          dp_opt_get_int(state->ctx->opts->basic,
-+                                                         SDAP_SEARCH_TIMEOUT));
-         if (subreq == NULL) {
-             tevent_req_error(req, ENOMEM);
-             return;
-@@ -985,7 +985,7 @@ static void groups_get_posix_check_done(struct tevent_req *subreq)
-     struct groups_get_state *state = tevent_req_data(req,
-                                                      struct groups_get_state);
- 
--    ret = sdap_posix_check_recv(subreq, &has_posix);
-+    ret = sdap_gc_posix_check_recv(subreq, &has_posix);
-     talloc_zfree(subreq);
-     if (ret != EOK) {
-         /* We can only finish the id_op on error as the connection
-diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
-index 1df0b85f4bda6442d8da66784ad7424306b1f051..a9bea4f80903aeb9d0fdb4d2b8f2acb36d81d6fe 100644
---- a/src/providers/ldap/sdap_async.c
-+++ b/src/providers/ldap/sdap_async.c
-@@ -2573,12 +2573,12 @@ int sdap_asq_search_recv(struct tevent_req *req,
- }
- 
- /* ==Posix attribute presence test================================= */
--static void sdap_posix_check_done(struct tevent_req *subreq);
--static errno_t sdap_posix_check_parse(struct sdap_handle *sh,
--                                      struct sdap_msg *msg,
--                                      void *pvt);
-+static void sdap_gc_posix_check_done(struct tevent_req *subreq);
-+static errno_t sdap_gc_posix_check_parse(struct sdap_handle *sh,
-+                                         struct sdap_msg *msg,
-+                                         void *pvt);
- 
--struct sdap_posix_check_state {
-+struct sdap_gc_posix_check_state {
-     struct tevent_context *ev;
-     struct sdap_options *opts;
-     struct sdap_handle *sh;
-@@ -2591,16 +2591,16 @@ struct sdap_posix_check_state {
- };
- 
- struct tevent_req *
--sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
--                      struct sdap_options *opts, struct sdap_handle *sh,
--                      int timeout)
-+sdap_gc_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
-+                         struct sdap_options *opts, struct sdap_handle *sh,
-+                         int timeout)
- {
-     struct tevent_req *req = NULL;
-     struct tevent_req *subreq = NULL;
--    struct sdap_posix_check_state *state;
-+    struct sdap_gc_posix_check_state *state;
-     errno_t ret;
- 
--    req = tevent_req_create(memctx, &state, struct sdap_posix_check_state);
-+    req = tevent_req_create(memctx, &state, struct sdap_gc_posix_check_state);
-     if (req == NULL) {
-         return NULL;
-     }
-@@ -2636,13 +2636,13 @@ sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
-                                  LDAP_SCOPE_SUBTREE, state->filter,
-                                  state->attrs,
-                                  NULL, NULL, 1, state->timeout,
--                                 sdap_posix_check_parse, state,
-+                                 sdap_gc_posix_check_parse, state,
-                                  SDAP_SRCH_FLG_SIZELIMIT_SILENT);
-     if (subreq == NULL) {
-         ret = ENOMEM;
-         goto fail;
-     }
--    tevent_req_set_callback(subreq, sdap_posix_check_done, req);
-+    tevent_req_set_callback(subreq, sdap_gc_posix_check_done, req);
- 
-     return req;
- 
-@@ -2652,13 +2652,13 @@ fail:
-     return req;
- }
- 
--static errno_t sdap_posix_check_parse(struct sdap_handle *sh,
--                                      struct sdap_msg *msg,
--                                      void *pvt)
-+static errno_t sdap_gc_posix_check_parse(struct sdap_handle *sh,
-+                                         struct sdap_msg *msg,
-+                                         void *pvt)
- {
-     struct berval **vals = NULL;
--    struct sdap_posix_check_state *state =
--        talloc_get_type(pvt, struct sdap_posix_check_state);
-+    struct sdap_gc_posix_check_state *state =
-+        talloc_get_type(pvt, struct sdap_gc_posix_check_state);
-     char *dn;
-     char *endptr;
- 
-@@ -2700,12 +2700,12 @@ done:
-     return EOK;
- }
- 
--static void sdap_posix_check_done(struct tevent_req *subreq)
-+static void sdap_gc_posix_check_done(struct tevent_req *subreq)
- {
-     struct tevent_req *req = tevent_req_callback_data(subreq,
-                                                       struct tevent_req);
--    struct sdap_posix_check_state *state =
--        tevent_req_data(req, struct sdap_posix_check_state);
-+    struct sdap_gc_posix_check_state *state =
-+        tevent_req_data(req, struct sdap_gc_posix_check_state);
-     errno_t ret;
- 
-     ret = sdap_get_generic_ext_recv(subreq, NULL, NULL, NULL);
-@@ -2730,11 +2730,11 @@ static void sdap_posix_check_done(struct tevent_req *subreq)
-     tevent_req_done(req);
- }
- 
--int sdap_posix_check_recv(struct tevent_req *req,
--                          bool *_has_posix)
-+int sdap_gc_posix_check_recv(struct tevent_req *req,
-+                             bool *_has_posix)
- {
--    struct sdap_posix_check_state *state = tevent_req_data(req,
--                                            struct sdap_posix_check_state);
-+    struct sdap_gc_posix_check_state *state = tevent_req_data(req,
-+                                            struct sdap_gc_posix_check_state);
- 
-     TEVENT_REQ_RETURN_ON_ERROR(req);
- 
-diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
-index 7216ba032e551196cf5258b4e58fbfc8cfe417ea..26f13e38bf6dff08a8cd0e6b3b5282effda80c9e 100644
---- a/src/providers/ldap/sdap_async.h
-+++ b/src/providers/ldap/sdap_async.h
-@@ -266,13 +266,19 @@ int sdap_deref_search_recv(struct tevent_req *req,
-                            size_t *reply_count,
-                            struct sdap_deref_attrs ***reply);
- 
-+/*
-+ * This request should only be ran against a Global Catalog connection
-+ * because it uses a NULL search base to search all domains in the forest,
-+ * which would return an error with an LDAP port:
-+ *  https://technet.microsoft.com/en-us/library/cc755809(v=ws.10).aspx
-+ */
- struct tevent_req *
--sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
--                      struct sdap_options *opts, struct sdap_handle *sh,
--                      int timeout);
-+sdap_gc_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
-+                         struct sdap_options *opts, struct sdap_handle *sh,
-+                         int timeout);
- 
--int sdap_posix_check_recv(struct tevent_req *req,
--                          bool *_has_posix);
-+int sdap_gc_posix_check_recv(struct tevent_req *req,
-+                             bool *_has_posix);
- 
- struct tevent_req *
- sdap_sd_search_send(TALLOC_CTX *memctx,
-diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
-index ec0c679823a8cd9820bb978f77799a3f86621271..ea9d51adc7f94145cd7e689893bf7fd81028c5bb 100644
---- a/src/providers/ldap/sdap_async_enum.c
-+++ b/src/providers/ldap/sdap_async_enum.c
-@@ -200,10 +200,10 @@ static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq)
-                                state->user_conn,
-                                use_id_mapping,
-                                true)) {
--        subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
--                                       sdap_id_op_handle(state->user_op),
--                                       dp_opt_get_int(state->ctx->opts->basic,
--                                                      SDAP_SEARCH_TIMEOUT));
-+        subreq = sdap_gc_posix_check_send(state, state->ev, state->ctx->opts,
-+                                          sdap_id_op_handle(state->user_op),
-+                                          dp_opt_get_int(state->ctx->opts->basic,
-+                                                         SDAP_SEARCH_TIMEOUT));
-         if (subreq == NULL) {
-             tevent_req_error(req, ENOMEM);
-             return;
-@@ -233,7 +233,7 @@ static void sdap_dom_enum_ex_posix_check_done(struct tevent_req *subreq)
-     struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
-                                                 struct sdap_dom_enum_ex_state);
- 
--    ret = sdap_posix_check_recv(subreq, &has_posix);
-+    ret = sdap_gc_posix_check_recv(subreq, &has_posix);
-     talloc_zfree(subreq);
-     if (ret != EOK && ret != ERR_NO_POSIX) {
-         /* We can only finish the id_op on error as the connection
--- 
-2.14.3
-
diff --git a/SOURCES/0073-DP-Create-a-new-handler-function-getAccountDomain.patch b/SOURCES/0073-DP-Create-a-new-handler-function-getAccountDomain.patch
deleted file mode 100644
index 72a0f99..0000000
--- a/SOURCES/0073-DP-Create-a-new-handler-function-getAccountDomain.patch
+++ /dev/null
@@ -1,455 +0,0 @@
-From 1bed72e4faa2734b0eef6a107b2dc24bf052e576 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 30 Oct 2017 20:50:41 +0100
-Subject: [PATCH 73/83] DP: Create a new handler function getAccountDomain()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Adds a new method getAccountDomain() which is a bit similar to
-getAccountInfo, except it doesn't fetch, parse and store the entry, but
-just returns the domain or a subdomain the entry was found in.
-
-At the moment, the method only supports requests by ID.
-
-A default handler is provided (and in this patch used by all the
-domains) which returns ERR_GET_ACCT_DOM_NOT_SUPPORTED. This return
-code should be evaluated by the responder so that this DP method is
-not called again, because it's not supported by the back end type.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit c0f9f5a0f6d71a1596ee3cef549b4b02295313c3)
----
- src/providers/ad/ad_init.c                       |   4 +
- src/providers/data_provider/dp.h                 |  20 ++++
- src/providers/data_provider/dp_custom_data.h     |   6 ++
- src/providers/data_provider/dp_iface.c           |   3 +-
- src/providers/data_provider/dp_iface.h           |  17 ++++
- src/providers/data_provider/dp_iface.xml         |   7 ++
- src/providers/data_provider/dp_iface_generated.c |  31 +++++++
- src/providers/data_provider/dp_iface_generated.h |   5 +
- src/providers/data_provider/dp_target_id.c       | 113 +++++++++++++++++++++++
- src/providers/files/files_init.c                 |   6 ++
- src/providers/ipa/ipa_init.c                     |   4 +
- src/providers/ldap/ldap_init.c                   |   4 +
- src/providers/proxy/proxy_init.c                 |   4 +
- src/util/util_errors.c                           |   1 +
- src/util/util_errors.h                           |   1 +
- 15 files changed, 225 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
-index e62025d4acd24844a5c7082d00c597516f35de16..7efb6aa71cbd2551422c87e0b0c5c1fe91390375 100644
---- a/src/providers/ad/ad_init.c
-+++ b/src/providers/ad/ad_init.c
-@@ -510,6 +510,10 @@ errno_t sssm_ad_id_init(TALLOC_CTX *mem_ctx,
-                   sdap_online_check_handler_send, sdap_online_check_handler_recv, id_ctx->sdap_id_ctx,
-                   struct sdap_id_ctx, void, struct dp_reply_std);
- 
-+    dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER,
-+                  default_account_domain_send, default_account_domain_recv, NULL,
-+                  void, struct dp_get_acct_domain_data, struct dp_reply_std);
-+
-     return EOK;
- }
- 
-diff --git a/src/providers/data_provider/dp.h b/src/providers/data_provider/dp.h
-index aa5b781158c54545b26034602bb25db46b189e87..ceb49da53b88142924e1792c6f64a22ec369677b 100644
---- a/src/providers/data_provider/dp.h
-+++ b/src/providers/data_provider/dp.h
-@@ -82,6 +82,7 @@ enum dp_methods {
-     DPM_HOSTID_HANDLER,
-     DPM_DOMAINS_HANDLER,
-     DPM_SESSION_HANDLER,
-+    DPM_ACCT_DOMAIN_HANDLER,
- 
-     DPM_REFRESH_ACCESS_RULES,
- 
-@@ -179,4 +180,23 @@ void dp_sbus_reset_users_memcache(struct data_provider *provider);
- void dp_sbus_reset_groups_memcache(struct data_provider *provider);
- void dp_sbus_reset_initgr_memcache(struct data_provider *provider);
- 
-+/*
-+ * A dummy handler for DPM_ACCT_DOMAIN_HANDLER.
-+ *
-+ * Its purpose is to always return ERR_GET_ACCT_DOM_NOT_SUPPORTED
-+ * which the responder should evaluate as "this back end does not
-+ * support locating entries' domain" and never call
-+ * DPM_ACCT_DOMAIN_HANDLER again
-+ *
-+ * This request cannot fail, except for critical errors like OOM.
-+ */
-+struct tevent_req *
-+default_account_domain_send(TALLOC_CTX *mem_ctx,
-+                            void *unused_ctx,
-+                            struct dp_get_acct_domain_data *data,
-+                            struct dp_req_params *params);
-+errno_t default_account_domain_recv(TALLOC_CTX *mem_ctx,
-+                                    struct tevent_req *req,
-+                                    struct dp_reply_std *data);
-+
- #endif /* _DP_H_ */
-diff --git a/src/providers/data_provider/dp_custom_data.h b/src/providers/data_provider/dp_custom_data.h
-index d9de288b62f4f6763ceb205dc596876cfc58bf6c..7c64bde4513961e79200e852c7277f77e064d5a3 100644
---- a/src/providers/data_provider/dp_custom_data.h
-+++ b/src/providers/data_provider/dp_custom_data.h
-@@ -43,6 +43,12 @@ struct dp_subdomains_data {
-     const char *domain_hint;
- };
- 
-+struct dp_get_acct_domain_data {
-+    uint32_t entry_type;
-+    uint32_t filter_type;
-+    const char *filter_value;
-+};
-+
- struct dp_id_data {
-     uint32_t entry_type;
-     uint32_t filter_type;
-diff --git a/src/providers/data_provider/dp_iface.c b/src/providers/data_provider/dp_iface.c
-index 28d70e686f63a3572ac595f493aa1d59436c563f..124be0048f38a93d06561ff7b0d1916838587103 100644
---- a/src/providers/data_provider/dp_iface.c
-+++ b/src/providers/data_provider/dp_iface.c
-@@ -33,7 +33,8 @@ struct iface_dp iface_dp = {
-     .autofsHandler = dp_autofs_handler,
-     .hostHandler = dp_host_handler,
-     .getDomains = dp_subdomains_handler,
--    .getAccountInfo = dp_get_account_info_handler
-+    .getAccountInfo = dp_get_account_info_handler,
-+    .getAccountDomain = dp_get_account_domain_handler,
- };
- 
- struct iface_dp_backend iface_dp_backend = {
-diff --git a/src/providers/data_provider/dp_iface.h b/src/providers/data_provider/dp_iface.h
-index 759b9e6c9eb7f53836ae0b641b34e6c31e65779f..0a2f81eb5c108aa7596c974157b0dfafb041869f 100644
---- a/src/providers/data_provider/dp_iface.h
-+++ b/src/providers/data_provider/dp_iface.h
-@@ -58,6 +58,23 @@ errno_t dp_subdomains_handler(struct sbus_request *sbus_req,
-                               void *dp_cli,
-                               const char *domain_hint);
- 
-+/*
-+ * Return a domain the account belongs to.
-+ *
-+ * The request uses the dp_reply_std structure for reply, with the following
-+ * semantics:
-+ *  - DP_ERR_OK - it is expected that the string message contains the domain name
-+ *                the entry was found in. A 'negative' reply where the
-+ *                request returns DP_ERR_OK, but no domain should be treated
-+ *                as authoritative, as if the entry does not exist.
-+ *  - DP_ERR_*  - the string message contains error string that corresponds
-+ *                to the errno field in dp_reply_std().
-+ */
-+errno_t dp_get_account_domain_handler(struct sbus_request *sbus_req,
-+                                      void *dp_cli,
-+                                      uint32_t entry_type,
-+                                      const char *filter);
-+
- /* org.freedesktop.sssd.DataProvider.Backend */
- errno_t dp_backend_is_online(struct sbus_request *sbus_req,
-                              void *dp_cli,
-diff --git a/src/providers/data_provider/dp_iface.xml b/src/providers/data_provider/dp_iface.xml
-index 2bfa9dfa7e9d02d2d12c3358967f6969438a97a2..c2431850bca4baa529fb18e0480e781308b12dd6 100644
---- a/src/providers/data_provider/dp_iface.xml
-+++ b/src/providers/data_provider/dp_iface.xml
-@@ -79,5 +79,12 @@
-             <arg name="error" type="u" direction="out" />
-             <arg name="error_message" type="s" direction="out" />
-         </method>
-+        <method name="getAccountDomain">
-+            <arg name="entry_type" type="u" direction="in" />
-+            <arg name="filter" type="s" direction="in" />
-+            <arg name="dp_error" type="q" direction="out" />
-+            <arg name="error" type="u" direction="out" />
-+            <arg name="domain_name" type="s" direction="out" />
-+        </method>
-     </interface>
- </node>
-diff --git a/src/providers/data_provider/dp_iface_generated.c b/src/providers/data_provider/dp_iface_generated.c
-index 11ee2e24a69cc8d4d19fdbeed613e76081aef15d..4d093444536b15d8a17f7e507b93948e1df6ffee 100644
---- a/src/providers/data_provider/dp_iface_generated.c
-+++ b/src/providers/data_provider/dp_iface_generated.c
-@@ -313,6 +313,30 @@ int iface_dp_getAccountInfo_finish(struct sbus_request *req, uint16_t arg_dp_err
-                                          DBUS_TYPE_INVALID);
- }
- 
-+/* arguments for org.freedesktop.sssd.dataprovider.getAccountDomain */
-+const struct sbus_arg_meta iface_dp_getAccountDomain__in[] = {
-+    { "entry_type", "u" },
-+    { "filter", "s" },
-+    { NULL, }
-+};
-+
-+/* arguments for org.freedesktop.sssd.dataprovider.getAccountDomain */
-+const struct sbus_arg_meta iface_dp_getAccountDomain__out[] = {
-+    { "dp_error", "q" },
-+    { "error", "u" },
-+    { "domain_name", "s" },
-+    { NULL, }
-+};
-+
-+int iface_dp_getAccountDomain_finish(struct sbus_request *req, uint16_t arg_dp_error, uint32_t arg_error, const char *arg_domain_name)
-+{
-+   return sbus_request_return_and_finish(req,
-+                                         DBUS_TYPE_UINT16, &arg_dp_error,
-+                                         DBUS_TYPE_UINT32, &arg_error,
-+                                         DBUS_TYPE_STRING, &arg_domain_name,
-+                                         DBUS_TYPE_INVALID);
-+}
-+
- /* methods for org.freedesktop.sssd.dataprovider */
- const struct sbus_method_meta iface_dp__methods[] = {
-     {
-@@ -357,6 +381,13 @@ const struct sbus_method_meta iface_dp__methods[] = {
-         offsetof(struct iface_dp, getAccountInfo),
-         invoke_uusss_method,
-     },
-+    {
-+        "getAccountDomain", /* name */
-+        iface_dp_getAccountDomain__in,
-+        iface_dp_getAccountDomain__out,
-+        offsetof(struct iface_dp, getAccountDomain),
-+        invoke_us_method,
-+    },
-     { NULL, }
- };
- 
-diff --git a/src/providers/data_provider/dp_iface_generated.h b/src/providers/data_provider/dp_iface_generated.h
-index 541a90b0b5a5bc0a346cbd04974d33c8bb0983c5..b629ec77487328a41615f3ca7e812088730f40c4 100644
---- a/src/providers/data_provider/dp_iface_generated.h
-+++ b/src/providers/data_provider/dp_iface_generated.h
-@@ -38,6 +38,7 @@
- #define IFACE_DP_HOSTHANDLER "hostHandler"
- #define IFACE_DP_GETDOMAINS "getDomains"
- #define IFACE_DP_GETACCOUNTINFO "getAccountInfo"
-+#define IFACE_DP_GETACCOUNTDOMAIN "getAccountDomain"
- 
- /* ------------------------------------------------------------------------
-  * DBus handlers
-@@ -110,6 +111,7 @@ struct iface_dp {
-     int (*hostHandler)(struct sbus_request *req, void *data, uint32_t arg_dp_flags, const char *arg_name, const char *arg_alias);
-     int (*getDomains)(struct sbus_request *req, void *data, const char *arg_domain_hint);
-     int (*getAccountInfo)(struct sbus_request *req, void *data, uint32_t arg_dp_flags, uint32_t arg_entry_type, const char *arg_filter, const char *arg_domain, const char *arg_extra);
-+    int (*getAccountDomain)(struct sbus_request *req, void *data, uint32_t arg_entry_type, const char *arg_filter);
- };
- 
- /* finish function for autofsHandler */
-@@ -124,6 +126,9 @@ int iface_dp_getDomains_finish(struct sbus_request *req, uint16_t arg_dp_error,
- /* finish function for getAccountInfo */
- int iface_dp_getAccountInfo_finish(struct sbus_request *req, uint16_t arg_dp_error, uint32_t arg_error, const char *arg_error_message);
- 
-+/* finish function for getAccountDomain */
-+int iface_dp_getAccountDomain_finish(struct sbus_request *req, uint16_t arg_dp_error, uint32_t arg_error, const char *arg_domain_name);
-+
- /* ------------------------------------------------------------------------
-  * DBus Interface Metadata
-  *
-diff --git a/src/providers/data_provider/dp_target_id.c b/src/providers/data_provider/dp_target_id.c
-index 820a6574cb3a224cce4b7d8286af306f234454a3..11a36e9ce9b1aefcabb04dfe51395b6f4e4bc899 100644
---- a/src/providers/data_provider/dp_target_id.c
-+++ b/src/providers/data_provider/dp_target_id.c
-@@ -490,3 +490,116 @@ done:
- 
-     return ret;
- }
-+
-+static bool
-+check_and_parse_acct_domain_filter(struct dp_get_acct_domain_data *data,
-+                                   const char *filter)
-+{
-+    /* We will use sizeof() to determine the length of a string so we don't
-+     * call strlen over and over again with each request. Not a bottleneck,
-+     * but unnecessary and simple to avoid. */
-+    static struct {
-+        const char *name;
-+        size_t lenght;
-+        uint32_t type;
-+    } types[] = {FILTER_TYPE("idnumber", BE_FILTER_IDNUM),
-+                 {0, 0, 0}};
-+    int i;
-+
-+    if (SBUS_IS_STRING_EMPTY(filter)) {
-+        return false;
-+    }
-+
-+    for (i = 0; types[i].name != NULL; i++) {
-+        if (strncmp(filter, types[i].name, types[i].lenght) == 0) {
-+            data->filter_type = types[i].type;
-+            data->filter_value = SBUS_SET_STRING(&filter[types[i].lenght]);
-+            return true;
-+        }
-+    }
-+
-+    if (strcmp(filter, ENUM_INDICATOR) == 0) {
-+        data->filter_type = BE_FILTER_ENUM;
-+        data->filter_value = NULL;
-+        return true;
-+    }
-+
-+    return false;
-+}
-+
-+errno_t dp_get_account_domain_handler(struct sbus_request *sbus_req,
-+                                      void *dp_cli,
-+                                      uint32_t entry_type,
-+                                      const char *filter)
-+{
-+    struct dp_get_acct_domain_data *data;
-+    const char *key = NULL;
-+    errno_t ret;
-+
-+    data = talloc_zero(sbus_req, struct dp_get_acct_domain_data);
-+    if (data == NULL) {
-+        return ENOMEM;
-+    }
-+    data->entry_type = entry_type;
-+
-+    if (!check_and_parse_acct_domain_filter(data, filter)) {
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-+    dp_req_with_reply(dp_cli, NULL, "AccountDomain", key, sbus_req,
-+                      DPT_ID, DPM_ACCT_DOMAIN_HANDLER, 0, data,
-+                      dp_req_reply_std, struct dp_reply_std);
-+
-+    ret = EOK;
-+
-+done:
-+    if (ret != EOK) {
-+        talloc_free(data);
-+    }
-+
-+    return ret;
-+}
-+
-+struct default_account_domain_state {
-+    struct dp_reply_std reply;
-+};
-+
-+struct tevent_req *
-+default_account_domain_send(TALLOC_CTX *mem_ctx,
-+                            void *unused_ctx,
-+                            struct dp_get_acct_domain_data *data,
-+                            struct dp_req_params *params)
-+{
-+    struct default_account_domain_state *state;
-+    struct tevent_req *req;
-+
-+    req = tevent_req_create(mem_ctx, &state,
-+                            struct default_account_domain_state);
-+    if (req == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
-+        return NULL;
-+    }
-+
-+    dp_reply_std_set(&state->reply,
-+                     DP_ERR_DECIDE, ERR_GET_ACCT_DOM_NOT_SUPPORTED,
-+                     NULL);
-+    tevent_req_done(req);
-+    tevent_req_post(req, params->ev);
-+    return req;
-+}
-+
-+errno_t default_account_domain_recv(TALLOC_CTX *mem_ctx,
-+                                    struct tevent_req *req,
-+                                    struct dp_reply_std *data)
-+{
-+    struct default_account_domain_state *state = NULL;
-+
-+    state = tevent_req_data(req, struct default_account_domain_state);
-+
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    *data = state->reply;
-+
-+    return EOK;
-+}
-diff --git a/src/providers/files/files_init.c b/src/providers/files/files_init.c
-index b91dfbac9bf9d4b678ebdfa6b1cb0971b4477dd9..8e5cd4cf913b79653616120d6ed6540e62ade932 100644
---- a/src/providers/files/files_init.c
-+++ b/src/providers/files/files_init.c
-@@ -88,5 +88,11 @@ int sssm_files_id_init(TALLOC_CTX *mem_ctx,
-                   ctx, struct files_id_ctx,
-                   struct dp_id_data, struct dp_reply_std);
- 
-+    dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER,
-+                  default_account_domain_send,
-+                  default_account_domain_recv,
-+                  NULL, void,
-+                  struct dp_get_acct_domain_data, struct dp_reply_std);
-+
-     return EOK;
- }
-diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c
-index f335d51fd65959d256c54a5d92c594a24e895b7c..754e5315c3a7f84ac2901986ecdda73e4dad26bc 100644
---- a/src/providers/ipa/ipa_init.c
-+++ b/src/providers/ipa/ipa_init.c
-@@ -754,6 +754,10 @@ errno_t sssm_ipa_id_init(TALLOC_CTX *mem_ctx,
-                   sdap_online_check_handler_send, sdap_online_check_handler_recv, id_ctx->sdap_id_ctx,
-                   struct sdap_id_ctx, void, struct dp_reply_std);
- 
-+    dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER,
-+                  default_account_domain_send, default_account_domain_recv, NULL,
-+                  void, struct dp_get_acct_domain_data, struct dp_reply_std);
-+
-     return EOK;
- }
- 
-diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
-index 43d905893081c31ed659fd1ef8343f965bdc5af0..c0ede8941ee8480c2ec4765f89d12e903edcf012 100644
---- a/src/providers/ldap/ldap_init.c
-+++ b/src/providers/ldap/ldap_init.c
-@@ -531,6 +531,10 @@ errno_t sssm_ldap_id_init(TALLOC_CTX *mem_ctx,
-                   sdap_online_check_handler_send, sdap_online_check_handler_recv, id_ctx,
-                   struct sdap_id_ctx, void, struct dp_reply_std);
- 
-+    dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER,
-+                  default_account_domain_send, default_account_domain_recv, NULL,
-+                  void, struct dp_get_acct_domain_data, struct dp_reply_std);
-+
-     return EOK;
- }
- 
-diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c
-index 7c9d3dafbdf1f9448cc8f8b473aea15cf4206afc..7d997cb16ee62f10f4b86c9c3ab373a48676fe75 100644
---- a/src/providers/proxy/proxy_init.c
-+++ b/src/providers/proxy/proxy_init.c
-@@ -351,6 +351,10 @@ errno_t sssm_proxy_id_init(TALLOC_CTX *mem_ctx,
-                   proxy_account_info_handler_send, proxy_account_info_handler_recv, ctx,
-                   struct proxy_id_ctx, struct dp_id_data, struct dp_reply_std);
- 
-+    dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER,
-+                  default_account_domain_send, default_account_domain_recv, NULL,
-+                  void, struct dp_get_acct_domain_data, struct dp_reply_std);
-+
-     ret = EOK;
- 
- done:
-diff --git a/src/util/util_errors.c b/src/util/util_errors.c
-index 5a92a2dcf6e65f93bc9732cebf562756357123b6..9a9ba3f3063cab4afb538c3a58527a2d2ed3fffd 100644
---- a/src/util/util_errors.c
-+++ b/src/util/util_errors.c
-@@ -115,6 +115,7 @@ struct err_string error_to_str[] = {
-     { "Unable to initialize SSL" }, /* ERR_SSL_FAILURE */
-     { "Unable to verify peer" }, /* ERR_UNABLE_TO_VERIFY_PEER */
-     { "Unable to resolve host" }, /* ERR_UNABLE_TO_RESOLVE_HOST */
-+    { "GetAccountDomain() not supported" }, /* ERR_GET_ACCT_DOM_NOT_SUPPORTED */
-     { "ERR_LAST" } /* ERR_LAST */
- };
- 
-diff --git a/src/util/util_errors.h b/src/util/util_errors.h
-index 509ccb805fb97e59f9da0ea2f991ece2f2030ca4..5ee9862c3f2f60c078693b1b85a40f15436e818c 100644
---- a/src/util/util_errors.h
-+++ b/src/util/util_errors.h
-@@ -137,6 +137,7 @@ enum sssd_errors {
-     ERR_SSL_FAILURE,
-     ERR_UNABLE_TO_VERIFY_PEER,
-     ERR_UNABLE_TO_RESOLVE_HOST,
-+    ERR_GET_ACCT_DOM_NOT_SUPPORTED,
-     ERR_LAST            /* ALWAYS LAST */
- };
- 
--- 
-2.14.3
-
diff --git a/SOURCES/0074-AD-Implement-a-real-getAccountDomain-handler-for-the.patch b/SOURCES/0074-AD-Implement-a-real-getAccountDomain-handler-for-the.patch
deleted file mode 100644
index 980917f..0000000
--- a/SOURCES/0074-AD-Implement-a-real-getAccountDomain-handler-for-the.patch
+++ /dev/null
@@ -1,553 +0,0 @@
-From 427a1f162e0ceb97e4e9491f81048646bd144910 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 7 Nov 2017 17:01:34 +0100
-Subject: [PATCH 74/83] AD: Implement a real getAccountDomain handler for the
- AD provider
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-After this patch, the AD provider drops the default getAccountDomain
-handler in favor of the handler added in this patch.
-
-The handler first checks if the domain is eligible for locating
-the domain of an ID with the help of the Global Catalog at all, which
-only happens if:
-    - the Global Catalog is enabled
-    - POSIX IDs are used, not ID-mapping
-    - the Global catalog contains some POSIX IDs
-
-If all these hold true, then the Global Catalog is searched with
-an empty search base, which searches the whole GC. If a single entry
-is returned, its original DN is converted to a domain name and returned.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 095844d6b48aef483c33e5a369a405ae686e044d)
----
- src/providers/ad/ad_id.c   | 469 +++++++++++++++++++++++++++++++++++++++++++++
- src/providers/ad/ad_id.h   |  10 +
- src/providers/ad/ad_init.c |   4 +-
- 3 files changed, 481 insertions(+), 2 deletions(-)
-
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index e14ada386f16851a65097952c85e57b7acda14aa..0b8f49819405c7dbbfa18b5359f7743441dc65e5 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -27,6 +27,7 @@
- #include "providers/ad/ad_pac.h"
- #include "providers/ldap/sdap_async_enum.h"
- #include "providers/ldap/sdap_idmap.h"
-+#include "providers/ldap/sdap_async.h"
- 
- static void
- disable_gc(struct ad_options *ad_options)
-@@ -1076,3 +1077,471 @@ ad_enumeration_recv(struct tevent_req *req)
-     return EOK;
- }
- 
-+static errno_t ad_get_account_domain_prepare_search(struct tevent_req *req);
-+static errno_t ad_get_account_domain_connect_retry(struct tevent_req *req);
-+static void ad_get_account_domain_connect_done(struct tevent_req *subreq);
-+static void ad_get_account_domain_posix_check_done(struct tevent_req *subreq);
-+static void ad_get_account_domain_search(struct tevent_req *req);
-+static void ad_get_account_domain_search_done(struct tevent_req *subreq);
-+static void ad_get_account_domain_evaluate(struct tevent_req *req);
-+
-+struct ad_get_account_domain_state {
-+    struct tevent_context *ev;
-+    struct ad_id_ctx *id_ctx;
-+    struct sdap_id_ctx *sdap_id_ctx;
-+    struct sdap_domain *sdom;
-+    uint32_t entry_type;
-+    uint32_t filter_type;
-+    char *clean_filter;
-+
-+    bool twopass;
-+
-+    struct sdap_search_base **search_bases;
-+    size_t base_iter;
-+    const char *base_filter;
-+    char *filter;
-+    const char **attrs;
-+    int dp_error;
-+    struct dp_reply_std reply;
-+    struct sdap_id_op *op;
-+    struct sysdb_attrs **objects;
-+    size_t count;
-+
-+    const char *found_domain_name;
-+};
-+
-+struct tevent_req *
-+ad_get_account_domain_send(TALLOC_CTX *mem_ctx,
-+                           struct ad_id_ctx *id_ctx,
-+                           struct dp_get_acct_domain_data *data,
-+                           struct dp_req_params *params)
-+{
-+    struct ad_get_account_domain_state *state;
-+    struct tevent_req *req;
-+    errno_t ret;
-+    bool use_id_mapping;
-+
-+    req = tevent_req_create(mem_ctx, &state,
-+                            struct ad_get_account_domain_state);
-+    if (req == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
-+        return NULL;
-+    }
-+    state->ev = params->ev;
-+    state->id_ctx = id_ctx;
-+    state->sdap_id_ctx = id_ctx->sdap_id_ctx;
-+    state->entry_type = data->entry_type & BE_REQ_TYPE_MASK;
-+    state->filter_type = data->filter_type;
-+    state->attrs = talloc_array(state, const char *, 2);
-+    if (state->attrs == NULL) {
-+        ret = ENOMEM;
-+        goto immediately;
-+    }
-+    state->attrs[0] = "objectclass";
-+    state->attrs[1] = NULL;
-+
-+    if (params->be_ctx->domain->mpg == true
-+            || state->entry_type == BE_REQ_USER_AND_GROUP) {
-+        state->twopass = true;
-+        if (state->entry_type == BE_REQ_USER_AND_GROUP) {
-+            state->entry_type = BE_REQ_GROUP;
-+        }
-+    }
-+
-+    /* The get-account-domain request only works with GC */
-+    if (dp_opt_get_bool(id_ctx->ad_options->basic, AD_ENABLE_GC) == false) {
-+        DEBUG(SSSDBG_CONF_SETTINGS,
-+              "Global catalog support is not enabled, "
-+              "cannot locate the account domain\n");
-+        ret = ERR_GET_ACCT_DOM_NOT_SUPPORTED;
-+        goto immediately;
-+    }
-+
-+    state->sdom = sdap_domain_get(id_ctx->sdap_id_ctx->opts,
-+                                  params->be_ctx->domain);
-+    if (state->sdom == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find sdap_domain\n");
-+        ret = EIO;
-+        goto immediately;
-+    }
-+
-+    /* Currently we only support locating the account domain
-+     * if ID mapping is disabled. With ID mapping enabled, we can
-+     * already shortcut the 'real' ID request
-+     */
-+    use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
-+                                        state->sdap_id_ctx->opts->idmap_ctx,
-+                                        state->sdom->dom->name,
-+                                        state->sdom->dom->domain_id);
-+    if (use_id_mapping == true) {
-+        DEBUG(SSSDBG_CONF_SETTINGS,
-+              "No point in locating domain with GC if ID-mapping "
-+              "is enabled\n");
-+        ret = ERR_GET_ACCT_DOM_NOT_SUPPORTED;
-+        goto immediately;
-+    }
-+
-+    ret = sss_filter_sanitize(state, data->filter_value, &state->clean_filter);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Cannot sanitize filter [%d]: %s\n", ret, sss_strerror(ret));
-+        goto immediately;
-+    }
-+
-+    ret = ad_get_account_domain_prepare_search(req);
-+    if (ret != EOK) {
-+        goto immediately;
-+    }
-+
-+    /* FIXME - should gc_ctx always default to ignore_offline on creation
-+     * time rather than setting the flag on first use?
-+     */
-+    id_ctx->gc_ctx->ignore_mark_offline = true;
-+    state->op = sdap_id_op_create(state, id_ctx->gc_ctx->conn_cache);
-+    if (state->op == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
-+        ret = ENOMEM;
-+        goto immediately;
-+    }
-+
-+    ret = ad_get_account_domain_connect_retry(req);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "Connection error");
-+        goto immediately;
-+    }
-+
-+    return req;
-+
-+immediately:
-+    dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL);
-+
-+    /* TODO For backward compatibility we always return EOK to DP now. */
-+    tevent_req_done(req);
-+    tevent_req_post(req, params->ev);
-+
-+    return req;
-+}
-+
-+static errno_t ad_get_account_domain_prepare_search(struct tevent_req *req)
-+{
-+    struct ad_get_account_domain_state *state = tevent_req_data(req,
-+                                          struct ad_get_account_domain_state);
-+    const char *attr_name = NULL;
-+    const char *objectclass = NULL;
-+
-+    switch (state->entry_type) {
-+    case BE_REQ_USER:
-+        state->search_bases = state->sdom->user_search_bases;
-+        attr_name = state->sdap_id_ctx->opts->user_map[SDAP_AT_USER_UID].name;
-+        objectclass = state->sdap_id_ctx->opts->user_map[SDAP_OC_USER].name;
-+        break;
-+    case BE_REQ_GROUP:
-+        state->search_bases = state->sdom->group_search_bases;
-+        attr_name = state->sdap_id_ctx->opts->group_map[SDAP_AT_GROUP_GID].name;
-+        objectclass = state->sdap_id_ctx->opts->group_map[SDAP_OC_GROUP].name;
-+        break;
-+    default:
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Unsupported request type %X\n",
-+              state->entry_type & BE_REQ_TYPE_MASK);
-+        return EINVAL;
-+    }
-+
-+    switch (state->filter_type) {
-+    case BE_FILTER_IDNUM:
-+        break;
-+    default:
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Unsupported filter type %X\n", state->filter_type);
-+        return EINVAL;
-+    }
-+
-+    talloc_zfree(state->base_filter);
-+    state->base_filter = talloc_asprintf(state,
-+                                         "(&(%s=%s)(objectclass=%s))",
-+                                         attr_name,
-+                                         state->clean_filter,
-+                                         objectclass);
-+    if (state->base_filter == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    return EOK;
-+}
-+
-+static errno_t ad_get_account_domain_connect_retry(struct tevent_req *req)
-+{
-+    struct ad_get_account_domain_state *state = tevent_req_data(req,
-+                                          struct ad_get_account_domain_state);
-+    struct tevent_req *subreq;
-+    errno_t ret;
-+
-+    subreq = sdap_id_op_connect_send(state->op, state, &ret);
-+    if (subreq == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    tevent_req_set_callback(subreq, ad_get_account_domain_connect_done, req);
-+    return ret;
-+}
-+
-+static void ad_get_account_domain_connect_done(struct tevent_req *subreq)
-+{
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct ad_get_account_domain_state *state = tevent_req_data(req,
-+                                          struct ad_get_account_domain_state);
-+    int dp_error = DP_ERR_FATAL;
-+    errno_t ret;
-+
-+    ret = sdap_id_op_connect_recv(subreq, &dp_error);
-+    talloc_zfree(subreq);
-+
-+    if (ret != EOK) {
-+        state->dp_error = dp_error;
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    /* If POSIX attributes have been requested with an AD server and we
-+     * have no idea about POSIX attributes support, run a one-time check
-+     */
-+    if (state->sdap_id_ctx->srv_opts &&
-+        state->sdap_id_ctx->srv_opts->posix_checked == false) {
-+        subreq = sdap_gc_posix_check_send(state,
-+                                          state->ev,
-+                                          state->sdap_id_ctx->opts,
-+                                          sdap_id_op_handle(state->op),
-+                                          dp_opt_get_int(
-+                                              state->sdap_id_ctx->opts->basic,
-+                                              SDAP_SEARCH_TIMEOUT));
-+        if (subreq == NULL) {
-+            tevent_req_error(req, ENOMEM);
-+            return;
-+        }
-+        tevent_req_set_callback(subreq, ad_get_account_domain_posix_check_done, req);
-+        return;
-+    }
-+
-+    ad_get_account_domain_search(req);
-+}
-+
-+static void ad_get_account_domain_posix_check_done(struct tevent_req *subreq)
-+{
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct ad_get_account_domain_state *state = tevent_req_data(req,
-+                                          struct ad_get_account_domain_state);
-+    int dp_error = DP_ERR_FATAL;
-+    bool has_posix;
-+    errno_t ret;
-+    errno_t ret2;
-+
-+    ret = sdap_gc_posix_check_recv(subreq, &has_posix);
-+    talloc_zfree(subreq);
-+    if (ret != EOK) {
-+        /* We can only finish the id_op on error as the connection
-+         * is re-used by the real search
-+         */
-+        ret2 = sdap_id_op_done(state->op, ret, &dp_error);
-+        if (dp_error == DP_ERR_OK && ret2 != EOK) {
-+            /* retry */
-+            ret = ad_get_account_domain_connect_retry(req);
-+            if (ret != EOK) {
-+                tevent_req_error(req, ret);
-+            }
-+            return;
-+        }
-+
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    state->sdap_id_ctx->srv_opts->posix_checked = true;
-+
-+    /*
-+     * If the GC has no POSIX attributes, there is nothing we can do.
-+     * Return an error and let the responders disable the functionality
-+     * from now on.
-+     */
-+    if (has_posix == false) {
-+        DEBUG(SSSDBG_CONF_SETTINGS,
-+              "The Global Catalog has no POSIX attributes\n");
-+
-+        disable_gc(state->id_ctx->ad_options);
-+        dp_reply_std_set(&state->reply,
-+                         DP_ERR_DECIDE, ERR_GET_ACCT_DOM_NOT_SUPPORTED,
-+                         NULL);
-+        tevent_req_done(req);
-+        return;
-+    }
-+
-+    ad_get_account_domain_search(req);
-+}
-+
-+static void ad_get_account_domain_search(struct tevent_req *req)
-+{
-+    struct ad_get_account_domain_state *state = tevent_req_data(req,
-+                                          struct ad_get_account_domain_state);
-+    struct tevent_req *subreq;
-+
-+    talloc_zfree(state->filter);
-+    state->filter = sdap_combine_filters(state, state->base_filter,
-+                        state->search_bases[state->base_iter]->filter);
-+    if (state->filter == NULL) {
-+        tevent_req_error(req, ENOMEM);
-+        return;
-+    }
-+
-+    subreq = sdap_get_generic_send(state, state->ev, state->sdap_id_ctx->opts,
-+                                   sdap_id_op_handle(state->op),
-+                                   "",
-+                                   LDAP_SCOPE_SUBTREE,
-+                                   state->filter,
-+                                   state->attrs, NULL, 0,
-+                                   dp_opt_get_int(state->sdap_id_ctx->opts->basic,
-+                                                  SDAP_SEARCH_TIMEOUT),
-+                                   false);
-+
-+    if (subreq == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
-+        tevent_req_error(req, EIO);
-+        return;
-+    }
-+
-+    tevent_req_set_callback(subreq, ad_get_account_domain_search_done, req);
-+}
-+
-+static void ad_get_account_domain_search_done(struct tevent_req *subreq)
-+{
-+    struct tevent_req *req = tevent_req_callback_data(subreq,
-+                                                      struct tevent_req);
-+    struct ad_get_account_domain_state *state = tevent_req_data(req,
-+                                          struct ad_get_account_domain_state);
-+    size_t count;
-+    struct sysdb_attrs **objects;
-+    errno_t ret;
-+
-+    ret = sdap_get_generic_recv(subreq, state,
-+                                &count, &objects);
-+    talloc_zfree(subreq);
-+    if (ret) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_FUNC,
-+          "Search returned %zu results.\n", count);
-+
-+    if (count > 0) {
-+        size_t copied;
-+
-+        state->objects =
-+                talloc_realloc(state,
-+                               state->objects,
-+                               struct sysdb_attrs *,
-+                               state->count + count + 1);
-+        if (!state->objects) {
-+            tevent_req_error(req, ENOMEM);
-+            return;
-+        }
-+
-+        copied = sdap_steal_objects_in_dom(state->sdap_id_ctx->opts,
-+                                           state->objects,
-+                                           state->count,
-+                                           NULL,
-+                                           objects, count,
-+                                           false);
-+
-+        state->count += copied;
-+        state->objects[state->count] = NULL;
-+    }
-+
-+    /* Even though we search with an empty search base (=across all domains)
-+     * the reason we iterate over search bases is that the search bases can
-+     * also contain a filter which might restrict the IDs we find
-+     */
-+    state->base_iter++;
-+    if (state->search_bases[state->base_iter]) {
-+        /* There are more search bases to try */
-+        ad_get_account_domain_search(req);
-+        return;
-+    }
-+
-+    /* No more searches, evaluate results */
-+    ad_get_account_domain_evaluate(req);
-+}
-+
-+static void ad_get_account_domain_evaluate(struct tevent_req *req)
-+{
-+    struct ad_get_account_domain_state *state = tevent_req_data(req,
-+                                          struct ad_get_account_domain_state);
-+    struct sss_domain_info *obj_dom;
-+    errno_t ret;
-+
-+    if (state->count == 0) {
-+        if (state->twopass
-+                && state->entry_type != BE_REQ_USER) {
-+            DEBUG(SSSDBG_TRACE_FUNC, "Retrying search\n");
-+
-+            state->entry_type = BE_REQ_USER;
-+            state->base_iter = 0;
-+            ret = ad_get_account_domain_prepare_search(req);
-+            if (ret != EOK) {
-+                DEBUG(SSSDBG_OP_FAILURE, "Cannot retry search\n");
-+                tevent_req_error(req, ret);
-+                return;
-+            }
-+
-+            ad_get_account_domain_search(req);
-+            return;
-+        }
-+
-+        DEBUG(SSSDBG_TRACE_FUNC, "Not found\n");
-+        dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ERR_NOT_FOUND, NULL);
-+        tevent_req_done(req);
-+        return;
-+    } else if (state->count > 1) {
-+        /* FIXME: If more than one entry was found, return error for now
-+         * as the account requsts have no way of returning multiple
-+         * messages back until we switch to the rdp_* requests
-+         * from the responder side
-+         */
-+        DEBUG(SSSDBG_OP_FAILURE, "Multiple entries found, error!\n");
-+        dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ERANGE, NULL);
-+        tevent_req_done(req);
-+        return;
-+    }
-+
-+    /* Exactly one entry was found */
-+    obj_dom = sdap_get_object_domain(state->sdap_id_ctx->opts,
-+                                     state->objects[0],
-+                                     state->sdom->dom);
-+    if (obj_dom == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Could not match entry with domain!\n");
-+        dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ERR_NOT_FOUND, NULL);
-+        tevent_req_done(req);
-+        return;
-+    }
-+
-+    DEBUG(SSSDBG_TRACE_INTERNAL,
-+          "Found object in domain %s\n", obj_dom->name);
-+    dp_reply_std_set(&state->reply, DP_ERR_DECIDE, EOK, obj_dom->name);
-+    tevent_req_done(req);
-+}
-+
-+errno_t ad_get_account_domain_recv(TALLOC_CTX *mem_ctx,
-+                                   struct tevent_req *req,
-+                                   struct dp_reply_std *data)
-+{
-+    struct ad_get_account_domain_state *state = NULL;
-+
-+    state = tevent_req_data(req, struct ad_get_account_domain_state);
-+
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    *data = state->reply;
-+
-+    return EOK;
-+}
-diff --git a/src/providers/ad/ad_id.h b/src/providers/ad/ad_id.h
-index 145fdc8f2dfdeda5a17b0ce5892a547da934c244..5154393c5f125f472c92155006aac14d04bbca1a 100644
---- a/src/providers/ad/ad_id.h
-+++ b/src/providers/ad/ad_id.h
-@@ -54,4 +54,14 @@ ad_enumeration_send(TALLOC_CTX *mem_ctx,
- errno_t
- ad_enumeration_recv(struct tevent_req *req);
- 
-+struct tevent_req *
-+ad_get_account_domain_send(TALLOC_CTX *mem_ctx,
-+                           struct ad_id_ctx *id_ctx,
-+                           struct dp_get_acct_domain_data *data,
-+                           struct dp_req_params *params);
-+
-+errno_t ad_get_account_domain_recv(TALLOC_CTX *mem_ctx,
-+                                   struct tevent_req *req,
-+                                   struct dp_reply_std *data);
-+
- #endif /* AD_ID_H_ */
-diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c
-index 7efb6aa71cbd2551422c87e0b0c5c1fe91390375..22a3ecf7e5a020da88b6c9164f5999d13a9aa5e3 100644
---- a/src/providers/ad/ad_init.c
-+++ b/src/providers/ad/ad_init.c
-@@ -511,8 +511,8 @@ errno_t sssm_ad_id_init(TALLOC_CTX *mem_ctx,
-                   struct sdap_id_ctx, void, struct dp_reply_std);
- 
-     dp_set_method(dp_methods, DPM_ACCT_DOMAIN_HANDLER,
--                  default_account_domain_send, default_account_domain_recv, NULL,
--                  void, struct dp_get_acct_domain_data, struct dp_reply_std);
-+                  ad_get_account_domain_send, ad_get_account_domain_recv, id_ctx,
-+                  struct ad_id_ctx, struct dp_get_acct_domain_data, struct dp_reply_std);
- 
-     return EOK;
- }
--- 
-2.14.3
-
diff --git a/SOURCES/0075-RESP-Expose-DP-method-getAccountDomain-to-responders.patch b/SOURCES/0075-RESP-Expose-DP-method-getAccountDomain-to-responders.patch
deleted file mode 100644
index 208b5dd..0000000
--- a/SOURCES/0075-RESP-Expose-DP-method-getAccountDomain-to-responders.patch
+++ /dev/null
@@ -1,239 +0,0 @@
-From cac78825ba2fcb2efcd7ff2e58b562b370bbb28c Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 30 Oct 2017 20:51:40 +0100
-Subject: [PATCH 75/83] RESP: Expose DP method getAccountDomain() to responders
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Adds a tevent request that calls the getAccountDomain DP method.
-This request will be used by responders to locate an object's domain.
-
-At the moment, only looking up UIDs and GIDs is supported.
-
-Internally, until we switch to the rdp_ interface everywhere, this
-interface hooks into the sss_dp_issue_request(). When we switch to
-the rdp_ interface, we'll be able to provide a nicer method parameters
-as well.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 95fd82a4d7b50e64fed6906bc5345f271e8247d9)
----
- src/responder/common/responder.h             |  36 +++++++
- src/responder/common/responder_get_domains.c | 155 +++++++++++++++++++++++++++
- 2 files changed, 191 insertions(+)
-
-diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
-index 9a57df558994c418d440eabf4a29f69c4a47faa5..9400e4b60d9fc77c23710174e4c00a83f6395985 100644
---- a/src/responder/common/responder.h
-+++ b/src/responder/common/responder.h
-@@ -375,6 +375,42 @@ struct tevent_req *sss_dp_get_domains_send(TALLOC_CTX *mem_ctx,
- 
- errno_t sss_dp_get_domains_recv(struct tevent_req *req);
- 
-+/*
-+ * Call a getAccountDomain request
-+ *
-+ * Only requests by ID are supported.
-+ *
-+ * @param   mem_ctx     Parent memory context
-+ * @param   rctx        Responder context
-+ * @param   domain      The SSSD domain we're querying. The response can
-+ *                      be either NULL or come from any of domain's subdomains
-+ *                      or domain itself
-+ * @param   type        Either SSS_DP_USER or SSS_DP_GROUP, other types
-+ *                      are not supported at the moment
-+ * @param   opt_id      The ID number we're trying to locate
-+ *
-+ * @return  A tevent request or NULL if allocating the request fails.
-+ */
-+struct tevent_req *sss_dp_get_account_domain_send(TALLOC_CTX *mem_ctx,
-+                                                  struct resp_ctx *rctx,
-+                                                  struct sss_domain_info *domain,
-+                                                  enum sss_dp_acct_type type,
-+                                                  uint32_t opt_id);
-+
-+/* Receive a getAccountDomain request result
-+ *
-+ * @param   mem_ctx     The memory context that will own the contents of _domain
-+ * @param   req         The request that had finished
-+ * @para    _domain     Either NULL (the request did not match any domain) or
-+ *                      a string that corresponds to either the input domain
-+ *                      or any of its subdomains
-+ *
-+ * @return EOK on success, errno otherwise
-+ */
-+errno_t sss_dp_get_account_domain_recv(TALLOC_CTX *mem_ctx,
-+                                       struct tevent_req *req,
-+                                       char **_domain);
-+
- errno_t schedule_get_domains_task(TALLOC_CTX *mem_ctx,
-                                   struct tevent_context *ev,
-                                   struct resp_ctx *rctx,
-diff --git a/src/responder/common/responder_get_domains.c b/src/responder/common/responder_get_domains.c
-index 4955af064040e03372e9a47fb264499d9a23b828..d69bce2300580beb42d3af8e66ff467db890f284 100644
---- a/src/responder/common/responder_get_domains.c
-+++ b/src/responder/common/responder_get_domains.c
-@@ -642,3 +642,158 @@ errno_t sss_parse_inp_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
- 
-     return state->error;
- }
-+
-+/* ========== Get domain of an ccount ================= */
-+struct sss_dp_get_account_domain_info {
-+    struct sss_domain_info *dom;
-+    enum sss_dp_acct_type type;
-+    uint32_t opt_id;
-+};
-+
-+static DBusMessage *sss_dp_get_account_domain_msg(void *pvt);
-+
-+struct tevent_req *sss_dp_get_account_domain_send(TALLOC_CTX *mem_ctx,
-+                                                  struct resp_ctx *rctx,
-+                                                  struct sss_domain_info *dom,
-+                                                  enum sss_dp_acct_type type,
-+                                                  uint32_t opt_id)
-+{
-+    struct tevent_req *req;
-+    struct sss_dp_get_account_domain_info *info;
-+    struct sss_dp_req_state *state;
-+    char *key;
-+    errno_t ret;
-+
-+    req = tevent_req_create(mem_ctx, &state, struct sss_dp_req_state);
-+    if (!req) {
-+        return NULL;
-+    }
-+
-+    info = talloc_zero(state, struct sss_dp_get_account_domain_info);
-+    if (info == NULL) {
-+        ret = ENOMEM;
-+        goto immediately;
-+    }
-+    info->type = type;
-+    info->opt_id = opt_id;
-+    info->dom = dom;
-+
-+    key = talloc_asprintf(state, "%d: %"SPRIuid"@%s", type, opt_id, dom->name);
-+    if (key == NULL) {
-+        ret = ENOMEM;
-+        goto immediately;
-+    }
-+
-+    ret = sss_dp_issue_request(state, rctx, key, dom,
-+                               sss_dp_get_account_domain_msg,
-+                               info, req);
-+    talloc_free(key);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Could not issue DP request [%d]: %s\n",
-+              ret, sss_strerror(ret));
-+        goto immediately;
-+    }
-+
-+    return req;
-+
-+immediately:
-+    if (ret == EOK) {
-+        tevent_req_done(req);
-+    } else {
-+        tevent_req_error(req, ret);
-+    }
-+    tevent_req_post(req, rctx->ev);
-+    return req;
-+}
-+
-+static DBusMessage *
-+sss_dp_get_account_domain_msg(void *pvt)
-+{
-+    DBusMessage *msg;
-+    dbus_bool_t dbret;
-+    struct sss_dp_get_account_domain_info *info;
-+    uint32_t entry_type;
-+    char *filter;
-+
-+    info = talloc_get_type(pvt, struct sss_dp_get_account_domain_info);
-+
-+    switch (info->type) {
-+    case SSS_DP_USER:
-+        entry_type = BE_REQ_USER;
-+        break;
-+    case SSS_DP_GROUP:
-+        entry_type = BE_REQ_GROUP;
-+        break;
-+    case SSS_DP_USER_AND_GROUP:
-+        entry_type = BE_REQ_USER_AND_GROUP;
-+        break;
-+    default:
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Unsupported lookup type %X for this request\n", info->type);
-+        return NULL;
-+    }
-+
-+    filter = talloc_asprintf(info, "idnumber=%u", info->opt_id);
-+    if (!filter) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
-+        return NULL;
-+    }
-+
-+    msg = dbus_message_new_method_call(NULL,
-+                                       DP_PATH,
-+                                       IFACE_DP,
-+                                       IFACE_DP_GETACCOUNTDOMAIN);
-+    if (msg == NULL) {
-+        talloc_free(filter);
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
-+        return NULL;
-+    }
-+
-+    /* create the message */
-+    DEBUG(SSSDBG_TRACE_FUNC,
-+          "Creating request for [%s][%#x][%s][%s:-]\n",
-+          info->dom->name, entry_type, be_req2str(entry_type), filter);
-+
-+    dbret = dbus_message_append_args(msg,
-+                                     DBUS_TYPE_UINT32, &entry_type,
-+                                     DBUS_TYPE_STRING, &filter,
-+                                     DBUS_TYPE_INVALID);
-+    talloc_free(filter);
-+    if (!dbret) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build message\n");
-+        dbus_message_unref(msg);
-+        return NULL;
-+    }
-+
-+    return msg;
-+}
-+
-+errno_t sss_dp_get_account_domain_recv(TALLOC_CTX *mem_ctx,
-+                                       struct tevent_req *req,
-+                                       char **_domain)
-+{
-+    errno_t ret;
-+    dbus_uint16_t err_maj;
-+    dbus_uint32_t err_min;
-+    char *msg;
-+
-+    ret = sss_dp_req_recv(mem_ctx, req, &err_maj, &err_min, &msg);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Could not get account info [%d]: %s\n",
-+              ret, sss_strerror(ret));
-+        return ret;
-+    }
-+
-+    if (err_maj != DP_ERR_OK) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Data Provider Error: %u, %u\n",
-+              (unsigned int)err_maj, (unsigned int)err_min);
-+        talloc_free(msg);
-+        return err_min ? err_min : EIO;
-+    }
-+
-+    *_domain = msg;
-+    return EOK;
-+}
--- 
-2.14.3
-
diff --git a/SOURCES/0076-NEGCACHE-Add-API-for-setting-and-checking-locate-acc.patch b/SOURCES/0076-NEGCACHE-Add-API-for-setting-and-checking-locate-acc.patch
deleted file mode 100644
index 4d554a2..0000000
--- a/SOURCES/0076-NEGCACHE-Add-API-for-setting-and-checking-locate-acc.patch
+++ /dev/null
@@ -1,371 +0,0 @@
-From 72fdce0007af1baa0504c2d11be8b19e1a3296f1 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 6 Nov 2017 10:09:16 +0100
-Subject: [PATCH 76/83] NEGCACHE: Add API for setting and checking
- locate-account-domain requests
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Extends the negative cache API with several request getsetters:
-    - sss_ncache_set/check_domain_locate_type - check if this request
-      type supports locating account domain or set that this request
-      type does not support the locator.
-
-    - sss_ncache_set/check_locate_gid/uid - check if it is time to call
-      the locator again or set that the locator should not be called
-      for IDs again for the duration of the negative cache.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 07452697a67902dc6876d2f40d364cf1eadf2431)
----
- src/responder/common/negcache.c  | 155 +++++++++++++++++++++++++++++++++++++++
- src/responder/common/negcache.h  |  64 ++++++++++++++++
- src/tests/cmocka/test_negcache.c |  75 +++++++++++++++++++
- 3 files changed, 294 insertions(+)
-
-diff --git a/src/responder/common/negcache.c b/src/responder/common/negcache.c
-index b751d89ee9e67eea32ec4ed0935fcd67d3e92f47..bd3c9d36805adc5cca5621c815576ac21cfbec38 100644
---- a/src/responder/common/negcache.c
-+++ b/src/responder/common/negcache.c
-@@ -37,6 +37,8 @@
- #define NC_GID_PREFIX NC_ENTRY_PREFIX"GID"
- #define NC_SID_PREFIX NC_ENTRY_PREFIX"SID"
- #define NC_CERT_PREFIX NC_ENTRY_PREFIX"CERT"
-+#define NC_DOMAIN_ACCT_LOCATE_PREFIX NC_ENTRY_PREFIX"DOM_LOCATE"
-+#define NC_DOMAIN_ACCT_LOCATE_TYPE_PREFIX NC_ENTRY_PREFIX"DOM_LOCATE_TYPE"
- 
- struct sss_nc_ctx {
-     struct tdb_context *tdb;
-@@ -665,6 +667,159 @@ int sss_ncache_set_cert(struct sss_nc_ctx *ctx, bool permanent,
-     return ret;
- }
- 
-+static char *domain_lookup_type_str(TALLOC_CTX *mem_ctx,
-+                                    struct sss_domain_info *dom,
-+                                    const char *lookup_type)
-+{
-+    return talloc_asprintf(mem_ctx,
-+                           "%s/%s/%s",
-+                           NC_DOMAIN_ACCT_LOCATE_TYPE_PREFIX,
-+                           dom->name,
-+                           lookup_type);
-+}
-+
-+int sss_ncache_set_domain_locate_type(struct sss_nc_ctx *ctx,
-+                                      struct sss_domain_info *dom,
-+                                      const char *lookup_type)
-+{
-+    char *str;
-+    int ret;
-+
-+    str = domain_lookup_type_str(ctx, dom, lookup_type);
-+    if (!str) return ENOMEM;
-+
-+    /* Permanent cache is always used here, because whether the lookup
-+     * type (getgrgid, getpwuid, ..) supports locating an entry's domain
-+     * doesn't change
-+     */
-+    ret = sss_ncache_set_str(ctx, str, true, false);
-+    talloc_free(str);
-+    return ret;
-+}
-+
-+int sss_ncache_check_domain_locate_type(struct sss_nc_ctx *ctx,
-+                                        struct sss_domain_info *dom,
-+                                        const char *lookup_type)
-+{
-+    char *str;
-+    int ret;
-+
-+    str = domain_lookup_type_str(ctx, dom, lookup_type);
-+    if (!str) return ENOMEM;
-+
-+    ret = sss_ncache_check_str(ctx, str);
-+    talloc_free(str);
-+    return ret;
-+}
-+
-+static char *locate_gid_str(TALLOC_CTX *mem_ctx,
-+                            struct sss_domain_info *dom,
-+                            gid_t gid)
-+{
-+    return talloc_asprintf(mem_ctx,
-+                           "%s/%s/%s/%"SPRIgid,
-+                           NC_DOMAIN_ACCT_LOCATE_PREFIX,
-+                           NC_GID_PREFIX,
-+                           dom->name,
-+                           gid);
-+}
-+
-+int sss_ncache_set_locate_gid(struct sss_nc_ctx *ctx,
-+                              struct sss_domain_info *dom,
-+                              gid_t gid)
-+{
-+    char *str;
-+    int ret;
-+
-+    if (dom == NULL) {
-+        return EINVAL;
-+    }
-+
-+    str = locate_gid_str(ctx, dom, gid);
-+    if (str == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    ret = sss_ncache_set_str(ctx, str, false, false);
-+    talloc_free(str);
-+    return ret;
-+}
-+
-+int sss_ncache_check_locate_gid(struct sss_nc_ctx *ctx,
-+                                struct sss_domain_info *dom,
-+                                gid_t gid)
-+{
-+    char *str;
-+    int ret;
-+
-+    if (dom == NULL) {
-+        return EINVAL;
-+    }
-+
-+    str = locate_gid_str(ctx, dom, gid);
-+    if (str == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    ret = sss_ncache_check_str(ctx, str);
-+    talloc_free(str);
-+    return ret;
-+}
-+
-+static char *locate_uid_str(struct sss_nc_ctx *ctx,
-+                            struct sss_domain_info *dom,
-+                            uid_t uid)
-+{
-+    return talloc_asprintf(ctx,
-+                           "%s/%s/%s/%"SPRIuid,
-+                           NC_DOMAIN_ACCT_LOCATE_PREFIX,
-+                           NC_UID_PREFIX,
-+                           dom->name,
-+                           uid);
-+}
-+
-+int sss_ncache_set_locate_uid(struct sss_nc_ctx *ctx,
-+                              struct sss_domain_info *dom,
-+                              uid_t uid)
-+{
-+    char *str;
-+    int ret;
-+
-+    if (dom == NULL) {
-+        return EINVAL;
-+    }
-+
-+    str = locate_uid_str(ctx, dom, uid);
-+    if (str == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    ret = sss_ncache_set_str(ctx, str, false, false);
-+    talloc_free(str);
-+    return ret;
-+}
-+
-+int sss_ncache_check_locate_uid(struct sss_nc_ctx *ctx,
-+                                struct sss_domain_info *dom,
-+                                uid_t uid)
-+{
-+    char *str;
-+    int ret;
-+
-+    if (dom == NULL) {
-+        return EINVAL;
-+    }
-+
-+    str = locate_uid_str(ctx, dom, uid);
-+    if (str == NULL) {
-+        return ENOMEM;
-+    }
-+
-+    ret = sss_ncache_check_str(ctx, str);
-+    talloc_free(str);
-+    return ret;
-+}
-+
- static int delete_permanent(struct tdb_context *tdb,
-                             TDB_DATA key, TDB_DATA data, void *state)
- {
-diff --git a/src/responder/common/negcache.h b/src/responder/common/negcache.h
-index 782ec140fb7dfe3ec82bed8d25290c0f7b8a36ea..2ed38e5b9a64d3393513ea2110a7c6fcb7675623 100644
---- a/src/responder/common/negcache.h
-+++ b/src/responder/common/negcache.h
-@@ -80,6 +80,70 @@ int sss_ncache_set_service_name(struct sss_nc_ctx *ctx, bool permanent,
- int sss_ncache_set_service_port(struct sss_nc_ctx *ctx, bool permanent,
-                                 struct sss_domain_info *dom,
-                                 uint16_t port, const char *proto);
-+/*
-+ * Mark the lookup_type as not supporting the negative cache. This
-+ * would be used by the corresponding checker to avoid needless
-+ * subsequent calls to the locator for configurations that do not
-+ * support the locator plugin.
-+ *
-+ * @param ctx   The negative cache
-+ * @param dom   The top-level domain. It is expected that the caller
-+ *              would use the top-level domain head here, because
-+ *              this negative cache is "per-request-type" which is the
-+ *              same for all subdomains of a domain
-+ * @param lookup_type   Lookup type, e.g. getpwuid, getgrnam.
-+ *
-+ * @return EOK on success, errno on failure.
-+ */
-+int sss_ncache_set_domain_locate_type(struct sss_nc_ctx *ctx,
-+                                      struct sss_domain_info *dom,
-+                                      const char *lookup_type);
-+/*
-+ * Check if the lookup_type supports the domain locator request.
-+ *
-+ * @param ctx   The negative cache
-+ * @param dom   The top-level domain. It is expected that the caller
-+ *              would use the top-level domain head here, because
-+ *              this negative cache is "per-request-type" which is the
-+ *              same for all subdomains of a domain
-+ * @param lookup_type   Lookup type, e.g. getpwuid, getgrnam.
-+ *
-+ * @return      ENOENT if the request supports the locator (or we
-+ *              haven't checked yet), EEXIST if the request does
-+ *              not support the domain locator request.
-+ */
-+int sss_ncache_check_domain_locate_type(struct sss_nc_ctx *ctx,
-+                                        struct sss_domain_info *dom,
-+                                        const char *key);
-+
-+/*
-+ * Call these two functions to mark a GID as checked until the negative
-+ * cache expires. This function is used to avoid a situation where
-+ * GID would be found in a subsequent domain, so any request that
-+ * searches for this GID again (even if it was cached) would first
-+ * run the locator again.
-+ *
-+ * While this negative cache entry is valid, it is expected that
-+ * the negatively cached entries in the domain's GID negative
-+ * cache (if any) are valid
-+ *
-+ * The sss_ncache_set_locate_gid() is called by the locator request
-+ * when it finishes, the sss_ncache_check_locate_gid() is called
-+ * by the caller of the locator request to find if the locator
-+ * should be called at all.
-+ */
-+int sss_ncache_set_locate_gid(struct sss_nc_ctx *ctx,
-+                              struct sss_domain_info *dom,
-+                              gid_t gid);
-+int sss_ncache_check_locate_gid(struct sss_nc_ctx *ctx,
-+                                struct sss_domain_info *dom,
-+                                gid_t gid);
-+int sss_ncache_check_locate_uid(struct sss_nc_ctx *ctx,
-+                                struct sss_domain_info *dom,
-+                                uid_t uid);
-+int sss_ncache_set_locate_uid(struct sss_nc_ctx *ctx,
-+                              struct sss_domain_info *dom,
-+                              uid_t uid);
- 
- int sss_ncache_reset_permanent(struct sss_nc_ctx *ctx);
- int sss_ncache_reset_users(struct sss_nc_ctx *ctx);
-diff --git a/src/tests/cmocka/test_negcache.c b/src/tests/cmocka/test_negcache.c
-index ba39f778d5ddc6a4e1708aef66fc2aa1c809f150..a0210928bd60e364c60717c8b37b2405730f34ab 100644
---- a/src/tests/cmocka/test_negcache.c
-+++ b/src/tests/cmocka/test_negcache.c
-@@ -883,6 +883,77 @@ static void test_sss_ncache_reset(void **state)
-     assert_int_equal(ret, ENOENT);
- }
- 
-+static void test_sss_ncache_locate_uid_gid(void **state)
-+{
-+    uid_t uid;
-+    gid_t gid;
-+    int ret;
-+    struct test_state *ts;
-+    struct sss_domain_info *dom;
-+    struct sss_domain_info *dom2;
-+
-+    ts = talloc_get_type_abort(*state, struct test_state);
-+
-+    uid = getuid();
-+    gid = getgid();
-+
-+    dom = talloc(ts, struct sss_domain_info);
-+    assert_non_null(dom);
-+    dom->name = discard_const_p(char, TEST_DOM_NAME);
-+
-+    dom2 = talloc(ts, struct sss_domain_info);
-+    assert_non_null(dom2);
-+    dom2->name = discard_const_p(char, TEST_DOM_NAME"2");
-+
-+    ret = sss_ncache_check_locate_gid(ts->ctx, dom, gid);
-+    assert_int_equal(ret, ENOENT);
-+    ret = sss_ncache_check_locate_uid(ts->ctx, dom, uid);
-+    assert_int_equal(ret, ENOENT);
-+
-+    ret = sss_ncache_set_locate_gid(ts->ctx, dom, gid);
-+    assert_int_equal(ret, EOK);
-+    ret = sss_ncache_set_locate_uid(ts->ctx, dom, uid);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = sss_ncache_check_locate_gid(ts->ctx, dom, gid);
-+    assert_int_equal(ret, EEXIST);
-+    ret = sss_ncache_check_locate_uid(ts->ctx, dom, uid);
-+    assert_int_equal(ret, EEXIST);
-+
-+    ret = sss_ncache_check_locate_gid(ts->ctx, dom2, gid);
-+    assert_int_equal(ret, ENOENT);
-+    ret = sss_ncache_check_locate_uid(ts->ctx, dom2, uid);
-+    assert_int_equal(ret, ENOENT);
-+}
-+
-+static void test_sss_ncache_domain_locate_type(void **state)
-+{
-+    int ret;
-+    struct test_state *ts;
-+    struct sss_domain_info *dom;
-+    struct sss_domain_info *dom2;
-+
-+    ts = talloc_get_type_abort(*state, struct test_state);
-+
-+    dom = talloc(ts, struct sss_domain_info);
-+    assert_non_null(dom);
-+    dom->name = discard_const_p(char, TEST_DOM_NAME);
-+
-+    dom2 = talloc(ts, struct sss_domain_info);
-+    assert_non_null(dom2);
-+    dom2->name = discard_const_p(char, TEST_DOM_NAME"2");
-+
-+    ret = sss_ncache_check_domain_locate_type(ts->ctx, dom, "foo");
-+    assert_int_equal(ret, ENOENT);
-+    ret = sss_ncache_set_domain_locate_type(ts->ctx, dom, "foo");
-+    assert_int_equal(ret, EOK);
-+    ret = sss_ncache_check_domain_locate_type(ts->ctx, dom, "foo");
-+    assert_int_equal(ret, EEXIST);
-+
-+    ret = sss_ncache_check_domain_locate_type(ts->ctx, dom2, "foo");
-+    assert_int_equal(ret, ENOENT);
-+}
-+
- int main(void)
- {
-     int rv;
-@@ -909,6 +980,10 @@ int main(void)
-                                         setup, teardown),
-         cmocka_unit_test_setup_teardown(test_sss_ncache_reset,
-                                         setup, teardown),
-+        cmocka_unit_test_setup_teardown(test_sss_ncache_locate_uid_gid,
-+                                        setup, teardown),
-+        cmocka_unit_test_setup_teardown(test_sss_ncache_domain_locate_type,
-+                                        setup, teardown),
-     };
- 
-     tests_set_cwd();
--- 
-2.14.3
-
diff --git a/SOURCES/0077-TESTS-Add-tests-for-the-object-by-id-cache_req-inter.patch b/SOURCES/0077-TESTS-Add-tests-for-the-object-by-id-cache_req-inter.patch
deleted file mode 100644
index 178e22e..0000000
--- a/SOURCES/0077-TESTS-Add-tests-for-the-object-by-id-cache_req-inter.patch
+++ /dev/null
@@ -1,439 +0,0 @@
-From 9a4c06ddf5ec8d610f49acf5d3e231d36b37c50b Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Sun, 19 Nov 2017 17:25:02 +0100
-Subject: [PATCH 77/83] TESTS: Add tests for the object-by-id cache_req
- interface
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This interface will be extended in later patches, but had no tests at
-all.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 6cd367da68ff56eb48b8b4167dbdd5e53992d194)
----
- src/tests/cmocka/test_responder_cache_req.c | 385 ++++++++++++++++++++++++++++
- 1 file changed, 385 insertions(+)
-
-diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c
-index 80086232fd437876c2b190fb972c2ee3194d9efd..f075480a019e476407a3081a795c3c289455aca8 100644
---- a/src/tests/cmocka/test_responder_cache_req.c
-+++ b/src/tests/cmocka/test_responder_cache_req.c
-@@ -197,6 +197,18 @@ static void cache_req_object_by_sid_test_done(struct tevent_req *req)
-     ctx->tctx->done = true;
- }
- 
-+static void cache_req_object_by_id_test_done(struct tevent_req *req)
-+{
-+    struct cache_req_test_ctx *ctx = NULL;
-+
-+    ctx = tevent_req_callback_data(req, struct cache_req_test_ctx);
-+
-+    ctx->tctx->error = cache_req_object_by_id_recv(ctx, req, &ctx->result);
-+    talloc_zfree(req);
-+
-+    ctx->tctx->done = true;
-+}
-+
- static void prepare_user(struct sss_domain_info *domain,
-                          struct test_user *user,
-                          uint64_t timeout,
-@@ -417,6 +429,33 @@ static void run_object_by_sid(struct cache_req_test_ctx *test_ctx,
-     talloc_free(req_mem_ctx);
- }
- 
-+static void run_object_by_id(struct cache_req_test_ctx *test_ctx,
-+                             struct sss_domain_info *domain,
-+                             id_t id,
-+                             const char **attrs,
-+                             int cache_refresh_percent,
-+                             errno_t exp_ret)
-+{
-+    TALLOC_CTX *req_mem_ctx;
-+    struct tevent_req *req;
-+    errno_t ret;
-+
-+    req_mem_ctx = talloc_new(global_talloc_context);
-+    check_leaks_push(req_mem_ctx);
-+
-+    req = cache_req_object_by_id_send(req_mem_ctx, test_ctx->tctx->ev,
-+            test_ctx->rctx, test_ctx->ncache, cache_refresh_percent,
-+            (domain == NULL ? NULL : domain->name), id, attrs);
-+    assert_non_null(req);
-+    tevent_req_set_callback(req, cache_req_object_by_id_test_done, test_ctx);
-+
-+    ret = test_ev_loop(test_ctx->tctx);
-+    assert_int_equal(ret, exp_ret);
-+    assert_true(check_leaks_pop(req_mem_ctx));
-+
-+    talloc_free(req_mem_ctx);
-+}
-+
- struct tevent_req *
- __wrap_sss_dp_get_account_send(TALLOC_CTX *mem_ctx,
-                                struct resp_ctx *rctx,
-@@ -2132,6 +2171,334 @@ void test_object_by_sid_group_multiple_domains_notfound(void **state)
-     assert_true(test_ctx->dp_called);
- }
- 
-+void test_object_by_id_user_cache_valid(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Setup user. */
-+    prepare_user(test_ctx->tctx->dom, &users[0], 1000, time(NULL));
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK);
-+    check_user(test_ctx, &users[0], test_ctx->tctx->dom);
-+}
-+
-+void test_object_by_id_user_cache_expired(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Setup user. */
-+    prepare_user(test_ctx->tctx->dom, &users[0], -1000, time(NULL));
-+
-+    /* Mock values. */
-+    /* DP should be contacted */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    mock_account_recv_simple();
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK);
-+    assert_true(test_ctx->dp_called);
-+    check_user(test_ctx, &users[0], test_ctx->tctx->dom);
-+}
-+
-+void test_object_by_id_user_cache_midpoint(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Setup user. */
-+    prepare_user(test_ctx->tctx->dom, &users[0], 50, time(NULL) - 26);
-+
-+    /* Mock values. */
-+    /* DP should be contacted without callback */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 50, ERR_OK);
-+    assert_true(test_ctx->dp_called);
-+    check_user(test_ctx, &users[0], test_ctx->tctx->dom);
-+}
-+
-+void test_object_by_id_user_ncache(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+    errno_t ret;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Setup user. We explicitly add the UID into BOTH UID and GID
-+     * namespaces, because otherwise the cache_req plugin would
-+     * search the Data Provider anyway, becase it can't be sure
-+     * the object can be of the other type or not
-+     */
-+    ret = sss_ncache_set_uid(test_ctx->ncache,
-+                             false,
-+                             test_ctx->tctx->dom,
-+                             users[0].uid);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = sss_ncache_set_gid(test_ctx->ncache,
-+                             false,
-+                             test_ctx->tctx->dom,
-+                             users[0].uid);
-+    assert_int_equal(ret, EOK);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ENOENT);
-+    assert_false(test_ctx->dp_called);
-+}
-+
-+void test_object_by_id_user_missing_found(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Mock values. */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    mock_account_recv_simple();
-+
-+    test_ctx->create_user1 = true;
-+    test_ctx->create_user2 = false;
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK);
-+    assert_true(test_ctx->dp_called);
-+    check_user(test_ctx, &users[0], test_ctx->tctx->dom);
-+}
-+
-+void test_object_by_id_user_missing_notfound(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Mock values. */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    mock_account_recv_simple();
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ENOENT);
-+    assert_true(test_ctx->dp_called);
-+}
-+
-+void test_object_by_id_user_multiple_domains_found(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Setup user. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 "responder_cache_req_test_d", true);
-+    assert_non_null(domain);
-+
-+    prepare_user(domain, &users[0], 1000, time(NULL));
-+
-+    /* Mock values. */
-+    will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, 0);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK);
-+    assert_true(test_ctx->dp_called);
-+    check_user(test_ctx, &users[0], domain);
-+}
-+
-+void test_object_by_id_user_multiple_domains_notfound(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Mock values. */
-+    will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, 0);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ENOENT);
-+    assert_true(test_ctx->dp_called);
-+}
-+
-+void test_object_by_id_group_cache_valid(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    const char *attrs[] = SYSDB_GRSRC_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Setup user. */
-+    prepare_group(test_ctx->tctx->dom, &groups[0], 1000, time(NULL));
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK);
-+    check_group(test_ctx, &groups[0], test_ctx->tctx->dom);
-+}
-+
-+void test_object_by_id_group_cache_expired(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    const char *attrs[] = SYSDB_GRSRC_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Setup user. */
-+    prepare_group(test_ctx->tctx->dom, &groups[0], -1000, time(NULL));
-+
-+    /* Mock values. */
-+    /* DP should be contacted */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    mock_account_recv_simple();
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK);
-+    assert_true(test_ctx->dp_called);
-+    check_group(test_ctx, &groups[0], test_ctx->tctx->dom);
-+}
-+
-+void test_object_by_id_group_cache_midpoint(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    const char *attrs[] = SYSDB_GRSRC_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Setup user. */
-+    prepare_group(test_ctx->tctx->dom, &groups[0], 50, time(NULL) - 26);
-+
-+    /* Mock values. */
-+    /* DP should be contacted without callback */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 50, ERR_OK);
-+    assert_true(test_ctx->dp_called);
-+    check_group(test_ctx, &groups[0], test_ctx->tctx->dom);
-+}
-+
-+void test_object_by_id_group_ncache(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    const char *attrs[] = SYSDB_GRSRC_ATTRS;
-+    errno_t ret;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Setup group. We explicitly add the UID into BOTH UID and GID
-+     * namespaces, because otherwise the cache_req plugin would
-+     * search the Data Provider anyway, becase it can't be sure
-+     * the object can be of the other type or not
-+     */
-+    ret = sss_ncache_set_uid(test_ctx->ncache,
-+                             false,
-+                             test_ctx->tctx->dom,
-+                             groups[0].gid);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = sss_ncache_set_gid(test_ctx->ncache,
-+                             false,
-+                             test_ctx->tctx->dom,
-+                             groups[0].gid);
-+    assert_int_equal(ret, EOK);
-+
-+    assert_int_equal(ret, EOK);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ENOENT);
-+    assert_false(test_ctx->dp_called);
-+}
-+
-+void test_object_by_id_group_missing_found(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    const char *attrs[] = SYSDB_GRSRC_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Mock values. */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    mock_account_recv_simple();
-+
-+    test_ctx->create_group1 = true;
-+    test_ctx->create_group2 = false;
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK);
-+    assert_true(test_ctx->dp_called);
-+    check_group(test_ctx, &groups[0], test_ctx->tctx->dom);
-+}
-+
-+void test_object_by_id_group_missing_notfound(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    const char *attrs[] = SYSDB_GRSRC_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Mock values. */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    mock_account_recv_simple();
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ENOENT);
-+    assert_true(test_ctx->dp_called);
-+}
-+
-+void test_object_by_id_group_multiple_domains_found(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *attrs[] = SYSDB_GRSRC_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Setup user. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 "responder_cache_req_test_d", true);
-+    assert_non_null(domain);
-+
-+    prepare_group(domain, &groups[0], 1000, time(NULL));
-+
-+    /* Mock values. */
-+    will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, 0);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK);
-+    assert_true(test_ctx->dp_called);
-+    check_group(test_ctx, &groups[0], domain);
-+}
-+
-+void test_object_by_id_group_multiple_domains_notfound(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    const char *attrs[] = SYSDB_GRSRC_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Mock values. */
-+    will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, 0);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ENOENT);
-+    assert_true(test_ctx->dp_called);
-+}
-+
- int main(int argc, const char *argv[])
- {
-     poptContext pc;
-@@ -2218,6 +2585,24 @@ int main(int argc, const char *argv[])
-         new_single_domain_test(object_by_sid_group_missing_notfound),
-         new_multi_domain_test(object_by_sid_group_multiple_domains_found),
-         new_multi_domain_test(object_by_sid_group_multiple_domains_notfound),
-+
-+        new_single_domain_test(object_by_id_user_cache_valid),
-+        new_single_domain_test(object_by_id_user_cache_expired),
-+        new_single_domain_test(object_by_id_user_cache_midpoint),
-+        new_single_domain_test(object_by_id_user_ncache),
-+        new_single_domain_test(object_by_id_user_missing_found),
-+        new_single_domain_test(object_by_id_user_missing_notfound),
-+        new_multi_domain_test(object_by_id_user_multiple_domains_found),
-+        new_multi_domain_test(object_by_id_user_multiple_domains_notfound),
-+
-+        new_single_domain_test(object_by_id_group_cache_valid),
-+        new_single_domain_test(object_by_id_group_cache_expired),
-+        new_single_domain_test(object_by_id_group_cache_midpoint),
-+        new_single_domain_test(object_by_id_group_ncache),
-+        new_single_domain_test(object_by_id_group_missing_found),
-+        new_single_domain_test(object_by_id_group_missing_notfound),
-+        new_multi_domain_test(object_by_id_group_multiple_domains_found),
-+        new_multi_domain_test(object_by_id_group_multiple_domains_notfound),
-     };
- 
-     /* Set debug level to invalid value so we can deside if -d 0 was used. */
--- 
-2.14.3
-
diff --git a/SOURCES/0078-CACHE_REQ-Export-cache_req_search_ncache_add-as-cach.patch b/SOURCES/0078-CACHE_REQ-Export-cache_req_search_ncache_add-as-cach.patch
deleted file mode 100644
index cf3ca1f..0000000
--- a/SOURCES/0078-CACHE_REQ-Export-cache_req_search_ncache_add-as-cach.patch
+++ /dev/null
@@ -1,77 +0,0 @@
-From 26ba3d0b033e52e63d6ec438d7be0df97cb4ce1b Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 30 Oct 2017 20:18:36 +0100
-Subject: [PATCH 78/83] CACHE_REQ: Export cache_req_search_ncache_add() as
- cache_req private interface
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Previously, it was enough to add an entry to the negative cache of the
-domain being processed in cache_req (cr->domain). But the locator plugin
-can return any domain from the processed domain's subdomain list as
-well.
-
-Therefore, this patch extends the internal API for the possibility of
-setting the negative cache in another domain as well.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 800b1a27543fa83bc6cd73d8e2789f3cdbaf584a)
----
- src/responder/common/cache_req/cache_req_private.h |  3 +++
- src/responder/common/cache_req/cache_req_search.c  | 10 ++++++++--
- 2 files changed, 11 insertions(+), 2 deletions(-)
-
-diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h
-index 0f630542d38a277d1819063fa4134bd7d2525c90..a156fc65fed80693cdd0473613aeaaa3f5bb2269 100644
---- a/src/responder/common/cache_req/cache_req_private.h
-+++ b/src/responder/common/cache_req/cache_req_private.h
-@@ -116,6 +116,9 @@ cache_req_steal_data_and_send(TALLOC_CTX *mem_ctx,
-                               const char *domain,
-                               struct cache_req_data *data);
- 
-+void cache_req_search_ncache_add_to_domain(struct cache_req *cr,
-+                                           struct sss_domain_info *domain);
-+
- errno_t
- cache_req_add_result(TALLOC_CTX *mem_ctx,
-                      struct cache_req_result *new_result,
-diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c
-index 56d0345cd8f98de574961d3c9628ae7a4c24f9be..9d5ad8056cda0284b1cc32cd51d7cb0ec12ad667 100644
---- a/src/responder/common/cache_req/cache_req_search.c
-+++ b/src/responder/common/cache_req/cache_req_search.c
-@@ -60,7 +60,8 @@ static errno_t cache_req_search_ncache(struct cache_req *cr)
-     return EOK;
- }
- 
--static void cache_req_search_ncache_add(struct cache_req *cr)
-+void cache_req_search_ncache_add_to_domain(struct cache_req *cr,
-+                                           struct sss_domain_info *domain)
- {
-     errno_t ret;
- 
-@@ -73,7 +74,7 @@ static void cache_req_search_ncache_add(struct cache_req *cr)
-     CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Adding [%s] to negative cache\n",
-                     cr->debugobj);
- 
--    ret = cr->plugin->ncache_add_fn(cr->ncache, cr->domain, cr->data);
-+    ret = cr->plugin->ncache_add_fn(cr->ncache, domain, cr->data);
-     if (ret != EOK) {
-         CACHE_REQ_DEBUG(SSSDBG_MINOR_FAILURE, cr,
-                         "Cannot set negative cache for [%s] [%d]: %s\n",
-@@ -84,6 +85,11 @@ static void cache_req_search_ncache_add(struct cache_req *cr)
-     return;
- }
- 
-+static void cache_req_search_ncache_add(struct cache_req *cr)
-+{
-+    return cache_req_search_ncache_add_to_domain(cr, cr->domain);
-+}
-+
- static errno_t cache_req_search_ncache_filter(TALLOC_CTX *mem_ctx,
-                                               struct cache_req *cr,
-                                               struct ldb_result **_result)
--- 
-2.14.3
-
diff --git a/SOURCES/0079-CACHE_REQ-Add-plugin-methods-required-for-the-domain.patch b/SOURCES/0079-CACHE_REQ-Add-plugin-methods-required-for-the-domain.patch
deleted file mode 100644
index 50c6e3c..0000000
--- a/SOURCES/0079-CACHE_REQ-Add-plugin-methods-required-for-the-domain.patch
+++ /dev/null
@@ -1,458 +0,0 @@
-From 4127348220f6b32886fcc1e3f890a2e9fdedf7ed Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 30 Oct 2017 20:52:42 +0100
-Subject: [PATCH 79/83] CACHE_REQ: Add plugin methods required for the
- domain-locator request
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Adds three new cache_req plugin methods:
-    - cache_req_dp_get_domain_check_fn - check if it is time to run the
-                                         locator request again
-    - cache_req_dp_get_domain_send/recv_fn - run the locator itself
-
-The reason we added also the checker is that when the locator runs,
-we add a temporary entry into the negative cache that would denote that
-the locator ran and the ordinary domain negative cache (UID negcache,
-GID negcache, ..) were set for the domains and can be still used to
-skip domains that we know do not contain the account without calling
-the getAccountDomain handler again.
-
-If we didn't have this checker, requesting an entry from a domain
-further down the domain list would always call the locator, only
-to always receive the same results.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 2856dac5818265a6b4e42d768b73c65e333d14ff)
----
- src/responder/common/cache_req/cache_req_plugin.h  | 69 ++++++++++++++++++++++
- .../cache_req/plugins/cache_req_enum_groups.c      |  5 +-
- .../common/cache_req/plugins/cache_req_enum_svc.c  |  5 +-
- .../cache_req/plugins/cache_req_enum_users.c       |  5 +-
- .../cache_req/plugins/cache_req_group_by_filter.c  |  5 +-
- .../cache_req/plugins/cache_req_group_by_id.c      |  5 +-
- .../cache_req/plugins/cache_req_group_by_name.c    |  5 +-
- .../cache_req/plugins/cache_req_host_by_name.c     |  5 +-
- .../plugins/cache_req_initgroups_by_name.c         |  5 +-
- .../plugins/cache_req_initgroups_by_upn.c          |  5 +-
- .../cache_req/plugins/cache_req_netgroup_by_name.c |  5 +-
- .../cache_req/plugins/cache_req_object_by_id.c     |  5 +-
- .../cache_req/plugins/cache_req_object_by_name.c   |  5 +-
- .../cache_req/plugins/cache_req_object_by_sid.c    |  5 +-
- .../cache_req/plugins/cache_req_svc_by_name.c      |  5 +-
- .../cache_req/plugins/cache_req_svc_by_port.c      |  5 +-
- .../cache_req/plugins/cache_req_user_by_cert.c     |  5 +-
- .../cache_req/plugins/cache_req_user_by_filter.c   |  5 +-
- .../cache_req/plugins/cache_req_user_by_id.c       |  5 +-
- .../cache_req/plugins/cache_req_user_by_name.c     |  5 +-
- .../cache_req/plugins/cache_req_user_by_upn.c      |  5 +-
- 21 files changed, 149 insertions(+), 20 deletions(-)
-
-diff --git a/src/responder/common/cache_req/cache_req_plugin.h b/src/responder/common/cache_req/cache_req_plugin.h
-index 8117325506b2951c3966fa50506ed0d55273ee81..803d0f4fa5a54900a458d170177e89f82b398bd9 100644
---- a/src/responder/common/cache_req/cache_req_plugin.h
-+++ b/src/responder/common/cache_req/cache_req_plugin.h
-@@ -153,6 +153,72 @@ typedef bool
- (*cache_req_dp_recv_fn)(struct tevent_req *subreq,
-                         struct cache_req *cr);
- 
-+/**
-+ * Check whether the results of the domain locator can still
-+ * be considered valid or whether it is time to call the request
-+ * again.
-+ *
-+ * @param   resp_ctx        The responder context
-+ * @param   domain          The domain to check. This should be the domain-head,
-+ *                          because the locator works across a domain and its
-+ *                          subdomains.
-+ * @param   data            The cache req data that contain primarily the key
-+ *                          to look for.
-+ *
-+ * @return True if the locator plugin should be ran again, false if
-+ * @return False false ifthe lookup should just proceed with the
-+ * data that is already in the negative cache.
-+ */
-+typedef bool
-+(*cache_req_dp_get_domain_check_fn)(struct resp_ctx *rctx,
-+                                    struct sss_domain_info *domain,
-+                                    struct cache_req_data *data);
-+/**
-+ * Send Data Provider request to locate the domain
-+ * of an entry
-+ *
-+ * @param   resp_ctx        The responder context
-+ * @param   domain          The domain to check. This should be the domain-head,
-+ *                          because the locator works across a domain and its
-+ *                          subdomains.
-+ * @param   data            The cache req data that contain primarily the key
-+ *                          to look for.
-+ *
-+ *
-+ * @return Tevent request on success.
-+ * @return NULL on error.
-+ */
-+typedef struct tevent_req *
-+(*cache_req_dp_get_domain_send_fn)(TALLOC_CTX *mem_ctx,
-+                                   struct resp_ctx *rctx,
-+                                   struct sss_domain_info *domain,
-+                                   struct cache_req_data *data);
-+
-+/**
-+ * Process result of Data Provider find-domain request.
-+ *
-+ * Do not free subreq! It will be freed in the caller.
-+ *
-+ * @param       mem_ctx         The memory context that owns the _found_domain
-+ *                              result parameter
-+ * @param       subreq          The request to finish
-+ * @param       cr              The cache_req being processed
-+ * @param       _found_domain   The domain the request account belongs to. This
-+ *                              parameter can be NULL even on success, in that
-+ *                              case the account was not found and no lookups are
-+ *                              needed, all domains can be skipped in this case.
-+ *
-+ * @return EOK if the request did not encounter any error. In this
-+ * case, the _found_domain parameter can be considered authoritative,
-+ * regarless of its value
-+ * @return errno on error. _found_domain should be NULL in this case.
-+ */
-+typedef errno_t
-+(*cache_req_dp_get_domain_recv_fn)(TALLOC_CTX *mem_ctx,
-+                                   struct tevent_req *subreq,
-+                                   struct cache_req *cr,
-+                                   char **_found_domain);
-+
- struct cache_req_plugin {
-     /**
-      * Plugin name.
-@@ -223,6 +289,9 @@ struct cache_req_plugin {
-     cache_req_lookup_fn lookup_fn;
-     cache_req_dp_send_fn dp_send_fn;
-     cache_req_dp_recv_fn dp_recv_fn;
-+    cache_req_dp_get_domain_check_fn dp_get_domain_check_fn;
-+    cache_req_dp_get_domain_send_fn dp_get_domain_send_fn;
-+    cache_req_dp_get_domain_recv_fn dp_get_domain_recv_fn;
- };
- 
- extern const struct cache_req_plugin cache_req_user_by_name;
-diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c
-index 15350ca8279bc77c73bcc4abe51c97a8a37cb8c8..d302994e8903dea1e25b3da3762aa2ed783daebd 100644
---- a/src/responder/common/cache_req/plugins/cache_req_enum_groups.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_enum_groups.c
-@@ -86,7 +86,10 @@ const struct cache_req_plugin cache_req_enum_groups = {
-     .ncache_filter_fn = cache_req_enum_groups_ncache_filter,
-     .lookup_fn = cache_req_enum_groups_lookup,
-     .dp_send_fn = cache_req_enum_groups_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c
-index 72b2f1a7d2d2e02ce1a995098d1f26003444bddb..282dc1cc83b1fda91d4c4937f99598fbdd6ec625 100644
---- a/src/responder/common/cache_req/plugins/cache_req_enum_svc.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_enum_svc.c
-@@ -79,7 +79,10 @@ const struct cache_req_plugin cache_req_enum_svc = {
-     .ncache_filter_fn = NULL,
-     .lookup_fn = cache_req_enum_svc_lookup,
-     .dp_send_fn = cache_req_enum_svc_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_enum_users.c b/src/responder/common/cache_req/plugins/cache_req_enum_users.c
-index a3ddcdd45548a2fa7c367f3fb3be103c115dedb4..f83ff30fdbbaacdb3bfb605a65ce70fbd8eb3a89 100644
---- a/src/responder/common/cache_req/plugins/cache_req_enum_users.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_enum_users.c
-@@ -86,7 +86,10 @@ const struct cache_req_plugin cache_req_enum_users = {
-     .ncache_filter_fn = cache_req_enum_users_ncache_filter,
-     .lookup_fn = cache_req_enum_users_lookup,
-     .dp_send_fn = cache_req_enum_users_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c
-index aa89953b88313605041cce599999fc5bbc741525..009f0f88523c8c4c02a25f0f5d6a83187e0a17f8 100644
---- a/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_filter.c
-@@ -134,7 +134,10 @@ const struct cache_req_plugin cache_req_group_by_filter = {
-     .ncache_filter_fn = NULL,
-     .lookup_fn = cache_req_group_by_filter_lookup,
-     .dp_send_fn = cache_req_group_by_filter_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c
-index 5ca64283a781318bc4e4d6920fff989c3f3919b4..70381266712d2c27c95027b54efab201c5df7690 100644
---- a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c
-@@ -155,7 +155,10 @@ const struct cache_req_plugin cache_req_group_by_id = {
-     .ncache_filter_fn = cache_req_group_by_id_ncache_filter,
-     .lookup_fn = cache_req_group_by_id_lookup,
-     .dp_send_fn = cache_req_group_by_id_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c
-index 7706051818590af77da75d3e4c7f671c89170f82..3be0d5ea557bad11529b897be1d7706a8809acb1 100644
---- a/src/responder/common/cache_req/plugins/cache_req_group_by_name.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_name.c
-@@ -197,7 +197,10 @@ const struct cache_req_plugin cache_req_group_by_name = {
-     .ncache_filter_fn = NULL,
-     .lookup_fn = cache_req_group_by_name_lookup,
-     .dp_send_fn = cache_req_group_by_name_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_host_by_name.c b/src/responder/common/cache_req/plugins/cache_req_host_by_name.c
-index 56048c5e4bcadfb341f4b42d978d53484abd65d2..696d9e50d94e824d2664ed5a8fe3150b821d570e 100644
---- a/src/responder/common/cache_req/plugins/cache_req_host_by_name.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_host_by_name.c
-@@ -99,7 +99,10 @@ const struct cache_req_plugin cache_req_host_by_name = {
-     .ncache_filter_fn = NULL,
-     .lookup_fn = cache_req_host_by_name_lookup,
-     .dp_send_fn = cache_req_host_by_name_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c
-index 75ac44e1ad36238f01342eced9188d07daa50720..c5bea9d84921cc567bf794d3ba5a57fadb81695b 100644
---- a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_name.c
-@@ -212,7 +212,10 @@ const struct cache_req_plugin cache_req_initgroups_by_name = {
-     .ncache_filter_fn = NULL,
-     .lookup_fn = cache_req_initgroups_by_name_lookup,
-     .dp_send_fn = cache_req_initgroups_by_name_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c
-index dfb21ac1a0090a3ef9029b38f5b1e8bdda3440c6..9bd00f357c630bae4a52e356577000bd8de94013 100644
---- a/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_initgroups_by_upn.c
-@@ -123,5 +123,8 @@ const struct cache_req_plugin cache_req_initgroups_by_upn = {
-     .ncache_filter_fn = NULL,
-     .lookup_fn = cache_req_initgroups_by_upn_lookup,
-     .dp_send_fn = cache_req_initgroups_by_upn_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
-diff --git a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c
-index ef0775d0b8eac4d679450f436d8427cff9c04582..d370d342ec5b2c0e0e9f1f4ea90b34b59bff60b6 100644
---- a/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_netgroup_by_name.c
-@@ -131,7 +131,10 @@ const struct cache_req_plugin cache_req_netgroup_by_name = {
-     .ncache_filter_fn = NULL,
-     .lookup_fn = cache_req_netgroup_by_name_lookup,
-     .dp_send_fn = cache_req_netgroup_by_name_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c
-index 339bd4f5fef827acc1aa3c123d041e426d9e4782..2af95313cb2df0f46a61519ac962074033f34a12 100644
---- a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c
-@@ -129,7 +129,10 @@ const struct cache_req_plugin cache_req_object_by_id = {
-     .ncache_filter_fn = cache_req_object_by_id_ncache_filter,
-     .lookup_fn = cache_req_object_by_id_lookup,
-     .dp_send_fn = cache_req_object_by_id_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c
-index 854d0b83c420ebebcb5e0e079c707081fa313632..a740fbb8d05efb4601e8e40d2a07896ecb251d4e 100644
---- a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c
-@@ -207,7 +207,10 @@ const struct cache_req_plugin cache_req_object_by_name = {
-     .ncache_filter_fn = NULL,
-     .lookup_fn = cache_req_object_by_name_lookup,
-     .dp_send_fn = cache_req_object_by_name_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c b/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c
-index 039a79df7bb1ab213ce4334835e9fc18e6d0faac..1af638ff9d94ffa3bf6e418433d5c4e98acfb2b8 100644
---- a/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_sid.c
-@@ -123,7 +123,10 @@ const struct cache_req_plugin cache_req_object_by_sid = {
-     .ncache_filter_fn = NULL,
-     .lookup_fn = cache_req_object_by_sid_lookup,
-     .dp_send_fn = cache_req_object_by_sid_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c
-index 4c32d9977cc06e43eed3a90e7dcf107e91efefb5..5b17051031e35c5767d27b19c922325cee4b6eac 100644
---- a/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_name.c
-@@ -155,7 +155,10 @@ const struct cache_req_plugin cache_req_svc_by_name = {
-     .ncache_filter_fn = NULL,
-     .lookup_fn = cache_req_svc_by_name_lookup,
-     .dp_send_fn = cache_req_svc_by_name_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c
-index 1e998f642c766d15d3f6fe777aa5c789629508e2..4c005df3972386fef3c5a858a2b691cb2a63fd57 100644
---- a/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_svc_by_port.c
-@@ -128,7 +128,10 @@ const struct cache_req_plugin cache_req_svc_by_port = {
-     .ncache_filter_fn = NULL,
-     .lookup_fn = cache_req_svc_by_port_lookup,
-     .dp_send_fn = cache_req_svc_by_port_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c b/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c
-index 7a0c7d8ce1644f1c41b64c6903e4e20eb3c2c081..a2dc1fad28ca09eeba77c563f17518671095ab42 100644
---- a/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_cert.c
-@@ -97,7 +97,10 @@ const struct cache_req_plugin cache_req_user_by_cert = {
-     .ncache_filter_fn = NULL,
-     .lookup_fn = cache_req_user_by_cert_lookup,
-     .dp_send_fn = cache_req_user_by_cert_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c
-index dd3f42e855389ecc73690e4d18c4977253b108a6..42b6e816372c51623f29e8a7e28859a9dfca640f 100644
---- a/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_filter.c
-@@ -134,7 +134,10 @@ const struct cache_req_plugin cache_req_user_by_filter = {
-     .ncache_filter_fn = NULL,
-     .lookup_fn = cache_req_user_by_filter_lookup,
-     .dp_send_fn = cache_req_user_by_filter_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c
-index 913f9be5bcc2dfd074b52cb3b15fb6948826e831..254330e92cc801b84bfb5e308d6d90ac54507d77 100644
---- a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c
-@@ -155,7 +155,10 @@ const struct cache_req_plugin cache_req_user_by_id = {
-     .ncache_filter_fn = cache_req_user_by_id_ncache_filter,
-     .lookup_fn = cache_req_user_by_id_lookup,
-     .dp_send_fn = cache_req_user_by_id_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c
-index 2e49de938d0af50089d0cf49860441c2b6ea679c..d24a2221b2a69d24d360c46c41073e19dc79036b 100644
---- a/src/responder/common/cache_req/plugins/cache_req_user_by_name.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_name.c
-@@ -202,7 +202,10 @@ const struct cache_req_plugin cache_req_user_by_name = {
-     .ncache_filter_fn = NULL,
-     .lookup_fn = cache_req_user_by_name_lookup,
-     .dp_send_fn = cache_req_user_by_name_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c b/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c
-index b8bcd241ed79c510aca214ad3788215ae2997d20..e08ab70ae081a5d532d7ab436687978416e7c493 100644
---- a/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_upn.c
-@@ -128,5 +128,8 @@ const struct cache_req_plugin cache_req_user_by_upn = {
-     .ncache_filter_fn = NULL,
-     .lookup_fn = cache_req_user_by_upn_lookup,
-     .dp_send_fn = cache_req_user_by_upn_dp_send,
--    .dp_recv_fn = cache_req_common_dp_recv
-+    .dp_recv_fn = cache_req_common_dp_recv,
-+    .dp_get_domain_check_fn = NULL,
-+    .dp_get_domain_send_fn = NULL,
-+    .dp_get_domain_recv_fn = NULL,
- };
--- 
-2.14.3
-
diff --git a/SOURCES/0080-CACHE_REQ-Add-a-private-request-cache_req_locate_dom.patch b/SOURCES/0080-CACHE_REQ-Add-a-private-request-cache_req_locate_dom.patch
deleted file mode 100644
index f00f399..0000000
--- a/SOURCES/0080-CACHE_REQ-Add-a-private-request-cache_req_locate_dom.patch
+++ /dev/null
@@ -1,177 +0,0 @@
-From d30dd0f52d452562e47f9a30b1630eff2f817792 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 30 Oct 2017 20:21:05 +0100
-Subject: [PATCH 80/83] CACHE_REQ: Add a private request
- cache_req_locate_domain()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Adds a new request cache_req_locate_domain_send/recv. This request, if the
-plugin that is being processed supports the locator, will call the plugin's
-dp_get_domain_send_fn(). On any error, the request returns just the error
-code. On success, the request returns the domain the object was found at.
-
-If the getAccountDomain() method returns that the back end does not support
-the locator method, all further getAccountDomain() calls are disabled for
-that domain.
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3468
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit 0a0b34f5fbe8f4a8c533a7d65f0f2961ee264054)
----
- src/responder/common/cache_req/cache_req_private.h |  7 ++
- src/responder/common/cache_req/cache_req_search.c  | 93 ++++++++++++++++++++++
- src/util/util_errors.c                             |  1 +
- src/util/util_errors.h                             |  1 +
- 4 files changed, 102 insertions(+)
-
-diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h
-index a156fc65fed80693cdd0473613aeaaa3f5bb2269..9586e3788045ff44eb2a4b626dc7fcaf11ec8028 100644
---- a/src/responder/common/cache_req/cache_req_private.h
-+++ b/src/responder/common/cache_req/cache_req_private.h
-@@ -106,6 +106,13 @@ errno_t cache_req_search_recv(TALLOC_CTX *mem_ctx,
-                               struct ldb_result **_result,
-                               bool *_dp_success);
- 
-+struct tevent_req *cache_req_locate_domain_send(TALLOC_CTX *mem_ctx,
-+                                                struct tevent_context *ev,
-+                                                struct cache_req *cr);
-+errno_t cache_req_locate_domain_recv(TALLOC_CTX *mem_ctx,
-+                                     struct tevent_req *req,
-+                                     char **_found_domain);
-+
- struct tevent_req *
- cache_req_steal_data_and_send(TALLOC_CTX *mem_ctx,
-                               struct tevent_context *ev,
-diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c
-index 9d5ad8056cda0284b1cc32cd51d7cb0ec12ad667..3365962d473b0982945de2541e44ba86b43a0db5 100644
---- a/src/responder/common/cache_req/cache_req_search.c
-+++ b/src/responder/common/cache_req/cache_req_search.c
-@@ -485,3 +485,96 @@ errno_t cache_req_search_recv(TALLOC_CTX *mem_ctx,
- 
-     return EOK;
- }
-+
-+struct cache_req_locate_domain_state {
-+    struct cache_req *cr;
-+
-+    char *found_domain;
-+};
-+
-+static void cache_req_locate_domain_done(struct tevent_req *subreq);
-+
-+struct tevent_req *cache_req_locate_domain_send(TALLOC_CTX *mem_ctx,
-+                                                struct tevent_context *ev,
-+                                                struct cache_req *cr)
-+{
-+    struct cache_req_locate_domain_state *state;
-+    struct tevent_req *req;
-+    struct tevent_req *subreq;
-+    errno_t ret;
-+    bool should_run;
-+
-+    req = tevent_req_create(mem_ctx, &state, struct cache_req_locate_domain_state);
-+    if (req == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
-+        return NULL;
-+    }
-+    state->cr = cr;
-+
-+    should_run = cr->plugin->dp_get_domain_check_fn(cr->rctx,
-+                                                    get_domains_head(cr->domain),
-+                                                    cr->data);
-+    if (should_run == false) {
-+        /* The request was tried too recently, don't issue a new one
-+         * as its results are still valid
-+         */
-+        ret = ERR_GET_ACCT_DOM_CACHED;
-+        goto immediate;
-+    }
-+
-+    subreq = cr->plugin->dp_get_domain_send_fn(state,
-+                                               cr->rctx,
-+                                               get_domains_head(cr->domain),
-+                                               cr->data);
-+    if (subreq == NULL) {
-+        ret = ENOMEM;
-+        goto immediate;
-+    }
-+    tevent_req_set_callback(subreq, cache_req_locate_domain_done, req);
-+    return req;
-+
-+immediate:
-+    if (ret == EOK) {
-+        tevent_req_done(req);
-+    } else {
-+        tevent_req_error(req, ret);
-+    }
-+    tevent_req_post(req, ev);
-+    return req;
-+}
-+
-+static void cache_req_locate_domain_done(struct tevent_req *subreq)
-+{
-+    struct tevent_req *req;
-+    struct cache_req_locate_domain_state *state;
-+    errno_t ret;
-+
-+    req = tevent_req_callback_data(subreq, struct tevent_req);
-+    state = tevent_req_data(req, struct cache_req_locate_domain_state);
-+
-+    ret = state->cr->plugin->dp_get_domain_recv_fn(state,
-+                                                   subreq,
-+                                                   state->cr,
-+                                                   &state->found_domain);
-+    talloc_zfree(subreq);
-+    if (ret != EOK) {
-+        tevent_req_error(req, ret);
-+        return;
-+    }
-+
-+    tevent_req_done(req);
-+}
-+
-+errno_t cache_req_locate_domain_recv(TALLOC_CTX *mem_ctx,
-+                                     struct tevent_req *req,
-+                                     char **_found_domain)
-+{
-+    struct cache_req_locate_domain_state *state = NULL;
-+
-+    state = tevent_req_data(req, struct cache_req_locate_domain_state);
-+
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    *_found_domain = talloc_steal(mem_ctx, state->found_domain);
-+    return EOK;
-+}
-diff --git a/src/util/util_errors.c b/src/util/util_errors.c
-index 9a9ba3f3063cab4afb538c3a58527a2d2ed3fffd..06c620b40aaa00d6ce58ace3a28449ffbdf8da88 100644
---- a/src/util/util_errors.c
-+++ b/src/util/util_errors.c
-@@ -116,6 +116,7 @@ struct err_string error_to_str[] = {
-     { "Unable to verify peer" }, /* ERR_UNABLE_TO_VERIFY_PEER */
-     { "Unable to resolve host" }, /* ERR_UNABLE_TO_RESOLVE_HOST */
-     { "GetAccountDomain() not supported" }, /* ERR_GET_ACCT_DOM_NOT_SUPPORTED */
-+    { "The last GetAccountDomain() result is still valid" }, /* ERR_GET_ACCT_DOM_CACHED */
-     { "ERR_LAST" } /* ERR_LAST */
- };
- 
-diff --git a/src/util/util_errors.h b/src/util/util_errors.h
-index 5ee9862c3f2f60c078693b1b85a40f15436e818c..bebd6e198fc0077891a602f80182a993ce3f789b 100644
---- a/src/util/util_errors.h
-+++ b/src/util/util_errors.h
-@@ -138,6 +138,7 @@ enum sssd_errors {
-     ERR_UNABLE_TO_VERIFY_PEER,
-     ERR_UNABLE_TO_RESOLVE_HOST,
-     ERR_GET_ACCT_DOM_NOT_SUPPORTED,
-+    ERR_GET_ACCT_DOM_CACHED,
-     ERR_LAST            /* ALWAYS LAST */
- };
- 
--- 
-2.14.3
-
diff --git a/SOURCES/0081-CACHE_REQ-Implement-the-plugin-methods-that-utilize-.patch b/SOURCES/0081-CACHE_REQ-Implement-the-plugin-methods-that-utilize-.patch
deleted file mode 100644
index 6c0f694..0000000
--- a/SOURCES/0081-CACHE_REQ-Implement-the-plugin-methods-that-utilize-.patch
+++ /dev/null
@@ -1,413 +0,0 @@
-From 7482c6affd4dfa77a8d465ff0283617792847725 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 6 Nov 2017 15:52:11 +0100
-Subject: [PATCH 81/83] CACHE_REQ: Implement the plugin methods that utilize
- the domain locator API
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Mainly, this patch adds handlers for the dp_get_domain_check_fn(),
-dp_get_domain_send_fn() and dp_get_domain_recv_fn() functions to
-requests that resolve objects by ID.
-
-This patch also adds domain-local negcache setter for by-id methods
-Previously, the by-ID methods only used global negative cache setters
-because the ID space is global and we always iterated over all domains.
-
-However, with addition of the domain locator plugin, we want also
-to skip only certain domains and the easiest way to to so is to add
-the IDs for domains that do not contain these IDs to the negative cache
-with the get-account-domain request.
-
-Therefore this patch also adds per-domain negative cache setters for
-the three plugins that search by ID.
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit a6eb9c4c3ff68d134bc745e8374f182737e9696b)
----
- src/responder/common/cache_req/cache_req_private.h |  5 ++
- .../common/cache_req/plugins/cache_req_common.c    | 17 +++++
- .../cache_req/plugins/cache_req_group_by_id.c      | 62 +++++++++++++++--
- .../cache_req/plugins/cache_req_object_by_id.c     | 77 ++++++++++++++++++++--
- .../cache_req/plugins/cache_req_user_by_id.c       | 63 ++++++++++++++++--
- src/tests/cmocka/common_mock_resp_dp.c             | 23 +++++++
- 6 files changed, 235 insertions(+), 12 deletions(-)
-
-diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h
-index 9586e3788045ff44eb2a4b626dc7fcaf11ec8028..95f24c0e5b9ab1150591d308c7288c57fe478c5d 100644
---- a/src/responder/common/cache_req/cache_req_private.h
-+++ b/src/responder/common/cache_req/cache_req_private.h
-@@ -187,4 +187,9 @@ bool
- cache_req_common_dp_recv(struct tevent_req *subreq,
-                          struct cache_req *cr);
- 
-+errno_t
-+cache_reg_common_get_acct_domain_recv(TALLOC_CTX *mem_ctx,
-+                                      struct tevent_req *subreq,
-+                                      struct cache_req *cr,
-+                                      char **_domain);
- #endif /* _CACHE_REQ_PRIVATE_H_ */
-diff --git a/src/responder/common/cache_req/plugins/cache_req_common.c b/src/responder/common/cache_req/plugins/cache_req_common.c
-index 1f86258bc14c7a382712959f24a4ec4c153572d4..408c91949ceb3ecaf743f270f58f4e3fcfc3ccb1 100644
---- a/src/responder/common/cache_req/plugins/cache_req_common.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_common.c
-@@ -147,3 +147,20 @@ done:
-     talloc_free(err_msg);
-     return bret;
- }
-+
-+errno_t
-+cache_reg_common_get_acct_domain_recv(TALLOC_CTX *mem_ctx,
-+                                      struct tevent_req *subreq,
-+                                      struct cache_req *cr,
-+                                      char **_domain)
-+{
-+    errno_t ret;
-+
-+    ret = sss_dp_get_account_domain_recv(mem_ctx, subreq, _domain);
-+    if (ret != EOK) {
-+        CACHE_REQ_DEBUG(SSSDBG_MINOR_FAILURE, cr,
-+                        "Could not get account domain [%d]: %s\n",
-+                        ret, sss_strerror(ret));
-+    }
-+    return ret;
-+}
-diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c
-index 70381266712d2c27c95027b54efab201c5df7690..ce84b1b4458b447ff6b4b036c6e8fe8f4d7758c8 100644
---- a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c
-@@ -39,6 +39,15 @@ cache_req_group_by_id_ncache_check(struct sss_nc_ctx *ncache,
-                                    struct sss_domain_info *domain,
-                                    struct cache_req_data *data)
- {
-+    errno_t ret;
-+
-+    if (domain != NULL) {
-+        ret = sss_ncache_check_gid(ncache, domain, data->id);
-+        if (ret == EEXIST) {
-+            return ret;
-+        }
-+    }
-+
-     return sss_ncache_check_gid(ncache, NULL, data->id);
- }
- 
-@@ -57,6 +66,14 @@ cache_req_group_by_id_global_ncache_add(struct sss_nc_ctx *ncache,
-     return sss_ncache_set_gid(ncache, false, NULL, data->id);
- }
- 
-+static errno_t
-+cache_req_group_by_id_ncache_add(struct sss_nc_ctx *ncache,
-+                                 struct sss_domain_info *domain,
-+                                 struct cache_req_data *data)
-+{
-+    return sss_ncache_set_gid(ncache, false, domain, data->id);
-+}
-+
- static errno_t
- cache_req_group_by_id_lookup(TALLOC_CTX *mem_ctx,
-                              struct cache_req *cr,
-@@ -132,6 +149,43 @@ cache_req_group_by_id_dp_send(TALLOC_CTX *mem_ctx,
-                                    SSS_DP_GROUP, string, id, flag);
- }
- 
-+static bool
-+cache_req_group_by_id_get_domain_check(struct resp_ctx *rctx,
-+                                       struct sss_domain_info *domain,
-+                                       struct cache_req_data *data)
-+{
-+    int nret;
-+
-+    nret = sss_ncache_check_locate_gid(rctx->ncache, domain, data->id);
-+    if (nret == EEXIST) {
-+        return false;
-+    }
-+
-+    return true;
-+}
-+
-+static struct tevent_req *
-+cache_req_group_by_id_get_domain_send(TALLOC_CTX *mem_ctx,
-+                                      struct resp_ctx *rctx,
-+                                      struct sss_domain_info *domain,
-+                                      struct cache_req_data *data)
-+{
-+    int nret;
-+
-+    nret = sss_ncache_set_locate_gid(rctx->ncache, domain, data->id);
-+    if (nret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              "Cannot set negative cache, this might result in performance degradation\n");
-+        /* Not fatal */
-+    }
-+
-+    return sss_dp_get_account_domain_send(mem_ctx,
-+                                          rctx,
-+                                          domain,
-+                                          SSS_DP_GROUP,
-+                                          data->id);
-+}
-+
- const struct cache_req_plugin cache_req_group_by_id = {
-     .name = "Group by ID",
-     .attr_expiration = SYSDB_CACHE_EXPIRE,
-@@ -151,14 +205,14 @@ const struct cache_req_plugin cache_req_group_by_id = {
-     .create_debug_name_fn = cache_req_group_by_id_create_debug_name,
-     .global_ncache_add_fn = cache_req_group_by_id_global_ncache_add,
-     .ncache_check_fn = cache_req_group_by_id_ncache_check,
--    .ncache_add_fn = NULL,
-+    .ncache_add_fn = cache_req_group_by_id_ncache_add,
-     .ncache_filter_fn = cache_req_group_by_id_ncache_filter,
-     .lookup_fn = cache_req_group_by_id_lookup,
-     .dp_send_fn = cache_req_group_by_id_dp_send,
-     .dp_recv_fn = cache_req_common_dp_recv,
--    .dp_get_domain_check_fn = NULL,
--    .dp_get_domain_send_fn = NULL,
--    .dp_get_domain_recv_fn = NULL,
-+    .dp_get_domain_check_fn = cache_req_group_by_id_get_domain_check,
-+    .dp_get_domain_send_fn = cache_req_group_by_id_get_domain_send,
-+    .dp_get_domain_recv_fn = cache_reg_common_get_acct_domain_recv,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c
-index 2af95313cb2df0f46a61519ac962074033f34a12..1327b480c1b1b68f9826fa229c9b001f2d92b79b 100644
---- a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c
-@@ -83,6 +83,26 @@ cache_req_object_by_id_global_ncache_add(struct sss_nc_ctx *ncache,
-     return EOK;
- }
- 
-+static errno_t
-+cache_req_object_by_id_ncache_add(struct sss_nc_ctx *ncache,
-+                                  struct sss_domain_info *domain,
-+                                  struct cache_req_data *data)
-+{
-+    errno_t ret;
-+
-+    ret = sss_ncache_set_uid(ncache, false, domain, data->id);
-+    if (ret != EOK) {
-+        return ret;
-+    }
-+
-+    ret = sss_ncache_set_gid(ncache, false, domain, data->id);
-+    if (ret != EOK) {
-+        return ret;
-+    }
-+
-+    return EOK;
-+}
-+
- static errno_t
- cache_req_object_by_id_lookup(TALLOC_CTX *mem_ctx,
-                               struct cache_req *cr,
-@@ -106,6 +126,55 @@ cache_req_object_by_id_dp_send(TALLOC_CTX *mem_ctx,
-                                    cr->data->id, NULL);
- }
- 
-+static bool
-+cache_req_object_by_id_get_domain_check(struct resp_ctx *rctx,
-+                                        struct sss_domain_info *domain,
-+                                        struct cache_req_data *data)
-+{
-+    int nret;
-+
-+    nret = sss_ncache_check_locate_uid(rctx->ncache, domain, data->id);
-+    if (nret == EEXIST) {
-+        nret = sss_ncache_check_locate_gid(rctx->ncache, domain, data->id);
-+        if (nret == EEXIST) {
-+            return false;
-+        }
-+    }
-+
-+    return true;
-+}
-+
-+static struct tevent_req *
-+cache_req_object_by_id_get_domain_send(TALLOC_CTX *mem_ctx,
-+                                       struct resp_ctx *rctx,
-+                                       struct sss_domain_info *domain,
-+                                       struct cache_req_data *data)
-+{
-+    int nret;
-+
-+    nret = sss_ncache_set_locate_uid(rctx->ncache, domain, data->id);
-+    if (nret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              "Cannot set negative cache, this might result in "
-+              "performance degradation\n");
-+        /* Not fatal */
-+    }
-+
-+    nret = sss_ncache_set_locate_gid(rctx->ncache, domain, data->id);
-+    if (nret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              "Cannot set negative cache, this might result in "
-+              "performance degradation\n");
-+        /* Not fatal */
-+    }
-+
-+    return sss_dp_get_account_domain_send(mem_ctx,
-+                                          rctx,
-+                                          domain,
-+                                          SSS_DP_USER_AND_GROUP,
-+                                          data->id);
-+}
-+
- const struct cache_req_plugin cache_req_object_by_id = {
-     .name = "Object by ID",
-     .attr_expiration = SYSDB_CACHE_EXPIRE,
-@@ -125,14 +194,14 @@ const struct cache_req_plugin cache_req_object_by_id = {
-     .create_debug_name_fn = cache_req_object_by_id_create_debug_name,
-     .global_ncache_add_fn = cache_req_object_by_id_global_ncache_add,
-     .ncache_check_fn = cache_req_object_by_id_ncache_check,
--    .ncache_add_fn = NULL,
-+    .ncache_add_fn = cache_req_object_by_id_ncache_add,
-     .ncache_filter_fn = cache_req_object_by_id_ncache_filter,
-     .lookup_fn = cache_req_object_by_id_lookup,
-     .dp_send_fn = cache_req_object_by_id_dp_send,
-     .dp_recv_fn = cache_req_common_dp_recv,
--    .dp_get_domain_check_fn = NULL,
--    .dp_get_domain_send_fn = NULL,
--    .dp_get_domain_recv_fn = NULL,
-+    .dp_get_domain_check_fn = cache_req_object_by_id_get_domain_check,
-+    .dp_get_domain_send_fn = cache_req_object_by_id_get_domain_send,
-+    .dp_get_domain_recv_fn = cache_reg_common_get_acct_domain_recv,
- };
- 
- struct tevent_req *
-diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c
-index 254330e92cc801b84bfb5e308d6d90ac54507d77..656fa41af5f39f68c64e241aa97c4eaf3ec57395 100644
---- a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c
-@@ -39,6 +39,15 @@ cache_req_user_by_id_ncache_check(struct sss_nc_ctx *ncache,
-                                   struct sss_domain_info *domain,
-                                   struct cache_req_data *data)
- {
-+    errno_t ret;
-+
-+    if (domain != NULL) {
-+        ret = sss_ncache_check_uid(ncache, domain, data->id);
-+        if (ret == EEXIST) {
-+            return ret;
-+        }
-+    }
-+
-     return sss_ncache_check_uid(ncache, NULL, data->id);
- }
- 
-@@ -57,6 +66,14 @@ cache_req_user_by_id_global_ncache_add(struct sss_nc_ctx *ncache,
-     return sss_ncache_set_uid(ncache, false, NULL, data->id);
- }
- 
-+static errno_t
-+cache_req_user_by_id_ncache_add(struct sss_nc_ctx *ncache,
-+                                struct sss_domain_info *domain,
-+                                struct cache_req_data *data)
-+{
-+    return sss_ncache_set_uid(ncache, false, domain, data->id);
-+}
-+
- static errno_t
- cache_req_user_by_id_lookup(TALLOC_CTX *mem_ctx,
-                             struct cache_req *cr,
-@@ -132,6 +149,44 @@ cache_req_user_by_id_dp_send(TALLOC_CTX *mem_ctx,
-                                    SSS_DP_USER, string, id, flag);
- }
- 
-+static bool
-+cache_req_user_by_id_get_domain_check(struct resp_ctx *rctx,
-+                                      struct sss_domain_info *domain,
-+                                      struct cache_req_data *data)
-+{
-+    int nret;
-+
-+    nret = sss_ncache_check_locate_uid(rctx->ncache, domain, data->id);
-+    if (nret == EEXIST) {
-+        return false;
-+    }
-+
-+    return true;
-+}
-+
-+static struct tevent_req *
-+cache_req_user_by_id_get_domain_send(TALLOC_CTX *mem_ctx,
-+                                     struct resp_ctx *rctx,
-+                                     struct sss_domain_info *domain,
-+                                     struct cache_req_data *data)
-+{
-+    int nret;
-+
-+    nret = sss_ncache_set_locate_uid(rctx->ncache, domain, data->id);
-+    if (nret != EOK) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+              "Cannot set negative cache, this might result in "
-+              "performance degradation\n");
-+        /* Not fatal */
-+    }
-+
-+    return sss_dp_get_account_domain_send(mem_ctx,
-+                                          rctx,
-+                                          domain,
-+                                          SSS_DP_USER,
-+                                          data->id);
-+}
-+
- const struct cache_req_plugin cache_req_user_by_id = {
-     .name = "User by ID",
-     .attr_expiration = SYSDB_CACHE_EXPIRE,
-@@ -151,14 +206,14 @@ const struct cache_req_plugin cache_req_user_by_id = {
-     .create_debug_name_fn = cache_req_user_by_id_create_debug_name,
-     .global_ncache_add_fn = cache_req_user_by_id_global_ncache_add,
-     .ncache_check_fn = cache_req_user_by_id_ncache_check,
--    .ncache_add_fn = NULL,
-+    .ncache_add_fn = cache_req_user_by_id_ncache_add,
-     .ncache_filter_fn = cache_req_user_by_id_ncache_filter,
-     .lookup_fn = cache_req_user_by_id_lookup,
-     .dp_send_fn = cache_req_user_by_id_dp_send,
-     .dp_recv_fn = cache_req_common_dp_recv,
--    .dp_get_domain_check_fn = NULL,
--    .dp_get_domain_send_fn = NULL,
--    .dp_get_domain_recv_fn = NULL,
-+    .dp_get_domain_check_fn = cache_req_user_by_id_get_domain_check,
-+    .dp_get_domain_send_fn = cache_req_user_by_id_get_domain_send,
-+    .dp_get_domain_recv_fn = cache_reg_common_get_acct_domain_recv,
- };
- 
- struct tevent_req *
-diff --git a/src/tests/cmocka/common_mock_resp_dp.c b/src/tests/cmocka/common_mock_resp_dp.c
-index 4b38a38e6f53499132f9fe14a0ec0af157cf85ca..f21ca53ad0d6b7f4ed28d0c1d9e491af31355d43 100644
---- a/src/tests/cmocka/common_mock_resp_dp.c
-+++ b/src/tests/cmocka/common_mock_resp_dp.c
-@@ -179,3 +179,26 @@ errno_t sss_dp_get_domains_recv(struct tevent_req *req)
- {
-     return test_request_recv(req);
- }
-+
-+struct tevent_req *
-+sss_dp_get_account_domain_send(TALLOC_CTX *mem_ctx,
-+                               struct resp_ctx *rctx,
-+                               struct sss_domain_info *domain,
-+                               enum sss_dp_acct_type type,
-+                               uint32_t opt_id)
-+{
-+    return test_req_succeed_send(mem_ctx, rctx->ev);
-+}
-+
-+errno_t sss_dp_get_account_domain_recv(TALLOC_CTX *mem_ctx,
-+                                       struct tevent_req *req,
-+                                       char **_domain)
-+{
-+    errno_t ret;
-+
-+    ret = sss_mock_type(errno_t);
-+    if (ret == EOK) {
-+        *_domain = sss_mock_ptr_type(char *);
-+    }
-+    return ret;
-+}
--- 
-2.14.3
-
diff --git a/SOURCES/0082-CACHE_REQ-Use-the-domain-locator-request-to-only-sea.patch b/SOURCES/0082-CACHE_REQ-Use-the-domain-locator-request-to-only-sea.patch
deleted file mode 100644
index 713322a..0000000
--- a/SOURCES/0082-CACHE_REQ-Use-the-domain-locator-request-to-only-sea.patch
+++ /dev/null
@@ -1,2048 +0,0 @@
-From 1b4b03720c409b183debe0e0532b1009301e9cb2 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Sun, 19 Nov 2017 22:47:00 +0100
-Subject: [PATCH 82/83] CACHE_REQ: Use the domain-locator request to only
- search domains where the entry was found
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Uses the internal cache_req interface around the getAccountDomain to only
-search the domain returned by the cache_req_locate_domain_recv() request.
-
-If that request returns that no domain matched, all domains (belonging
-to the currently processed main domain) are skipped by setting the
-per-type negative cache.
-
-if a domain is reported as containing an object, all domains except that
-one are marked with the negative cache entries.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3468
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit f2a5e29f063f9d623c1336d76f4b2bc500c1a5e2)
----
- src/responder/common/cache_req/cache_req.c        |  402 +++++-
- src/responder/common/cache_req/cache_req_domain.h |    1 +
- src/tests/cmocka/test_responder_cache_req.c       | 1373 +++++++++++++++++++++
- 3 files changed, 1758 insertions(+), 18 deletions(-)
-
-diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c
-index 110df561101be538e3f0496addfa2e14e42ea918..ad9bc040dd999a205713141e6a1512e47b69c45e 100644
---- a/src/responder/common/cache_req/cache_req.c
-+++ b/src/responder/common/cache_req/cache_req.c
-@@ -363,6 +363,53 @@ static void cache_req_global_ncache_add(struct cache_req *cr)
-     return;
- }
- 
-+static bool cache_req_check_acct_domain_lookup_type(struct cache_req *cr,
-+                                                    struct sss_domain_info *dom)
-+{
-+    struct sss_domain_info *head;
-+    int nret;
-+
-+    head = get_domains_head(dom);
-+    if (head == NULL) {
-+        return false;
-+    }
-+
-+    nret = sss_ncache_check_domain_locate_type(cr->rctx->ncache,
-+                                               head,
-+                                               cr->plugin->name);
-+    if (nret == ENOENT) {
-+        return true;
-+    }
-+    return false;
-+}
-+
-+static errno_t cache_req_set_acct_domain_lookup_type(struct cache_req *cr,
-+                                                     struct sss_domain_info *dom)
-+{
-+    struct sss_domain_info *head;
-+
-+    head = get_domains_head(dom);
-+    if (head == NULL) {
-+        return EINVAL;
-+    }
-+
-+    return sss_ncache_set_domain_locate_type(cr->rctx->ncache,
-+                                             head,
-+                                             cr->plugin->name);
-+}
-+
-+static void cache_req_domain_set_locate_flag(struct cache_req_domain *domains,
-+                                             struct cache_req *cr)
-+{
-+    struct cache_req_domain *crd_iter;
-+
-+    DLIST_FOR_EACH(crd_iter, domains) {
-+        if (cache_req_check_acct_domain_lookup_type(cr, crd_iter->domain)) {
-+            crd_iter->locate_domain = true;
-+        }
-+    }
-+}
-+
- static bool
- cache_req_assume_upn(struct cache_req *cr)
- {
-@@ -391,6 +438,227 @@ cache_req_assume_upn(struct cache_req *cr)
-     return true;
- }
- 
-+struct cache_req_locate_dom_state {
-+    /* input data */
-+    struct tevent_context *ev;
-+    struct cache_req *cr;
-+    struct cache_req_domain *req_domains;
-+
-+    /* Return values in case the first cache lookup succeeds */
-+    struct ldb_result *result;
-+    bool dp_success;
-+};
-+
-+static void cache_req_locate_dom_cache_done(struct tevent_req *subreq);
-+static void cache_req_locate_dom_done(struct tevent_req *subreq);
-+static void cache_req_locate_dom_mark_neg_all(
-+                                struct cache_req_locate_dom_state *state);
-+static void cache_req_locate_dom_mark_neg_domains(
-+                                struct cache_req_locate_dom_state *state,
-+                                const char *found_domain_name);
-+
-+static struct tevent_req *cache_req_locate_dom_send(TALLOC_CTX *mem_ctx,
-+                                                    struct tevent_context *ev,
-+                                                    struct cache_req *cr,
-+                                                    struct cache_req_domain *req_domains)
-+{
-+    struct tevent_req *req;
-+    struct tevent_req *subreq;
-+    struct cache_req_locate_dom_state *state = NULL;
-+    errno_t ret;
-+
-+    req = tevent_req_create(mem_ctx, &state,
-+                            struct cache_req_locate_dom_state);
-+    if (req == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
-+        return NULL;
-+    }
-+    state->ev = ev;
-+    state->cr = cr;
-+    state->req_domains = req_domains;
-+
-+    /* It is wasteful to run the domain locator request if the results are
-+     * present in the cache, because the domain locator always contacts
-+     * the DP. Therefore, first run a cache-only search and only if the
-+     * requested data is not available, run the locator
-+     *
-+     * FIXME - this could be optimized further if we are running the
-+     * second iteration with cache_first, then we don't need to search
-+     * again
-+     */
-+    subreq = cache_req_search_send(state,
-+                                   state->ev,
-+                                   state->cr,
-+                                   false,       /* Don't bypass cache */
-+                                   true);       /* Do bypass DP */
-+    if (subreq == NULL) {
-+        ret = ENOMEM;
-+        goto immediately;
-+    }
-+    tevent_req_set_callback(subreq, cache_req_locate_dom_cache_done, req);
-+
-+    return req;
-+
-+immediately:
-+    tevent_req_error(req, ret);
-+    tevent_req_post(req, ev);
-+    return req;
-+}
-+
-+static void cache_req_locate_dom_cache_done(struct tevent_req *subreq)
-+{
-+    struct cache_req_locate_dom_state *state = NULL;
-+    struct tevent_req *req;
-+    errno_t ret;
-+
-+    req = tevent_req_callback_data(subreq, struct tevent_req);
-+    state = tevent_req_data(req, struct cache_req_locate_dom_state);
-+
-+    ret = cache_req_search_recv(state, subreq, &state->result, &state->dp_success);
-+    talloc_zfree(subreq);
-+
-+    switch (ret) {
-+    case EOK:
-+        /* Just finish the request and let the caller handle the result */
-+        DEBUG(SSSDBG_TRACE_INTERNAL, "Result found in the cache\n");
-+        tevent_req_done(req);
-+        return;
-+    case ENOENT:
-+        /* Not cached and locator was requested, run the locator
-+         * DP request plugin
-+         */
-+        subreq = cache_req_locate_domain_send(state,
-+                                              state->ev,
-+                                              state->cr);
-+        if (subreq == NULL) {
-+            tevent_req_error(req, ENOMEM);
-+            return;
-+        }
-+        tevent_req_set_callback(subreq, cache_req_locate_dom_done, req);
-+        return;
-+    default:
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "cache_req_search_recv returned [%d]: %s\n", ret, sss_strerror(ret));
-+        break;
-+    }
-+
-+    tevent_req_error(req, ret);
-+    return;
-+}
-+
-+static void cache_req_locate_dom_done(struct tevent_req *subreq)
-+{
-+    struct cache_req_locate_dom_state *state;
-+    struct tevent_req *req;
-+    errno_t ret;
-+    char *found_domain_name;
-+    int nret;
-+
-+    req = tevent_req_callback_data(subreq, struct tevent_req);
-+    state = tevent_req_data(req, struct cache_req_locate_dom_state);
-+
-+    ret = cache_req_locate_domain_recv(state, subreq, &found_domain_name);
-+    talloc_zfree(subreq);
-+    switch (ret) {
-+    case ERR_GET_ACCT_DOM_NOT_SUPPORTED:
-+        nret = cache_req_set_acct_domain_lookup_type(state->cr,
-+                                                     state->cr->domain);
-+        if (nret != EOK) {
-+            DEBUG(SSSDBG_MINOR_FAILURE,
-+                  "Failed to disable domain locating functionality for %s\n",
-+                  state->cr->plugin->name);
-+        }
-+        DEBUG(SSSDBG_CONF_SETTINGS,
-+              "Disabled domain locating functionality for %s\n",
-+              state->cr->plugin->name);
-+        break;
-+    case ERR_NOT_FOUND:
-+        cache_req_locate_dom_mark_neg_all(state);
-+        break;
-+    case EOK:
-+        cache_req_locate_dom_mark_neg_domains(state, found_domain_name);
-+        break;
-+    default:
-+        /* We explicitly ignore errors here */
-+        break;
-+    }
-+
-+    tevent_req_done(req);
-+    return;
-+}
-+
-+static void cache_req_locate_dom_mark_neg_all(
-+                                struct cache_req_locate_dom_state *state)
-+{
-+    struct cache_req_domain *iter;
-+
-+    DLIST_FOR_EACH(iter, state->req_domains) {
-+        if (get_domains_head(state->cr->domain) != get_domains_head(iter->domain)) {
-+            /* Only add to negative cache for domains from the same "main"
-+             * domain" */
-+            continue;
-+        }
-+        cache_req_search_ncache_add_to_domain(state->cr, iter->domain);
-+    }
-+}
-+
-+static void cache_req_locate_dom_mark_neg_domains(
-+                                struct cache_req_locate_dom_state *state,
-+                                const char *found_domain_name)
-+{
-+    struct sss_domain_info *found_domain;
-+    struct cache_req_domain *iter;
-+
-+    found_domain = find_domain_by_name(get_domains_head(state->cr->domain),
-+                                       found_domain_name,
-+                                       true);
-+    if (found_domain == NULL) {
-+        DEBUG(SSSDBG_MINOR_FAILURE,
-+                "Cannot find domain %s\n", found_domain_name);
-+        return;
-+    }
-+
-+    /* Set negcache in all subdomains of the one being examined
-+     * except the found one */
-+    DLIST_FOR_EACH(iter, state->req_domains) {
-+        if (strcasecmp(found_domain_name,
-+                       iter->domain->name) == 0) {
-+            continue;
-+        }
-+
-+        if (get_domains_head(found_domain) != get_domains_head(iter->domain)) {
-+            /* Don't set negative cache for domains outside the main
-+             * domain/subdomain tree b/c the locator request is not
-+             * authoritative for them
-+             */
-+            continue;
-+        }
-+        cache_req_search_ncache_add_to_domain(state->cr, iter->domain);
-+    }
-+}
-+
-+static errno_t cache_req_locate_dom_cache_recv(TALLOC_CTX *mem_ctx,
-+                                               struct tevent_req *req,
-+                                               struct ldb_result **_result,
-+                                               bool *_dp_success)
-+{
-+    struct cache_req_locate_dom_state *state;
-+
-+    state = tevent_req_data(req, struct cache_req_locate_dom_state);
-+
-+    if (_dp_success != NULL) {
-+        *_dp_success = state->dp_success;
-+    }
-+
-+    TEVENT_REQ_RETURN_ON_ERROR(req);
-+
-+    if (_result != NULL) {
-+        *_result = talloc_steal(mem_ctx, state->result);
-+    }
-+
-+    return EOK;
-+}
-+
- struct cache_req_search_domains_state {
-     /* input data */
-     struct tevent_context *ev;
-@@ -398,6 +666,7 @@ struct cache_req_search_domains_state {
- 
-     /* work data */
-     struct cache_req_domain *cr_domain;
-+    struct cache_req_domain *req_domains;
-     struct sss_domain_info *selected_domain;
-     struct cache_req_result **results;
-     size_t num_results;
-@@ -408,6 +677,10 @@ struct cache_req_search_domains_state {
- };
- 
- static errno_t cache_req_search_domains_next(struct tevent_req *req);
-+static errno_t cache_req_handle_result(struct tevent_req *req,
-+                                       struct ldb_result *result);
-+
-+static void cache_req_search_domains_locate_done(struct tevent_req *subreq);
- 
- static void cache_req_search_domains_done(struct tevent_req *subreq);
- 
-@@ -417,6 +690,7 @@ cache_req_search_domains_send(TALLOC_CTX *mem_ctx,
-                               struct cache_req *cr,
-                               struct cache_req_domain *cr_domain,
-                               bool check_next,
-+                              bool first_iteration,
-                               bool bypass_cache,
-                               bool bypass_dp)
- {
-@@ -435,11 +709,23 @@ cache_req_search_domains_send(TALLOC_CTX *mem_ctx,
-     state->cr = cr;
- 
-     state->cr_domain = cr_domain;
-+    state->req_domains = cr_domain;
-     state->check_next = check_next;
-     state->dp_success = true;
-     state->bypass_cache = bypass_cache;
-     state->bypass_dp = bypass_dp;
- 
-+    if (cr->plugin->dp_get_domain_send_fn != NULL
-+            && ((state->check_next && cr_domain->next != NULL)
-+                || (state->bypass_cache && !first_iteration))) {
-+        /* If the request is not qualified with a domain name AND
-+         * there are multiple domains to search OR if this is the second
-+         * pass during the "check-cache-first" schema, it makes sense
-+         * to try to run the domain-locator plugin
-+         */
-+        cache_req_domain_set_locate_flag(cr_domain, cr);
-+    }
-+
-     ret = cache_req_search_domains_next(req);
-     if (ret == EAGAIN) {
-         return req;
-@@ -510,12 +796,23 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
-             return ret;
-         }
- 
-+        if (state->cr_domain->locate_domain) {
-+            subreq = cache_req_locate_dom_send(state,
-+                                               state->ev,
-+                                               cr,
-+                                               state->req_domains);
-+            if (subreq == NULL) {
-+                return ENOMEM;
-+            }
-+            tevent_req_set_callback(subreq, cache_req_search_domains_locate_done, req);
-+            return EAGAIN;
-+        }
-+
-         subreq = cache_req_search_send(state, state->ev, cr,
-                                        state->bypass_cache, state->bypass_dp);
-         if (subreq == NULL) {
-             return ENOMEM;
-         }
--
-         tevent_req_set_callback(subreq, cache_req_search_domains_done, req);
- 
-         /* we will continue with the following domain the next time */
-@@ -549,6 +846,89 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
-     return ENOENT;
- }
- 
-+static void cache_req_search_domains_locate_done(struct tevent_req *subreq)
-+{
-+    struct cache_req_search_domains_state *state;
-+    struct ldb_result *result = NULL;
-+    struct tevent_req *req;
-+    bool dp_success;
-+    errno_t ret;
-+
-+    req = tevent_req_callback_data(subreq, struct tevent_req);
-+    state = tevent_req_data(req, struct cache_req_search_domains_state);
-+
-+    ret = cache_req_locate_dom_cache_recv(state, subreq, &result, &dp_success);
-+    talloc_zfree(subreq);
-+
-+    /* Remember if any DP request fails, but here it shouldn't matter
-+     * as the only DP request that should realistically happen is midpoint
-+     * refresh */
-+    state->dp_success = !dp_success ? false : state->dp_success;
-+
-+    /* Don't locate the domain again */
-+    state->cr_domain->locate_domain = false;
-+
-+    switch (ret) {
-+    case EOK:
-+        if (result != NULL) {
-+            /* Handle result as normally */
-+            ret = cache_req_handle_result(req, result);
-+            if (ret != EAGAIN) {
-+                goto done;
-+            }
-+        }
-+        break;
-+    default:
-+        /* Some serious error has happened. Finish. */
-+        goto done;
-+    }
-+
-+    /* This is a domain less search, continue with the next domain. */
-+    ret = cache_req_search_domains_next(req);
-+
-+done:
-+    switch (ret) {
-+    case EOK:
-+        tevent_req_done(req);
-+        break;
-+    case EAGAIN:
-+        break;
-+    default:
-+        tevent_req_error(req, ret);
-+        break;
-+    }
-+    return;
-+}
-+
-+static errno_t cache_req_handle_result(struct tevent_req *req,
-+                                       struct ldb_result *result)
-+{
-+    struct cache_req_search_domains_state *state;
-+    errno_t ret;
-+
-+    state = tevent_req_data(req, struct cache_req_search_domains_state);
-+
-+    /* We got some data from this search. Save it. */
-+    ret = cache_req_create_and_add_result(state,
-+                                          state->cr,
-+                                          state->selected_domain,
-+                                          result,
-+                                          state->cr->data->name.lookup,
-+                                          &state->results,
-+                                          &state->num_results);
-+    if (ret != EOK) {
-+        /* We were unable to save data. */
-+        return ret;
-+    }
-+
-+    if (!state->check_next || !state->cr->plugin->search_all_domains) {
-+        /* We are not interested in more results. */
-+        return EOK;
-+    }
-+
-+    return EAGAIN;
-+}
-+
- static void cache_req_search_domains_done(struct tevent_req *subreq)
- {
-     struct cache_req_search_domains_state *state;
-@@ -568,25 +948,10 @@ static void cache_req_search_domains_done(struct tevent_req *subreq)
- 
-     switch (ret) {
-     case EOK:
--        /* We got some data from this search. Save it. */
--        ret = cache_req_create_and_add_result(state,
--                                              state->cr,
--                                              state->selected_domain,
--                                              result,
--                                              state->cr->data->name.lookup,
--                                              &state->results,
--                                              &state->num_results);
--        if (ret != EOK) {
--            /* We were unable to save data. */
-+        ret = cache_req_handle_result(req, result);
-+        if (ret != EAGAIN) {
-             goto done;
-         }
--
--        if (!state->check_next || !state->cr->plugin->search_all_domains) {
--            /* We are not interested in more results. */
--            ret = EOK;
--            goto done;
--        }
--
-         break;
-     case ENOENT:
-         if (state->check_next == false) {
-@@ -1030,6 +1395,7 @@ cache_req_search_domains(struct tevent_req *req,
- 
-     subreq = cache_req_search_domains_send(state, state->ev, state->cr,
-                                            cr_domain, check_next,
-+                                           state->first_iteration,
-                                            bypass_cache, bypass_dp);
-     if (subreq == NULL) {
-         return ENOMEM;
-diff --git a/src/responder/common/cache_req/cache_req_domain.h b/src/responder/common/cache_req/cache_req_domain.h
-index ebdc71dd635d5d8a5d06e30e96c5d4101b6d98bf..5769b6aee309d9ba3edd5bb73a3cef6dc3193fdc 100644
---- a/src/responder/common/cache_req/cache_req_domain.h
-+++ b/src/responder/common/cache_req/cache_req_domain.h
-@@ -26,6 +26,7 @@
- struct cache_req_domain {
-     struct sss_domain_info *domain;
-     bool fqnames;
-+    bool locate_domain;
- 
-     struct cache_req_domain *prev;
-     struct cache_req_domain *next;
-diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c
-index f075480a019e476407a3081a795c3c289455aca8..0ee0070d0c9fbb89020f522b2f7613f1076a8cbb 100644
---- a/src/tests/cmocka/test_responder_cache_req.c
-+++ b/src/tests/cmocka/test_responder_cache_req.c
-@@ -27,6 +27,7 @@
- #include "tests/cmocka/common_mock_resp.h"
- #include "db/sysdb.h"
- #include "responder/common/cache_req/cache_req.h"
-+#include "db/sysdb_private.h"   /* new_subdomain() */
- 
- #define TESTS_PATH "tp_" BASE_FILE_STEM
- #define TEST_CONF_DB "test_responder_cache_req_conf.ldb"
-@@ -63,6 +64,11 @@ struct test_group {
-                                     test_multi_domain_setup, \
-                                     test_multi_domain_teardown)
- 
-+#define new_subdomain_test(test) \
-+    cmocka_unit_test_setup_teardown(test_ ## test, \
-+                                    test_subdomain_setup, \
-+                                    test_subdomain_teardown)
-+
- #define run_cache_req(ctx, send_fn, done_fn, dom, crp, lookup, expret) do { \
-     TALLOC_CTX *req_mem_ctx;                                                \
-     struct tevent_req *req;                                                 \
-@@ -110,6 +116,7 @@ struct cache_req_test_ctx {
-     struct sss_test_ctx *tctx;
-     struct resp_ctx *rctx;
-     struct sss_nc_ctx *ncache;
-+    struct sss_domain_info *subdomain;
- 
-     struct cache_req_result *result;
-     bool dp_called;
-@@ -120,6 +127,8 @@ struct cache_req_test_ctx {
-     bool create_user2;
-     bool create_group1;
-     bool create_group2;
-+    bool create_subgroup1;
-+    bool create_subuser1;
- };
- 
- const char *domains[] = {"responder_cache_req_test_a",
-@@ -128,6 +137,8 @@ const char *domains[] = {"responder_cache_req_test_a",
-                          "responder_cache_req_test_d",
-                          NULL};
- 
-+const char *subdomain_name = "responder_cache_req_test_a_sub";
-+
- struct cli_protocol_version *register_cli_protocol_version(void)
- {
-     static struct cli_protocol_version version[] = {
-@@ -487,6 +498,26 @@ __wrap_sss_dp_get_account_send(TALLOC_CTX *mem_ctx,
-         prepare_group(ctx->tctx->dom, &groups[1], 1000, time(NULL));
-     }
- 
-+    if (ctx->create_subgroup1) {
-+        struct sss_domain_info *domain = NULL;
-+
-+        domain = find_domain_by_name(ctx->tctx->dom,
-+                                     subdomain_name,
-+                                     true);
-+        assert_non_null(domain);
-+        prepare_group(domain, &groups[0], 1000, time(NULL));
-+    }
-+
-+    if (ctx->create_subuser1) {
-+        struct sss_domain_info *domain = NULL;
-+
-+        domain = find_domain_by_name(ctx->tctx->dom,
-+                                     subdomain_name,
-+                                     true);
-+        assert_non_null(domain);
-+        prepare_user(domain, &users[0], 1000, time(NULL));
-+    }
-+
-     return test_req_succeed_send(mem_ctx, rctx->ev);
- }
- 
-@@ -581,6 +612,67 @@ static int test_multi_domain_teardown(void **state)
-     return 0;
- }
- 
-+static int test_subdomain_setup(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    int ret;
-+    const char *const testdom[4] = { subdomain_name, "TEST_A.SUB", "test_a", "S-3" };
-+
-+    assert_true(leak_check_setup());
-+
-+    test_dom_suite_setup(TESTS_PATH);
-+
-+    test_ctx = talloc_zero(global_talloc_context, struct cache_req_test_ctx);
-+    assert_non_null(test_ctx);
-+    *state = test_ctx;
-+
-+    test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH, TEST_CONF_DB,
-+                                         TEST_DOM_NAME, TEST_ID_PROVIDER, NULL);
-+    assert_non_null(test_ctx->tctx);
-+
-+    test_ctx->rctx = mock_rctx(test_ctx, test_ctx->tctx->ev,
-+                               test_ctx->tctx->dom, NULL);
-+    assert_non_null(test_ctx->rctx);
-+
-+    ret = sss_ncache_init(test_ctx, 10, 0, &test_ctx->ncache);
-+    assert_int_equal(ret, EOK);
-+
-+    test_ctx->subdomain = new_subdomain(test_ctx, test_ctx->tctx->dom,
-+                              testdom[0], testdom[1], testdom[2], testdom[3],
-+                              false, false, NULL, NULL, 0,
-+                              test_ctx->tctx->confdb);
-+    assert_non_null(test_ctx->subdomain);
-+
-+    ret = sysdb_subdomain_store(test_ctx->tctx->sysdb,
-+                                testdom[0], testdom[1], testdom[2], testdom[3],
-+                                false, false, NULL, 0, NULL);
-+    assert_int_equal(ret, EOK);
-+
-+    ret = sysdb_update_subdomains(test_ctx->tctx->dom,
-+                                  test_ctx->tctx->confdb);
-+    assert_int_equal(ret, EOK);
-+
-+    *state = test_ctx;
-+    check_leaks_push(test_ctx);
-+    return 0;
-+}
-+
-+static int test_subdomain_teardown(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    talloc_zfree(test_ctx->result);
-+    talloc_zfree(test_ctx->rctx->cr_domains);
-+
-+    assert_true(check_leaks_pop(test_ctx));
-+    talloc_zfree(test_ctx);
-+    test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
-+    assert_true(leak_check_teardown());
-+    return 0;
-+}
-+
- void test_user_by_name_multiple_domains_found(void **state)
- {
-     struct cache_req_test_ctx *test_ctx = NULL;
-@@ -974,6 +1066,7 @@ void test_user_by_id_multiple_domains_found(void **state)
-     /* Mock values. */
-     will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-     will_return_always(sss_dp_req_recv, 0);
-+    will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
- 
-     /* Test. */
-     run_user_by_id(test_ctx, NULL, 0, ERR_OK);
-@@ -990,12 +1083,317 @@ void test_user_by_id_multiple_domains_notfound(void **state)
-     /* Mock values. */
-     will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-     will_return_always(sss_dp_req_recv, 0);
-+    will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
- 
-     /* Test. */
-     run_user_by_id(test_ctx, NULL, 0, ENOENT);
-     assert_true(test_ctx->dp_called);
- }
- 
-+void test_user_by_id_multiple_domains_locator_cache_valid(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d");
-+    assert_non_null(locator_domain);
-+
-+    /* Setup user. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 "responder_cache_req_test_d", true);
-+    assert_non_null(domain);
-+    prepare_user(domain, &users[0], 1000, time(NULL));
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+    will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
-+
-+    will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, EOK);
-+
-+    /* Test. */
-+    run_user_by_id(test_ctx, NULL, 0, ERR_OK);
-+    /* Even though the locator tells us to skip all domains except d, the domains
-+     * are standalone and the result of the locator request is only valid within
-+     * the subdomains
-+     */
-+    assert_true(test_ctx->dp_called);
-+    check_user(test_ctx, &users[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_user_by_id_multiple_domains_locator_cache_expired(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d");
-+    assert_non_null(locator_domain);
-+
-+    /* Setup user. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 "responder_cache_req_test_d", true);
-+    assert_non_null(domain);
-+    prepare_user(domain, &users[0], -1000, time(NULL));
-+
-+    will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, EOK);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+    will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
-+
-+    /* Test. */
-+    run_user_by_id(test_ctx, NULL, 0, ERR_OK);
-+
-+    assert_true(test_ctx->dp_called);
-+    check_user(test_ctx, &users[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_user_by_id_sub_domains_locator_cache_valid(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Setup user. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    prepare_user(domain, &users[0], 1000, time(NULL));
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    run_user_by_id(test_ctx, NULL, 0, ERR_OK);
-+
-+    /* Even though the ID is present in the last domain,
-+     * we're not calling sss_dp_get_account_send,
-+     * because the locator will cause cache_req to skip
-+     * all domains except _d
-+     */
-+    assert_false(test_ctx->dp_called);
-+    check_user(test_ctx, &users[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_user_by_id_sub_domains_locator_cache_expired(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Setup user. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    prepare_user(domain, &users[0], -1000, time(NULL));
-+
-+    /* Note - DP will only be called once (so, we're not using will_return_always)
-+     * because the locator will tell us which domain to look into. For the recv
-+     * function, we use always b/c internally it mocks several values.
-+     */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, 0);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    run_user_by_id(test_ctx, NULL, 0, ERR_OK);
-+
-+    assert_true(test_ctx->dp_called);
-+    check_user(test_ctx, &users[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_user_by_id_sub_domains_locator_cache_midpoint(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Setup user. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    prepare_user(domain, &users[0], 50, time(NULL) - 26);
-+
-+    /* Note - DP will only be called once and we're not waiting
-+     * for the results (so, we're not mocking _recv)
-+     */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    run_user_by_id(test_ctx, NULL, 50, ERR_OK);
-+
-+    assert_true(test_ctx->dp_called);
-+    check_user(test_ctx, &users[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_user_by_id_sub_domains_locator_missing_found(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Note - DP will only be called once (so, we're not using will_return_always)
-+     * because the locator will tell us which domain to look into. For the recv
-+     * function, we use always b/c internally it mocks several values.
-+     */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, 0);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    test_ctx->create_subuser1 = true;
-+    run_user_by_id(test_ctx, NULL, 0, ERR_OK);
-+
-+    assert_true(test_ctx->dp_called);
-+
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    check_user(test_ctx, &users[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_user_by_id_sub_domains_locator_missing_notfound(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    will_return(sss_dp_get_account_domain_recv, ERR_NOT_FOUND);
-+
-+    /* Test. */
-+    run_user_by_id(test_ctx, NULL, 0, ENOENT);
-+    assert_false(test_ctx->dp_called);
-+}
-+
-+void test_user_by_id_sub_domains_locator_cache_expired_two_calls(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Setup user. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    test_ctx->create_subuser1 = true;
-+    prepare_user(domain, &users[0], -1000, time(NULL));
-+
-+    /* Note - DP will only be called once (so, we're not using will_return_always)
-+     * because the locator will tell us which domain to look into. For the recv
-+     * function, we use always b/c internally it mocks several values.
-+     */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, 0);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    run_user_by_id(test_ctx, NULL, 0, ERR_OK);
-+    assert_true(test_ctx->dp_called);
-+    check_user(test_ctx, &users[0], domain);
-+
-+    /* Request the same user again */
-+    test_ctx->tctx->done = false;
-+    talloc_zfree(test_ctx->result);
-+
-+    run_user_by_id(test_ctx, NULL, 0, ERR_OK);
-+    check_user(test_ctx, &users[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
- void test_user_by_id_cache_valid(void **state)
- {
-     struct cache_req_test_ctx *test_ctx = NULL;
-@@ -1332,6 +1730,7 @@ void test_group_by_id_multiple_domains_found(void **state)
-     /* Mock values. */
-     will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-     will_return_always(sss_dp_req_recv, 0);
-+    will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
- 
-     /* Test. */
-     run_group_by_id(test_ctx, NULL, 0, ERR_OK);
-@@ -1348,12 +1747,318 @@ void test_group_by_id_multiple_domains_notfound(void **state)
-     /* Mock values. */
-     will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-     will_return_always(sss_dp_req_recv, 0);
-+    will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
- 
-     /* Test. */
-     run_group_by_id(test_ctx, NULL, 0, ENOENT);
-     assert_true(test_ctx->dp_called);
- }
- 
-+void test_group_by_id_multiple_domains_locator_cache_valid(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d");
-+    assert_non_null(locator_domain);
-+
-+    /* Setup group. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 "responder_cache_req_test_d", true);
-+    assert_non_null(domain);
-+    prepare_group(domain, &groups[0], 1000, time(NULL));
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+    will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
-+
-+    will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, EOK);
-+
-+    /* Test. */
-+    run_group_by_id(test_ctx, NULL, 0, ERR_OK);
-+
-+    /* Even though the locator tells us to skip all domains except d, the domains
-+     * are standalone and the result of the locator request is only valid within
-+     * the subdomains
-+     */
-+    assert_true(test_ctx->dp_called);
-+    check_group(test_ctx, &groups[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_group_by_id_multiple_domains_locator_cache_expired(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d");
-+    assert_non_null(locator_domain);
-+
-+    /* Setup group. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 "responder_cache_req_test_d", true);
-+    assert_non_null(domain);
-+    prepare_group(domain, &groups[0], -1000, time(NULL));
-+
-+    will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, EOK);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+    will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
-+
-+    /* Test. */
-+    run_group_by_id(test_ctx, NULL, 0, ERR_OK);
-+
-+    assert_true(test_ctx->dp_called);
-+    check_group(test_ctx, &groups[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_group_by_id_sub_domains_locator_cache_valid(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Setup group. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    prepare_group(domain, &groups[0], 1000, time(NULL));
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    run_group_by_id(test_ctx, NULL, 0, ERR_OK);
-+
-+    /* Even though the ID is present in the last domain,
-+     * we're not calling sss_dp_get_account_send,
-+     * because the locator will cause cache_req to skip
-+     * all domains except _d
-+     */
-+    assert_false(test_ctx->dp_called);
-+    check_group(test_ctx, &groups[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_group_by_id_sub_domains_locator_cache_expired(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Setup group. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    prepare_group(domain, &groups[0], -1000, time(NULL));
-+
-+    /* Note - DP will only be called once (so, we're not using will_return_always)
-+     * because the locator will tell us which domain to look into. For the recv
-+     * function, we use always b/c internally it mocks several values.
-+     */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, 0);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    run_group_by_id(test_ctx, NULL, 0, ERR_OK);
-+
-+    assert_true(test_ctx->dp_called);
-+    check_group(test_ctx, &groups[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_group_by_id_sub_domains_locator_cache_midpoint(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Setup group. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    prepare_group(domain, &groups[0], 50, time(NULL) - 26);
-+
-+    /* Note - DP will only be called once and we're not waiting
-+     * for the results (so, we're not mocking _recv)
-+     */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    run_group_by_id(test_ctx, NULL, 50, ERR_OK);
-+
-+    assert_true(test_ctx->dp_called);
-+    check_group(test_ctx, &groups[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_group_by_id_sub_domains_locator_missing_found(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Note - DP will only be called once (so, we're not using will_return_always)
-+     * because the locator will tell us which domain to look into. For the recv
-+     * function, we use always b/c internally it mocks several values.
-+     */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, 0);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    test_ctx->create_subgroup1 = true;
-+    run_group_by_id(test_ctx, NULL, 0, ERR_OK);
-+
-+    assert_true(test_ctx->dp_called);
-+
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    check_group(test_ctx, &groups[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_group_by_id_sub_domains_locator_missing_notfound(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    will_return(sss_dp_get_account_domain_recv, ERR_NOT_FOUND);
-+
-+    /* Test. */
-+    run_group_by_id(test_ctx, NULL, 0, ENOENT);
-+    assert_false(test_ctx->dp_called);
-+}
-+
-+void test_group_by_id_sub_domains_locator_cache_expired_two_calls(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Setup group. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    test_ctx->create_subgroup1 = true;
-+    prepare_group(domain, &groups[0], -1000, time(NULL));
-+
-+    /* Note - DP will only be called once (so, we're not using will_return_always)
-+     * because the locator will tell us which domain to look into. For the recv
-+     * function, we use always b/c internally it mocks several values.
-+     */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, 0);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    run_group_by_id(test_ctx, NULL, 0, ERR_OK);
-+    assert_true(test_ctx->dp_called);
-+    check_group(test_ctx, &groups[0], domain);
-+
-+    /* Request the same group again */
-+    test_ctx->tctx->done = false;
-+    talloc_zfree(test_ctx->result);
-+
-+    run_group_by_id(test_ctx, NULL, 0, ERR_OK);
-+    check_group(test_ctx, &groups[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
- void test_group_by_id_cache_valid(void **state)
- {
-     struct cache_req_test_ctx *test_ctx = NULL;
-@@ -2311,6 +3016,7 @@ void test_object_by_id_user_multiple_domains_found(void **state)
-     /* Mock values. */
-     will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-     will_return_always(sss_dp_req_recv, 0);
-+    will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
- 
-     /* Test. */
-     run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK);
-@@ -2328,6 +3034,7 @@ void test_object_by_id_user_multiple_domains_notfound(void **state)
-     /* Mock values. */
-     will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-     will_return_always(sss_dp_req_recv, 0);
-+    will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
- 
-     /* Test. */
-     run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ENOENT);
-@@ -2476,6 +3183,7 @@ void test_object_by_id_group_multiple_domains_found(void **state)
-     /* Mock values. */
-     will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-     will_return_always(sss_dp_req_recv, 0);
-+    will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
- 
-     /* Test. */
-     run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK);
-@@ -2493,12 +3201,641 @@ void test_object_by_id_group_multiple_domains_notfound(void **state)
-     /* Mock values. */
-     will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-     will_return_always(sss_dp_req_recv, 0);
-+    will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
- 
-     /* Test. */
-     run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ENOENT);
-     assert_true(test_ctx->dp_called);
- }
- 
-+void test_object_by_id_user_multiple_domains_locator_cache_valid(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d");
-+    assert_non_null(locator_domain);
-+
-+    /* Setup user. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 "responder_cache_req_test_d", true);
-+    assert_non_null(domain);
-+    prepare_user(domain, &users[0], 1000, time(NULL));
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+    will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
-+
-+    will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, EOK);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK);
-+    /* Even though the locator tells us to skip all domains except d, the domains
-+     * are standalone and the result of the locator request is only valid within
-+     * the subdomains
-+     */
-+    assert_true(test_ctx->dp_called);
-+    check_user(test_ctx, &users[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_object_by_id_user_multiple_domains_locator_cache_expired(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d");
-+    assert_non_null(locator_domain);
-+
-+    /* Setup user. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 "responder_cache_req_test_d", true);
-+    assert_non_null(domain);
-+    prepare_user(domain, &users[0], -1000, time(NULL));
-+
-+    will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, EOK);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+    will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK);
-+
-+    assert_true(test_ctx->dp_called);
-+    check_user(test_ctx, &users[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_object_by_id_user_sub_domains_locator_cache_valid(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Setup user. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    prepare_user(domain, &users[0], 1000, time(NULL));
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK);
-+
-+    /* Even though the ID is present in the last domain,
-+     * we're not calling sss_dp_get_account_send,
-+     * because the locator will cause cache_req to skip
-+     * all domains except _d
-+     */
-+    assert_false(test_ctx->dp_called);
-+    check_user(test_ctx, &users[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_object_by_id_user_sub_domains_locator_cache_expired(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Setup user. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    prepare_user(domain, &users[0], -1000, time(NULL));
-+
-+    /* Note - DP will only be called once (so, we're not using will_return_always)
-+     * because the locator will tell us which domain to look into. For the recv
-+     * function, we use always b/c internally it mocks several values.
-+     */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, 0);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK);
-+
-+    assert_true(test_ctx->dp_called);
-+    check_user(test_ctx, &users[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_object_by_id_user_sub_domains_locator_cache_midpoint(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Setup user. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    prepare_user(domain, &users[0], 50, time(NULL) - 26);
-+
-+    /* Note - DP will only be called once and we're not waiting
-+     * for the results (so, we're not mocking _recv)
-+     */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 50, ERR_OK);
-+
-+    assert_true(test_ctx->dp_called);
-+    check_user(test_ctx, &users[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_object_by_id_user_sub_domains_locator_missing_found(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Note - DP will only be called once (so, we're not using will_return_always)
-+     * because the locator will tell us which domain to look into. For the recv
-+     * function, we use always b/c internally it mocks several values.
-+     */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, 0);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    test_ctx->create_subuser1 = true;
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ERR_OK);
-+
-+    assert_true(test_ctx->dp_called);
-+
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    check_user(test_ctx, &users[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_object_by_id_user_sub_domains_locator_missing_notfound(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    will_return(sss_dp_get_account_domain_recv, ERR_NOT_FOUND);
-+
-+    /* The test won't even ask the DP for the object, just iterate
-+     * over the domains using the negative cache and quit
-+     */
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, ENOENT);
-+    assert_false(test_ctx->dp_called);
-+}
-+
-+void test_object_by_id_user_sub_domains_locator_cache_expired_two_calls(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Setup user. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    test_ctx->create_subuser1 = true;
-+    prepare_user(domain, &users[0], -1000, time(NULL));
-+
-+    /* Note - DP will only be called once (so, we're not using will_return_always)
-+     * because the locator will tell us which domain to look into. For the recv
-+     * function, we use always b/c internally it mocks several values.
-+     */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, 0);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, EOK);
-+    assert_true(test_ctx->dp_called);
-+    check_user(test_ctx, &users[0], domain);
-+
-+    /* Request the same user again */
-+    test_ctx->tctx->done = false;
-+    talloc_zfree(test_ctx->result);
-+
-+    run_object_by_id(test_ctx, NULL, users[0].uid, attrs, 0, EOK);
-+    check_user(test_ctx, &users[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_object_by_id_group_multiple_domains_locator_cache_valid(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d");
-+    assert_non_null(locator_domain);
-+
-+    /* Setup group. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 "responder_cache_req_test_d", true);
-+    assert_non_null(domain);
-+    prepare_group(domain, &groups[0], 1000, time(NULL));
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+    will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
-+
-+    will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, EOK);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK);
-+    /* Even though the locator tells us to skip all domains except d, the domains
-+     * are standalone and the result of the locator request is only valid within
-+     * the subdomains
-+     */
-+    assert_true(test_ctx->dp_called);
-+    check_group(test_ctx, &groups[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_object_by_id_group_multiple_domains_locator_cache_expired(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, "responder_cache_req_test_d");
-+    assert_non_null(locator_domain);
-+
-+    /* Setup group. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 "responder_cache_req_test_d", true);
-+    assert_non_null(domain);
-+    prepare_group(domain, &groups[0], -1000, time(NULL));
-+
-+    will_return_always(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, EOK);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+    will_return_always(sss_dp_get_account_domain_recv, ERR_GET_ACCT_DOM_NOT_SUPPORTED);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK);
-+
-+    assert_true(test_ctx->dp_called);
-+    check_group(test_ctx, &groups[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_object_by_id_group_sub_domains_locator_cache_valid(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Setup group. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    prepare_group(domain, &groups[0], 1000, time(NULL));
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK);
-+
-+    /* Even though the ID is present in the last domain,
-+     * we're not calling sss_dp_get_account_send,
-+     * because the locator will cause cache_req to skip
-+     * all domains except _d
-+     */
-+    assert_false(test_ctx->dp_called);
-+    check_group(test_ctx, &groups[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_object_by_id_group_sub_domains_locator_cache_expired(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Setup group. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    prepare_group(domain, &groups[0], -1000, time(NULL));
-+
-+    /* Note - DP will only be called once (so, we're not using will_return_always)
-+     * because the locator will tell us which domain to look into. For the recv
-+     * function, we use always b/c internally it mocks several values.
-+     */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, 0);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK);
-+
-+    assert_true(test_ctx->dp_called);
-+    check_group(test_ctx, &groups[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_object_by_id_group_sub_domains_locator_cache_midpoint(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Setup group. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    prepare_group(domain, &groups[0], 50, time(NULL) - 26);
-+
-+    /* Note - DP will only be called once and we're not waiting
-+     * for the results (so, we're not mocking _recv)
-+     */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 50, ERR_OK);
-+
-+    assert_true(test_ctx->dp_called);
-+    check_group(test_ctx, &groups[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_object_by_id_group_sub_domains_locator_missing_found(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Note - DP will only be called once (so, we're not using will_return_always)
-+     * because the locator will tell us which domain to look into. For the recv
-+     * function, we use always b/c internally it mocks several values.
-+     */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, 0);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    test_ctx->create_subgroup1 = true;
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ERR_OK);
-+
-+    assert_true(test_ctx->dp_called);
-+
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    check_group(test_ctx, &groups[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
-+void test_object_by_id_group_sub_domains_locator_missing_notfound(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    will_return(sss_dp_get_account_domain_recv, ERR_NOT_FOUND);
-+
-+    /* The test won't even ask the DP for the object, just iterate
-+     * over the domains using the negative cache and quit
-+     */
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, ENOENT);
-+    assert_false(test_ctx->dp_called);
-+}
-+
-+void test_object_by_id_group_sub_domains_locator_cache_expired_two_calls(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    struct sss_domain_info *domain = NULL;
-+    const char *locator_domain;
-+    TALLOC_CTX *tmp_ctx;
-+    const char *attrs[] = SYSDB_PW_ATTRS;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    tmp_ctx = talloc_new(test_ctx);
-+    assert_non_null(tmp_ctx);
-+
-+    /* Has to be a talloc ptr, not just const, so it's stealable inside cache_req */
-+    locator_domain = talloc_strdup(tmp_ctx, subdomain_name);
-+    assert_non_null(locator_domain);
-+
-+    /* Setup group. */
-+    domain = find_domain_by_name(test_ctx->tctx->dom,
-+                                 subdomain_name,
-+                                 true);
-+    assert_non_null(domain);
-+    test_ctx->create_subgroup1 = true;
-+    prepare_group(domain, &groups[0], -1000, time(NULL));
-+
-+    /* Note - DP will only be called once (so, we're not using will_return_always)
-+     * because the locator will tell us which domain to look into. For the recv
-+     * function, we use always b/c internally it mocks several values.
-+     */
-+    will_return(__wrap_sss_dp_get_account_send, test_ctx);
-+    will_return_always(sss_dp_req_recv, 0);
-+
-+    will_return(sss_dp_get_account_domain_recv, EOK);
-+    will_return(sss_dp_get_account_domain_recv, locator_domain);
-+
-+    /* Test. */
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, EOK);
-+    assert_true(test_ctx->dp_called);
-+    check_group(test_ctx, &groups[0], domain);
-+
-+    /* Request the same group again */
-+    test_ctx->tctx->done = false;
-+    talloc_zfree(test_ctx->result);
-+
-+    run_object_by_id(test_ctx, NULL, groups[0].gid, attrs, 0, EOK);
-+    check_group(test_ctx, &groups[0], domain);
-+
-+    talloc_free(tmp_ctx);
-+}
-+
- int main(int argc, const char *argv[])
- {
-     poptContext pc;
-@@ -2557,6 +3894,24 @@ int main(int argc, const char *argv[])
-         new_multi_domain_test(group_by_id_multiple_domains_found),
-         new_multi_domain_test(group_by_id_multiple_domains_notfound),
- 
-+        new_multi_domain_test(group_by_id_multiple_domains_locator_cache_valid),
-+        new_multi_domain_test(group_by_id_multiple_domains_locator_cache_expired),
-+        new_subdomain_test(group_by_id_sub_domains_locator_cache_valid),
-+        new_subdomain_test(group_by_id_sub_domains_locator_cache_expired),
-+        new_subdomain_test(group_by_id_sub_domains_locator_cache_midpoint),
-+        new_subdomain_test(group_by_id_sub_domains_locator_missing_found),
-+        new_subdomain_test(group_by_id_sub_domains_locator_missing_notfound),
-+        new_subdomain_test(group_by_id_sub_domains_locator_cache_expired_two_calls),
-+
-+        new_multi_domain_test(user_by_id_multiple_domains_locator_cache_valid),
-+        new_multi_domain_test(user_by_id_multiple_domains_locator_cache_expired),
-+        new_subdomain_test(user_by_id_sub_domains_locator_cache_valid),
-+        new_subdomain_test(user_by_id_sub_domains_locator_cache_expired),
-+        new_subdomain_test(user_by_id_sub_domains_locator_cache_midpoint),
-+        new_subdomain_test(user_by_id_sub_domains_locator_missing_found),
-+        new_subdomain_test(user_by_id_sub_domains_locator_missing_notfound),
-+        new_subdomain_test(user_by_id_sub_domains_locator_cache_expired_two_calls),
-+
-         new_single_domain_test(user_by_recent_filter_valid),
-         new_single_domain_test(users_by_recent_filter_valid),
-         new_single_domain_test(group_by_recent_filter_valid),
-@@ -2603,6 +3958,24 @@ int main(int argc, const char *argv[])
-         new_single_domain_test(object_by_id_group_missing_notfound),
-         new_multi_domain_test(object_by_id_group_multiple_domains_found),
-         new_multi_domain_test(object_by_id_group_multiple_domains_notfound),
-+
-+        new_multi_domain_test(object_by_id_user_multiple_domains_locator_cache_valid),
-+        new_multi_domain_test(object_by_id_user_multiple_domains_locator_cache_expired),
-+        new_subdomain_test(object_by_id_user_sub_domains_locator_cache_valid),
-+        new_subdomain_test(object_by_id_user_sub_domains_locator_cache_expired),
-+        new_subdomain_test(object_by_id_user_sub_domains_locator_cache_midpoint),
-+        new_subdomain_test(object_by_id_user_sub_domains_locator_missing_found),
-+        new_subdomain_test(object_by_id_user_sub_domains_locator_missing_notfound),
-+        new_subdomain_test(object_by_id_user_sub_domains_locator_cache_expired_two_calls),
-+
-+        new_multi_domain_test(object_by_id_group_multiple_domains_locator_cache_valid),
-+        new_multi_domain_test(object_by_id_group_multiple_domains_locator_cache_expired),
-+        new_subdomain_test(object_by_id_group_sub_domains_locator_cache_valid),
-+        new_subdomain_test(object_by_id_group_sub_domains_locator_cache_expired),
-+        new_subdomain_test(object_by_id_group_sub_domains_locator_cache_midpoint),
-+        new_subdomain_test(object_by_id_group_sub_domains_locator_missing_found),
-+        new_subdomain_test(object_by_id_group_sub_domains_locator_missing_notfound),
-+        new_subdomain_test(object_by_id_group_sub_domains_locator_cache_expired_two_calls),
-     };
- 
-     /* Set debug level to invalid value so we can deside if -d 0 was used. */
--- 
-2.14.3
-
diff --git a/SOURCES/0083-MAN-Document-how-the-Global-Catalog-is-used-currentl.patch b/SOURCES/0083-MAN-Document-how-the-Global-Catalog-is-used-currentl.patch
deleted file mode 100644
index 4a339e0..0000000
--- a/SOURCES/0083-MAN-Document-how-the-Global-Catalog-is-used-currentl.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From 251e4914e55c6b66ab6eabd3b3e2e2b7b49029e3 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Sun, 19 Nov 2017 22:31:44 +0100
-Subject: [PATCH 83/83] MAN: Document how the Global Catalog is used currently
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The existing documentation was outdated. Remove it and document what the
-current patchset adds.
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3468
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit a72919af8347b5bbc65a3b1fb3e5d31447240b24)
----
- src/man/sssd-ad.5.xml | 13 ++++++++++---
- 1 file changed, 10 insertions(+), 3 deletions(-)
-
-diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
-index 649042d587de3d3600fff59866681e302c721af8..c4a3fc2b5780eb0f15935a2c38f48418c5f7bb52 100644
---- a/src/man/sssd-ad.5.xml
-+++ b/src/man/sssd-ad.5.xml
-@@ -84,9 +84,16 @@
-             <programlisting>
- ldap_id_mapping = False
-             </programlisting>
--            In order to retrieve users and groups using POSIX attributes from trusted
--            domains, the AD administrator must make sure that the POSIX attributes
--            are replicated to the Global Catalog.
-+            If POSIX attributes should be used, it is recommended for
-+            performance reasons that the attributes are also replicated
-+            to the Global Catalog. If POSIX attributes are replicated,
-+            SSSD will attempt to locate the domain of a requested
-+            numerical ID with the help of the Global Catalog and only
-+            search that domain. In contrast, if POSIX attributes are not
-+            replicated to the Global Catalog, SSSD must search all the
-+            domains in the forest sequentially. Please note that that the
-+            <quote>cache_first</quote> option might be also helpful in
-+            speeding up domainless searches.
-         </para>
-         <para>
-             Users, groups and other entities served by SSSD are always treated as
--- 
-2.14.3
-
diff --git a/SOURCES/0084-p11_child-make-sure-OCSP-checks-are-done.patch b/SOURCES/0084-p11_child-make-sure-OCSP-checks-are-done.patch
deleted file mode 100644
index e2b497f..0000000
--- a/SOURCES/0084-p11_child-make-sure-OCSP-checks-are-done.patch
+++ /dev/null
@@ -1,54 +0,0 @@
-From 62275e72ff0b9849c899f0fecea90731fff9da0a Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 7 Dec 2017 17:08:33 +0100
-Subject: [PATCH 84/86] p11_child: make sure OCSP checks are done
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-If CERT_VerifyCertificateNow() is used with
-'certificateUsageCheckAllUsages' OCSP checks are skipped even if OCSP
-was enabled.
-
-This patch calls CERT_CheckOCSPStatus() explicitly if OCSP checks are
-enabled.
-
-Related to https://pagure.io/SSSD/sssd/issue/3560
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 2297cc7d6cd5c38a7d64027165e4e82ca497f418)
----
- src/p11_child/p11_child_nss.c | 17 +++++++++++++++++
- 1 file changed, 17 insertions(+)
-
-diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
-index 21c508eb1b1b68b3606d0a5eed36573b01f27a19..bf533f3efe4d680f4c6dbd10a0d2c5a5da371c67 100644
---- a/src/p11_child/p11_child_nss.c
-+++ b/src/p11_child/p11_child_nss.c
-@@ -338,6 +338,23 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-                       PR_GetError(), PORT_ErrorToString(PR_GetError()));
-                 continue;
-             }
-+
-+            /* with 'certificateUsageCheckAllUsages' set
-+             * CERT_VerifyCertificateNow() does not do OCSP so it must be done
-+             * explicitly */
-+            if (cert_verify_opts->do_ocsp) {
-+                rv = CERT_CheckOCSPStatus(handle, cert_list_node->cert,
-+                                          PR_Now(), NULL);
-+                if (rv != SECSuccess) {
-+                    DEBUG(SSSDBG_OP_FAILURE,
-+                          "Certificate [%s][%s] failed OCSP check [%d][%s], "
-+                          "skipping.\n",
-+                          cert_list_node->cert->nickname,
-+                          cert_list_node->cert->subjectName,
-+                          PR_GetError(), PORT_ErrorToString(PR_GetError()));
-+                    continue;
-+                }
-+            }
-         }
- 
-         if (key_id_in != NULL) {
--- 
-2.14.3
-
diff --git a/SOURCES/0085-IPA-Include-SYSDB_OBJECTCATEGORY-not-OBJECTCLASS-in-.patch b/SOURCES/0085-IPA-Include-SYSDB_OBJECTCATEGORY-not-OBJECTCLASS-in-.patch
deleted file mode 100644
index 49fffa3..0000000
--- a/SOURCES/0085-IPA-Include-SYSDB_OBJECTCATEGORY-not-OBJECTCLASS-in-.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From 0f707b5f99f4cc17b61026e7a0e7787e776fae87 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 6 Dec 2017 15:45:13 +0100
-Subject: [PATCH 85/86] IPA: Include SYSDB_OBJECTCATEGORY, not OBJECTCLASS in
- cache search results
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The function get_object_from_cache() returns an ldb_message that is
-passed to apply_subdomain_homedir() which expects SYSDB_OBJECTCATEGORY
-to be present in the message, otherwise it errors out.
-
-However, get_object_from_cache() was reading only SYSDB_OBJECTCLASS.
-
-This patch changes get_object_from_cache() to ready
-SYSDB_OBJECTCATEGORY.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3599
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit dc49e07a0dbbbf3d69d09a7c6f236d82c86c7def)
----
- src/providers/ipa/ipa_subdomains_id.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index 2ba9813a44b4d914d9c2ef7a1a7504546f52954c..d40671086854f9c1a3f8bc7fc711009298dc31c8 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -965,7 +965,7 @@ errno_t get_object_from_cache(TALLOC_CTX *mem_ctx,
-     const char *attrs[] = { SYSDB_NAME,
-                             SYSDB_UIDNUM,
-                             SYSDB_SID_STR,
--                            SYSDB_OBJECTCLASS,
-+                            SYSDB_OBJECTCATEGORY,
-                             SYSDB_UUID,
-                             SYSDB_GHOST,
-                             SYSDB_HOMEDIR,
--- 
-2.14.3
-
diff --git a/SOURCES/0086-nss-idmap-allow-NULL-result-in-_timeout-calls.patch b/SOURCES/0086-nss-idmap-allow-NULL-result-in-_timeout-calls.patch
deleted file mode 100644
index 95bdd75..0000000
--- a/SOURCES/0086-nss-idmap-allow-NULL-result-in-_timeout-calls.patch
+++ /dev/null
@@ -1,113 +0,0 @@
-From 2a3accc78bb9658401b33ad5a3a2f1bc4bc3c269 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 7 Dec 2017 17:42:45 +0100
-Subject: [PATCH 86/86] nss-idmap: allow NULL result in *_timeout calls
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-To make the *_timeout calls more resilient checks are added if the
-result parameter is NULL. It will not be used in this case.
-
-Related to https://pagure.io/SSSD/sssd/issue/2478
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-Reviewed-by: Alexander Bokovoy <abokovoy@redhat.com>
-(cherry picked from commit bba068c535d23eebff61f592bddb3a6438446d6f)
----
- src/sss_client/idmap/sss_nss_ex.c | 46 +++++++++++++++++++++++++++------------
- 1 file changed, 32 insertions(+), 14 deletions(-)
-
-diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c
-index dcd9619a8b07ced7498f61b7e809fa46ebffe09e..861b1e1e92db4f7e6e8d74a812dc3c9220711773 100644
---- a/src/sss_client/idmap/sss_nss_ex.c
-+++ b/src/sss_client/idmap/sss_nss_ex.c
-@@ -367,13 +367,17 @@ int sss_nss_getpwnam_timeout(const char *name, struct passwd *pwd,
-         return ret;
-     }
- 
--    *result = NULL;
--
-     ret = sss_get_ex(&inp, flags, timeout);
-     free(discard_const(inp.rd.data));
--    if (ret == 0) {
--        *result = inp.result.pwrep.result;
-+
-+    if (result != NULL) {
-+        if (ret == 0) {
-+            *result = inp.result.pwrep.result;
-+        } else {
-+            *result = NULL;
-+        }
-     }
-+
-     return ret;
- }
- 
-@@ -395,12 +399,17 @@ int sss_nss_getpwuid_timeout(uid_t uid, struct passwd *pwd,
- 
-     SAFEALIGN_COPY_UINT32(&req_data[0], &uid, NULL);
-     SAFEALIGN_COPY_UINT32(&req_data[1], &flags, NULL);
--    *result = NULL;
- 
-     ret = sss_get_ex(&inp, flags, timeout);
--    if (ret == 0) {
--        *result = inp.result.pwrep.result;
-+
-+    if (result != NULL) {
-+        if (ret == 0) {
-+            *result = inp.result.pwrep.result;
-+        } else {
-+            *result = NULL;
-+        }
-     }
-+
-     return ret;
- }
- 
-@@ -421,13 +430,17 @@ int sss_nss_getgrnam_timeout(const char *name, struct group *grp,
-         return ret;
-     }
- 
--    *result = NULL;
--
-     ret = sss_get_ex(&inp, flags, timeout);
-     free(discard_const(inp.rd.data));
--    if (ret == 0) {
--        *result = inp.result.grrep.result;
-+
-+    if (result != NULL) {
-+        if (ret == 0) {
-+            *result = inp.result.grrep.result;
-+        } else {
-+            *result = NULL;
-+        }
-     }
-+
-     return ret;
- }
- 
-@@ -448,12 +461,17 @@ int sss_nss_getgrgid_timeout(gid_t gid, struct group *grp,
- 
-     SAFEALIGN_COPY_UINT32(&req_data[0], &gid, NULL);
-     SAFEALIGN_COPY_UINT32(&req_data[1], &flags, NULL);
--    *result = NULL;
- 
-     ret = sss_get_ex(&inp, flags, timeout);
--    if (ret == 0) {
--        *result = inp.result.grrep.result;
-+
-+    if (result != NULL) {
-+        if (ret == 0) {
-+            *result = inp.result.grrep.result;
-+        } else {
-+            *result = NULL;
-+        }
-     }
-+
-     return ret;
- }
- 
--- 
-2.14.3
-
diff --git a/SOURCES/0087-cache-Check-for-max_id-min_id-in-cache_req.patch b/SOURCES/0087-cache-Check-for-max_id-min_id-in-cache_req.patch
deleted file mode 100644
index 04860c2..0000000
--- a/SOURCES/0087-cache-Check-for-max_id-min_id-in-cache_req.patch
+++ /dev/null
@@ -1,353 +0,0 @@
-From 2f712c8fe0ecaa07f7b15ebeae5213978d033278 Mon Sep 17 00:00:00 2001
-From: amitkuma <amitkuma@redhat.com>
-Date: Thu, 30 Nov 2017 22:18:39 +0530
-Subject: [PATCH 87/87] cache: Check for max_id/min_id in cache_req
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The cache_req code doesn't check the min_id/max_id
-boundaries for requests by ID.
-Extending the .lookup_fn function in each plugin
-that searches by ID for a check that returns non-zero
-if the entry is out of the range and 0 if not.
-
-Resolves: https://pagure.io/SSSD/sssd/issue/3569
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 2af80640f18966d65cf82106059ce3c060df93bf)
----
- src/responder/common/cache_req/cache_req.c         |   1 +
- src/responder/common/cache_req/cache_req_private.h |   3 +
- src/responder/common/cache_req/cache_req_search.c  |   5 +
- .../common/cache_req/plugins/cache_req_common.c    |  11 ++
- .../cache_req/plugins/cache_req_group_by_id.c      |   6 +
- .../cache_req/plugins/cache_req_object_by_id.c     |   6 +
- .../cache_req/plugins/cache_req_user_by_id.c       |   5 +
- src/tests/cmocka/test_responder_cache_req.c        | 127 +++++++++++++++++----
- src/util/util_errors.c                             |   1 +
- src/util/util_errors.h                             |   1 +
- 10 files changed, 141 insertions(+), 25 deletions(-)
-
-diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c
-index ad9bc040dd999a205713141e6a1512e47b69c45e..134688b0f62c6546763d91468af3f54b73b6073a 100644
---- a/src/responder/common/cache_req/cache_req.c
-+++ b/src/responder/common/cache_req/cache_req.c
-@@ -953,6 +953,7 @@ static void cache_req_search_domains_done(struct tevent_req *subreq)
-             goto done;
-         }
-         break;
-+    case ERR_ID_OUTSIDE_RANGE:
-     case ENOENT:
-         if (state->check_next == false) {
-             /* Not found. */
-diff --git a/src/responder/common/cache_req/cache_req_private.h b/src/responder/common/cache_req/cache_req_private.h
-index 95f24c0e5b9ab1150591d308c7288c57fe478c5d..9538b9568ca7f77e377cfee67235c8a52ebbe454 100644
---- a/src/responder/common/cache_req/cache_req_private.h
-+++ b/src/responder/common/cache_req/cache_req_private.h
-@@ -192,4 +192,7 @@ cache_reg_common_get_acct_domain_recv(TALLOC_CTX *mem_ctx,
-                                       struct tevent_req *subreq,
-                                       struct cache_req *cr,
-                                       char **_domain);
-+
-+errno_t cache_req_idminmax_check(struct cache_req_data *data,
-+                                 struct sss_domain_info *domain);
- #endif /* _CACHE_REQ_PRIVATE_H_ */
-diff --git a/src/responder/common/cache_req/cache_req_search.c b/src/responder/common/cache_req/cache_req_search.c
-index 3365962d473b0982945de2541e44ba86b43a0db5..7423feb6305df87d368bcc10ba28b9b29d57ecf0 100644
---- a/src/responder/common/cache_req/cache_req_search.c
-+++ b/src/responder/common/cache_req/cache_req_search.c
-@@ -203,6 +203,11 @@ static errno_t cache_req_search_cache(TALLOC_CTX *mem_ctx,
- 
-         *_result = result;
-         break;
-+    case ERR_ID_OUTSIDE_RANGE:
-+        CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
-+                        "ID [%s] was filtered out\n",
-+                        cr->debugobj);
-+        break;
-     case ENOENT:
-         CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr,
-                         "Object [%s] was not found in cache\n",
-diff --git a/src/responder/common/cache_req/plugins/cache_req_common.c b/src/responder/common/cache_req/plugins/cache_req_common.c
-index 408c91949ceb3ecaf743f270f58f4e3fcfc3ccb1..bb11eaa86a8bca3f9d15afe48dab9921319d184e 100644
---- a/src/responder/common/cache_req/plugins/cache_req_common.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_common.c
-@@ -26,6 +26,17 @@
- #include "providers/data_provider.h"
- #include "responder/common/cache_req/cache_req_plugin.h"
- 
-+errno_t cache_req_idminmax_check(struct cache_req_data *data,
-+	                         struct sss_domain_info *domain)
-+{
-+   if (((domain->id_min != 0) && (data->id < domain->id_min)) ||
-+       ((domain->id_max != 0) && (data->id > domain->id_max))) {
-+        DEBUG(SSSDBG_FUNC_DATA, "id exceeds min/max boundaries\n");
-+        return ERR_ID_OUTSIDE_RANGE;
-+   }
-+   return EOK;
-+}
-+
- static struct ldb_message *
- cache_req_well_known_sid_msg(TALLOC_CTX *mem_ctx,
-                              const char *sid,
-diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c
-index ce84b1b4458b447ff6b4b036c6e8fe8f4d7758c8..d178283c33c84e277b83772d04973aa6069af967 100644
---- a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c
-@@ -81,6 +81,12 @@ cache_req_group_by_id_lookup(TALLOC_CTX *mem_ctx,
-                              struct sss_domain_info *domain,
-                              struct ldb_result **_result)
- {
-+    errno_t ret;
-+
-+    ret = cache_req_idminmax_check(data, domain);
-+    if (ret != EOK) {
-+	return ret;
-+    }
-     return sysdb_getgrgid_with_views(mem_ctx, domain, data->id, _result);
- }
- 
-diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c
-index 1327b480c1b1b68f9826fa229c9b001f2d92b79b..be9488d298885320139ccfcd3c59a83ff088e77d 100644
---- a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c
-@@ -110,6 +110,12 @@ cache_req_object_by_id_lookup(TALLOC_CTX *mem_ctx,
-                               struct sss_domain_info *domain,
-                               struct ldb_result **_result)
- {
-+    errno_t ret;
-+
-+    ret = cache_req_idminmax_check(data, domain);
-+    if (ret != EOK) {
-+        return ret;
-+    }
-     return sysdb_search_object_by_id(mem_ctx, domain, data->id,
-                                      data->attrs, _result);
- }
-diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c
-index 656fa41af5f39f68c64e241aa97c4eaf3ec57395..151c3e17acf6ef0d958d5a73a36e1c93b9e7a9a9 100644
---- a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c
-+++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c
-@@ -81,6 +81,11 @@ cache_req_user_by_id_lookup(TALLOC_CTX *mem_ctx,
-                             struct sss_domain_info *domain,
-                             struct ldb_result **_result)
- {
-+    errno_t ret;
-+    ret = cache_req_idminmax_check(data, domain);
-+    if (ret != EOK) {
-+        return ret;
-+    }
-     return sysdb_getpwuid_with_views(mem_ctx, domain, data->id, _result);
- }
- 
-diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c
-index 0ee0070d0c9fbb89020f522b2f7613f1076a8cbb..5f50b27a5ee846c9ccf71e1e661359a07c2e02e8 100644
---- a/src/tests/cmocka/test_responder_cache_req.c
-+++ b/src/tests/cmocka/test_responder_cache_req.c
-@@ -59,6 +59,11 @@ struct test_group {
-                                     test_single_domain_setup, \
-                                     test_single_domain_teardown)
- 
-+#define new_single_domain_id_limit_test(test) \
-+    cmocka_unit_test_setup_teardown(test_ ## test, \
-+                                    test_single_domain_id_limits_setup, \
-+                                    test_single_domain_teardown)
-+
- #define new_multi_domain_test(test) \
-     cmocka_unit_test_setup_teardown(test_ ## test, \
-                                     test_multi_domain_setup, \
-@@ -521,33 +526,39 @@ __wrap_sss_dp_get_account_send(TALLOC_CTX *mem_ctx,
-     return test_req_succeed_send(mem_ctx, rctx->ev);
- }
- 
-+static int test_single_domain_setup_common(void **state,
-+                                           struct sss_test_conf_param *params)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+    errno_t ret;
-+
-+    assert_true(leak_check_setup());
-+
-+    test_dom_suite_setup(TESTS_PATH);
-+
-+    test_ctx = talloc_zero(global_talloc_context, struct cache_req_test_ctx);
-+    assert_non_null(test_ctx);
-+    *state = test_ctx;
-+
-+    test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH, TEST_CONF_DB,
-+                                         TEST_DOM_NAME, TEST_ID_PROVIDER, params);
-+    assert_non_null(test_ctx->tctx);
-+
-+    test_ctx->rctx = mock_rctx(test_ctx, test_ctx->tctx->ev,
-+                               test_ctx->tctx->dom, NULL);
-+    assert_non_null(test_ctx->rctx);
-+
-+    ret = sss_ncache_init(test_ctx, 10, 0, &test_ctx->ncache);
-+    assert_int_equal(ret, EOK);
-+
-+    check_leaks_push(test_ctx);
-+
-+    return 0;
-+}
-+
- static int test_single_domain_setup(void **state)
- {
--    struct cache_req_test_ctx *test_ctx = NULL;
--    errno_t ret;
--
--    assert_true(leak_check_setup());
--
--    test_dom_suite_setup(TESTS_PATH);
--
--    test_ctx = talloc_zero(global_talloc_context, struct cache_req_test_ctx);
--    assert_non_null(test_ctx);
--    *state = test_ctx;
--
--    test_ctx->tctx = create_dom_test_ctx(test_ctx, TESTS_PATH, TEST_CONF_DB,
--                                         TEST_DOM_NAME, TEST_ID_PROVIDER, NULL);
--    assert_non_null(test_ctx->tctx);
--
--    test_ctx->rctx = mock_rctx(test_ctx, test_ctx->tctx->ev,
--                               test_ctx->tctx->dom, NULL);
--    assert_non_null(test_ctx->rctx);
--
--    ret = sss_ncache_init(test_ctx, 10, 0, &test_ctx->ncache);
--    assert_int_equal(ret, EOK);
--
--    check_leaks_push(test_ctx);
--
--    return 0;
-+    return test_single_domain_setup_common(state, NULL);
- }
- 
- static int test_single_domain_teardown(void **state)
-@@ -565,6 +576,16 @@ static int test_single_domain_teardown(void **state)
-     return 0;
- }
- 
-+static int test_single_domain_id_limits_setup(void **state)
-+{
-+    struct sss_test_conf_param params[] = {
-+        { "min_id", "100" },
-+        { "max_id", "10000" },
-+        { NULL, NULL },             /* Sentinel */
-+    };
-+    return test_single_domain_setup_common(state, params);
-+}
-+
- static int test_multi_domain_setup(void **state)
- {
-     struct cache_req_test_ctx *test_ctx = NULL;
-@@ -596,6 +617,32 @@ static int test_multi_domain_setup(void **state)
-     return 0;
- }
- 
-+void test_user_by_id_below_id_range(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Test. */
-+    run_cache_req(test_ctx, cache_req_user_by_id_send,
-+                  cache_req_user_by_id_test_done, test_ctx->tctx->dom,
-+                  0, 10, ENOENT);
-+    assert_false(test_ctx->dp_called);
-+}
-+
-+void test_user_by_id_above_id_range(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Test. */
-+    run_cache_req(test_ctx, cache_req_user_by_id_send,
-+                  cache_req_user_by_id_test_done, test_ctx->tctx->dom,
-+                  0, 100000, ENOENT);
-+    assert_false(test_ctx->dp_called);
-+}
-+
- static int test_multi_domain_teardown(void **state)
- {
-     struct cache_req_test_ctx *test_ctx;
-@@ -1332,6 +1379,32 @@ void test_user_by_id_sub_domains_locator_missing_found(void **state)
-     talloc_free(tmp_ctx);
- }
- 
-+void test_group_by_id_below_id_range(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Test. */
-+    run_cache_req(test_ctx, cache_req_group_by_id_send,
-+                  cache_req_group_by_id_test_done, test_ctx->tctx->dom,
-+                  0, 10, ENOENT);
-+    assert_false(test_ctx->dp_called);
-+}
-+
-+void test_group_by_id_above_id_range(void **state)
-+{
-+    struct cache_req_test_ctx *test_ctx = NULL;
-+
-+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
-+
-+    /* Test. */
-+    run_cache_req(test_ctx, cache_req_group_by_id_send,
-+                  cache_req_group_by_id_test_done, test_ctx->tctx->dom,
-+                  0, 100000, ENOENT);
-+    assert_false(test_ctx->dp_called);
-+}
-+
- void test_user_by_id_sub_domains_locator_missing_notfound(void **state)
- {
-     struct cache_req_test_ctx *test_ctx = NULL;
-@@ -3874,6 +3947,8 @@ int main(int argc, const char *argv[])
-         new_single_domain_test(user_by_id_missing_notfound),
-         new_multi_domain_test(user_by_id_multiple_domains_found),
-         new_multi_domain_test(user_by_id_multiple_domains_notfound),
-+        new_single_domain_id_limit_test(user_by_id_below_id_range),
-+        new_single_domain_id_limit_test(user_by_id_above_id_range),
- 
-         new_single_domain_test(group_by_name_cache_valid),
-         new_single_domain_test(group_by_name_cache_expired),
-@@ -3884,6 +3959,8 @@ int main(int argc, const char *argv[])
-         new_multi_domain_test(group_by_name_multiple_domains_found),
-         new_multi_domain_test(group_by_name_multiple_domains_notfound),
-         new_multi_domain_test(group_by_name_multiple_domains_parse),
-+        new_single_domain_id_limit_test(group_by_id_below_id_range),
-+        new_single_domain_id_limit_test(group_by_id_above_id_range),
- 
-         new_single_domain_test(group_by_id_cache_valid),
-         new_single_domain_test(group_by_id_cache_expired),
-diff --git a/src/util/util_errors.c b/src/util/util_errors.c
-index 06c620b40aaa00d6ce58ace3a28449ffbdf8da88..39ce3d7dcf4af4c489a0a9b7768668497cb84ba5 100644
---- a/src/util/util_errors.c
-+++ b/src/util/util_errors.c
-@@ -117,6 +117,7 @@ struct err_string error_to_str[] = {
-     { "Unable to resolve host" }, /* ERR_UNABLE_TO_RESOLVE_HOST */
-     { "GetAccountDomain() not supported" }, /* ERR_GET_ACCT_DOM_NOT_SUPPORTED */
-     { "The last GetAccountDomain() result is still valid" }, /* ERR_GET_ACCT_DOM_CACHED */
-+    { "ID is outside the allowed range" }, /* ERR_ID_OUTSIDE_RANGE */
-     { "ERR_LAST" } /* ERR_LAST */
- };
- 
-diff --git a/src/util/util_errors.h b/src/util/util_errors.h
-index bebd6e198fc0077891a602f80182a993ce3f789b..621a3b116edac45960190684055bcd0692135957 100644
---- a/src/util/util_errors.h
-+++ b/src/util/util_errors.h
-@@ -139,6 +139,7 @@ enum sssd_errors {
-     ERR_UNABLE_TO_RESOLVE_HOST,
-     ERR_GET_ACCT_DOM_NOT_SUPPORTED,
-     ERR_GET_ACCT_DOM_CACHED,
-+    ERR_ID_OUTSIDE_RANGE,
-     ERR_LAST            /* ALWAYS LAST */
- };
- 
--- 
-2.14.3
-
diff --git a/SOURCES/0088-Revert-p11_child-make-sure-OCSP-checks-are-done.patch b/SOURCES/0088-Revert-p11_child-make-sure-OCSP-checks-are-done.patch
deleted file mode 100644
index 18b947b..0000000
--- a/SOURCES/0088-Revert-p11_child-make-sure-OCSP-checks-are-done.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 424aa780fbb645214b92cf09f23c905b93bdf267 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 12 Dec 2017 15:28:27 +0100
-Subject: [PATCH 88/89] Revert "p11_child: make sure OCSP checks are done"
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This reverts commit 2297cc7d6cd5c38a7d64027165e4e82ca497f418.
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit c221b5fb4d3fc511cebcae2f042e43fb1c577bc7)
----
- src/p11_child/p11_child_nss.c | 17 -----------------
- 1 file changed, 17 deletions(-)
-
-diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
-index bf533f3efe4d680f4c6dbd10a0d2c5a5da371c67..21c508eb1b1b68b3606d0a5eed36573b01f27a19 100644
---- a/src/p11_child/p11_child_nss.c
-+++ b/src/p11_child/p11_child_nss.c
-@@ -338,23 +338,6 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-                       PR_GetError(), PORT_ErrorToString(PR_GetError()));
-                 continue;
-             }
--
--            /* with 'certificateUsageCheckAllUsages' set
--             * CERT_VerifyCertificateNow() does not do OCSP so it must be done
--             * explicitly */
--            if (cert_verify_opts->do_ocsp) {
--                rv = CERT_CheckOCSPStatus(handle, cert_list_node->cert,
--                                          PR_Now(), NULL);
--                if (rv != SECSuccess) {
--                    DEBUG(SSSDBG_OP_FAILURE,
--                          "Certificate [%s][%s] failed OCSP check [%d][%s], "
--                          "skipping.\n",
--                          cert_list_node->cert->nickname,
--                          cert_list_node->cert->subjectName,
--                          PR_GetError(), PORT_ErrorToString(PR_GetError()));
--                    continue;
--                }
--            }
-         }
- 
-         if (key_id_in != NULL) {
--- 
-2.14.3
-
diff --git a/SOURCES/0089-p11_child-properly-check-results-of-CERT_VerifyCerti.patch b/SOURCES/0089-p11_child-properly-check-results-of-CERT_VerifyCerti.patch
deleted file mode 100644
index 85e867a..0000000
--- a/SOURCES/0089-p11_child-properly-check-results-of-CERT_VerifyCerti.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From 56402a2b350ebdcfd49685a5a3c0fd42131b2196 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 12 Dec 2017 15:24:57 +0100
-Subject: [PATCH 89/89] p11_child: properly check results of
- CERT_VerifyCertificateNow
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-With certificateUsageCheckAllUsages not only the return code of
-CERT_VerifyCertificateNow() should be checked but also the usages for
-which the certificate was verified. The usages checked here will all
-involve CA signature checks and OCSP checks if OCSP is enabled.
-
-Related to https://pagure.io/SSSD/sssd/issue/3560
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 787ba9c882f1d7ff9ea4f2745e779c5fb04dfafc)
----
- src/p11_child/p11_child_nss.c | 14 ++++++++++++--
- 1 file changed, 12 insertions(+), 2 deletions(-)
-
-diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
-index 21c508eb1b1b68b3606d0a5eed36573b01f27a19..cb894280c18fcbd59c5499e36d30f3ba305c0ea2 100644
---- a/src/p11_child/p11_child_nss.c
-+++ b/src/p11_child/p11_child_nss.c
-@@ -45,6 +45,15 @@
- #include "util/crypto/sss_crypto.h"
- #include "util/cert.h"
- 
-+#define EXP_USAGES (  certificateUsageSSLClient \
-+                    | certificateUsageSSLServer \
-+                    | certificateUsageSSLServerWithStepUp \
-+                    | certificateUsageEmailSigner \
-+                    | certificateUsageEmailRecipient \
-+                    | certificateUsageObjectSigner \
-+                    | certificateUsageStatusResponder \
-+                    | certificateUsageSSLCA )
-+
- enum op_mode {
-     OP_NONE,
-     OP_AUTH,
-@@ -136,6 +145,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-     char *cert_b64 = NULL;
-     char *multi = NULL;
-     PRCList *node;
-+    SECCertificateUsage returned_usage = 0;
- 
-     nss_ctx = NSS_InitContext(nss_db, "", "", SECMOD_DB, &parameters, flags);
-     if (nss_ctx == NULL) {
-@@ -329,8 +339,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db,
-             rv = CERT_VerifyCertificateNow(handle, cert_list_node->cert,
-                                            PR_TRUE,
-                                            certificateUsageCheckAllUsages,
--                                           NULL, NULL);
--            if (rv != SECSuccess) {
-+                                           NULL, &returned_usage);
-+            if (rv != SECSuccess || ((returned_usage & EXP_USAGES) == 0)) {
-                 DEBUG(SSSDBG_OP_FAILURE,
-                       "Certificate [%s][%s] not valid [%d][%s], skipping.\n",
-                       cert_list_node->cert->nickname,
--- 
-2.14.3
-
diff --git a/SOURCES/0090-ifp-use-realloc-in-ifp_list_ctx_remaining_capacity.patch b/SOURCES/0090-ifp-use-realloc-in-ifp_list_ctx_remaining_capacity.patch
deleted file mode 100644
index c731709..0000000
--- a/SOURCES/0090-ifp-use-realloc-in-ifp_list_ctx_remaining_capacity.patch
+++ /dev/null
@@ -1,92 +0,0 @@
-From 674c5c3ba930a8546371ea8e138ff20a15090431 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 15 Dec 2017 12:09:06 +0100
-Subject: [PATCH 90/90] ifp: use realloc in ifp_list_ctx_remaining_capacity()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-ifp_list_ctx_remaining_capacity() might be called multiple times if
-results from multiple domains are added to the result list.
-
-The current use of talloc_zero_array() which was introduced with commit
-b0b9222 will override results which are already in the list. This causes
-a regression since it worked before.
-
-This patch replaces it with talloc_realloc().
-
-Resolves https://pagure.io/SSSD/sssd/issue/3608
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 510ac193900a7bb9dfae10c0ca4607c224b265af)
----
- src/responder/ifp/ifp_private.h |  1 +
- src/responder/ifp/ifpsrv_util.c | 16 ++++++++++++----
- 2 files changed, 13 insertions(+), 4 deletions(-)
-
-diff --git a/src/responder/ifp/ifp_private.h b/src/responder/ifp/ifp_private.h
-index 13455bbf70860fb6dbfa3bb65fe3bd565d53257d..b406e7f5bab3e0dbc9696a5ab58e46b6ee7839eb 100644
---- a/src/responder/ifp/ifp_private.h
-+++ b/src/responder/ifp/ifp_private.h
-@@ -93,6 +93,7 @@ struct ifp_list_ctx {
-     struct ifp_ctx *ctx;
- 
-     const char **paths;
-+    size_t paths_max;
-     size_t path_count;
- };
- 
-diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c
-index 1df646339526186e862dcd09cddd971b77c20a8b..da4ab06796a99c930b7a4ad21ca408814f8b4c49 100644
---- a/src/responder/ifp/ifpsrv_util.c
-+++ b/src/responder/ifp/ifpsrv_util.c
-@@ -372,7 +372,9 @@ struct ifp_list_ctx *ifp_list_ctx_new(struct sbus_request *sbus_req,
-     list_ctx->ctx = ctx;
-     list_ctx->dom = ctx->rctx->domains;
-     list_ctx->filter = filter;
--    list_ctx->paths = talloc_zero_array(list_ctx, const char *, 1);
-+    list_ctx->paths_max = 1;
-+    list_ctx->paths = talloc_zero_array(list_ctx, const char *,
-+                                        list_ctx->paths_max);
-     if (list_ctx->paths == NULL) {
-         talloc_free(list_ctx);
-         return NULL;
-@@ -387,6 +389,7 @@ errno_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx,
- {
-     size_t capacity = list_ctx->limit - list_ctx->path_count;
-     errno_t ret;
-+    size_t c;
- 
-     if (list_ctx->limit == 0) {
-         capacity = entries;
-@@ -396,19 +399,24 @@ errno_t ifp_list_ctx_remaining_capacity(struct ifp_list_ctx *list_ctx,
-     if (capacity < entries) {
-         DEBUG(SSSDBG_MINOR_FAILURE,
-               "IFP list request has limit of %"PRIu32" entries but back end "
--              "returned %zu entries\n", list_ctx->limit, entries);
-+              "returned %zu entries\n", list_ctx->limit,
-+                                        list_ctx->path_count + entries);
-     } else {
-         capacity = entries;
-     }
- 
- immediately:
--    talloc_zfree(list_ctx->paths);
--    list_ctx->paths = talloc_zero_array(list_ctx, const char *, capacity);
-+    list_ctx->paths_max = list_ctx->path_count + capacity;
-+    list_ctx->paths = talloc_realloc(list_ctx, list_ctx->paths, const char *,
-+                                     list_ctx->paths_max);
-     if (list_ctx->paths == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero_array() failed\n");
-         ret = ENOMEM;
-         goto done;
-     }
-+    for (c = list_ctx->path_count; c < list_ctx->paths_max; c++) {
-+        list_ctx->paths[c] = NULL;
-+    }
- 
-     *_capacity = capacity;
-     ret = EOK;
--- 
-2.14.3
-
diff --git a/SOURCES/0091-IPA-Delay-the-first-periodic-refresh-of-trusted-doma.patch b/SOURCES/0091-IPA-Delay-the-first-periodic-refresh-of-trusted-doma.patch
deleted file mode 100644
index c828f38..0000000
--- a/SOURCES/0091-IPA-Delay-the-first-periodic-refresh-of-trusted-doma.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From a2f7322b9d8e47c0c93463d9fe1f37dc869799df Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 8 Jan 2018 18:30:57 +0100
-Subject: [PATCH 91/96] IPA: Delay the first periodic refresh of trusted
- domains
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-When the IPA subdomains code is initialized, the responders send a request
-to fetch subdomains. This request first stores the list of trusted domains
-to the cache and then runs the ipa-getkeytab helper.
-
-At the same time, the periodical task to update the subdomains is also
-started. The task founds out that all the trusted domains are already known
-and finishes the request, which replies to the Data Provider requests as
-well even while the ipa-getkeytab request is still running.
-
-This unblocks requests from the responders, which try to connect to the AD
-DCs even before the keytab is available, which switches the SSSD status to
-offline.
-
-This patch simply delays the first periodic task in the IPA subdomains code
-by 10 minutes, thus mitigating the startup race.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3601
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-Reviewed-by: Michal Židek <mzidek@redhat.com>
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit 261a84355d9d033ca03f46727dbc2cf4921f154e)
----
- src/providers/ipa/ipa_subdomains.c | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
-index 3d3341a3eff5e55ae0c6fa5ad40603adc609e692..7d2cf80c8137a0428880c5474d4d94ca3ad1a5d4 100644
---- a/src/providers/ipa/ipa_subdomains.c
-+++ b/src/providers/ipa/ipa_subdomains.c
-@@ -2379,6 +2379,11 @@ errno_t ipa_subdomains_init(TALLOC_CTX *mem_ctx,
-     struct ipa_options *ipa_options;
-     time_t period;
-     errno_t ret;
-+    /* Delay the first ptask that refreshes the trusted domains so that a race between
-+     * the first responder-induced request and the ptask doesn't cause issues, see
-+     * also upstream ticket #3601
-+     */
-+    const time_t ptask_first_delay = 600;
- 
-     ipa_options = ipa_id_ctx->ipa_options;
- 
-@@ -2401,7 +2406,7 @@ errno_t ipa_subdomains_init(TALLOC_CTX *mem_ctx,
-                   struct ipa_subdomains_ctx, struct dp_subdomains_data, struct dp_reply_std);
- 
-     period = be_ctx->domain->subdomain_refresh_interval;
--    ret = be_ptask_create(sd_ctx, be_ctx, period, 0, 0, 0, period,
-+    ret = be_ptask_create(sd_ctx, be_ctx, period, ptask_first_delay, 0, 0, period,
-                           BE_PTASK_OFFLINE_DISABLE, 0,
-                           ipa_subdomains_ptask_send, ipa_subdomains_ptask_recv, sd_ctx,
-                           "Subdomains Refresh", NULL);
--- 
-2.14.3
-
diff --git a/SOURCES/0092-sysdb-add-userMappedCertificate-to-the-index.patch b/SOURCES/0092-sysdb-add-userMappedCertificate-to-the-index.patch
deleted file mode 100644
index 346c8b5..0000000
--- a/SOURCES/0092-sysdb-add-userMappedCertificate-to-the-index.patch
+++ /dev/null
@@ -1,55 +0,0 @@
-From 57a83eb8657a125d203a335b052d965c7a3b15de Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 8 Jan 2018 18:22:17 +0100
-Subject: [PATCH 92/96] sysdb: add userMappedCertificate to the index
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Related to https://pagure.io/SSSD/sssd/issue/3503
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 5b78fff78bb44d1af5420db23b02210f755f5f17)
----
- src/db/sysdb_private.h |  1 +
- src/db/sysdb_upgrade.c | 12 ++++++++++++
- 2 files changed, 13 insertions(+)
-
-diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h
-index cac06ba46da23080d1ab661502d0792bd37b9291..c0a8e29ab9578acb27cf8d1db049c4260904fdda 100644
---- a/src/db/sysdb_private.h
-+++ b/src/db/sysdb_private.h
-@@ -78,6 +78,7 @@
-      "@IDXATTR: canonicalUserPrincipalName\n" \
-      "@IDXATTR: uniqueID\n" \
-      "@IDXATTR: mail\n" \
-+     "@IDXATTR: userMappedCertificate\n" \
-      "\n" \
-      "dn: @MODULES\n" \
-      "@LIST: asq,memberof\n" \
-diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c
-index bc157a24664239bc1255e49a1825243a07acc90f..46df971e98f73dc28bc6764a478f13d871515124 100644
---- a/src/db/sysdb_upgrade.c
-+++ b/src/db/sysdb_upgrade.c
-@@ -2475,6 +2475,18 @@ int sysdb_upgrade_19(struct sysdb_ctx *sysdb, const char **ver)
-         goto done;
-     }
- 
-+    ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL);
-+    if (ret != LDB_SUCCESS) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-+    ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_USER_MAPPED_CERT);
-+    if (ret != LDB_SUCCESS) {
-+        ret = ENOMEM;
-+        goto done;
-+    }
-+
-     ret = ldb_modify(sysdb->ldb, msg);
-     if (ret != LDB_SUCCESS) {
-         ret = sysdb_error_to_errno(ret);
--- 
-2.14.3
-
diff --git a/SOURCES/0093-AD-Inherit-the-MPG-setting-from-the-main-domain.patch b/SOURCES/0093-AD-Inherit-the-MPG-setting-from-the-main-domain.patch
deleted file mode 100644
index 875f5fb..0000000
--- a/SOURCES/0093-AD-Inherit-the-MPG-setting-from-the-main-domain.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From e67f94d854ef125626294771473a1204726eeba4 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 15 Jan 2018 22:11:24 +0100
-Subject: [PATCH 93/96] AD: Inherit the MPG setting from the main domain
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-If the auto_private_groups option was set in the domain section for
-direct integration, it only had an effect on the joined domain, not any
-of the subdomains, so requesting a user from the child domain would look
-like this:
-    $ id childuser@child.win.trust.test
-    uid=30000(childuser@child.win.trust.test) gid=40000(usergroup@child.win.trust.test) groups=40000(usergroup@child.win.trust.test)
-The expected result, visible after this patch is:
-    $ id childuser@child.win.trust.test
-    uid=30000(childuser@child.win.trust.test) gid=30000(childuser@child.win.trust.test) groups=30000(childuser@child.win.trust.test),40000(usergroup@child.win.trust.test)
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3613
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 29ebf45f96b13590ae76a19c7c16c53f172e4ae4)
----
- src/providers/ad/ad_subdomains.c | 7 +++++++
- 1 file changed, 7 insertions(+)
-
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index 3fb9b950f171d85817cce35ac92ad7c4974ccb68..1b9483a5dce937d6acdd813486a1e8c18210d35f 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -391,6 +391,13 @@ ad_subdom_store(struct sdap_idmap_ctx *idmap_ctx,
-     }
- 
-     mpg = sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx, name, sid_str);
-+    if (mpg == false) {
-+        /* Domains that use the POSIX attributes set by the admin must
-+         * inherit the MPG setting from the parent domain so that the
-+         * auto_private_groups options works for trusted domains as well
-+         */
-+        mpg = domain->mpg;
-+    }
- 
-     ret = sysdb_subdomain_store(domain->sysdb, name, realm, flat, sid_str,
-                                 mpg, enumerate, domain->forest, 0, NULL);
--- 
-2.14.3
-
diff --git a/SOURCES/0094-SDAP-skip-builtin-AD-groups-in-sdap_save_grpmem.patch b/SOURCES/0094-SDAP-skip-builtin-AD-groups-in-sdap_save_grpmem.patch
deleted file mode 100644
index 72c1f2c..0000000
--- a/SOURCES/0094-SDAP-skip-builtin-AD-groups-in-sdap_save_grpmem.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-From 75da39f57ba0223be9bd9906cd3ed902623aed10 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Mon, 18 Dec 2017 20:30:04 +0100
-Subject: [PATCH 94/96] SDAP: skip builtin AD groups in sdap_save_grpmem()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-While processing group memberships SSSD might accidentally save builtin
-or other well known AD groups. With this patch those groups are skipped
-similar as e.g. in sdap_save_group().
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3610
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit c36a66b7fb77cff29400c751b363a342923e122e)
----
- src/providers/ldap/sdap_async_groups.c | 11 +++++++++++
- 1 file changed, 11 insertions(+)
-
-diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c
-index b1cfb7e4a4c054e5d365da5fca65da27c9ef5461..bbe6f1386eadbe4eb7b47bea9e5a6bb8ff4ee8eb 100644
---- a/src/providers/ldap/sdap_async_groups.c
-+++ b/src/providers/ldap/sdap_async_groups.c
-@@ -880,6 +880,8 @@ static int sdap_save_grpmem(TALLOC_CTX *memctx,
-     int ret;
-     const char *remove_attrs[] = {SYSDB_MEMBER, SYSDB_ORIG_MEMBER, SYSDB_GHOST,
-                                   NULL};
-+    const char *check_dom;
-+    const char *check_name;
- 
-     if (dom->ignore_group_members) {
-         DEBUG(SSSDBG_CRIT_FAILURE,
-@@ -905,6 +907,15 @@ static int sdap_save_grpmem(TALLOC_CTX *memctx,
-         group_dom = sss_get_domain_by_sid_ldap_fallback(get_domains_head(dom),
-                                                         group_sid);
-         if (group_dom == NULL) {
-+            ret = well_known_sid_to_name(group_sid, &check_dom, &check_name);
-+            if (ret == EOK) {
-+                DEBUG(SSSDBG_TRACE_FUNC,
-+                      "Skipping group with SID [%s][%s\\%s] which is "
-+                      "currently not handled by SSSD.\n",
-+                      group_sid, check_dom, check_name);
-+                return EOK;
-+            }
-+
-             DEBUG(SSSDBG_TRACE_FUNC, "SID [%s] does not belong to any known "
-                                      "domain, using [%s].\n", group_sid,
-                                                               dom->name);
--- 
-2.14.3
-
diff --git a/SOURCES/0095-SYSDB-Read-the-ldb_message-from-loop-s-index-counter.patch b/SOURCES/0095-SYSDB-Read-the-ldb_message-from-loop-s-index-counter.patch
deleted file mode 100644
index b0469ba..0000000
--- a/SOURCES/0095-SYSDB-Read-the-ldb_message-from-loop-s-index-counter.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From 80e4aa68587d5a70bfd41f78f17902bf06b447a1 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 23 Jan 2018 11:11:14 +0100
-Subject: [PATCH 95/96] SYSDB: Read the ldb_message from loop's index counter
- when reading subdomain UPNs
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-There was a typo in code that read the UPN suffixes from the subdomain
-ldb_message. As a result, the UPN suffixes from the first domain were
-always consulted for all domains.
-
-Related to:
-https://pagure.io/SSSD/sssd/issue/3431
-
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-(cherry picked from commit a8a3fcbf6f75a7c2665e8bf503c186e07dfab333)
----
- src/db/sysdb_subdomains.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c
-index 0dd05c24c963f12a28ef6f6b64dc40faa7fcc649..b0863b7935b060cb545197005c84f51efbc2d49c 100644
---- a/src/db/sysdb_subdomains.c
-+++ b/src/db/sysdb_subdomains.c
-@@ -386,7 +386,7 @@ errno_t sysdb_update_subdomains(struct sss_domain_info *domain,
-                                              SYSDB_SUBDOMAIN_FOREST, NULL);
- 
-         upn_suffixes = NULL;
--        tmp_el = ldb_msg_find_element(res->msgs[0], SYSDB_UPN_SUFFIXES);
-+        tmp_el = ldb_msg_find_element(res->msgs[i], SYSDB_UPN_SUFFIXES);
-         if (tmp_el != NULL) {
-             upn_suffixes = sss_ldb_el_to_string_list(tmp_ctx, tmp_el);
-             if (upn_suffixes == NULL) {
--- 
-2.14.3
-
diff --git a/SOURCES/0096-nss-idmap-check-timed-muted-return-code.patch b/SOURCES/0096-nss-idmap-check-timed-muted-return-code.patch
deleted file mode 100644
index 974484c..0000000
--- a/SOURCES/0096-nss-idmap-check-timed-muted-return-code.patch
+++ /dev/null
@@ -1,73 +0,0 @@
-From 63c09393b926f0d00317a1ca1dc6c7c992c40f4e Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 16 Jan 2018 18:09:00 +0100
-Subject: [PATCH 96/96] nss-idmap: check timed muted return code
-
-Check return values and make sure the mutex is released in case of
-errors.
-
-Related to https://pagure.io/SSSD/sssd/issue/2478
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 3e32cb2ad36a9dd2654c7f63469dc595f1bb8593)
----
- src/sss_client/idmap/common_ex.c     | 2 ++
- src/sss_client/idmap/sss_nss_ex.c    | 5 ++++-
- src/sss_client/idmap/sss_nss_idmap.c | 5 ++++-
- 3 files changed, 10 insertions(+), 2 deletions(-)
-
-diff --git a/src/sss_client/idmap/common_ex.c b/src/sss_client/idmap/common_ex.c
-index 5efe9fabed7896ce674615472dbb256c4eae2144..e655bb864e063665cb56bcd3ff419e46c766478b 100644
---- a/src/sss_client/idmap/common_ex.c
-+++ b/src/sss_client/idmap/common_ex.c
-@@ -83,6 +83,7 @@ int sss_nss_timedlock(unsigned int timeout_ms, int *time_left_ms)
-     if (ret == 0) {
-         ret = clock_gettime(CLOCK_REALTIME, &endtime);
-         if (ret != 0) {
-+            sss_nss_unlock();
-             return ret;
-         }
- 
-@@ -92,6 +93,7 @@ int sss_nss_timedlock(unsigned int timeout_ms, int *time_left_ms)
-             TIMESPECSUB(&endtime, &starttime, &diff);
-             left = timeout_ms - TIMESPEC_TO_MS(&diff);
-             if (left <= 0) {
-+                sss_nss_unlock();
-                 return EIO;
-             } else if (left > SSS_CLI_SOCKET_TIMEOUT) {
-                 *time_left_ms = SSS_CLI_SOCKET_TIMEOUT;
-diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c
-index 861b1e1e92db4f7e6e8d74a812dc3c9220711773..af6a95180656b598bcb94c209dfa821cb0275f02 100644
---- a/src/sss_client/idmap/sss_nss_ex.c
-+++ b/src/sss_client/idmap/sss_nss_ex.c
-@@ -202,7 +202,10 @@ int sss_get_ex(struct nss_input *inp, uint32_t flags, unsigned int timeout)
-         }
-     }
- 
--    sss_nss_timedlock(timeout, &time_left);
-+    ret = sss_nss_timedlock(timeout, &time_left);
-+    if (ret != 0) {
-+        return ret;
-+    }
- 
-     if (!skip_mc && !skip_data) {
-         /* previous thread might already initialize entry in mmap cache */
-diff --git a/src/sss_client/idmap/sss_nss_idmap.c b/src/sss_client/idmap/sss_nss_idmap.c
-index 6e7685d2b1d80956b6a6668e9bbb146abd9e86ed..cbf8c11f2870e3574c75fe109cb19268e8a0b56d 100644
---- a/src/sss_client/idmap/sss_nss_idmap.c
-+++ b/src/sss_client/idmap/sss_nss_idmap.c
-@@ -257,7 +257,10 @@ static int sss_nss_getyyybyxxx(union input inp, enum sss_cli_command cmd,
-     if (timeout == NO_TIMEOUT) {
-         sss_nss_lock();
-     } else {
--        sss_nss_timedlock(timeout, &time_left);
-+        ret = sss_nss_timedlock(timeout, &time_left);
-+        if (ret != 0) {
-+            return ret;
-+        }
-     }
- 
-     nret = sss_nss_make_request_timeout(cmd, &rd, time_left, &repbuf, &replen,
--- 
-2.14.3
-
diff --git a/SOURCES/0097-DESKPROFILE-Add-checks-for-user-and-host-category.patch b/SOURCES/0097-DESKPROFILE-Add-checks-for-user-and-host-category.patch
deleted file mode 100644
index 1199481..0000000
--- a/SOURCES/0097-DESKPROFILE-Add-checks-for-user-and-host-category.patch
+++ /dev/null
@@ -1,155 +0,0 @@
-From 2349423ad813e8a4fe090c283603b4cf18919662 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
-Date: Mon, 22 Jan 2018 00:02:43 +0100
-Subject: [PATCH 97/97] DESKPROFILE: Add checks for user and host category
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-freeipa-deskprofile-plugin can have both user and host category set as
-"all" and when it happens, no users and groups or hosts or hostgroups
-are going to be set.
-
-Let's treat this expected (but so far missed) situation on SSSD side.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3449
-
-Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit b72e444bc1cd2fe8d9617f09b446c678d4684fff)
----
- src/providers/ipa/ipa_deskprofile_rules_util.c | 100 ++++++++++++++++++++-----
- 1 file changed, 82 insertions(+), 18 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_deskprofile_rules_util.c b/src/providers/ipa/ipa_deskprofile_rules_util.c
-index 53c433145666af00a994420ccd1a926b11937fc9..01b7d0527c2a15e0f4d2bdce1867ad0482fca7b0 100644
---- a/src/providers/ipa/ipa_deskprofile_rules_util.c
-+++ b/src/providers/ipa/ipa_deskprofile_rules_util.c
-@@ -684,6 +684,8 @@ ipa_deskprofile_rules_save_rule_to_disk(
-     TALLOC_CTX *tmp_ctx;
-     const char *rule_name;
-     const char *data;
-+    const char *hostcat;
-+    const char *usercat;
-     char *shortname;
-     char *domainname;
-     char *base_dn;
-@@ -722,6 +724,28 @@ ipa_deskprofile_rules_save_rule_to_disk(
-         goto done;
-     }
- 
-+    ret = sysdb_attrs_get_string(rule, IPA_HOST_CATEGORY, &hostcat);
-+    if (ret == ENOENT) {
-+        hostcat = NULL;
-+    } else if (ret != EOK) {
-+        DEBUG(SSSDBG_TRACE_FUNC,
-+              "Failed to get the Desktop Profile Rule host category for rule "
-+              "\"%s\" [%d]: %s\n",
-+              rule_name, ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-+    ret = sysdb_attrs_get_string(rule, IPA_USER_CATEGORY, &usercat);
-+    if (ret == ENOENT) {
-+        usercat = NULL;
-+    } else if (ret != EOK) {
-+        DEBUG(SSSDBG_TRACE_FUNC,
-+              "Failed to get the Desktop Profile Rule user category for rule "
-+              "\"%s\" [%d]: %s\n",
-+              rule_name, ret, sss_strerror(ret));
-+        goto done;
-+    }
-+
-     rule_prio = talloc_asprintf(tmp_ctx, "%06d", prio);
-     if (rule_prio == NULL) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to allocate rule priority\n");
-@@ -753,26 +777,66 @@ ipa_deskprofile_rules_save_rule_to_disk(
-         goto done;
-     }
- 
--    ret = ipa_deskprofile_rule_check_memberuser(tmp_ctx, domain, rule,
--                                                rule_name, rule_prio,
--                                                base_dn, username,
--                                                &user_prio, &group_prio);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE,
--              "ipa_deskprofile_rule_check_memberuser() failed [%d]: %s\n",
--              ret, sss_strerror(ret));
--        goto done;
-+    if (usercat != NULL && strcasecmp(usercat, "all") == 0) {
-+        user_prio = talloc_strdup(tmp_ctx, rule_prio);
-+        if (user_prio == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Failed to allocate the user priority "
-+                  "when user category is \"all\"\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+
-+        group_prio = talloc_strdup(tmp_ctx, rule_prio);
-+        if (group_prio == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Failed to allocate the group priority "
-+                  "when user category is \"all\"\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+    } else {
-+        ret = ipa_deskprofile_rule_check_memberuser(tmp_ctx, domain, rule,
-+                                                    rule_name, rule_prio,
-+                                                    base_dn, username,
-+                                                    &user_prio, &group_prio);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "ipa_deskprofile_rule_check_memberuser() failed [%d]: %s\n",
-+                  ret, sss_strerror(ret));
-+            goto done;
-+        }
-     }
- 
--    ret = ipa_deskprofile_rule_check_memberhost(tmp_ctx, domain, rule,
--                                                rule_name, rule_prio,
--                                                base_dn, hostname,
--                                                &host_prio, &hostgroup_prio);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_CRIT_FAILURE,
--              "ipa_deskprofile_rule_check_memberhost() failed [%d]: %s\n",
--              ret, sss_strerror(ret));
--        goto done;
-+    if (hostcat != NULL && strcasecmp(hostcat, "all") == 0) {
-+        host_prio = talloc_strdup(tmp_ctx, rule_prio);
-+        if (host_prio == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Failed to allocate the host priority "
-+                  "when host category is \"all\"\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+
-+        hostgroup_prio = talloc_strdup(tmp_ctx, rule_prio);
-+        if (hostgroup_prio == NULL) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "Failed to allocate the hostgroup priority "
-+                  "when host category is \"all\"\n");
-+            ret = ENOMEM;
-+            goto done;
-+        }
-+    } else {
-+        ret = ipa_deskprofile_rule_check_memberhost(tmp_ctx, domain, rule,
-+                                                    rule_name, rule_prio,
-+                                                    base_dn, hostname,
-+                                                    &host_prio, &hostgroup_prio);
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "ipa_deskprofile_rule_check_memberhost() failed [%d]: %s\n",
-+                  ret, sss_strerror(ret));
-+            goto done;
-+        }
-     }
- 
-     ret = ipa_deskprofile_get_normalized_rule_name(mem_ctx, rule_name,
--- 
-2.14.3
-
diff --git a/SOURCES/0098-SELINUX-Check-if-SELinux-is-managed-in-selinux_child.patch b/SOURCES/0098-SELINUX-Check-if-SELinux-is-managed-in-selinux_child.patch
deleted file mode 100644
index c0912b0..0000000
--- a/SOURCES/0098-SELINUX-Check-if-SELinux-is-managed-in-selinux_child.patch
+++ /dev/null
@@ -1,203 +0,0 @@
-From ae37ee533a791e038aab47683278fced2bc0b687 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
-Date: Thu, 1 Feb 2018 11:34:21 +0100
-Subject: [PATCH 98/99] SELINUX: Check if SELinux is managed in selinux_child
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-If SELinux policy is not managed at all, don't call any SELinux user
-handling functions and instead return that no update is needed.
-
-Pair-Programmed-With: Jakub Hrozek <jhrozek@redhat.com>
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3618
-(cherry picked from commit 450b472a68abf442479755c7916c757907b35ea5)
----
- src/providers/ipa/selinux_child.c |  3 +-
- src/util/sss_semanage.c           | 82 +++++++++++++++++++++++++++++++--------
- src/util/util.h                   |  3 ++
- 3 files changed, 70 insertions(+), 18 deletions(-)
-
-diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c
-index a7e20f715626d0f3ecef7cc06f3de5d44b6a15c1..c659976e80cb7317671da52fe4777ee821589e36 100644
---- a/src/providers/ipa/selinux_child.c
-+++ b/src/providers/ipa/selinux_child.c
-@@ -27,7 +27,6 @@
- #include <unistd.h>
- #include <sys/stat.h>
- #include <popt.h>
--#include <selinux/selinux.h>
- 
- #include "util/util.h"
- #include "util/child_common.h"
-@@ -173,7 +172,7 @@ static bool seuser_needs_update(struct input_buffer *ibuf)
-     char *db_mls_range = NULL;
-     errno_t ret;
- 
--    ret = getseuserbyname(ibuf->username, &db_seuser, &db_mls_range);
-+    ret = sss_get_seuser(ibuf->username, &db_seuser, &db_mls_range);
-     DEBUG(SSSDBG_TRACE_INTERNAL,
-           "getseuserbyname: ret: %d seuser: %s mls: %s\n",
-           ret, db_seuser ? db_seuser : "unknown",
-diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c
-index 37278cc986a1ea49dc2218a635d52b9d54ca089d..25b6bcdad2ad7e7ac710497f13d6a6e22360b0dd 100644
---- a/src/util/sss_semanage.c
-+++ b/src/util/sss_semanage.c
-@@ -22,8 +22,9 @@
- #include "config.h"
- 
- #include <stdio.h>
--#ifdef HAVE_SEMANAGE
-+#if defined(HAVE_SEMANAGE) && defined(HAVE_SELINUX)
- #include <semanage/semanage.h>
-+#include <selinux/selinux.h>
- #endif
- 
- #include "util/util.h"
-@@ -32,7 +33,7 @@
- #define DEFAULT_SERANGE "s0"
- #endif
- 
--#ifdef HAVE_SEMANAGE
-+#if defined(HAVE_SEMANAGE) && defined(HAVE_SELINUX)
- /* turn libselinux messages into SSSD DEBUG() calls */
- static void sss_semanage_error_callback(void *varg,
-                                         semanage_handle_t *handle,
-@@ -73,33 +74,47 @@ static void sss_semanage_close(semanage_handle_t *handle)
-     semanage_handle_destroy(handle);
- }
- 
--static int sss_semanage_init(semanage_handle_t **_handle)
-+static int sss_is_selinux_managed(semanage_handle_t *handle)
- {
-     int ret;
--    semanage_handle_t *handle = NULL;
- 
--    handle = semanage_handle_create();
--    if (!handle) {
--        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux management handle\n");
--        ret = EIO;
--        goto done;
-+    if (handle == NULL) {
-+        return EINVAL;
-     }
- 
--    semanage_msg_set_callback(handle,
--                              sss_semanage_error_callback,
--                              NULL);
--
-     ret = semanage_is_managed(handle);
-     if (ret == 0) {
-         DEBUG(SSSDBG_TRACE_FUNC, "SELinux policy not managed via libsemanage\n");
--        ret = ERR_SELINUX_NOT_MANAGED;
--        goto done;
-+        return ERR_SELINUX_NOT_MANAGED;
-     } else if (ret == -1) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Call to semanage_is_managed failed\n");
-+        return EIO;
-+    }
-+
-+    return EOK;
-+}
-+
-+static int sss_semanage_init(semanage_handle_t **_handle)
-+{
-+    int ret;
-+    semanage_handle_t *handle = NULL;
-+
-+    handle = semanage_handle_create();
-+    if (!handle) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux management handle\n");
-         ret = EIO;
-         goto done;
-     }
- 
-+    semanage_msg_set_callback(handle,
-+                              sss_semanage_error_callback,
-+                              NULL);
-+
-+    ret = sss_is_selinux_managed(handle);
-+    if (ret != EOK) {
-+        goto done;
-+    }
-+
-     ret = semanage_access_check(handle);
-     if (ret < SEMANAGE_CAN_READ) {
-         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot read SELinux policy store\n");
-@@ -229,6 +244,34 @@ done:
-     return ret;
- }
- 
-+int sss_get_seuser(const char *linuxuser,
-+                   char **selinuxuser,
-+                   char **level)
-+{
-+    int ret;
-+    semanage_handle_t *handle;
-+
-+    handle = semanage_handle_create();
-+    if (handle == NULL) {
-+        DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create SELinux management handle\n");
-+        return EIO;
-+    }
-+
-+    semanage_msg_set_callback(handle,
-+                              sss_semanage_error_callback,
-+                              NULL);
-+
-+    /* We only needed the handle for this call. Close the handle right
-+     * after it */
-+    ret = sss_is_selinux_managed(handle);
-+    sss_semanage_close(handle);
-+    if (ret != EOK) {
-+        return ret;
-+    }
-+
-+    return getseuserbyname(linuxuser, selinuxuser, level);
-+}
-+
- int set_seuser(const char *login_name, const char *seuser_name,
-                const char *mls)
- {
-@@ -382,7 +425,7 @@ done:
-     sss_semanage_close(handle);
-     return ret;
- }
--#else /* HAVE_SEMANAGE */
-+#else /* HAVE_SEMANAGE && HAVE_SELINUX */
- int set_seuser(const char *login_name, const char *seuser_name,
-                const char *mls)
- {
-@@ -393,4 +436,11 @@ int del_seuser(const char *login_name)
- {
-     return EOK;
- }
-+
-+int sss_get_seuser(const char *linuxuser,
-+                   char **selinuxuser,
-+                   char **level)
-+{
-+    return EOK;
-+}
- #endif  /* HAVE_SEMANAGE */
-diff --git a/src/util/util.h b/src/util/util.h
-index 2521b1789b0b8701b1fbcce33890eedb7fe18d5e..be818a9531897e4f988cae48bf6ba30aea0e6d56 100644
---- a/src/util/util.h
-+++ b/src/util/util.h
-@@ -654,6 +654,9 @@ errno_t restore_creds(struct sss_creds *saved_creds);
- int set_seuser(const char *login_name, const char *seuser_name,
-                const char *mlsrange);
- int del_seuser(const char *login_name);
-+int sss_get_seuser(const char *linuxuser,
-+                   char **selinuxuser,
-+                   char **level);
- 
- /* 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);
--- 
-2.14.3
-
diff --git a/SOURCES/0099-util-Add-sss_-prefix-to-some-functions.patch b/SOURCES/0099-util-Add-sss_-prefix-to-some-functions.patch
deleted file mode 100644
index 829aea5..0000000
--- a/SOURCES/0099-util-Add-sss_-prefix-to-some-functions.patch
+++ /dev/null
@@ -1,142 +0,0 @@
-From 9e1df30e737566ca92c93cb09028717415120f47 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
-Date: Tue, 6 Feb 2018 19:17:55 +0100
-Subject: [PATCH 99/99] util: Add sss_ prefix to some functions
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Add sss_ prefix to del_seuser and set_seuser for consistency
-with sss_get_seuser. Also sss_ prefix makes it clear that
-these functions come from SSSD.
-
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3618
-(cherry picked from commit 6b9c38df5712b951e31800efea2df0802e333e08)
----
- src/providers/ipa/selinux_child.c |  4 ++--
- src/tools/sss_useradd.c           |  2 +-
- src/tools/sss_userdel.c           |  2 +-
- src/tools/sss_usermod.c           |  2 +-
- src/util/sss_semanage.c           | 12 ++++++------
- src/util/util.h                   |  6 +++---
- 6 files changed, 14 insertions(+), 14 deletions(-)
-
-diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c
-index c659976e80cb7317671da52fe4777ee821589e36..a601b28c4c68afca51758b1967d1bfc1d51fb450 100644
---- a/src/providers/ipa/selinux_child.c
-+++ b/src/providers/ipa/selinux_child.c
-@@ -157,9 +157,9 @@ static int sc_set_seuser(const char *login_name, const char *seuser_name,
-          * default. We need to remove the SELinux user from the DB
-          * in that case
-          */
--        ret = del_seuser(login_name);
-+        ret = sss_del_seuser(login_name);
-     } else {
--        ret = set_seuser(login_name, seuser_name, mls);
-+        ret = sss_set_seuser(login_name, seuser_name, mls);
-     }
-     umask(old_mask);
-     return ret;
-diff --git a/src/tools/sss_useradd.c b/src/tools/sss_useradd.c
-index 8521b83011b42c9e2acca4136f154acb3919440c..ca2cbd6c119e5a1735e5b3b524cddeccb68a2578 100644
---- a/src/tools/sss_useradd.c
-+++ b/src/tools/sss_useradd.c
-@@ -205,7 +205,7 @@ int main(int argc, const char **argv)
- 
-     /* Set SELinux login context - must be done after transaction is done
-      * b/c libselinux calls getpwnam */
--    ret = set_seuser(tctx->octx->name, pc_selinux_user, NULL);
-+    ret = sss_set_seuser(tctx->octx->name, pc_selinux_user, NULL);
-     if (ret != EOK) {
-         ERROR("Cannot set SELinux login context\n");
-         ret = EXIT_FAILURE;
-diff --git a/src/tools/sss_userdel.c b/src/tools/sss_userdel.c
-index d085dc3cabd31b2ee82b13c6cbc39c7658b071d1..fb0f2c2ab6163738da2dcf4177c06cd5dc524345 100644
---- a/src/tools/sss_userdel.c
-+++ b/src/tools/sss_userdel.c
-@@ -254,7 +254,7 @@ int main(int argc, const char **argv)
- 
-     /* Set SELinux login context - must be done after transaction is done
-      * b/c libselinux calls getpwnam */
--    ret = del_seuser(tctx->octx->name);
-+    ret = sss_del_seuser(tctx->octx->name);
-     if (ret != EOK) {
-         ERROR("Cannot reset SELinux login context\n");
-         ret = EXIT_FAILURE;
-diff --git a/src/tools/sss_usermod.c b/src/tools/sss_usermod.c
-index 55e94394766f5f46bb3c14c231186f2d79d6b6ab..6a818f13ad2a7e087e23fa2190b83aeb1eabdbac 100644
---- a/src/tools/sss_usermod.c
-+++ b/src/tools/sss_usermod.c
-@@ -300,7 +300,7 @@ int main(int argc, const char **argv)
- 
-     /* Set SELinux login context - must be done after transaction is done
-      * b/c libselinux calls getpwnam */
--    ret = set_seuser(tctx->octx->name, pc_selinux_user, NULL);
-+    ret = sss_set_seuser(tctx->octx->name, pc_selinux_user, NULL);
-     if (ret != EOK) {
-         ERROR("Cannot set SELinux login context\n");
-         ret = EXIT_FAILURE;
-diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c
-index 25b6bcdad2ad7e7ac710497f13d6a6e22360b0dd..1150b6236c2c227fe2fc69f2505b6e254a1e64ec 100644
---- a/src/util/sss_semanage.c
-+++ b/src/util/sss_semanage.c
-@@ -272,8 +272,8 @@ int sss_get_seuser(const char *linuxuser,
-     return getseuserbyname(linuxuser, selinuxuser, level);
- }
- 
--int set_seuser(const char *login_name, const char *seuser_name,
--               const char *mls)
-+int sss_set_seuser(const char *login_name, const char *seuser_name,
-+                   const char *mls)
- {
-     semanage_handle_t *handle = NULL;
-     semanage_seuser_key_t *key = NULL;
-@@ -346,7 +346,7 @@ done:
-     return ret;
- }
- 
--int del_seuser(const char *login_name)
-+int sss_del_seuser(const char *login_name)
- {
-     semanage_handle_t *handle = NULL;
-     semanage_seuser_key_t *key = NULL;
-@@ -426,13 +426,13 @@ done:
-     return ret;
- }
- #else /* HAVE_SEMANAGE && HAVE_SELINUX */
--int set_seuser(const char *login_name, const char *seuser_name,
--               const char *mls)
-+int sss_set_seuser(const char *login_name, const char *seuser_name,
-+                   const char *mls)
- {
-     return EOK;
- }
- 
--int del_seuser(const char *login_name)
-+int sss_del_seuser(const char *login_name)
- {
-     return EOK;
- }
-diff --git a/src/util/util.h b/src/util/util.h
-index be818a9531897e4f988cae48bf6ba30aea0e6d56..ef8ef7f57d7949aa2735171f11195dbcdc42288a 100644
---- a/src/util/util.h
-+++ b/src/util/util.h
-@@ -651,9 +651,9 @@ errno_t restore_creds(struct sss_creds *saved_creds);
-  * certain permissions. Therefore the caller should make sure the umask is
-  * not too restricted (especially when called from the daemon code).
-  */
--int set_seuser(const char *login_name, const char *seuser_name,
--               const char *mlsrange);
--int del_seuser(const char *login_name);
-+int sss_set_seuser(const char *login_name, const char *seuser_name,
-+                   const char *mlsrange);
-+int sss_del_seuser(const char *login_name);
- int sss_get_seuser(const char *linuxuser,
-                    char **selinuxuser,
-                    char **level);
--- 
-2.14.3
-
diff --git a/SOURCES/0100-MAN-Explain-how-does-auto_private_groups-affect-subd.patch b/SOURCES/0100-MAN-Explain-how-does-auto_private_groups-affect-subd.patch
deleted file mode 100644
index ae772b2..0000000
--- a/SOURCES/0100-MAN-Explain-how-does-auto_private_groups-affect-subd.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From a09a7a03f5b330cc45a0007a56d4789116a91e46 Mon Sep 17 00:00:00 2001
-From: amitkuma <amitkuma@redhat.com>
-Date: Tue, 6 Feb 2018 16:27:00 +0530
-Subject: [PATCH 100/100] MAN: Explain how does auto_private_groups affect
- subdomains
-
-Fix explains how auto_private_groups affects subdomains.
-a. POSIX sudomains, gets inherited to subdomain.
-b. ID-mapping subdomains, already enabled.
-
-Resolves: https://pagure.io/SSSD/sssd/issue/3627
-
-Reviewed-by: Rob Crittenden <rcritten@redhat.com>
-(cherry picked from commit 52ae76737f2df3012d67f6a0b5052c86022bffdd)
----
- src/man/sssd.conf.5.xml | 11 ++++++++++-
- 1 file changed, 10 insertions(+), 1 deletion(-)
-
-diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
-index 47da07c33bdcfbf2fa94ff932492e9ea4bbfe846..8d06f57539e3fc55189234aab2aea950ba14713a 100644
---- a/src/man/sssd.conf.5.xml
-+++ b/src/man/sssd.conf.5.xml
-@@ -2830,7 +2830,16 @@ subdomain_inherit = ldap_purge_cache_timeout
-                             If this option is enabled, SSSD will automatically
-                             create user private groups based on user's
-                             UID number. The GID number is ignored in this case.
--                        </para>
-+		        </para>
-+			<para>
-+			    For POSIX subdomains, setting the option in the main
-+			    domain is inherited in the subdomain.
-+			</para>
-+			<para>
-+			    For ID-mapping subdomains, auto_private_groups is
-+			    already enabled for the subdomains and setting it to
-+			    false will not have any effect for the subdomain.
-+			</para>
-                         <para>
-                             NOTE: Because the GID number and the user private group
-                             are inferred frm the UID number, it is not supported
--- 
-2.14.3
-
diff --git a/SOURCES/0101-AD-Use-the-right-sdap_domain-for-the-forest-root.patch b/SOURCES/0101-AD-Use-the-right-sdap_domain-for-the-forest-root.patch
deleted file mode 100644
index 128a9ea..0000000
--- a/SOURCES/0101-AD-Use-the-right-sdap_domain-for-the-forest-root.patch
+++ /dev/null
@@ -1,201 +0,0 @@
-From d56d41e76741f418e88e479b91193db3ee3f1688 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Wed, 17 Jan 2018 21:59:24 +0100
-Subject: [PATCH 101/101] AD: Use the right sdap_domain for the forest root
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Each ad_id_ctx structure which represents a trusted AD domain contains a
-list of sdap_domain structures representing all the other domains. This
-is used to e.g. be able to reach another domain's ad_id_ctx and use its
-LDAP connection.
-
-However, the sdap search call that was searching for trusted domains in
-the forest that the root domain knows about, was unconditionally using
-the first sdap_domain structure in the list linked from the root_domain's
-ad_id_ctx structure.
-
-It should be noted that this search only happens in case the machine is
-joined to one of the non-root domains in the forest and searches the root
-domain explicitly.
-
-In case sdap_domain structures linked from the ad_id_ctx representing
-the root domain were ordered so that the first sdap_domain in the list
-was representing a different domain than the one linked from the
-ad_id_ctx, the sdap search would have used a wrong search base derived
-from the unexpected sdap_domain which would result in a referral being
-returned.
-
-This patch explicitly looks up the sdap_domain structure that
-corresponds to the root domain.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3594
-
-Reviewed-by: Sumit Bose <sbose@redhat.com>
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
-(cherry picked from commit 9ac071272ce0152eb293d3181a5c12b395655521)
----
- src/providers/ad/ad_subdomains.c | 110 +++++++++++++++++++++++++++------------
- 1 file changed, 77 insertions(+), 33 deletions(-)
-
-diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
-index 1b9483a5dce937d6acdd813486a1e8c18210d35f..bd94ba8ea93679df8d01508b3d4d85217d9c1c87 100644
---- a/src/providers/ad/ad_subdomains.c
-+++ b/src/providers/ad/ad_subdomains.c
-@@ -57,6 +57,71 @@
- /* do not refresh more often than every 5 seconds for now */
- #define AD_SUBDOMAIN_REFRESH_LIMIT 5
- 
-+static struct sss_domain_info *
-+ads_get_root_domain(struct be_ctx *be_ctx, struct sysdb_attrs *attrs)
-+{
-+    struct sss_domain_info *dom;
-+    const char *name;
-+    errno_t ret;
-+
-+    if (attrs == NULL) {
-+        /* Clients joined to the forest root directly don't even discover
-+         * the root domain, so the attrs are expected to be NULL in this
-+         * case
-+         */
-+        return be_ctx->domain;
-+    }
-+
-+    ret = sysdb_attrs_get_string(attrs, AD_AT_TRUST_PARTNER, &name);
-+    if (ret != EOK) {
-+        DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
-+        return NULL;
-+    }
-+
-+    /* With a subsequent run, the root should already be known */
-+    for (dom = be_ctx->domain; dom != NULL;
-+         dom = get_next_domain(dom, SSS_GND_ALL_DOMAINS)) {
-+
-+        if (strcasecmp(dom->name, name) == 0) {
-+            /* The forest root is special, although it might be disabled for
-+             * general lookups we still want to try to get the domains in the
-+             * forest from a DC of the forest root */
-+            if (sss_domain_get_state(dom) == DOM_DISABLED
-+                    && !sss_domain_is_forest_root(dom)) {
-+                return NULL;
-+            }
-+            return dom;
-+        }
-+    }
-+
-+    return NULL;
-+}
-+
-+static struct sdap_domain *
-+ads_get_root_sdap_domain(struct be_ctx *be_ctx,
-+                         struct sdap_options *opts,
-+                         struct sysdb_attrs *attrs)
-+{
-+    struct sdap_domain *root_sdom;
-+    struct sss_domain_info *root_dom;
-+
-+    root_dom = ads_get_root_domain(be_ctx, attrs);
-+    if (root_dom == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "ads_get_root_domain did not find the domain\n");
-+        return NULL;
-+    }
-+
-+    root_sdom = sdap_domain_get(opts, root_dom);
-+    if (root_sdom == NULL) {
-+        DEBUG(SSSDBG_OP_FAILURE,
-+              "Failed to find sdap_domain for the root domain\n");
-+        return NULL;
-+    }
-+
-+    return root_sdom;
-+}
-+
- static errno_t ad_get_enabled_domains(TALLOC_CTX *mem_ctx,
-                                       struct ad_id_ctx *ad_id_ctx,
-                                       const char *ad_domain,
-@@ -755,6 +820,7 @@ struct ad_get_slave_domain_state {
-     struct sdap_options *opts;
-     struct sdap_idmap_ctx *idmap_ctx;
-     struct sysdb_attrs *root_attrs;
-+    struct sdap_domain *root_sdom;
-     struct sdap_id_op *sdap_op;
- };
- 
-@@ -786,6 +852,13 @@ ad_get_slave_domain_send(TALLOC_CTX *mem_ctx,
-     state->opts = root_id_ctx->sdap_id_ctx->opts;
-     state->idmap_ctx = root_id_ctx->sdap_id_ctx->opts->idmap_ctx;
-     state->root_attrs = root_attrs;
-+    state->root_sdom = ads_get_root_sdap_domain(state->be_ctx,
-+                                                state->opts,
-+                                                state->root_attrs);
-+    if (state->root_sdom == NULL) {
-+        ret = ERR_DOMAIN_NOT_FOUND;
-+        goto immediately;
-+    }
- 
-     state->sdap_op = sdap_id_op_create(state, root_id_ctx->ldap_ctx->conn_cache);
-     if (state->sdap_op == NULL) {
-@@ -861,7 +934,7 @@ static void ad_get_slave_domain_connect_done(struct tevent_req *subreq)
- 
-     subreq = sdap_search_bases_send(state, state->ev, state->opts,
-                                     sdap_id_op_handle(state->sdap_op),
--                                    state->opts->sdom->search_bases,
-+                                    state->root_sdom->search_bases,
-                                     NULL, false, 0,
-                                     SLAVE_DOMAIN_FILTER, attrs);
-     if (subreq == NULL) {
-@@ -965,38 +1038,6 @@ static errno_t ad_get_slave_domain_recv(struct tevent_req *req)
-     return EOK;
- }
- 
--static struct sss_domain_info *
--ads_get_root_domain(struct be_ctx *be_ctx, struct sysdb_attrs *attrs)
--{
--    struct sss_domain_info *dom;
--    const char *name;
--    errno_t ret;
--
--    ret = sysdb_attrs_get_string(attrs, AD_AT_TRUST_PARTNER, &name);
--    if (ret != EOK) {
--        DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_string failed.\n");
--        return NULL;
--    }
--
--    /* With a subsequent run, the root should already be known */
--    for (dom = be_ctx->domain; dom != NULL;
--         dom = get_next_domain(dom, SSS_GND_ALL_DOMAINS)) {
--
--        if (strcasecmp(dom->name, name) == 0) {
--            /* The forest root is special, although it might be disabled for
--             * general lookups we still want to try to get the domains in the
--             * forest from a DC of the forest root */
--            if (sss_domain_get_state(dom) == DOM_DISABLED
--                    && !sss_domain_is_forest_root(dom)) {
--                return NULL;
--            }
--            return dom;
--        }
--    }
--
--    return NULL;
--}
--
- static struct ad_id_ctx *
- ads_get_root_id_ctx(struct be_ctx *be_ctx,
-                     struct ad_id_ctx *ad_id_ctx,
-@@ -1416,6 +1457,9 @@ static void ad_subdomains_refresh_root_done(struct tevent_req *subreq)
-     req = tevent_req_callback_data(subreq, struct tevent_req);
-     state = tevent_req_data(req, struct ad_subdomains_refresh_state);
- 
-+    /* Note: For clients joined to the root domain, root_attrs is NULL,
-+     * see ad_get_root_domain_send()
-+     */
-     ret = ad_get_root_domain_recv(state, subreq, &root_attrs, &root_id_ctx);
-     talloc_zfree(subreq);
-     if (ret != EOK) {
--- 
-2.14.3
-
diff --git a/SOURCES/0102-AD-sdap_get_ad_tokengroups_done-allocate-temporary-d.patch b/SOURCES/0102-AD-sdap_get_ad_tokengroups_done-allocate-temporary-d.patch
deleted file mode 100644
index 5f9991f..0000000
--- a/SOURCES/0102-AD-sdap_get_ad_tokengroups_done-allocate-temporary-d.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From f6f8fca59937b746b3c47cf0aeb23ea554a43fab Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 16 Feb 2018 12:07:28 +0100
-Subject: [PATCH] AD: sdap_get_ad_tokengroups_done() allocate temporary data on
- state
-
-Related to https://pagure.io/SSSD/sssd/issue/3639
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit db52090e33b8f1747b7d77bab64ab8c9f9f5ecc2)
----
- src/providers/ldap/sdap_async_initgroups_ad.c | 5 +----
- 1 file changed, 1 insertion(+), 4 deletions(-)
-
-diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c
-index 61aa69a2dfbe22cac37a5b7fddc07473527e5de5..ee0cd6707924b02d239ce4c329d9853268d49a80 100644
---- a/src/providers/ldap/sdap_async_initgroups_ad.c
-+++ b/src/providers/ldap/sdap_async_initgroups_ad.c
-@@ -372,7 +372,6 @@ immediately:
- 
- static void sdap_get_ad_tokengroups_done(struct tevent_req *subreq)
- {
--    TALLOC_CTX *tmp_ctx = NULL;
-     struct sdap_get_ad_tokengroups_state *state = NULL;
-     struct tevent_req *req = NULL;
-     struct sysdb_attrs **users = NULL;
-@@ -386,7 +385,7 @@ static void sdap_get_ad_tokengroups_done(struct tevent_req *subreq)
-     req = tevent_req_callback_data(subreq, struct tevent_req);
-     state = tevent_req_data(req, struct sdap_get_ad_tokengroups_state);
- 
--    ret = sdap_get_generic_recv(subreq, tmp_ctx, &num_users, &users);
-+    ret = sdap_get_generic_recv(subreq, state, &num_users, &users);
-     talloc_zfree(subreq);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_MINOR_FAILURE,
-@@ -449,8 +448,6 @@ static void sdap_get_ad_tokengroups_done(struct tevent_req *subreq)
-     ret = EOK;
- 
- done:
--    talloc_free(tmp_ctx);
--
-     if (ret != EOK) {
-         tevent_req_error(req, ret);
-         return;
--- 
-2.14.3
-
diff --git a/SOURCES/0103-AD-do-not-allocate-temporary-data-on-long-living-con.patch b/SOURCES/0103-AD-do-not-allocate-temporary-data-on-long-living-con.patch
deleted file mode 100644
index 7140380..0000000
--- a/SOURCES/0103-AD-do-not-allocate-temporary-data-on-long-living-con.patch
+++ /dev/null
@@ -1,89 +0,0 @@
-From 3dae415229a7a2526a886ea55a12377fdc62361e Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 16 Feb 2018 12:09:01 +0100
-Subject: [PATCH] AD: do not allocate temporary data on long living context
-
-Related to https://pagure.io/SSSD/sssd/issue/3639
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit e6ad16e05f42a1678a8c6cd14eb54ca75b8d775e)
----
- src/providers/ad/ad_common.c      | 5 +++--
- src/providers/ad/ad_common.h      | 3 ++-
- src/providers/ad/ad_id.c          | 2 +-
- src/tests/cmocka/test_ad_common.c | 4 ++--
- 4 files changed, 8 insertions(+), 6 deletions(-)
-
-diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
-index 84845e285bef336b503b9d27bfc6eb99d6ee43ff..2a1647173b76b410371315eb364e9a3785714a93 100644
---- a/src/providers/ad/ad_common.c
-+++ b/src/providers/ad/ad_common.c
-@@ -1402,13 +1402,14 @@ ad_ldap_conn_list(TALLOC_CTX *mem_ctx,
- }
- 
- struct sdap_id_conn_ctx **
--ad_user_conn_list(struct ad_id_ctx *ad_ctx,
-+ad_user_conn_list(TALLOC_CTX *mem_ctx,
-+                  struct ad_id_ctx *ad_ctx,
-                   struct sss_domain_info *dom)
- {
-     struct sdap_id_conn_ctx **clist;
-     int cindex = 0;
- 
--    clist = talloc_zero_array(ad_ctx, struct sdap_id_conn_ctx *, 3);
-+    clist = talloc_zero_array(mem_ctx, struct sdap_id_conn_ctx *, 3);
-     if (clist == NULL) {
-         return NULL;
-     }
-diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
-index ce33b37c75f45ae72adb268858cce34759b8b02f..931aafc6c031e0979460925a1402517b054b202c 100644
---- a/src/providers/ad/ad_common.h
-+++ b/src/providers/ad/ad_common.h
-@@ -175,7 +175,8 @@ ad_ldap_conn_list(TALLOC_CTX *mem_ctx,
-                   struct sss_domain_info *dom);
- 
- struct sdap_id_conn_ctx **
--ad_user_conn_list(struct ad_id_ctx *ad_ctx,
-+ad_user_conn_list(TALLOC_CTX *mem_ctx,
-+                  struct ad_id_ctx *ad_ctx,
-                   struct sss_domain_info *dom);
- 
- struct sdap_id_conn_ctx *
-diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
-index 0b8f49819405c7dbbfa18b5359f7743441dc65e5..782d9bc402e71d6b20976367f6afbae82bd25750 100644
---- a/src/providers/ad/ad_id.c
-+++ b/src/providers/ad/ad_id.c
-@@ -367,7 +367,7 @@ get_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx,
- 
-     switch (ar->entry_type & BE_REQ_TYPE_MASK) {
-     case BE_REQ_USER: /* user */
--        clist = ad_user_conn_list(ad_ctx, dom);
-+        clist = ad_user_conn_list(mem_ctx, ad_ctx, dom);
-         break;
-     case BE_REQ_BY_SECID:   /* by SID */
-     case BE_REQ_USER_AND_GROUP: /* get SID */
-diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c
-index 80b3bb5599a95578b7734d5dfcd20a2a7428a084..a8a447e91bd5107bbfc9d8445d0508778a5012f8 100644
---- a/src/tests/cmocka/test_ad_common.c
-+++ b/src/tests/cmocka/test_ad_common.c
-@@ -771,7 +771,7 @@ void test_user_conn_list(void **state)
-                                                      struct ad_common_test_ctx);
-     assert_non_null(test_ctx);
- 
--    conn_list = ad_user_conn_list(test_ctx->ad_ctx,
-+    conn_list = ad_user_conn_list(test_ctx, test_ctx->ad_ctx,
-                                   test_ctx->dom);
-     assert_non_null(conn_list);
- 
-@@ -780,7 +780,7 @@ void test_user_conn_list(void **state)
-     assert_null(conn_list[1]);
-     talloc_free(conn_list);
- 
--    conn_list = ad_user_conn_list(test_ctx->ad_ctx,
-+    conn_list = ad_user_conn_list(test_ctx, test_ctx->ad_ctx,
-                                   test_ctx->subdom);
-     assert_non_null(conn_list);
- 
--- 
-2.14.3
-
diff --git a/SOURCES/0104-nss-idmap-do-not-set-a-limit.patch b/SOURCES/0104-nss-idmap-do-not-set-a-limit.patch
deleted file mode 100644
index 894d05e..0000000
--- a/SOURCES/0104-nss-idmap-do-not-set-a-limit.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 814108dc02a4de5d0333e9c2713f809fc3d2da47 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Wed, 18 Apr 2018 10:20:06 +0200
-Subject: [PATCH] nss-idmap: do not set a limit
-
-If the limit is set the needed size to return all groups cannot be
-returned.
-
-Related to https://pagure.io/SSSD/sssd/issue/3715
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 46a4c265629d9b725c41f22849741ce7342bdd85)
-
-DOWNSTREAM:
-Resolves: rhbz#1570527 - memory management issue in the sssd_nss_ex interface can cause the ns-slapd process on IPA server to crash [rhel-7.5.z]
----
- src/sss_client/idmap/sss_nss_ex.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c
-index af6a95180656b598bcb94c209dfa821cb0275f02..f56bffcc24a7e2503e23a892541a9242ed4b5069 100644
---- a/src/sss_client/idmap/sss_nss_ex.c
-+++ b/src/sss_client/idmap/sss_nss_ex.c
-@@ -96,7 +96,9 @@ errno_t sss_nss_mc_get(struct nss_input *inp)
-                                          inp->result.initgrrep.start,
-                                          inp->result.initgrrep.ngroups,
-                                          &(inp->result.initgrrep.groups),
--                                         *(inp->result.initgrrep.ngroups));
-+                                         /* no limit so that needed size can
-+                                          * be returned properly */
-+                                         -1);
-         break;
-     default:
-         return EINVAL;
--- 
-2.14.3
-
diff --git a/SOURCES/0105-nss-idmap-use-right-group-list-pointer-after-sss_get.patch b/SOURCES/0105-nss-idmap-use-right-group-list-pointer-after-sss_get.patch
deleted file mode 100644
index 5e524cd..0000000
--- a/SOURCES/0105-nss-idmap-use-right-group-list-pointer-after-sss_get.patch
+++ /dev/null
@@ -1,69 +0,0 @@
-From c3e0098383fb199d678df54bfd129123a8184e70 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Wed, 18 Apr 2018 10:23:22 +0200
-Subject: [PATCH] nss-idmap: use right group list pointer after sss_get_ex()
-
-If the initial array is too small it will be reallocated during
-sss_get_ex() and the pointer might change and the initial memory area
-should not be used anymore.
-
-Related to https://pagure.io/SSSD/sssd/issue/3715
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 2c4dc7a4d98c439c69625f12ba4c3c8253f4cc5b)
----
- src/sss_client/idmap/sss_nss_ex.c | 18 +++++++++---------
- 1 file changed, 9 insertions(+), 9 deletions(-)
-
-diff --git a/src/sss_client/idmap/sss_nss_ex.c b/src/sss_client/idmap/sss_nss_ex.c
-index f56bffcc24a7e2503e23a892541a9242ed4b5069..5bcfe8850b5355d6cbe0efc5e52fe076737f2a08 100644
---- a/src/sss_client/idmap/sss_nss_ex.c
-+++ b/src/sss_client/idmap/sss_nss_ex.c
-@@ -485,7 +485,6 @@ int sss_nss_getgrouplist_timeout(const char *name, gid_t group,
-                                  uint32_t flags, unsigned int timeout)
- {
-     int ret;
--    gid_t *new_groups;
-     long int new_ngroups;
-     long int start = 1;
-     struct nss_input inp = {
-@@ -498,27 +497,28 @@ int sss_nss_getgrouplist_timeout(const char *name, gid_t group,
-     }
- 
-     new_ngroups = MAX(1, *ngroups);
--    new_groups = malloc(new_ngroups * sizeof(gid_t));
--    if (new_groups == NULL) {
-+    inp.result.initgrrep.groups = malloc(new_ngroups * sizeof(gid_t));
-+    if (inp.result.initgrrep.groups == NULL) {
-         free(discard_const(inp.rd.data));
-         return ENOMEM;
-     }
--    new_groups[0] = group;
-+    inp.result.initgrrep.groups[0] = group;
- 
--    inp.result.initgrrep.groups = new_groups,
-     inp.result.initgrrep.ngroups = &new_ngroups;
-     inp.result.initgrrep.start = &start;
- 
--
-+    /* inp.result.initgrrep.groups, inp.result.initgrrep.ngroups and
-+     * inp.result.initgrrep.start might be modified by sss_get_ex() */
-     ret = sss_get_ex(&inp, flags, timeout);
-     free(discard_const(inp.rd.data));
-     if (ret != 0) {
--        free(new_groups);
-+        free(inp.result.initgrrep.groups);
-         return ret;
-     }
- 
--    memcpy(groups, new_groups, MIN(*ngroups, start) * sizeof(gid_t));
--    free(new_groups);
-+    memcpy(groups, inp.result.initgrrep.groups,
-+           MIN(*ngroups, start) * sizeof(gid_t));
-+    free(inp.result.initgrrep.groups);
- 
-     if (start > *ngroups) {
-         ret = ERANGE;
--- 
-2.14.3
-
diff --git a/SOURCES/0106-nss-add-a-netgroup-counter-to-struct-nss_enum_index.patch b/SOURCES/0106-nss-add-a-netgroup-counter-to-struct-nss_enum_index.patch
deleted file mode 100644
index 2611011..0000000
--- a/SOURCES/0106-nss-add-a-netgroup-counter-to-struct-nss_enum_index.patch
+++ /dev/null
@@ -1,119 +0,0 @@
-From f9859498b52d89bf60dbddd898752f859f4952d3 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 15 Mar 2018 12:50:20 +0100
-Subject: [PATCH] nss: add a netgroup counter to struct nss_enum_index
-
-Netgroups are not looked up with the help of a single request but by
-calling setnetgrent(), getnetgrent() and endnetgrent() where
-getnetgrent() might be called multiple times depending on the number of
-netgroup elements. Since the caller does not provide a state the state
-has to be maintained by the SSSD nss responder. Besides the netgroup
-name this is mainly the number of elements already returned.
-
-This number is used to select the next element to return and currently
-it is assumed that there are not changes to the netgroup while the
-client is requesting the individual elements. But if e.g. the 3 nss
-calls are not used correctly or the netgroup is modified while the
-client is sending getnetgrent() calls the stored number might be out of
-range. To be on the safe side the stored number should be always
-compared with the current number of netgroup elements.
-
-Related to https://pagure.io/SSSD/sssd/issue/3679
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 08db22b1b1a2e742edbca92e35087294d963adda)
-
-DOWNSTREAM:
-Resolves: rhbz#1579703 - crash in nss_protocol_fill_netgrent. sssd_nss[19234]: segfault at 80 ip 000055612688c2a0 sp 00007ffddf9b9cd0 error 4 in sssd_nss[55612687e000+39000] [rhel-7.5.z]
----
- src/db/sysdb.h                         | 3 ++-
- src/db/sysdb_search.c                  | 5 ++++-
- src/responder/nss/nss_enum.c           | 3 ++-
- src/responder/nss/nss_private.h        | 1 +
- src/responder/nss/nss_protocol_netgr.c | 7 +++++++
- 5 files changed, 16 insertions(+), 3 deletions(-)
-
-diff --git a/src/db/sysdb.h b/src/db/sysdb.h
-index fd18ecefed2b2c5f35060fa47fd160a8968e073b..2660314a75a574d7f5625c8672e5261587056d1a 100644
---- a/src/db/sysdb.h
-+++ b/src/db/sysdb.h
-@@ -1219,7 +1219,8 @@ errno_t sysdb_attrs_to_list(TALLOC_CTX *mem_ctx,
- 
- errno_t sysdb_netgr_to_entries(TALLOC_CTX *mem_ctx,
-                                struct ldb_result *res,
--                               struct sysdb_netgroup_ctx ***entries);
-+                               struct sysdb_netgroup_ctx ***entries,
-+                               size_t *netgroup_count);
- 
- errno_t sysdb_dn_sanitize(TALLOC_CTX *mem_ctx, const char *input,
-                           char **sanitized);
-diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
-index a6a81e23d257331614085403b4dca8ded860600b..9f37cbcd50a778145518c15b6146ad812a5b4fa3 100644
---- a/src/db/sysdb_search.c
-+++ b/src/db/sysdb_search.c
-@@ -1829,7 +1829,8 @@ done:
- 
- errno_t sysdb_netgr_to_entries(TALLOC_CTX *mem_ctx,
-                                struct ldb_result *res,
--                               struct sysdb_netgroup_ctx ***entries)
-+                               struct sysdb_netgroup_ctx ***entries,
-+                               size_t *netgroup_count)
- {
-     errno_t ret;
-     size_t size = 0;
-@@ -1933,6 +1934,8 @@ errno_t sysdb_netgr_to_entries(TALLOC_CTX *mem_ctx,
-     tmp_entry[c] = NULL;
- 
-     *entries = talloc_steal(mem_ctx, tmp_entry);
-+    *netgroup_count = c;
-+
-     ret = EOK;
- 
- done:
-diff --git a/src/responder/nss/nss_enum.c b/src/responder/nss/nss_enum.c
-index da844fbced529f606a3e98669fb7b95e0696ce00..b2b22bbae8a373ed3abb47381fabd989d4931690 100644
---- a/src/responder/nss/nss_enum.c
-+++ b/src/responder/nss/nss_enum.c
-@@ -144,7 +144,8 @@ static void nss_setent_internal_done(struct tevent_req *subreq)
-             /* We need to expand the netgroup into triples and members. */
-             ret = sysdb_netgr_to_entries(state->enum_ctx,
-                                          result[0]->ldb_result,
--                                         &state->enum_ctx->netgroup);
-+                                         &state->enum_ctx->netgroup,
-+                                         &state->enum_ctx->netgroup_count);
-             if (ret != EOK) {
-                 goto done;
-             }
-diff --git a/src/responder/nss/nss_private.h b/src/responder/nss/nss_private.h
-index 5fc19d26be9adda4d967086e7b239e49a78866ee..aa8d8e9cde0d73e72d3aa4c186f104d6baae411f 100644
---- a/src/responder/nss/nss_private.h
-+++ b/src/responder/nss/nss_private.h
-@@ -41,6 +41,7 @@ struct nss_enum_index {
- struct nss_enum_ctx {
-     struct cache_req_result **result;
-     struct sysdb_netgroup_ctx **netgroup;
-+    size_t netgroup_count;
- 
-     /* Ongoing cache request that is constructing enumeration result. */
-     struct tevent_req *ongoing;
-diff --git a/src/responder/nss/nss_protocol_netgr.c b/src/responder/nss/nss_protocol_netgr.c
-index ed04fd25821031554e20e14afebaca9b828a748b..9f27c6b78d47f188dea99600a634a18be2512bfb 100644
---- a/src/responder/nss/nss_protocol_netgr.c
-+++ b/src/responder/nss/nss_protocol_netgr.c
-@@ -126,6 +126,13 @@ nss_protocol_fill_netgrent(struct nss_ctx *nss_ctx,
-     idx = cmd_ctx->enum_index;
-     entries = cmd_ctx->enum_ctx->netgroup;
- 
-+    if (idx->result > cmd_ctx->enum_ctx->netgroup_count) {
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Unconsistent state while processing netgroups.\n");
-+        ret = EINVAL;
-+        goto done;
-+    }
-+
-     /* First two fields (length and reserved), filled up later. */
-     ret = sss_packet_grow(packet, 2 * sizeof(uint32_t));
-     if (ret != EOK) {
--- 
-2.17.0
-
diff --git a/SOURCES/0107-nss-initialize-nss_enum_index-in-nss_setnetgrent.patch b/SOURCES/0107-nss-initialize-nss_enum_index-in-nss_setnetgrent.patch
deleted file mode 100644
index 3ae5b68..0000000
--- a/SOURCES/0107-nss-initialize-nss_enum_index-in-nss_setnetgrent.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 1e2f20f89b1b699e569dfecb7cba98ec8f6fc936 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Thu, 15 Mar 2018 12:43:34 +0100
-Subject: [PATCH] nss: initialize nss_enum_index in nss_setnetgrent()
-
-setnetgrent() is the first call when looking up a netgroup and sets the
-netgroup name for upcoming getnetgrent() and endnetgrent() calls.
-Currently the state is reset by calling endnetgrent() but it would be
-more robust to unconditionally reset the state in setnetgrent() as well
-in case calling endnetgrent() was forgotten.
-
-Related to https://pagure.io/SSSD/sssd/issue/3679
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 37a84285aeb497ed4909d16916bbf934af3f68b3)
----
- src/responder/nss/nss_cmd.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c
-index 956ee53cb88dd24faaa95ac39c8d9540af66cfb2..9f8479b7b350823ee81b5af15199e0dda9acda8b 100644
---- a/src/responder/nss/nss_cmd.c
-+++ b/src/responder/nss/nss_cmd.c
-@@ -756,6 +756,9 @@ static errno_t nss_setnetgrent(struct cli_ctx *cli_ctx,
-         goto done;
-     }
- 
-+    state_ctx->netgrent.domain = 0;
-+    state_ctx->netgrent.result = 0;
-+
-     talloc_zfree(state_ctx->netgroup);
-     state_ctx->netgroup = talloc_strdup(state_ctx, netgroup);
-     if (state_ctx->netgroup == NULL) {
--- 
-2.17.0
-
diff --git a/SOURCES/0108-NSS-nss_clear_netgroup_hash_table-do-not-free-data.patch b/SOURCES/0108-NSS-nss_clear_netgroup_hash_table-do-not-free-data.patch
deleted file mode 100644
index 89c55c3..0000000
--- a/SOURCES/0108-NSS-nss_clear_netgroup_hash_table-do-not-free-data.patch
+++ /dev/null
@@ -1,52 +0,0 @@
-From d92cb9cb3860d7ff1b3ab64b459edf6051f69291 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 4 May 2018 17:00:55 +0200
-Subject: [PATCH] NSS: nss_clear_netgroup_hash_table() do not free data
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-nss_clear_netgroup_hash_table() is called during the clearEnumCache SBUS
-request, which is e.g. used during 'sss_cache -E', to remove netgroup
-data cached in the memory of the NSS responder.
-
-Currently nss_clear_netgroup_hash_table() calls
-'sss_ptr_hash_delete_all(nss_ctx->netgrent, true);' which not only
-removes all entries in the 'netgerent' hash table but frees them as
-well.
-
-The second step is not needed because nss_setnetgrent_set_timeout()
-takes care that the data is freed after a timeout. Additionally freeing
-the data in nss_clear_netgroup_hash_table() can even do harm when the
-request is received by the NSS responder while waiting for the backend
-to acquire the netgroup data. Because if the backend is done the NSS
-responder tries do use enum_ctx which might have been freed in the
-meantime.
-
-Because of this nss_clear_netgroup_hash_table() should only remove the
-data from the hash table but not free it.
-
-Related to https://pagure.io/SSSD/sssd/issue/3731
-
-Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-(cherry picked from commit b13cc2d1413a0d5bbe36e06e5ffd87dbf5c0cb9f)
----
- src/responder/nss/nsssrv.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c
-index 11d19fd30c86283d537623db12e52caa6cc4dcd3..123a2d73ce93a025c789524fa90b41d9a0afb58b 100644
---- a/src/responder/nss/nsssrv.c
-+++ b/src/responder/nss/nsssrv.c
-@@ -142,7 +142,7 @@ static int nss_clear_netgroup_hash_table(struct sbus_request *dbus_req, void *da
- 
-     DEBUG(SSSDBG_TRACE_FUNC, "Invalidating netgroup hash table\n");
- 
--    sss_ptr_hash_delete_all(nss_ctx->netgrent, true);
-+    sss_ptr_hash_delete_all(nss_ctx->netgrent, false);
- 
-     return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
- }
--- 
-2.17.0
-
diff --git a/SOURCES/0109-winbind-idmap-plugin-support-inferface-version-6.patch b/SOURCES/0109-winbind-idmap-plugin-support-inferface-version-6.patch
deleted file mode 100644
index a2b93a0..0000000
--- a/SOURCES/0109-winbind-idmap-plugin-support-inferface-version-6.patch
+++ /dev/null
@@ -1,236 +0,0 @@
-From 9ae62c07c579fa9b3f0804c12cc0715f5f2524d4 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 15 May 2018 11:55:35 +0200
-Subject: [PATCH] winbind idmap plugin: support inferface version 6
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-With Samba 4.7 the interface version of the idmap plugin was updated to
-6. The patch adds support for this new version but can be complied with
-the older version as well.
-
-A configure option is added to select the version, if no version is
-given configure tries to detect the version with the help of an internal
-Samba library libidmap-samba4.so.
-
-To make sure that always the right version is used configure will fail
-if Samba is used (--with-samba, default) and no version can be
-determined.
-
-Resolves https://pagure.io/SSSD/sssd/issue/3741
-
-Reviewed-by: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit c6b99b070268c3807833e9f894d9a36304014417)
-
-DOWNSTREAM:
-Resolves: rhbz#1580281 - Samba can not register sss idmap module because it's using an outdated SMB_IDMAP_INTERFACE_VERSION [rhel-7.5.z]
----
- contrib/ci/configure.sh                       |  9 ++
- contrib/sssd.spec.in                          | 12 +++
- src/external/samba.m4                         | 82 +++++++++++++++++++
- src/lib/winbind_idmap_sss/winbind_idmap_sss.c |  6 ++
- src/lib/winbind_idmap_sss/winbind_idmap_sss.h |  6 +-
- 5 files changed, 114 insertions(+), 1 deletion(-)
-
-diff --git a/contrib/ci/configure.sh b/contrib/ci/configure.sh
-index 9d18d0c187561a2dc3bc47d3e8913626e7ff3046..09da5b4e7b0b4a7859bcf81db987394ac91f4fa2 100644
---- a/contrib/ci/configure.sh
-+++ b/contrib/ci/configure.sh
-@@ -35,6 +35,7 @@ declare -a CONFIGURE_ARG_LIST=(
- if [[ "$DISTRO_BRANCH" == -redhat-redhatenterprise*-6.*- ||
-       "$DISTRO_BRANCH" == -redhat-centos-6.*- ]]; then
-     CONFIGURE_ARG_LIST+=(
-+        "--with-smb-idmap-interface-version=5"
-         "--disable-cifs-idmap-plugin"
-         "--with-syslog=syslog"
-         "--without-python3-bindings"
-@@ -56,6 +57,14 @@ if [[ "$DISTRO_BRANCH" == -redhat-redhatenterprise*-7.*- ||
-     )
- fi
- 
-+# Different versions of Debian might need different versions here but this is
-+# sufficient to make the CI work
-+if [[ "$DISTRO_BRANCH" == -debian-* ]]; then
-+    CONFIGURE_ARG_LIST+=(
-+        "--with-smb-idmap-interface-version=5"
-+    )
-+fi
-+
- declare -r -a CONFIGURE_ARG_LIST
- 
- fi # _CONFIGURE_SH
-diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
-index d9323bf1a2d84f4219f8ab11886e5ce87b401c15..3ddd054dea8a4b5dd46457acf9aaabed29ab754e 100644
---- a/contrib/sssd.spec.in
-+++ b/contrib/sssd.spec.in
-@@ -127,6 +127,14 @@
-     %global with_gdm_pam_extensions 0
- %endif
- 
-+# Do not try to detect the idmap version on RHEL6 to avoid conflicts between
-+# samba and samba4 package
-+%if (0%{?fedora} || 0%{?rhel} >= 7)
-+    %global detect_idmap_version 1
-+%else
-+    %global with_idmap_version --with-smb-idmap-interface-version=5
-+%endif
-+
- Name: @PACKAGE_NAME@
- Version: @PACKAGE_VERSION@
- Release: 0@PRERELEASE_VERSION@%{?dist}
-@@ -225,6 +233,9 @@ BuildRequires: nfs-utils-lib-devel
- 
- BuildRequires: samba4-devel
- BuildRequires: libsmbclient-devel
-+%if (0%{?detect_idmap_version} == 1)
-+BuildRequires: samba-winbind
-+%endif
- 
- %if (0%{?enable_systemtap} == 1)
- BuildRequires: systemtap-sdt-devel
-@@ -747,6 +758,7 @@ autoreconf -ivf
-     %{?enable_systemtap_opt} \
-     %{?with_secret_responder} \
-     %{?with_kcm_option} \
-+    %{?with_idmap_version} \
-     %{?experimental}
- 
- make %{?_smp_mflags} all
-diff --git a/src/external/samba.m4 b/src/external/samba.m4
-index 91a583a0d0f514dab40d4f65cc32b17d0368f540..610831bf054e3687eb13025e954acf345fca1a00 100644
---- a/src/external/samba.m4
-+++ b/src/external/samba.m4
-@@ -39,4 +39,86 @@ them. In this case, you will need to execute configure script with argument
- --without-samba
-         ]])
-     fi
-+
-+    AC_ARG_WITH([smb-idmap-interface-version],
-+                [AC_HELP_STRING([--with-smb-idmap-interface-version=[5|6]],
-+                                [Idmap interface version of installed Samba]
-+                               )
-+                ]
-+               )
-+
-+    if test x"$with_smb_idmap_interface_version" != x; then
-+        if test x"$with_smb_idmap_interface_version" = x5 -o x"$with_smb_idmap_interface_version" = x6; then
-+            idmap_test_result=$with_smb_idmap_interface_version
-+        else
-+            AC_MSG_ERROR([Illegal value -$with_smb_idmap_interface_version- for option --with-smb-idmap-interface-version])
-+        fi
-+    else
-+
-+        AC_MSG_CHECKING([Samba's idmap plugin interface version])
-+        sambalibdir="`$PKG_CONFIG --variable=libdir smbclient`"/samba
-+        SAVE_CFLAGS=$CFLAGS
-+        SAVE_LIBS=$LIBS
-+        CFLAGS="$CFLAGS $SMBCLIENT_CFLAGS -I/usr/include/samba-4.0"
-+        LIBS="$LIBS -L${sambalibdir} -lidmap-samba4 -Wl,-rpath ${sambalibdir}"
-+        AC_RUN_IFELSE(
-+            [AC_LANG_SOURCE([
-+#include <stdlib.h>
-+#include <stdint.h>
-+#include <stdbool.h>
-+#include <tevent.h>
-+#include <core/ntstatus.h>
-+
-+struct winbindd_domain;
-+
-+/* overwrite some winbind internal functions */
-+struct winbindd_domain *find_domain_from_name(const char *domain_name)
-+{
-+    return NULL;
-+}
-+
-+bool get_global_winbindd_state_offline(void) {
-+    return false;
-+}
-+
-+struct tevent_context *winbind_event_context(void)
-+{
-+    return NULL;
-+}
-+
-+struct idmap_methods;
-+
-+NTSTATUS smb_register_idmap(int version, const char *name, struct idmap_methods *methods);
-+
-+int main(void)
-+{
-+    int v;
-+    NTSTATUS ret;
-+
-+    /* Check the versions we know about */
-+    for (v = 5; v <= 6; v++) {
-+        ret = smb_register_idmap(v, NULL, NULL);
-+        if (ret != NT_STATUS_OBJECT_TYPE_MISMATCH) {
-+            return v;
-+        }
-+    }
-+
-+    return -1;
-+}])],
-+            [AC_MSG_ERROR([idmap version test program is not expected to return 0])],
-+            [idmap_test_result=$?; AC_MSG_RESULT([idmap test result is: $idmap_test_result])]
-+        )
-+    fi
-+
-+    CFLAGS=$SAVE_CFLAGS
-+    LIBS=$SAVE_LIBS
-+
-+    if test $idmap_test_result -eq 5 -o $idmap_test_result -eq 6 ; then
-+        idmap_version=$idmap_test_result
-+    else
-+        AC_MSG_ERROR([Cannot determine Samba's idmap interface version, please use --with-smb-idmap-interface-version])
-+    fi
-+    AC_MSG_NOTICE([Samba's idmap interface version: $idmap_version])
-+    AC_DEFINE_UNQUOTED(SMB_IDMAP_INTERFACE_VERSION, $idmap_version,
-+                       [Detected version of Samba's idmap plugin interface])
- fi
-diff --git a/src/lib/winbind_idmap_sss/winbind_idmap_sss.c b/src/lib/winbind_idmap_sss/winbind_idmap_sss.c
-index 26f753708303f513e265de465e4d888f84e22b6a..ea5e727c3461524c3af84ea35c6ee032a5948ddf 100644
---- a/src/lib/winbind_idmap_sss/winbind_idmap_sss.c
-+++ b/src/lib/winbind_idmap_sss/winbind_idmap_sss.c
-@@ -190,7 +190,13 @@ static struct idmap_methods sss_methods = {
-     .sids_to_unixids = idmap_sss_sids_to_unixids,
- };
- 
-+#if SMB_IDMAP_INTERFACE_VERSION == 5
- NTSTATUS idmap_sss_init(void)
-+#elif SMB_IDMAP_INTERFACE_VERSION == 6
-+NTSTATUS idmap_sss_init(TALLOC_CTX *ctx)
-+#else
-+#error Unexpected Samba idmpa inferface version
-+#endif
- {
-     return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "sss", &sss_methods);
- }
-diff --git a/src/lib/winbind_idmap_sss/winbind_idmap_sss.h b/src/lib/winbind_idmap_sss/winbind_idmap_sss.h
-index 0f27c8561a540b63fb365edb79867eb4eb8d6e21..868049ffff7bd788507bf02d61245ff254aca465 100644
---- a/src/lib/winbind_idmap_sss/winbind_idmap_sss.h
-+++ b/src/lib/winbind_idmap_sss/winbind_idmap_sss.h
-@@ -32,6 +32,8 @@
- #include <ndr.h>
- #include <gen_ndr/security.h>
- 
-+#include "config.h"
-+
- /* The following definitions are taken from the Samba header files
-  * - winbindd/idmap_proto.h
-  * - idmap.d
-@@ -64,7 +66,9 @@ struct id_map {
-     enum id_mapping status;
- };
- 
--#define SMB_IDMAP_INTERFACE_VERSION 5
-+#ifndef SMB_IDMAP_INTERFACE_VERSION
-+#error Missing Samba idmap interface version
-+#endif
- 
- struct idmap_domain {
-     const char *name;
--- 
-2.17.0
-
diff --git a/SOURCES/0110-winbind-idmap-plugin-fix-detection.patch b/SOURCES/0110-winbind-idmap-plugin-fix-detection.patch
deleted file mode 100644
index ad6b2e6..0000000
--- a/SOURCES/0110-winbind-idmap-plugin-fix-detection.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From f2a1f317dfa76ec7b5ff7a218b82f92e2de5f30d Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 18 May 2018 21:34:44 +0200
-Subject: [PATCH] winbind idmap plugin: fix detection
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Currently when compiling the detection code for the idmap interface
-version only SMBCLIENT_CFLAGS are used. Since libsmbclient does not use
-NTSTATUS the cflags do not contain '-DHAVE_IMMEDIATE_STRUCTURES=1' which
-make NTSTATUS to a struct instead of an integer. Since Samba itself
-might be complied with this define (it typically is) we have to make
-sure we use it as well. Otherwise the test program might crash on
-platforms where this change changes the calling convention as well.
-
-Related to https://pagure.io/SSSD/sssd/issue/3741
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 095bbe17b25369b967e97162d945cb001a13029e)
----
- src/external/samba.m4 | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/external/samba.m4 b/src/external/samba.m4
-index 610831bf054e3687eb13025e954acf345fca1a00..794cac2461d7fbd5e690ea105cd346cbe6fcce9a 100644
---- a/src/external/samba.m4
-+++ b/src/external/samba.m4
-@@ -59,7 +59,7 @@ them. In this case, you will need to execute configure script with argument
-         sambalibdir="`$PKG_CONFIG --variable=libdir smbclient`"/samba
-         SAVE_CFLAGS=$CFLAGS
-         SAVE_LIBS=$LIBS
--        CFLAGS="$CFLAGS $SMBCLIENT_CFLAGS -I/usr/include/samba-4.0"
-+        CFLAGS="$CFLAGS $SMBCLIENT_CFLAGS $NDR_NBT_CFLAGS $NDR_KRB5PAC_CFLAGS -I/usr/include/samba-4.0"
-         LIBS="$LIBS -L${sambalibdir} -lidmap-samba4 -Wl,-rpath ${sambalibdir}"
-         AC_RUN_IFELSE(
-             [AC_LANG_SOURCE([
-@@ -98,7 +98,7 @@ int main(void)
-     /* Check the versions we know about */
-     for (v = 5; v <= 6; v++) {
-         ret = smb_register_idmap(v, NULL, NULL);
--        if (ret != NT_STATUS_OBJECT_TYPE_MISMATCH) {
-+        if (!NT_STATUS_EQUAL(ret, NT_STATUS_OBJECT_TYPE_MISMATCH)) {
-             return v;
-         }
-     }
--- 
-2.17.0
-
diff --git a/SOURCES/0111-Do-not-keep-allocating-external-groups-on-a-long-liv.patch b/SOURCES/0111-Do-not-keep-allocating-external-groups-on-a-long-liv.patch
deleted file mode 100644
index 825aa79..0000000
--- a/SOURCES/0111-Do-not-keep-allocating-external-groups-on-a-long-liv.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From d2e17974c6bcb3ae2fc8a2cde696d387385c7d61 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 3 Apr 2018 21:48:37 +0200
-Subject: [PATCH] Do not keep allocating external groups on a long-lived
- context
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The hash table with the external groups was never freed, so the
-server_mode->ext_groups context was growing over time.
-
-This patch keeps the new hash on the state if something failed, then
-frees the previous hash and finally steals the new hash onto the server
-mode.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3719
-
-Signed-off-by: Sumit Bose <sbose@redhat.com>
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 10213efaf1f9f587b47a82778a252d79863f665e)
-
-DOWNSTREAM:
-Resolves: rhbz#1583746 - The SSSD IPA provider allocates information about external groups on a long lived memory context, causing memory growth of the sssd_be process [rhel-7.5.z]
----
- src/providers/ipa/ipa_subdomains_ext_groups.c | 11 ++++++++---
- 1 file changed, 8 insertions(+), 3 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains_ext_groups.c b/src/providers/ipa/ipa_subdomains_ext_groups.c
-index 9e1d6c3a9bdeda56b421a2dc9198dff0b84c54ce..63ff7c7d7373a4e6a18fc914eff7ca00d477bca6 100644
---- a/src/providers/ipa/ipa_subdomains_ext_groups.c
-+++ b/src/providers/ipa/ipa_subdomains_ext_groups.c
-@@ -583,14 +583,19 @@ static void ipa_get_ext_groups_done(struct tevent_req *subreq)
-     DEBUG(SSSDBG_TRACE_FUNC, "[%zu] external groups found.\n",
-                               state->reply_count);
- 
--    ret = process_ext_groups(state->server_mode->ext_groups,
--                             state->reply_count, state->reply, &ext_group_hash);
-+    ret = process_ext_groups(state,
-+                             state->reply_count,
-+                             state->reply,
-+                             &ext_group_hash);
-     if (ret != EOK) {
-         DEBUG(SSSDBG_OP_FAILURE, "process_ext_groups failed.\n");
-         goto fail;
-     }
- 
--    state->server_mode->ext_groups->ext_groups = ext_group_hash;
-+    talloc_free(state->server_mode->ext_groups->ext_groups);
-+    state->server_mode->ext_groups->ext_groups = talloc_steal(
-+            state->server_mode->ext_groups,
-+            ext_group_hash);
-     /* Do we have to make the update timeout configurable? */
-     state->server_mode->ext_groups->next_update = time(NULL) + 10;
- 
--- 
-2.17.0
-
diff --git a/SOURCES/0112-TESTS-Extend-the-schema-with-sshPublicKey-attribute.patch b/SOURCES/0112-TESTS-Extend-the-schema-with-sshPublicKey-attribute.patch
deleted file mode 100644
index 5d2d383..0000000
--- a/SOURCES/0112-TESTS-Extend-the-schema-with-sshPublicKey-attribute.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-From c981d4f4a40ac6cb3650ae1934b0931b0ea5b6f6 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Sun, 17 Jun 2018 21:48:36 +0200
-Subject: [PATCH] TESTS: Extend the schema with sshPublicKey attribute
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This will allow to store the users with a sshPublicKey attribute
-provided that they have the right objectclass as well.
-
-Related to:
-https://pagure.io/SSSD/sssd/issue/3747
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 1575ec97e080656f69b3f93e641c76e74ffb8182)
-
-DOWNSTREAM:
-Resolves: rhbz#1594178 - Login with sshkeys stored in ipa not working after update to RHEL-7.5 [rhel-7.5.z]
----
- src/tests/intg/data/ssh_schema.ldif | 11 +++++++++++
- src/tests/intg/ds_openldap.py       |  6 ++++++
- 2 files changed, 17 insertions(+)
- create mode 100644 src/tests/intg/data/ssh_schema.ldif
-
-diff --git a/src/tests/intg/data/ssh_schema.ldif b/src/tests/intg/data/ssh_schema.ldif
-new file mode 100644
-index 0000000000000000000000000000000000000000..efe05706b9ded5614a7f3f5e0bab28a7eb869daa
---- /dev/null
-+++ b/src/tests/intg/data/ssh_schema.ldif
-@@ -0,0 +1,11 @@
-+dn: cn=openssh-lpk,cn=schema,cn=config
-+objectClass: olcSchemaConfig
-+cn: openssh-lpk
-+olcAttributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey'
-+  DESC 'MANDATORY: OpenSSH Public key'
-+  EQUALITY octetStringMatch
-+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
-+olcObjectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
-+  DESC 'MANDATORY: OpenSSH LPK objectclass'
-+  MAY ( sshPublicKey $ uid )
-+  )
-diff --git a/src/tests/intg/ds_openldap.py b/src/tests/intg/ds_openldap.py
-index 842ff910803658834841c8f9181f3c4af29b955a..c9a4b6de8c53c6644b3de9047d657ee35ce06512 100644
---- a/src/tests/intg/ds_openldap.py
-+++ b/src/tests/intg/ds_openldap.py
-@@ -186,6 +186,12 @@ class DSOpenLDAP(DS):
-         db_config_file.write(db_config)
-         db_config_file.close()
- 
-+        # Import ad schema
-+        subprocess.check_call(
-+            ["slapadd", "-F", self.conf_slapd_d_dir, "-b", "cn=config",
-+             "-l", "data/ssh_schema.ldif"],
-+        )
-+
-     def _start_daemon(self):
-         """Start the instance."""
-         if subprocess.call(["slapd", "-F", self.conf_slapd_d_dir,
--- 
-2.14.4
-
diff --git a/SOURCES/0113-TESTS-Allow-adding-sshPublicKey-for-users.patch b/SOURCES/0113-TESTS-Allow-adding-sshPublicKey-for-users.patch
deleted file mode 100644
index 630e1b0..0000000
--- a/SOURCES/0113-TESTS-Allow-adding-sshPublicKey-for-users.patch
+++ /dev/null
@@ -1,78 +0,0 @@
-From db4a80c1e798872d4b1196ef9a768b35e7962d28 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Sun, 17 Jun 2018 22:06:22 +0200
-Subject: [PATCH] TESTS: Allow adding sshPublicKey for users
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Adds the objectclass and allows storing a list of sshPublicKey
-attributes for users. Since there is no harm in adding the extra
-objectclass, we can do it unconditionally.
-
-Related to:
-https://pagure.io/SSSD/sssd/issue/3747
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 56cda832e9f61c52e9cfde1f0864507de718ffbb)
----
- src/tests/intg/ldap_ent.py | 15 +++++++++++----
- 1 file changed, 11 insertions(+), 4 deletions(-)
-
-diff --git a/src/tests/intg/ldap_ent.py b/src/tests/intg/ldap_ent.py
-index 6b6d8f903cbcc277d892c3212ca382f4aaadc671..a4c987969d3dcefba2af69e095b220180e0fa54c 100644
---- a/src/tests/intg/ldap_ent.py
-+++ b/src/tests/intg/ldap_ent.py
-@@ -24,7 +24,8 @@ def user(base_dn, uid, uidNumber, gidNumber,
-          homeDirectory=None,
-          loginShell=None,
-          cn=None,
--         sn=None):
-+         sn=None,
-+         sshPubKey=()):
-     """
-     Generate an RFC2307(bis) user add-modlist for passing to ldap.add*
-     """
-@@ -33,7 +34,8 @@ def user(base_dn, uid, uidNumber, gidNumber,
-     user = (
-         "uid=" + uid + ",ou=Users," + base_dn,
-         [
--            ('objectClass', [b'top', b'inetOrgPerson', b'posixAccount']),
-+            ('objectClass', [b'top', b'inetOrgPerson',
-+                             b'posixAccount', b'ldapPublicKey']),
-             ('cn', [uidNumber if cn is None else cn.encode('utf-8')]),
-             ('sn', [b'User' if sn is None else sn.encode('utf-8')]),
-             ('uidNumber', [uidNumber]),
-@@ -51,6 +53,9 @@ def user(base_dn, uid, uidNumber, gidNumber,
-     )
-     if gecos is not None:
-         user[1].append(('gecos', [gecos.encode('utf-8')]))
-+    if len(sshPubKey) > 0:
-+        pubkeys = [key.encode('utf-8') for key in sshPubKey]
-+        user[1].append(('sshPublicKey', pubkeys))
-     return user
- 
- 
-@@ -118,7 +123,8 @@ class List(list):
-                  homeDirectory=None,
-                  loginShell=None,
-                  cn=None,
--                 sn=None):
-+                 sn=None,
-+                 sshPubKey=()):
-         """Add an RFC2307(bis) user add-modlist."""
-         self.append(user(base_dn or self.base_dn,
-                          uid, uidNumber, gidNumber,
-@@ -127,7 +133,8 @@ class List(list):
-                          homeDirectory=homeDirectory,
-                          loginShell=loginShell,
-                          cn=cn,
--                         sn=sn))
-+                         sn=sn,
-+                         sshPubKey=sshPubKey))
- 
-     def add_group(self, cn, gidNumber, member_uids=[],
-                   base_dn=None):
--- 
-2.14.4
-
diff --git a/SOURCES/0114-TESTS-Add-a-basic-SSH-responder-test.patch b/SOURCES/0114-TESTS-Add-a-basic-SSH-responder-test.patch
deleted file mode 100644
index 8dbcf01..0000000
--- a/SOURCES/0114-TESTS-Add-a-basic-SSH-responder-test.patch
+++ /dev/null
@@ -1,276 +0,0 @@
-From 612dda4bbd706be9e7c3674e4d0420f9ebd1ea83 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 18 Jun 2018 09:12:13 +0200
-Subject: [PATCH] TESTS: Add a basic SSH responder test
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Adds a basic test that makes sure that a list of SSH public keys can be
-retrieved. This is to make sure we don't break the SSH integration later
-on.
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3747
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 804c5b538ad89a1a3897b93f39d716fa50530842)
----
- src/tests/intg/Makefile.am        |   1 +
- src/tests/intg/test_ssh_pubkey.py | 232 ++++++++++++++++++++++++++++++++++++++
- 2 files changed, 233 insertions(+)
- create mode 100644 src/tests/intg/test_ssh_pubkey.py
-
-diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am
-index 209e5a0c73db99b11aa6967f30db23933d21acb0..285ce21f04dddb6388c595470eac8f31bc224a60 100644
---- a/src/tests/intg/Makefile.am
-+++ b/src/tests/intg/Makefile.am
-@@ -35,6 +35,7 @@ dist_noinst_DATA = \
-     data/ad_data.ldif \
-     data/ad_schema.ldif \
-     test_pysss_nss_idmap.py \
-+    test_ssh_pubkey.py \
-     $(NULL)
- 
- config.py: config.py.m4
-diff --git a/src/tests/intg/test_ssh_pubkey.py b/src/tests/intg/test_ssh_pubkey.py
-new file mode 100644
-index 0000000000000000000000000000000000000000..fbf55566e341373873057ec4e3af1d7f83202aa7
---- /dev/null
-+++ b/src/tests/intg/test_ssh_pubkey.py
-@@ -0,0 +1,232 @@
-+#
-+# ssh public key integration test
-+#
-+# Copyright (c) 2018 Red Hat, Inc.
-+#
-+# This is free software; you can redistribute it and/or modify it
-+# under the terms of the GNU General Public License as published by
-+# the Free Software Foundation; version 2 only
-+#
-+# This program is distributed in the hope that it will be useful, but
-+# WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+# General Public License for more details.
-+#
-+# You should have received a copy of the GNU General Public License
-+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-+#
-+
-+import os
-+import stat
-+import signal
-+import subprocess
-+import time
-+import ldap
-+import ldap.modlist
-+import pytest
-+
-+import config
-+import ds_openldap
-+import ent
-+import ldap_ent
-+from util import unindent, get_call_output
-+
-+LDAP_BASE_DN = "dc=example,dc=com"
-+
-+USER1_PUBKEY1 = "ssh-dss AAAAB3NzaC1kc3MAAACBAPMkvcU53RVhBtjwiC3IqeRIWR9Qwdv8\
-+DmZzEsDD3Csd6jYxMsPZoXcPrHqwYcEj1s5MVqhdSFS0Cjz13e7gO6OMLInO3xMBSSFHjfp9RE1H\
-+pgc4WisazzyJaW9EMkQo/DqvkFkKh31oqAmxcSbLAFJRg4TTIqm18qu8IRKS6m/RAAAAFQC97TA5\
-+JSsMsaX1bRszC7y4PhMBvQAAAIEAt9Yo9v/h9W4nDbzUdkGwNRszlPEK+T12bJv0O9Fk6subD3Do\
-+6A4Qru/Nr6voXoq8b018Wb7iFWvKOoz5uT/plWBKLXL2NN7ovTR+dUJIzvwurQZroukmU1EghNey\
-+lkSHmDlxSoMK6Nh21uGu6l+b6x5pXNaZHMpsywG4kY8SoC0AAACAAWLHneEGvqkYA8La4Eob+Hjj\
-+mAKilx8byxm3Kfb1XO+ZrR6XxadofZOaUYRMpPKgFjKAKPxJftPLiDjWM7lSe6h8df0dUMLVXt6m\
-+eA83kE0uK5JOOGJfJDqmRed2YnfxUDNNFQGT4xFWGrNtYNbGyw9BWKbkooAsLqaO04zP3Rs= \
-+user1@LDAP"
-+
-+USER1_PUBKEY2 = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAwHUUF3HPH+DkU6j8k7Q1wHG\
-+RJY9NeLqSav3h95mTSCQYPSC7I9RTJ4OORgqCbEzrP/DYrrn4TtQ9dhRJar3ZY+F36SH5yFIXORb\
-+lAIbFU+/anahBuFS9vHi1MqFPckGmwJ4QCpjQhdYxo1ro0e1RuGSaQNp/w9N6S/fDz4Cj4I99xDz\
-+SeQeGHxYv0e60plQ8dUajmnaGmYRJHF9a6Ban7IWySActCja7eQP2zIRXEZMpuhl1E0U4y+gHTFI\
-+gD3zQai3QrXm8RUrQURIJ0u6BlGS910OPbHqLpLTFWG08L8sNUcYzC+DY6yoCSO0n/Df3pVRS4C9\
-+5Krf3FqppMTjdfQ== user1@LDAP"
-+
-+
-+@pytest.fixture(scope="module")
-+def ds_inst(request):
-+    """LDAP server instance fixture"""
-+    ds_inst = ds_openldap.DSOpenLDAP(
-+        config.PREFIX, 10389, LDAP_BASE_DN,
-+        "cn=admin", "Secret123"
-+    )
-+
-+    try:
-+        ds_inst.setup()
-+    except:
-+        ds_inst.teardown()
-+        raise
-+    request.addfinalizer(ds_inst.teardown)
-+    return ds_inst
-+
-+
-+@pytest.fixture(scope="module")
-+def ldap_conn(request, ds_inst):
-+    """LDAP server connection fixture"""
-+    ldap_conn = ds_inst.bind()
-+    ldap_conn.ds_inst = ds_inst
-+    request.addfinalizer(ldap_conn.unbind_s)
-+    return ldap_conn
-+
-+
-+def create_ldap_entries(ldap_conn, ent_list=None):
-+    """Add LDAP entries from ent_list"""
-+    if ent_list is not None:
-+        for entry in ent_list:
-+            ldap_conn.add_s(entry[0], entry[1])
-+
-+
-+def cleanup_ldap_entries(ldap_conn, ent_list=None):
-+    """Remove LDAP entries added by create_ldap_entries"""
-+    if ent_list is None:
-+        for ou in ("Users", "Groups", "Netgroups", "Services", "Policies"):
-+            for entry in ldap_conn.search_s("ou=" + ou + "," +
-+                                            ldap_conn.ds_inst.base_dn,
-+                                            ldap.SCOPE_ONELEVEL,
-+                                            attrlist=[]):
-+                ldap_conn.delete_s(entry[0])
-+    else:
-+        for entry in ent_list:
-+            ldap_conn.delete_s(entry[0])
-+
-+
-+def create_ldap_cleanup(request, ldap_conn, ent_list=None):
-+    """Add teardown for removing all user/group LDAP entries"""
-+    request.addfinalizer(lambda: cleanup_ldap_entries(ldap_conn, ent_list))
-+
-+
-+def create_ldap_fixture(request, ldap_conn, ent_list=None):
-+    """Add LDAP entries and add teardown for removing them"""
-+    create_ldap_entries(ldap_conn, ent_list)
-+    create_ldap_cleanup(request, ldap_conn, ent_list)
-+
-+
-+SCHEMA_RFC2307_BIS = "rfc2307bis"
-+
-+
-+def format_basic_conf(ldap_conn, schema):
-+    """Format a basic SSSD configuration"""
-+    schema_conf = "ldap_schema         = " + schema + "\n"
-+    schema_conf += "ldap_group_object_class = groupOfNames\n"
-+    return unindent("""\
-+        [sssd]
-+        domains             = LDAP
-+        services            = nss, ssh
-+
-+        [nss]
-+
-+        [ssh]
-+        debug_level=10
-+
-+        [domain/LDAP]
-+        {schema_conf}
-+        id_provider         = ldap
-+        auth_provider       = ldap
-+        ldap_uri            = {ldap_conn.ds_inst.ldap_url}
-+        ldap_search_base    = {ldap_conn.ds_inst.base_dn}
-+        ldap_sudo_use_host_filter = false
-+        debug_level=10
-+    """).format(**locals())
-+
-+
-+def create_conf_file(contents):
-+    """Create sssd.conf with specified contents"""
-+    conf = open(config.CONF_PATH, "w")
-+    conf.write(contents)
-+    conf.close()
-+    os.chmod(config.CONF_PATH, stat.S_IRUSR | stat.S_IWUSR)
-+
-+
-+def cleanup_conf_file():
-+    """Remove sssd.conf, if it exists"""
-+    if os.path.lexists(config.CONF_PATH):
-+        os.unlink(config.CONF_PATH)
-+
-+
-+def create_conf_cleanup(request):
-+    """Add teardown for removing sssd.conf"""
-+    request.addfinalizer(cleanup_conf_file)
-+
-+
-+def create_conf_fixture(request, contents):
-+    """
-+    Create sssd.conf with specified contents and add teardown for removing it
-+    """
-+    create_conf_file(contents)
-+    create_conf_cleanup(request)
-+
-+
-+def create_sssd_process():
-+    """Start the SSSD process"""
-+    if subprocess.call(["sssd", "-D", "-f"]) != 0:
-+        raise Exception("sssd start failed")
-+
-+
-+def get_sssd_pid():
-+    pid_file = open(config.PIDFILE_PATH, "r")
-+    pid = int(pid_file.read())
-+    return pid
-+
-+
-+def cleanup_sssd_process():
-+    """Stop the SSSD process and remove its state"""
-+    try:
-+        pid = get_sssd_pid()
-+        os.kill(pid, signal.SIGTERM)
-+        while True:
-+            try:
-+                os.kill(pid, signal.SIGCONT)
-+            except:
-+                break
-+            time.sleep(1)
-+    except:
-+        pass
-+    for path in os.listdir(config.DB_PATH):
-+        os.unlink(config.DB_PATH + "/" + path)
-+    for path in os.listdir(config.MCACHE_PATH):
-+        os.unlink(config.MCACHE_PATH + "/" + path)
-+
-+
-+def create_sssd_fixture(request):
-+    """Start SSSD and add teardown for stopping it and removing its state"""
-+    create_sssd_process()
-+    create_sssd_cleanup(request)
-+
-+
-+def create_sssd_cleanup(request):
-+    """Add teardown for stopping SSSD and removing its state"""
-+    request.addfinalizer(cleanup_sssd_process)
-+
-+
-+@pytest.fixture
-+def add_user_with_ssh_key(request, ldap_conn):
-+    ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn)
-+    ent_list.add_user("user1", 1001, 2001,
-+                      sshPubKey=(USER1_PUBKEY1, USER1_PUBKEY2))
-+    ent_list.add_user("user2", 1002, 2001)
-+    create_ldap_fixture(request, ldap_conn, ent_list)
-+
-+    conf = format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS)
-+    create_conf_fixture(request, conf)
-+    create_sssd_fixture(request)
-+    return None
-+
-+
-+def test_ssh_pubkey_retrieve(add_user_with_ssh_key):
-+    """
-+    Test that we can retrieve an SSH public key for a user who has one
-+    and can't retrieve a key for a user who does not have one.
-+    """
-+    sshpubkey = get_call_output(["sss_ssh_authorizedkeys", "user1"])
-+    assert sshpubkey == USER1_PUBKEY1 + '\n' + USER1_PUBKEY2 + '\n'
-+
-+    sshpubkey = get_call_output(["sss_ssh_authorizedkeys", "user2"])
-+    assert len(sshpubkey) == 0
--- 
-2.14.4
-
diff --git a/SOURCES/0115-SSH-Do-not-exit-abruptly-if-SSHD-closes-its-end-of-t.patch b/SOURCES/0115-SSH-Do-not-exit-abruptly-if-SSHD-closes-its-end-of-t.patch
deleted file mode 100644
index 711e447..0000000
--- a/SOURCES/0115-SSH-Do-not-exit-abruptly-if-SSHD-closes-its-end-of-t.patch
+++ /dev/null
@@ -1,88 +0,0 @@
-From d1b01f0a04e54c55183fd5cee4b713e28e4e2cd7 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 28 May 2018 21:41:49 +0200
-Subject: [PATCH] SSH: Do not exit abruptly if SSHD closes its end of the pipe
- before reading all the SSH keys
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3747
-
-Before writing the keys to sshd, ignore SIGPIPE so that if the pipe
-towards the authorizedkeys helper is closed, the sss_ssh_authorizedkeys
-helper is not terminated with SIGPIPE, but instead proceeds and then the
-write(2) calls would non-terminally fail with EPIPE.
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit cb138d7d060611e891d341db08477e41f9a3d17d)
----
- src/sss_client/ssh/sss_ssh_authorizedkeys.c | 35 ++++++++++++++++++++++++++++-
- 1 file changed, 34 insertions(+), 1 deletion(-)
-
-diff --git a/src/sss_client/ssh/sss_ssh_authorizedkeys.c b/src/sss_client/ssh/sss_ssh_authorizedkeys.c
-index 782a9f44379bff5346c896b3e03570720632c0be..b0280fbf8b0ed0501d792973241b826fc4a7a04d 100644
---- a/src/sss_client/ssh/sss_ssh_authorizedkeys.c
-+++ b/src/sss_client/ssh/sss_ssh_authorizedkeys.c
-@@ -21,6 +21,7 @@
- #include <stdio.h>
- #include <talloc.h>
- #include <popt.h>
-+#include <signal.h>
- 
- #include "util/util.h"
- #include "util/crypto/sss_crypto.h"
-@@ -99,8 +100,16 @@ int main(int argc, const char **argv)
-         goto fini;
-     }
- 
-+    /* if sshd closes its end of the pipe, we don't want sss_ssh_authorizedkeys
-+     * to exit abruptly, but to finish gracefully instead because the valid
-+     * key can be present in the data already written
-+     */
-+    signal(SIGPIPE, SIG_IGN);
-+
-     /* print results */
-     for (i = 0; i < ent->num_pubkeys; i++) {
-+        char *repr_break = NULL;
-+
-         ret = sss_ssh_format_pubkey(mem_ctx, &ent->pubkeys[i], &repr);
-         if (ret != EOK) {
-             DEBUG(SSSDBG_OP_FAILURE,
-@@ -109,7 +118,31 @@ int main(int argc, const char **argv)
-             continue;
-         }
- 
--        printf("%s\n", repr);
-+        /* OpenSSH expects a linebreak after each key */
-+        repr_break = talloc_asprintf(mem_ctx, "%s\n", repr);
-+        talloc_zfree(repr);
-+        if (repr_break == NULL) {
-+            ret = ENOMEM;
-+            goto fini;
-+        }
-+
-+        ret = sss_atomic_write_s(STDOUT_FILENO, repr_break, strlen(repr_break));
-+        /* Avoid spiking memory with too many large keys */
-+        talloc_zfree(repr_break);
-+        if (ret < 0) {
-+            ret = errno;
-+            if (ret == EPIPE) {
-+                DEBUG(SSSDBG_MINOR_FAILURE,
-+                      "SSHD closed the pipe before all keys could be written\n");
-+                /* Return 0 so that openssh doesn't abort pubkey auth */
-+                ret = 0;
-+                goto fini;
-+            }
-+            DEBUG(SSSDBG_CRIT_FAILURE,
-+                  "sss_atomic_write_s() failed (%d): %s\n",
-+                  ret, strerror(ret));
-+            goto fini;
-+        }
-     }
- 
-     ret = EXIT_SUCCESS;
--- 
-2.14.4
-
diff --git a/SOURCES/0116-TESTS-Add-a-helper-binary-that-can-trigger-the-SIGPI.patch b/SOURCES/0116-TESTS-Add-a-helper-binary-that-can-trigger-the-SIGPI.patch
deleted file mode 100644
index 494b327..0000000
--- a/SOURCES/0116-TESTS-Add-a-helper-binary-that-can-trigger-the-SIGPI.patch
+++ /dev/null
@@ -1,213 +0,0 @@
-From 187b9f28f1ea2e3fa4b5e3385050701fdc1d0f69 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Mon, 28 May 2018 21:49:41 +0200
-Subject: [PATCH] TESTS: Add a helper binary that can trigger the SIGPIPE to
- authorizedkeys
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Adds a test tool that simulates the behaviour of OpenSSH in the sense
-that it starts to read the output from the sss_ssh_authorizedkeys tool,
-but then closes the pipe before reading the whole output.
-
-Related:
-https://pagure.io/SSSD/sssd/issue/3747
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 909c16edb26a3c48b10a49e7919a35d13d31c52e)
----
- Makefile.am                 |  15 ++++-
- src/tests/test_ssh_client.c | 133 ++++++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 147 insertions(+), 1 deletion(-)
- create mode 100644 src/tests/test_ssh_client.c
-
-diff --git a/Makefile.am b/Makefile.am
-index 5917bd904054055a259eb69217282e4fb914c700..01fa4e43e48dcb722056d614e19f02687d32014b 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -331,6 +331,7 @@ endif   # HAVE_CMOCKA
- check_PROGRAMS = \
-     stress-tests \
-     krb5-child-test \
-+    test_ssh_client \
-     $(non_interactive_cmocka_based_tests) \
-     $(non_interactive_check_based_tests)
- 
-@@ -2294,6 +2295,18 @@ krb5_child_test_LDADD = \
-     $(SSSD_INTERNAL_LTLIBS) \
-     libsss_test_common.la
- 
-+test_ssh_client_SOURCES = \
-+    src/tests/test_ssh_client.c \
-+    $(NULL)
-+test_ssh_client_CFLAGS = \
-+    $(AM_CFLAGS) \
-+    -DSSH_CLIENT_DIR=\"$(abs_top_builddir)\" \
-+    $(NULL)
-+test_ssh_client_LDADD = \
-+    $(SSSD_INTERNAL_LTLIBS) \
-+    $(SSSD_LIBS) \
-+    $(NULL)
-+
- if BUILD_DBUS_TESTS
- 
- sbus_tests_SOURCES = \
-@@ -3418,7 +3431,6 @@ test_iobuf_LDADD = \
-     $(SSSD_LIBS) \
-     $(NULL)
- 
--
- EXTRA_simple_access_tests_DEPENDENCIES = \
-     $(ldblib_LTLIBRARIES)
- simple_access_tests_SOURCES = \
-@@ -3607,6 +3619,7 @@ intgcheck-prepare:
- 	    $(INTGCHECK_CONFIGURE_FLAGS) \
- 	    CFLAGS="$$CFLAGS -DKCM_PEER_UID=$$(id -u)"; \
- 	$(MAKE) $(AM_MAKEFLAGS) ; \
-+	$(MAKE) $(AM_MAKEFLAGS) test_ssh_client; \
- 	: Force single-thread install to workaround concurrency issues; \
- 	$(MAKE) $(AM_MAKEFLAGS) -j1 install; \
- 	: Remove .la files from LDB module directory to avoid loader warnings; \
-diff --git a/src/tests/test_ssh_client.c b/src/tests/test_ssh_client.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..8f963941f3249561178436d6f6dfc376780a4cda
---- /dev/null
-+++ b/src/tests/test_ssh_client.c
-@@ -0,0 +1,133 @@
-+/*
-+    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 <popt.h>
-+#include <sys/wait.h>
-+#include "util/util.h"
-+
-+#ifdef SSH_CLIENT_DIR
-+#define SSH_AK_CLIENT_PATH SSH_CLIENT_DIR"/sss_ssh_authorizedkeys"
-+#else
-+#error "The path to the ssh authorizedkeys helper is not defined"
-+#endif /* SSH_CLIENT_DIR */
-+
-+int main(int argc, const char *argv[])
-+{
-+    poptContext pc;
-+    int opt;
-+    struct poptOption long_options[] = {
-+        POPT_AUTOHELP
-+        SSSD_DEBUG_OPTS
-+        POPT_TABLEEND
-+    };
-+    struct stat sb;
-+    int ret;
-+    int status;
-+    int p[2];
-+    pid_t pid;
-+    const char *pc_user = NULL;
-+    char *av[3];
-+    char buf[5]; /* Ridiculously small buffer by design */
-+
-+    /* 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);
-+    poptSetOtherOptionHelp(pc, "USER");
-+    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 3;
-+        }
-+    }
-+
-+    pc_user = poptGetArg(pc);
-+    if (pc_user == NULL) {
-+        fprintf(stderr, "No user specified\n");
-+        return 3;
-+    }
-+
-+    poptFreeContext(pc);
-+
-+    DEBUG_CLI_INIT(debug_level);
-+
-+    ret = stat(SSH_AK_CLIENT_PATH, &sb);
-+    if (ret != 0) {
-+        ret = errno;
-+        DEBUG(SSSDBG_CRIT_FAILURE,
-+              "Could not stat %s [%d]: %s\n",
-+              SSH_AK_CLIENT_PATH, ret, strerror(ret));
-+        return 3;
-+    }
-+
-+    ret = pipe(p);
-+    if (ret != 0) {
-+        perror("pipe");
-+        return 3;
-+    }
-+
-+    switch (pid = fork()) {
-+    case -1:
-+        ret = errno;
-+        close(p[0]);
-+        close(p[1]);
-+        DEBUG(SSSDBG_CRIT_FAILURE, "fork failed: %d\n", ret);
-+        return 3;
-+    case 0:
-+        /* child */
-+        av[0] = discard_const(SSH_AK_CLIENT_PATH);
-+        av[1] = discard_const(pc_user);
-+        av[2] = NULL;
-+
-+        close(p[0]);
-+        ret = dup2(p[1], STDOUT_FILENO);
-+        if (ret == -1) {
-+            perror("dup2");
-+            return 3;
-+        }
-+
-+        execv(av[0], av);
-+        return 3;
-+    default:
-+        /* parent */
-+        break;
-+    }
-+
-+    close(p[1]);
-+    read(p[0], buf, sizeof(buf));
-+    close(p[0]);
-+
-+    pid = waitpid(pid, &status, 0);
-+    if (pid == -1) {
-+        perror("waitpid");
-+        return 3;
-+    }
-+
-+    if (WIFEXITED(status)) {
-+        printf("sss_ssh_authorizedkeys exited with return code %d\n", WEXITSTATUS(status));
-+        return 0;
-+    } else if (WIFSIGNALED(status)) {
-+        printf("sss_ssh_authorizedkeys exited with signal %d\n", WTERMSIG(status));
-+        return 1;
-+    }
-+
-+    printf("sss_ssh_authorizedkeys exited for another reason\n");
-+    return 2;
-+}
--- 
-2.14.4
-
diff --git a/SOURCES/0117-TESTS-Add-a-regression-test-for-SIGHUP-handling-in-s.patch b/SOURCES/0117-TESTS-Add-a-regression-test-for-SIGHUP-handling-in-s.patch
deleted file mode 100644
index c791974..0000000
--- a/SOURCES/0117-TESTS-Add-a-regression-test-for-SIGHUP-handling-in-s.patch
+++ /dev/null
@@ -1,94 +0,0 @@
-From 103a22b85df5c371aefb08e476a3ab950e6882a3 Mon Sep 17 00:00:00 2001
-From: Jakub Hrozek <jhrozek@redhat.com>
-Date: Tue, 19 Jun 2018 11:39:02 +0200
-Subject: [PATCH] TESTS: Add a regression test for SIGHUP handling in
- sss_ssh_authorizedkeys
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-A regression test for:
-https://pagure.io/SSSD/sssd/issue/3747
-
-Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
-(cherry picked from commit 4cc3c1a1b1070c12bcc4351880d8207e47b37496)
----
- src/tests/intg/test_ssh_pubkey.py | 58 +++++++++++++++++++++++++++++++++++++++
- 1 file changed, 58 insertions(+)
-
-diff --git a/src/tests/intg/test_ssh_pubkey.py b/src/tests/intg/test_ssh_pubkey.py
-index fbf55566e341373873057ec4e3af1d7f83202aa7..8fb41c62d87ec210c9aad8582023fe1cb00f2b4e 100644
---- a/src/tests/intg/test_ssh_pubkey.py
-+++ b/src/tests/intg/test_ssh_pubkey.py
-@@ -24,6 +24,8 @@ import time
- import ldap
- import ldap.modlist
- import pytest
-+import string
-+import random
- 
- import config
- import ds_openldap
-@@ -230,3 +232,59 @@ def test_ssh_pubkey_retrieve(add_user_with_ssh_key):
- 
-     sshpubkey = get_call_output(["sss_ssh_authorizedkeys", "user2"])
-     assert len(sshpubkey) == 0
-+
-+
-+@pytest.fixture()
-+def sighup_client(request):
-+    test_ssh_cli_path = os.path.join(config.ABS_BUILDDIR,
-+                                     "..", "..", "..", "test_ssh_client")
-+    assert os.access(test_ssh_cli_path, os.X_OK)
-+    return test_ssh_cli_path
-+
-+
-+@pytest.fixture
-+def add_user_with_many_keys(request, ldap_conn):
-+    # Generate a large list of unique ssh pubkeys
-+    pubkey_list = []
-+    while len(pubkey_list) < 50:
-+        new_pubkey = list(USER1_PUBKEY1)
-+        new_pubkey[10] = random.choice(string.ascii_uppercase)
-+        new_pubkey[11] = random.choice(string.ascii_uppercase)
-+        new_pubkey[12] = random.choice(string.ascii_uppercase)
-+        str_new_pubkey = ''.join(c for c in new_pubkey)
-+        if str_new_pubkey in pubkey_list:
-+            continue
-+        pubkey_list.append(str_new_pubkey)
-+
-+    ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn)
-+    ent_list.add_user("user1", 1001, 2001, sshPubKey=pubkey_list)
-+    create_ldap_fixture(request, ldap_conn, ent_list)
-+
-+    conf = format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS)
-+    create_conf_fixture(request, conf)
-+    create_sssd_fixture(request)
-+    return None
-+
-+
-+def test_ssh_sighup(add_user_with_many_keys, sighup_client):
-+    """
-+    A regression test for https://pagure.io/SSSD/sssd/issue/3747
-+
-+    OpenSSH can close its end of the pipe towards sss_ssh_authorizedkeys
-+    before all of the output is read. In that case, older versions
-+    of sss_ssh_authorizedkeys were receiving a SIGPIPE
-+    """
-+    cli_path = sighup_client
-+
-+    # python actually does the sensible, but unexpected (for a C programmer)
-+    # thing and handles SIGPIPE. In order to reproduce the bug, we need
-+    # to unset the SIGPIPE handler
-+    signal.signal(signal.SIGPIPE, signal.SIG_DFL)
-+
-+    process = subprocess.Popen([cli_path, "user1"],
-+                               stdout=subprocess.PIPE,
-+                               stderr=subprocess.PIPE)
-+    _, _ = process.communicate()
-+    # If the test tool detects that sss_ssh_authorizedkeys was killed with a
-+    # signal, it would have returned 1
-+    assert process.returncode == 0
--- 
-2.14.4
-
diff --git a/SOURCES/0118-TESTS-Order-list-of-entries-in-some-lists.patch b/SOURCES/0118-TESTS-Order-list-of-entries-in-some-lists.patch
deleted file mode 100644
index 8e7ca54..0000000
--- a/SOURCES/0118-TESTS-Order-list-of-entries-in-some-lists.patch
+++ /dev/null
@@ -1,175 +0,0 @@
-From 1a73dbe9747aec2818fabd179e0fb46695d66433 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Michal=20=C5=BDidek?= <mzidek@redhat.com>
-Date: Mon, 13 Nov 2017 16:15:21 +0100
-Subject: [PATCH] TESTS: Order list of entries in some lists
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Some tests started to fail because we depended on specific
-order of users in groups or messages in ldb results to be
-returned and that order changed.
-
-This patch adds a simple helper functions into these tests
-that order the entries before comparison with expected results.
-more deterministic.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3563
-
-Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
-(cherry picked from commit caae0e53e6091806634943699f4398b6a20273b4)
-
-DOWNSTREAM:
-Resolves: rhbz#1596292 - home dir disappear in sssd cache on the IPA master for AD users [rhel-7.5.z]
----
- src/tests/cmocka/test_nss_srv.c     | 22 +++++++++++++++++++
- src/tests/cmocka/test_sysdb_views.c | 42 ++++++++++++++++++++++++++++++++-----
- 2 files changed, 59 insertions(+), 5 deletions(-)
-
-diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
-index 6aa726153183b5a871a75d398727ea7132358ca6..21bd80fb7f6562f6a31452bac6a26c109fef4cb1 100644
---- a/src/tests/cmocka/test_nss_srv.c
-+++ b/src/tests/cmocka/test_nss_srv.c
-@@ -585,6 +585,25 @@ static errno_t delete_group(struct nss_test_ctx *ctx,
-     return ret;
- }
- 
-+static int cmp_func(const void *a, const void *b)
-+{
-+    char *str1 = *(char **)discard_const(a);
-+    char *str2 = *(char **)discard_const(b);
-+
-+    return strcmp(str1, str2);
-+}
-+
-+static void order_string_array(char **_list, int size)
-+{
-+    if (size < 2 || _list == NULL || *_list == NULL) {
-+        /* Nothing to do */
-+        return;
-+    }
-+
-+    qsort(_list, size, sizeof(char *), cmp_func);
-+    return;
-+}
-+
- static void assert_groups_equal(struct group *expected,
-                                 struct group *gr, const int nmem)
- {
-@@ -594,6 +613,9 @@ static void assert_groups_equal(struct group *expected,
-     assert_string_equal(gr->gr_name, expected->gr_name);
-     assert_string_equal(gr->gr_passwd, expected->gr_passwd);
- 
-+    order_string_array(gr->gr_mem, nmem);
-+    order_string_array(expected->gr_mem, nmem);
-+
-     for (i = 0; i < nmem; i++) {
-         assert_string_equal(gr->gr_mem[i], expected->gr_mem[i]);
-     }
-diff --git a/src/tests/cmocka/test_sysdb_views.c b/src/tests/cmocka/test_sysdb_views.c
-index 0378254b4440b29c3182faf2adde8c3db8a4ce97..dd3eb50f9310ff925734dcf51a669d08a638aefd 100644
---- a/src/tests/cmocka/test_sysdb_views.c
-+++ b/src/tests/cmocka/test_sysdb_views.c
-@@ -22,6 +22,7 @@
-     along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
- 
-+#include <stdlib.h>
- #include <stdarg.h>
- #include <stddef.h>
- #include <setjmp.h>
-@@ -612,6 +613,31 @@ static int test_enum_users_setup(void **state)
-     return 0;
- }
- 
-+static int cmp_func(const void *a, const void *b)
-+{
-+    const char *str1;
-+    const char *str2;
-+    struct ldb_message *msg1 = *(struct ldb_message **)discard_const(a);
-+    struct ldb_message *msg2 = *(struct ldb_message **)discard_const(b);
-+
-+    str1 = ldb_msg_find_attr_as_string(msg1, SYSDB_NAME, NULL);
-+    str2 = ldb_msg_find_attr_as_string(msg2, SYSDB_NAME, NULL);
-+
-+    return strcmp(str1, str2);
-+}
-+
-+/* Make the order of ldb results deterministic */
-+static void order_ldb_res_msgs(struct ldb_result *res)
-+{
-+    if (res == NULL || res->count < 2) {
-+        /* Nothing to do */
-+        return;
-+    }
-+
-+    qsort(res->msgs, res->count, sizeof(struct ldb_message *), cmp_func);
-+    return;
-+}
-+
- static void assert_user_attrs(struct ldb_message *msg,
-                               struct sss_domain_info *dom,
-                               const char *shortname,
-@@ -660,8 +686,9 @@ static void check_enumpwent(int ret, struct sss_domain_info *dom,
-     assert_int_equal(ret, EOK);
-     assert_int_equal(res->count, N_ELEMENTS(users)-1);
- 
--    assert_user_attrs(res->msgs[0], dom, "barney", views);
--    assert_user_attrs(res->msgs[1], dom, "alice", views);
-+    order_ldb_res_msgs(res);
-+    assert_user_attrs(res->msgs[0], dom, "alice", views);
-+    assert_user_attrs(res->msgs[1], dom, "barney", views);
-     assert_user_attrs(res->msgs[2], dom, "bob", views);
- }
- 
-@@ -703,6 +730,7 @@ static void test_sysdb_enumpwent_filter(void **state)
-     ret = sysdb_enumpwent_filter(test_ctx, test_ctx->domain, "b*", 0, &res);
-     assert_int_equal(ret, EOK);
-     assert_int_equal(res->count, 2);
-+    order_ldb_res_msgs(res);
-     assert_user_attrs(res->msgs[0], test_ctx->domain, "barney", false);
-     assert_user_attrs(res->msgs[1], test_ctx->domain, "bob", false);
- 
-@@ -749,6 +777,7 @@ static void test_sysdb_enumpwent_filter_views(void **state)
-                                             "b*", NULL, &res);
-     assert_int_equal(ret, EOK);
-     assert_int_equal(res->count, 2);
-+    order_ldb_res_msgs(res);
-     assert_user_attrs(res->msgs[0], test_ctx->domain, "barney", true);
-     assert_user_attrs(res->msgs[1], test_ctx->domain, "bob", true);
- 
-@@ -896,10 +925,11 @@ static void check_enumgrent(int ret, struct sss_domain_info *dom,
- {
-     assert_int_equal(ret, EOK);
-     assert_int_equal(res->count, N_ELEMENTS(groups)-1);
--    assert_group_attrs(res->msgs[0], dom, "three",
--                       views ? TEST_GID_OVERRIDE_BASE + 2 : 0);
--    assert_group_attrs(res->msgs[1], dom, "one",
-+    order_ldb_res_msgs(res);
-+    assert_group_attrs(res->msgs[0], dom, "one",
-                        views ? TEST_GID_OVERRIDE_BASE : 0);
-+    assert_group_attrs(res->msgs[1], dom, "three",
-+                       views ? TEST_GID_OVERRIDE_BASE + 2 : 0);
-     assert_group_attrs(res->msgs[2], dom, "two",
-                        views ? TEST_GID_OVERRIDE_BASE + 1 : 0);
- }
-@@ -942,6 +972,7 @@ static void test_sysdb_enumgrent_filter(void **state)
-     ret = sysdb_enumgrent_filter(test_ctx, test_ctx->domain, "t*", 0, &res);
-     assert_int_equal(ret, EOK);
-     assert_int_equal(res->count, 2);
-+    order_ldb_res_msgs(res);
-     assert_group_attrs(res->msgs[0], test_ctx->domain, "three", 0);
-     assert_group_attrs(res->msgs[1], test_ctx->domain, "two", 0);
- 
-@@ -988,6 +1019,7 @@ static void test_sysdb_enumgrent_filter_views(void **state)
-                                             "t*", NULL, &res);
-     assert_int_equal(ret, EOK);
-     assert_int_equal(res->count, 2);
-+    order_ldb_res_msgs(res);
-     assert_group_attrs(res->msgs[0], test_ctx->domain,
-                        "three", TEST_GID_OVERRIDE_BASE + 2);
-     assert_group_attrs(res->msgs[1], test_ctx->domain, "two",
--- 
-2.14.4
-
diff --git a/SOURCES/0119-sysdb-add-sysdb_getgrgid_attrs.patch b/SOURCES/0119-sysdb-add-sysdb_getgrgid_attrs.patch
deleted file mode 100644
index 747a123..0000000
--- a/SOURCES/0119-sysdb-add-sysdb_getgrgid_attrs.patch
+++ /dev/null
@@ -1,171 +0,0 @@
-From f46dc8010a7d5fbb398e282d680703e1bd5963f4 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 29 May 2018 15:33:34 +0200
-Subject: [PATCH] sysdb: add sysdb_getgrgid_attrs()
-
-sysdb_getgrgid() is the only MPG aware by GID request but only supports
-a fixes set of attributes. The new call allows to add additional
-arguments.
-
-Related to https://pagure.io/SSSD/sssd/issue/3748
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 8aa56a9e8744a7611fa26a254c4f9228e919c8ed)
----
- src/db/sysdb.h          |  6 ++++++
- src/db/sysdb_ops.c      |  3 +++
- src/db/sysdb_search.c   | 31 ++++++++++++++++++++++++++-----
- src/tests/sysdb-tests.c | 37 +++++++++++++++++++++++++++++++++++++
- 4 files changed, 72 insertions(+), 5 deletions(-)
-
-diff --git a/src/db/sysdb.h b/src/db/sysdb.h
-index 2660314a75a574d7f5625c8672e5261587056d1a..affd1c9053e43ff24c98cc8fb23eec2c4b69f955 100644
---- a/src/db/sysdb.h
-+++ b/src/db/sysdb.h
-@@ -779,6 +779,12 @@ int sysdb_getgrgid(TALLOC_CTX *mem_ctx,
-                    gid_t gid,
-                    struct ldb_result **res);
- 
-+int sysdb_getgrgid_attrs(TALLOC_CTX *mem_ctx,
-+                         struct sss_domain_info *domain,
-+                         gid_t gid,
-+                         const char **attrs,
-+                         struct ldb_result **res);
-+
- int sysdb_enumgrent(TALLOC_CTX *mem_ctx,
-                     struct sss_domain_info *domain,
-                     struct ldb_result **res);
-diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
-index 024683317cab99743681db804f7026c8dbb33a38..c0d343bdabd324cbe8b9745c65c2a6e5a56321e1 100644
---- a/src/db/sysdb_ops.c
-+++ b/src/db/sysdb_ops.c
-@@ -709,6 +709,9 @@ int sysdb_search_group_by_name(TALLOC_CTX *mem_ctx,
-     return sysdb_search_by_name(mem_ctx, domain, name, SYSDB_GROUP, attrs, msg);
- }
- 
-+/* Please note that sysdb_search_group_by_gid() is not aware of MPGs. If MPG
-+ * support is needed either the caller must handle it or sysdb_getgrgid() or
-+ * sysdb_getgrgid_attrs() should be used. */
- int sysdb_search_group_by_gid(TALLOC_CTX *mem_ctx,
-                               struct sss_domain_info *domain,
-                               gid_t gid,
-diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
-index 9f37cbcd50a778145518c15b6146ad812a5b4fa3..3d78a38b36e65febd50e41fc1d1be29eceeb7649 100644
---- a/src/db/sysdb_search.c
-+++ b/src/db/sysdb_search.c
-@@ -1036,24 +1036,37 @@ done:
-     return ret;
- }
- 
--int sysdb_getgrgid(TALLOC_CTX *mem_ctx,
--                   struct sss_domain_info *domain,
--                   gid_t gid,
--                   struct ldb_result **_res)
-+int sysdb_getgrgid_attrs(TALLOC_CTX *mem_ctx,
-+                         struct sss_domain_info *domain,
-+                         gid_t gid,
-+                         const char **additional_attrs,
-+                         struct ldb_result **_res)
- {
-     TALLOC_CTX *tmp_ctx;
-     unsigned long int ul_gid = gid;
--    static const char *attrs[] = SYSDB_GRSRC_ATTRS;
-     const char *fmt_filter;
-     struct ldb_dn *base_dn;
-     struct ldb_result *res;
-     int ret;
-+    static const char *default_attrs[] = SYSDB_GRSRC_ATTRS;
-+    const char **attrs = NULL;
- 
-     tmp_ctx = talloc_new(NULL);
-     if (!tmp_ctx) {
-         return ENOMEM;
-     }
- 
-+    if (additional_attrs == NULL) {
-+        attrs = default_attrs;
-+    } else {
-+        ret = add_strings_lists(tmp_ctx, additional_attrs, default_attrs,
-+                                false, discard_const(&attrs));
-+        if (ret != EOK) {
-+            DEBUG(SSSDBG_OP_FAILURE, "add_strings_lists failed.\n");
-+            goto done;
-+        }
-+    }
-+
-     if (domain->mpg) {
-         fmt_filter = SYSDB_GRGID_MPG_FILTER;
-         base_dn = ldb_dn_new_fmt(tmp_ctx, domain->sysdb->ldb,
-@@ -1092,6 +1105,14 @@ done:
-     return ret;
- }
- 
-+int sysdb_getgrgid(TALLOC_CTX *mem_ctx,
-+                   struct sss_domain_info *domain,
-+                   gid_t gid,
-+                   struct ldb_result **_res)
-+{
-+    return sysdb_getgrgid_attrs(mem_ctx, domain, gid, NULL, _res);
-+}
-+
- int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx,
-                            struct sss_domain_info *domain,
-                            const char *name_filter,
-diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
-index fc9936968bcde8370c7054ba303de4463b35e15a..30574679f51362d03d7b9e3f8a1d55889817e4c1 100644
---- a/src/tests/sysdb-tests.c
-+++ b/src/tests/sysdb-tests.c
-@@ -1114,6 +1114,42 @@ done:
- }
- END_TEST
- 
-+START_TEST (test_sysdb_getgrgid_attrs)
-+{
-+    struct sysdb_test_ctx *test_ctx;
-+    struct test_data *data;
-+    struct ldb_result *res;
-+    int ret;
-+    const char *attrs[] = { SYSDB_CREATE_TIME, NULL };
-+    uint64_t ctime;
-+
-+    /* Setup */
-+    ret = setup_sysdb_tests(&test_ctx);
-+    if (ret != EOK) {
-+        fail("Could not set up the test");
-+        return;
-+    }
-+
-+    data = test_data_new_group(test_ctx, _i);
-+    fail_if(data == NULL, "OOM");
-+
-+    ret = sysdb_getgrgid_attrs(test_ctx,
-+                               test_ctx->domain,
-+                               data->gid, attrs, &res);
-+    if (ret) {
-+        fail("sysdb_getgrgid_attrs failed for gid %d (%d: %s)",
-+             data->gid, ret, strerror(ret));
-+        goto done;
-+    }
-+
-+    ctime = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_CREATE_TIME, 0);
-+    fail_unless(ctime != 0, "Missing create time");
-+
-+done:
-+    talloc_free(test_ctx);
-+}
-+END_TEST
-+
- START_TEST (test_sysdb_search_groups)
- {
-     struct sysdb_test_ctx *test_ctx;
-@@ -7072,6 +7108,7 @@ Suite *create_sysdb_suite(void)
- 
-     /* Verify the groups can be queried by GID */
-     tcase_add_loop_test(tc_sysdb, test_sysdb_getgrgid, 28010, 28020);
-+    tcase_add_loop_test(tc_sysdb, test_sysdb_getgrgid_attrs, 28010, 28020);
- 
-     /* Find the users by GID using a filter */
-     tcase_add_loop_test(tc_sysdb, test_sysdb_search_groups, 28010, 28020);
--- 
-2.14.4
-
diff --git a/SOURCES/0120-ipa-use-mpg-aware-group-lookup-in-get_object_from_ca.patch b/SOURCES/0120-ipa-use-mpg-aware-group-lookup-in-get_object_from_ca.patch
deleted file mode 100644
index b5ea5f9..0000000
--- a/SOURCES/0120-ipa-use-mpg-aware-group-lookup-in-get_object_from_ca.patch
+++ /dev/null
@@ -1,61 +0,0 @@
-From a6de362d3cfe16550eb16d01900f44c9aeb8cc50 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 29 May 2018 15:42:55 +0200
-Subject: [PATCH] ipa: use mpg aware group lookup in get_object_from_cache()
-
-Since with algorithmic id-mapping SSSD automatically creates user
-private groups for AD user with the help of magic private groups (mpg)
-get_object_from_cache() should use mpg aware calls to make sure the
-right user object is found when handling a request to look up a user
-private group.
-
-Only the lookup by gid had to be modified because
-sysdb_search_group_by_name() used for lookups by name is aware of MPGs.
-
-Related to https://pagure.io/SSSD/sssd/issue/3748
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit 032221568fe4287686d0ebb11b5c1fe51cc4735f)
----
- src/providers/ipa/ipa_subdomains_id.c | 18 ++++++++++++++++--
- 1 file changed, 16 insertions(+), 2 deletions(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index d40671086854f9c1a3f8bc7fc711009298dc31c8..3943579b07c7b2d32dde192b97b86eb036b91885 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -1030,7 +1030,14 @@ errno_t get_object_from_cache(TALLOC_CTX *mem_ctx,
- 
-         switch (ar->entry_type & BE_REQ_TYPE_MASK) {
-         case BE_REQ_GROUP:
--            ret = sysdb_search_group_by_gid(mem_ctx, dom, id, attrs, &msg);
-+            ret = sysdb_getgrgid_attrs(mem_ctx, dom, id, attrs, &res);
-+            if (ret == EOK) {
-+                if (res->count == 0) {
-+                    ret = ENOENT;
-+                } else {
-+                    msg = res->msgs[0];
-+                }
-+            }
-             break;
-         case BE_REQ_INITGROUPS:
-         case BE_REQ_USER:
-@@ -1038,7 +1045,14 @@ errno_t get_object_from_cache(TALLOC_CTX *mem_ctx,
-             ret = sysdb_search_user_by_uid(mem_ctx, dom, id, attrs, &msg);
-             if (ret == ENOENT && (ar->entry_type & BE_REQ_TYPE_MASK)
-                                                      == BE_REQ_USER_AND_GROUP) {
--                ret = sysdb_search_group_by_gid(mem_ctx, dom, id, attrs, &msg);
-+                ret = sysdb_getgrgid_attrs(mem_ctx, dom, id, attrs, &res);
-+                if (ret == EOK) {
-+                    if (res->count == 0) {
-+                        ret = ENOENT;
-+                    } else {
-+                        msg = res->msgs[0];
-+                    }
-+                }
-             }
-             break;
-         default:
--- 
-2.14.4
-
diff --git a/SOURCES/0121-ipa-allow-mpg-group-objects-in-apply_subdomain_homed.patch b/SOURCES/0121-ipa-allow-mpg-group-objects-in-apply_subdomain_homed.patch
deleted file mode 100644
index b785997..0000000
--- a/SOURCES/0121-ipa-allow-mpg-group-objects-in-apply_subdomain_homed.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 8bbee851484f7fa51af542ed2757e2eea36bf535 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 29 May 2018 15:44:28 +0200
-Subject: [PATCH] ipa: allow mpg group objects in apply_subdomain_homedir()
-
-Since with algorithmic id-mapping SSSD automatically creates user
-private groups for AD user with the help of magic private groups (mpg)
-apply_subdomain_homedir() should be aware the in mpg domains a group
-lookup might actually return a user object. Since the related sysdb
-calls are clever and replace the objectcategory so that it matches the
-original request type we have to check for the group category in the mpg
-case as well. apply_subdomain_homedir() checks the uidNumber later as
-well to make sure the object has the needed attributes for a user.
-
-Related to https://pagure.io/SSSD/sssd/issue/3748
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit e66517dcf63f1d4aaf866c22371dac7740ce0a48)
----
- src/providers/ipa/ipa_subdomains_id.c | 9 ++++++++-
- 1 file changed, 8 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/ipa/ipa_subdomains_id.c b/src/providers/ipa/ipa_subdomains_id.c
-index 3943579b07c7b2d32dde192b97b86eb036b91885..c2064d33029a27a2c5d4b5344034ce90f8e746b8 100644
---- a/src/providers/ipa/ipa_subdomains_id.c
-+++ b/src/providers/ipa/ipa_subdomains_id.c
-@@ -895,9 +895,16 @@ apply_subdomain_homedir(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
-         goto done;
-     }
- 
-+    /* The object is a user if SYSDB_OBJECTCATEGORY is SYSDB_USER_CLASS or in
-+     * case of a MPG group lookup if SYSDB_OBJECTCATEGORY is SYSDB_GROUP_CLASS.
-+     */
-     for (c = 0; c < msg_el->num_values; c++) {
-         if (strncmp(SYSDB_USER_CLASS, (const char *)msg_el->values[c].data,
--                    msg_el->values[c].length) == 0) {
-+                    msg_el->values[c].length) == 0
-+                || (dom->mpg
-+                    && strncmp(SYSDB_GROUP_CLASS,
-+                               (const char *)msg_el->values[c].data,
-+                               msg_el->values[c].length) == 0)) {
-             break;
-         }
-     }
--- 
-2.14.4
-
diff --git a/SOURCES/0122-AD-LDAP-do-not-fall-back-to-mpg-user-lookup-on-GC-co.patch b/SOURCES/0122-AD-LDAP-do-not-fall-back-to-mpg-user-lookup-on-GC-co.patch
deleted file mode 100644
index 68dba38..0000000
--- a/SOURCES/0122-AD-LDAP-do-not-fall-back-to-mpg-user-lookup-on-GC-co.patch
+++ /dev/null
@@ -1,68 +0,0 @@
-From 4dbfa49f50fd785f374209c2e59205e79533788e Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Tue, 29 May 2018 15:46:33 +0200
-Subject: [PATCH] AD/LDAP: do not fall back to mpg user lookup on GC connection
-
-For MPG domains a group lookup might fall back to a user lookup to check
-if the request is for a user private group. Since we cannot be sure that
-all needed attributes for a user are replicated to the Global Catalog we
-do not want to lookup the user during the fall back from the Global
-Catalog.
-
-Since we cannot skip Global Catalog lookups for groups completely due to
-membership to groups with universal scope this patch adds a flag to tell
-the lower level lookup calls to not fall back on connections to a Global
-Catalog.
-
-Related to https://pagure.io/SSSD/sssd/issue/3748
-
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit ad6ab352879264fdade8861aff53aa035a2e2240)
----
- src/providers/ad/ad_common.c     | 1 +
- src/providers/ldap/ldap_common.h | 2 ++
- src/providers/ldap/ldap_id.c     | 3 ++-
- 3 files changed, 5 insertions(+), 1 deletion(-)
-
-diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
-index 2a1647173b76b410371315eb364e9a3785714a93..1dca2fe279cb7d6d647aed42e3b3fabfb34b7dac 100644
---- a/src/providers/ad/ad_common.c
-+++ b/src/providers/ad/ad_common.c
-@@ -1375,6 +1375,7 @@ ad_gc_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx,
-     if (dp_opt_get_bool(ad_ctx->ad_options->basic, AD_ENABLE_GC)) {
-         clist[cindex] = ad_ctx->gc_ctx;
-         clist[cindex]->ignore_mark_offline = true;
-+        clist[cindex]->no_mpg_user_fallback = true;
-         cindex++;
-     }
- 
-diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
-index 44dbc3fb0678412f46366321e0be836313380949..21cb57b0e7b265972db74ac78a3c1fb4ba2a9529 100644
---- a/src/providers/ldap/ldap_common.h
-+++ b/src/providers/ldap/ldap_common.h
-@@ -57,6 +57,8 @@ struct sdap_id_conn_ctx {
-     struct sdap_id_conn_ctx *prev, *next;
-     /* do not go offline, try another connection */
-     bool ignore_mark_offline;
-+    /* do not fall back to user lookups for mpg domains on this connection */
-+    bool no_mpg_user_fallback;
- };
- 
- struct sdap_id_ctx {
-diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
-index 3824f8f9aa8d2892664f1182376bedf6fb8627f6..365d90fd1cdfba86c719b3669d057444a7449d66 100644
---- a/src/providers/ldap/ldap_id.c
-+++ b/src/providers/ldap/ldap_id.c
-@@ -1076,7 +1076,8 @@ static void groups_get_done(struct tevent_req *subreq)
-     }
- 
-     if (ret == ENOENT
--            && state->domain->mpg == true) {
-+            && state->domain->mpg == true
-+            && !state->conn->no_mpg_user_fallback) {
-         /* The requested filter did not find a group. Before giving up, we must
-          * also check if the GID can be resolved through a primary group of a
-          * user
--- 
-2.14.4
-
diff --git a/SOURCES/0123-deskprofile-don-t-bail-if-we-fail-to-save-one-profil.patch b/SOURCES/0123-deskprofile-don-t-bail-if-we-fail-to-save-one-profil.patch
deleted file mode 100644
index 85fe196..0000000
--- a/SOURCES/0123-deskprofile-don-t-bail-if-we-fail-to-save-one-profil.patch
+++ /dev/null
@@ -1,45 +0,0 @@
-From 7f698a050cea2baad34c84f8ae9e611dbf03ac7f Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fidencio@redhat.com>
-Date: Thu, 12 Jul 2018 23:55:03 +0200
-Subject: [PATCH] deskprofile: don't bail if we fail to save one profile
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Due to different reasons (a bug on fleet-commander, for instance?) we
-may face the situation where one profile ends up stored in freeipa on a
-half-broken state (with no data, for instance).
-
-In case it happens, we should try our best to save the not broken
-profiles and just skip the broken ones instead of bailing the whole
-operation.
-
-Resolves:
-https://pagure.io/SSSD/sssd/issue/3773
-
-Signed-off-by: Fabiano Fidêncio <fidencio@redhat.com>
-Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
-(cherry picked from commit efd6702e5f70bb3df0f840dd3ce9f8f9264661ba)
-
-DOWNSTREAM:
-Resolves: rhbz#1601360 - SSSD bails out saving desktop profiles in case an invalid profile is found [rhel-7.5.z]
----
- src/providers/ipa/ipa_session.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/providers/ipa/ipa_session.c b/src/providers/ipa/ipa_session.c
-index 3c7dd33c30ac6331319fc62cac466c4fbf04c0a5..a93c21224ee4d539d412e61ea06cbde3b928416a 100644
---- a/src/providers/ipa/ipa_session.c
-+++ b/src/providers/ipa/ipa_session.c
-@@ -766,7 +766,7 @@ ipa_pam_session_handler_save_deskprofile_rules(
-             DEBUG(SSSDBG_OP_FAILURE,
-                   "Failed to save a Desktop Profile Rule to disk [%d]: %s\n",
-                   ret, sss_strerror(ret));
--            goto done;
-+            continue;
-         }
-     }
- 
--- 
-2.14.4
-
diff --git a/SPECS/sssd.spec b/SPECS/sssd.spec
index 475c27c..2b87898 100644
--- a/SPECS/sssd.spec
+++ b/SPECS/sssd.spec
@@ -47,141 +47,62 @@
 %endif
 
 Name: sssd
-Version: 1.16.0
-Release: 19%{?dist}.8
+Version: 1.16.2
+Release: 13%{?dist}
 Group: Applications/System
 Summary: System Security Services Daemon
 License: GPLv3+
 URL: https://pagure.io/SSSD/sssd/
 Source0: https://releases.pagure.org/SSSD/sssd/sssd-%{version}.tar.gz
-Source1: cert9.db
-Source2: key4.db
 BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
 
 ### Patches ###
-Patch0001: 0001-NSS-Move-memcache-setup-to-separate-function.patch
-Patch0002: 0002-NSS-Specify-memcache_timeout-0-semantics.patch
-Patch0003: 0003-MAN-Document-memcache_timeout-0-meaning.patch
-Patch0004: 0004-CONFIG-Add-a-new-option-auto_private_groups.patch
-Patch0005: 0005-CONFDB-Remove-the-obsolete-option-magic_private_grou.patch
-Patch0006: 0006-SDAP-Allow-the-mpg-flag-for-the-main-domain.patch
-Patch0007: 0007-LDAP-Turn-group-request-into-user-request-for-MPG-do.patch
-Patch0008: 0008-SYSDB-Prevent-users-and-groups-ID-collision-in-MPG-d.patch
-Patch0009: 0009-TESTS-Add-integration-tests-for-the-auto_private_gro.patch
-Patch0010: 0010-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch
-Patch0011: 0011-MAN-GPO-Security-Filtering-limitation.patch
-Patch0012: 0012-sudo-always-use-srv_opts-from-id-context.patch
-Patch0013: 0013-AD-Remember-last-site-discovered.patch
-Patch0014: 0014-sysdb-add-functions-to-get-set-client-site.patch
-Patch0015: 0015-AD-Remember-last-site-discovered-in-sysdb.patch
-Patch0016: 0016-UTIL-Add-wrapper-function-to-configure-logger.patch
-Patch0017: 0017-Add-parameter-logger-to-daemons.patch
-Patch0018: 0018-SYSTEMD-Replace-parameter-debug-to-files-with-DEBUG_.patch
-Patch0019: 0019-SYSTEMD-Add-environment-file-to-responder-service-fi.patch
-Patch0020: 0020-UTIL-Hide-and-deprecate-parameter-debug-to-files.patch
-Patch0021: 0021-LDAP-Bind-to-the-LDAP-server-also-in-the-auth.patch
-Patch0022: 0022-sss_client-create-nss_common.h.patch
-Patch0023: 0023-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch
-Patch0024: 0024-NSS-add-_EX-version-of-some-requests.patch
-Patch0025: 0025-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch
-Patch0026: 0026-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch
-Patch0027: 0027-nss-make-memcache_delete_entry-public.patch
-Patch0028: 0028-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch
-Patch0029: 0029-NSS-TESTS-add-unit-tests-for-_EX-requests.patch
-Patch0030: 0030-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch
-Patch0031: 0031-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch
-Patch0032: 0032-BUILD-Properly-expand-variables-in-sssd-ifp.service.patch
-Patch0033: 0033-SYSTEMD-Clean-pid-file-in-corner-cases.patch
-Patch0034: 0034-CHILD-Pass-information-about-logger-to-children.patch
-Patch0035: 0035-LDAP-Improve-error-treatment-from-sdap_cli_connect-i.patch
-Patch0036: 0036-p11_child-return-multiple-certs.patch
-Patch0037: 0037-PAM-handled-multiple-certs-in-the-responder.patch
-Patch0038: 0038-pam_sss-refactoring-use-struct-cert_auth_info.patch
-Patch0039: 0039-p11_child-use-options-to-select-certificate-for-auth.patch
-Patch0040: 0040-pam-add-prompt-string-for-certificate-authentication.patch
-Patch0041: 0041-PAM-allow-missing-logon_name-during-certificate-auth.patch
-Patch0042: 0042-p11_child-add-descriptions-for-error-codes-to-debug-.patch
-Patch0043: 0043-pam-filter-certificates-in-the-responder-not-in-the-.patch
-Patch0044: 0044-PAM-add-certificate-s-label-to-the-selection-prompt.patch
-Patch0045: 0045-SYSDB-Remove-code-causing-a-covscan-warning.patch
-Patch0046: 0046-SYSDB-Better-debugging-for-email-conflicts.patch
-Patch0047: 0047-NSS-Use-enum_ctx-as-memory_context-in-_setnetgrent_s.patch
-Patch0048: 0048-TOOLS-Add-a-new-sssctl-command-access-report.patch
-Patch0049: 0049-dp-use-void-to-express-empty-output-argument-list.patch
-Patch0050: 0050-dp-add-method-to-refresh-access-control-rules.patch
-Patch0051: 0051-ipa-implement-method-to-refresh-HBAC-rules.patch
-Patch0052: 0052-ifp-add-method-to-refresh-access-control-rules-in-do.patch
-Patch0053: 0053-sssctl-call-dbus-instead-of-pam-to-refresh-HBAC-rule.patch
-Patch0054: 0054-sysdb-be_refresh_get_values_ex-remove-unused-option.patch
-Patch0055: 0055-sysdb-do-not-use-objectClass-for-users-and-groups.patch
-Patch0056: 0056-sysdb-do-not-use-LDB_SCOPE_ONELEVEL.patch
-Patch0057: 0057-sysdb-remove-IDXONE-and-objectClass-from-users-and-g.patch
-Patch0058: 0058-mmap_cache-make-checks-independent-of-input-size.patch
-Patch0059: 0059-NSS-Fix-covscan-warning.patch
-Patch0060: 0060-responder-Fix-talloc-hierarchy-in-sized_output_name.patch
-Patch0061: 0061-test_responder-Check-memory-leak-in-sized_output_nam.patch
-Patch0062: 0062-UTIL-add-find_domain_by_object_name_ex.patch
-Patch0063: 0063-ipa-handle-users-from-different-domains-in-ipa_resol.patch
-Patch0064: 0064-overrides-fixes-for-sysdb_invalidate_overrides.patch
-Patch0065: 0065-ipa-check-for-SYSDB_OVERRIDE_DN-in-process_members-a.patch
-Patch0066: 0066-IPA-use-cache-searches-in-get_groups_dns.patch
-Patch0067: 0067-ipa-compare-DNs-instead-of-group-names-in-ipa_s2n_sa.patch
-Patch0068: 0068-SDAP-Split-out-utility-function-sdap_get_object_doma.patch
-Patch0069: 0069-LDAP-Extract-the-check-whether-to-run-a-POSIX-check-.patch
-Patch0070: 0070-LDAP-Only-run-the-POSIX-check-with-a-GC-connection.patch
-Patch0071: 0071-SDAP-Search-with-a-NULL-search-base-when-looking-up-.patch
-Patch0072: 0072-SDAP-Rename-sdap_posix_check-to-sdap_gc_posix_check.patch
-Patch0073: 0073-DP-Create-a-new-handler-function-getAccountDomain.patch
-Patch0074: 0074-AD-Implement-a-real-getAccountDomain-handler-for-the.patch
-Patch0075: 0075-RESP-Expose-DP-method-getAccountDomain-to-responders.patch
-Patch0076: 0076-NEGCACHE-Add-API-for-setting-and-checking-locate-acc.patch
-Patch0077: 0077-TESTS-Add-tests-for-the-object-by-id-cache_req-inter.patch
-Patch0078: 0078-CACHE_REQ-Export-cache_req_search_ncache_add-as-cach.patch
-Patch0079: 0079-CACHE_REQ-Add-plugin-methods-required-for-the-domain.patch
-Patch0080: 0080-CACHE_REQ-Add-a-private-request-cache_req_locate_dom.patch
-Patch0081: 0081-CACHE_REQ-Implement-the-plugin-methods-that-utilize-.patch
-Patch0082: 0082-CACHE_REQ-Use-the-domain-locator-request-to-only-sea.patch
-Patch0083: 0083-MAN-Document-how-the-Global-Catalog-is-used-currentl.patch
-Patch0084: 0084-p11_child-make-sure-OCSP-checks-are-done.patch
-Patch0085: 0085-IPA-Include-SYSDB_OBJECTCATEGORY-not-OBJECTCLASS-in-.patch
-Patch0086: 0086-nss-idmap-allow-NULL-result-in-_timeout-calls.patch
-Patch0087: 0087-cache-Check-for-max_id-min_id-in-cache_req.patch
-Patch0088: 0088-Revert-p11_child-make-sure-OCSP-checks-are-done.patch
-Patch0089: 0089-p11_child-properly-check-results-of-CERT_VerifyCerti.patch
-Patch0090: 0090-ifp-use-realloc-in-ifp_list_ctx_remaining_capacity.patch
-Patch0091: 0091-IPA-Delay-the-first-periodic-refresh-of-trusted-doma.patch
-Patch0092: 0092-sysdb-add-userMappedCertificate-to-the-index.patch
-Patch0093: 0093-AD-Inherit-the-MPG-setting-from-the-main-domain.patch
-Patch0094: 0094-SDAP-skip-builtin-AD-groups-in-sdap_save_grpmem.patch
-Patch0095: 0095-SYSDB-Read-the-ldb_message-from-loop-s-index-counter.patch
-Patch0096: 0096-nss-idmap-check-timed-muted-return-code.patch
-Patch0097: 0097-DESKPROFILE-Add-checks-for-user-and-host-category.patch
-Patch0098: 0098-SELINUX-Check-if-SELinux-is-managed-in-selinux_child.patch
-Patch0099: 0099-util-Add-sss_-prefix-to-some-functions.patch
-Patch0100: 0100-MAN-Explain-how-does-auto_private_groups-affect-subd.patch
-Patch0101: 0101-AD-Use-the-right-sdap_domain-for-the-forest-root.patch
-Patch0102: 0102-AD-sdap_get_ad_tokengroups_done-allocate-temporary-d.patch
-Patch0103: 0103-AD-do-not-allocate-temporary-data-on-long-living-con.patch
-Patch0104: 0104-nss-idmap-do-not-set-a-limit.patch
-Patch0105: 0105-nss-idmap-use-right-group-list-pointer-after-sss_get.patch
-Patch0106: 0106-nss-add-a-netgroup-counter-to-struct-nss_enum_index.patch
-Patch0107: 0107-nss-initialize-nss_enum_index-in-nss_setnetgrent.patch
-Patch0108: 0108-NSS-nss_clear_netgroup_hash_table-do-not-free-data.patch
-Patch0109: 0109-winbind-idmap-plugin-support-inferface-version-6.patch
-Patch0110: 0110-winbind-idmap-plugin-fix-detection.patch
-Patch0111: 0111-Do-not-keep-allocating-external-groups-on-a-long-liv.patch
-Patch0112: 0112-TESTS-Extend-the-schema-with-sshPublicKey-attribute.patch
-Patch0113: 0113-TESTS-Allow-adding-sshPublicKey-for-users.patch
-Patch0114: 0114-TESTS-Add-a-basic-SSH-responder-test.patch
-Patch0115: 0115-SSH-Do-not-exit-abruptly-if-SSHD-closes-its-end-of-t.patch
-Patch0116: 0116-TESTS-Add-a-helper-binary-that-can-trigger-the-SIGPI.patch
-Patch0117: 0117-TESTS-Add-a-regression-test-for-SIGHUP-handling-in-s.patch
-Patch0118: 0118-TESTS-Order-list-of-entries-in-some-lists.patch
-Patch0119: 0119-sysdb-add-sysdb_getgrgid_attrs.patch
-Patch0120: 0120-ipa-use-mpg-aware-group-lookup-in-get_object_from_ca.patch
-Patch0121: 0121-ipa-allow-mpg-group-objects-in-apply_subdomain_homed.patch
-Patch0122: 0122-AD-LDAP-do-not-fall-back-to-mpg-user-lookup-on-GC-co.patch
-Patch0123: 0123-deskprofile-don-t-bail-if-we-fail-to-save-one-profil.patch
+Patch0001: 0001-krb5-locator-add-support-for-multiple-addresses.patch
+Patch0002: 0002-krb5-locator-fix-IPv6-support.patch
+Patch0003: 0003-krb5-locator-make-plugin-more-robust.patch
+Patch0004: 0004-krb5-locator-add-unit-tests.patch
+Patch0005: 0005-AD-IPA-Create-kdcinfo-file-for-sub-domains.patch
+Patch0006: 0006-krb5-refactor-removal-of-krb5info-files.patch
+Patch0007: 0007-krb5_common-add-callback-only-once.patch
+Patch0008: 0008-data-provider-run-offline-callbacks-only-once.patch
+Patch0009: 0009-TESTS-Extend-the-schema-with-sshPublicKey-attribute.patch
+Patch0010: 0010-TESTS-Allow-adding-sshPublicKey-for-users.patch
+Patch0011: 0011-TESTS-Add-a-basic-SSH-responder-test.patch
+Patch0012: 0012-SSH-Do-not-exit-abruptly-if-SSHD-closes-its-end-of-t.patch
+Patch0013: 0013-TESTS-Add-a-helper-binary-that-can-trigger-the-SIGPI.patch
+Patch0014: 0014-TESTS-Add-a-regression-test-for-SIGHUP-handling-in-s.patch
+Patch0015: 0015-Revert-LDAP-IPA-add-local-email-address-to-aliases.patch
+Patch0016: 0016-util-Remove-the-unused-function-is_email_from_domain.patch
+Patch0017: 0017-TESTS-Allow-storing-e-mail-address-for-users.patch
+Patch0018: 0018-TESTS-Add-regression-test-for-looking-up-users-with-.patch
+Patch0019: 0019-MAN-Remove-outdated-notes-from-the-re_expression-des.patch
+Patch0020: 0020-SUDO-Create-the-socket-with-stricter-permissions.patch
+Patch0021: 0021-MAN-Give-information-regarding-priority-of-ldap-look.patch
+Patch0022: 0022-AD-LDAP-Do-not-misuse-the-ignore_mark_offline-to-che.patch
+Patch0023: 0023-AD-expose-the-helper-function-to-format-the-site-DNS.patch
+Patch0024: 0024-RESOLV-Add-a-resolv_hostport_list-request.patch
+Patch0025: 0025-KRB5-IPA-AD-Add-a-utility-function-to-create-a-krb5_.patch
+Patch0026: 0026-KRB5-Allow-writing-multiple-addresses-to-the-kdcinfo.patch
+Patch0027: 0027-IPA-Add-the-options-that-the-IPA-subdomains-code-wil.patch
+Patch0028: 0028-IPA-Populate-kdcinfo-files-on-trust-clients-with-con.patch
+Patch0029: 0029-MAN-Document-the-options-available-for-AD-trusted-do.patch
+Patch0030: 0030-AD-consider-resource_groups-in-PAC-as-well.patch
+Patch0031: 0031-LDAP-Remove-the-legacy-POSIX-check-itself.patch
+Patch0032: 0032-LDAP-AD-Remove-the-legacy-POSIX-check-from-user-grou.patch
+Patch0033: 0033-AD-Remove-the-legacy-check-from-ad_get_account_domai.patch
+Patch0034: 0034-AD-Add-Global-Catalog-usability-check-in-subdomain-c.patch
+Patch0035: 0035-SDAP-Detect-schemaNamingContext-from-the-rootDSE.patch
+Patch0036: 0036-deskprofile-don-t-bail-if-we-fail-to-save-one-profil.patch
+Patch0037: 0037-SUDO-Fix-running-in-unprivileged-responder.patch
+Patch0038: 0038-SUDO-Root-should-be-able-to-read-write-sssd-sudo-soc.patch
+Patch0039: 0039-sdap-respect-passwordGracelimit.patch
+Patch0040: 0040-MC-Remove-check-if-record-is-in-the-mapped-address-s.patch
+Patch0041: 0041-Revert-CRYPTO-Suppress-warning-Wstringop-truncation.patch
+Patch0042: 0042-Revert-Revert-CRYPTO-Suppress-warning-Wstringop-trun.patch
+Patch0043: 0043-CRYPTO-Save-prefix-in-s3crypt_sha512.patch
+Patch0044: 0044-crypto-tests-Add-unit-test-for-s3crypt_sha512.patch
+Patch0045: 0045-SSS_CERT-Close-file-descriptors-after-executing-p11_.patch
+Patch0046: 0046-SELINUX-Also-call-is_selinux_enabled-as-a-check-for-.patch
 
 #This patch should not be removed in RHEL-7
 Patch999: 0999-NOUPSTREAM-Default-to-root-if-sssd-user-is-not-spec
@@ -213,6 +134,7 @@ BuildRequires: autoconf
 BuildRequires: automake
 BuildRequires: libtool
 BuildRequires: m4
+BuildRequires: gcc
 BuildRequires: popt-devel
 BuildRequires: libtalloc-devel
 BuildRequires: libtevent-devel
@@ -296,6 +218,13 @@ Requires(postun): systemd-units chkconfig
 # gpo_child -> libsmbclient -> samba-client-libs -> libwbclient
 OrderWithRequires: libwbclient
 OrderWithRequires: sssd-libwbclient
+# Explicitly require RHEL-7.6 versions of the Samba libraries
+# in order to prevent untested combinations of a new SSSD and
+# older libraries. See e.g. rhbz#1593756
+Requires: libtalloc >= 2.1.13-1
+Requires: libtevent >= 0.9.36-1
+Requires: libldb >= 1.3.4-1
+Requires: libtdb >= 1.3.15-1
 
 ### Provides ###
 Provides: libsss_sudo-devel = %{version}-%{release}
@@ -679,9 +608,6 @@ for p in %patches ; do
     UpdateTimestamps -p1 $p
 done
 
-cp %{SOURCE1} src/tests/cmocka/p11_nssdb_2certs/
-cp %{SOURCE2} src/tests/cmocka/p11_nssdb_2certs/
-
 %build
 autoreconf -ivf
 
@@ -1329,29 +1255,91 @@ systemctl try-restart sssd >/dev/null 2>&1 || :
 }
 
 %changelog
-* Thu Jul 26 2018 Jakub Hrozek <jhrozek@redhat.com> - 1.16.0-19.8
-- Resolves: rhbz#1601360 - SSSD bails out saving desktop profiles in case an invalid profile is found [rhel-7.5.z]
-
-* Tue Jul 24 2018 Jakub Hrozek <jhrozek@redhat.com> - 1.16.0-19.7
-- Resolves: rhbz#1596292 - home dir disappear in sssd cache on the IPA master for AD users [rhel-7.5.z]
-
-* Fri Jul 20 2018 Jakub Hrozek <jhrozek@redhat.com> - 1.16.0-19.6
-- Resolves: rhbz#1594178 - Login with sshkeys stored in ipa not working after update to RHEL-7.5 [rhel-7.5.z]
-
-* Thu May 31 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-19.5
-- Resolves: rhbz#1583746 - The SSSD IPA provider allocates information about external groups on a long lived memory context, causing memory growth of the sssd_be process [rhel-7.5.z]
-
-* Mon May 21 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-19.4
-- Resolves: rhbz#1580281 - Samba can not register sss idmap module because it's using an outdated SMB_IDMAP_INTERFACE_VERSION [rhel-7.5.z]
-
-* Fri May 18 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-19.3
-- Resolves: rhbz#1579780 - After updating to RHEL 7.5 failing to clear the sssd cache [rhel-7.5.z]
-
-* Fri May 18 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-19.2
-- Resolves: rhbz#1579703 - crash in nss_protocol_fill_netgrent. sssd_nss[19234]: segfault at 80 ip 000055612688c2a0 sp 00007ffddf9b9cd0 error 4 in sssd_nss[55612687e000+39000] [rhel-7.5.z]
-
-* Mon Apr 23 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-19.1
-- Resolves: rhbz#1570527 - memory management issue in the sssd_nss_ex interface can cause the ns-slapd process on IPA server to crash [rhel-7.5.z]
+* Wed Sep  5 2018 Jakub Hrozek <jhrozek@redhat.com> - 1.16.2-13
+- Resolves: rhbz#1593756 - sssd needs to require a newer version of
+                           libtalloc and libtevent to avoid an issue
+                           in GPO processing
+
+* Thu Aug  9 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-12
+- Resolves: rhbz#1610667 - sssd_ssh leaks file descriptors when more than one certificate is converted into an SSH key
+- Resolves: rhbz#1583360 - The IPA selinux provider can return an error if SELinux is completely disabled
+
+* Thu Aug  2 2018 Jakub Hrozek <jhrozek@redhat.com> - 1.16.2-11
+- Resolves: rhbz#1602781 - Local users failed to login with same password
+
+* Wed Aug  1 2018 Jakub Hrozek <jhrozek@redhat.com> - 1.16.2-10
+- Resolves: rhbz#1586127 - Spurious check in the sssd nss memcache can cause the memory cache to be skipped
+
+* Thu Jul 26 2018 Jakub Hrozek <jhrozek@redhat.com> - 1.16.2-9
+- Resolves: rhbz#1522928 - sssd doesn't allow user with expired password
+
+* Thu Jul 26 2018 Jakub Hrozek <jhrozek@redhat.com> - 1.16.2-8
+- Resolves: rhbz#1607313 - When sssd is running as non-root user, the sudo pipe is created as sssd:sssd but then the private pipe ownership fails
+
+* Fri Jul 13 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-7
+- Resolves: rhbz#1600822 - SSSD bails out saving desktop profiles in case an invalid profile is found
+
+* Wed Jul 11 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-6
+- Resolves: rhbz#1582975 - The search filter for detecting POSIX attributes in global catalog is too broad and can cause a high load on the servers
+
+* Fri Jun 29 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-5
+- Resolves: rhbz#1583725 - SSSD AD uses LDAP filter to detect POSIX attributes stored in AD GC also for regular AD DC queries
+- Resolves: rhbz#1416528 - sssd in cross realm trust configuration should be able to use AD KDCs from a client site defined in sssd.conf or a snippet
+- Resolves: rhbz#1592964 - Groups go missing with PAC enabled in sssd
+
+* Mon Jun 25 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-4
+- Resolves: rhbz#1590603 - EMBARGOED CVE-2018-10852 sssd: information leak from the sssd-sudo responder [rhel-7]
+- Resolves: rhbz#1450778 - Full information regarding priority of lookup of principal in keytab not in man page
+
+* Fri Jun 22 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-3
+- Resolves: rhbz#1494690 - kdcinfo files are not created for subdomains of a directly joined AD client
+- Resolves: rhbz#1583343 - Login with sshkeys stored in ipa not working after update to RHEL-7.5
+- Resolves: rhbz#1527662 - Handle conflicting e-mail addresses more gracefully
+- Resolves: rhbz#1509691 - Document how to change the regular expression for SSSD so that group names with an @-sign can be parsed
+
+* Fri Jun 22 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-2
+- Related: rhbz#1558498 - Rebase sssd to the latests upstream release of the 1.16 branch
+
+* Mon Jun 11 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.2-1
+- Resolves: rhbz#1558498 - Rebase sssd to the latests upstream release of the 1.16 branch
+- Resolves: rhbz#1523019 - Reset password with two factor authentication fails
+- Resolves: rhbz#1534749 - Requesting an AD user's private group and then the user itself returns an emty homedir
+- Resolves: rhbz#1537272 - SSH public key authentication keeps working after keys are removed from ID view
+- Resolves: rhbz#1537279 - Certificate is not removed from cache when it's removed from the override
+- Resolves: rhbz#1562025 - externalUser sudo attribute must be fully-qualified
+- Resolves: rhbz#1577335 - /usr/libexec/sssd/sssd_autofs SIGABRT crash daily
+- Resolves: rhbz#1508530 - How should sudo behave without sudoHost attribute?
+- Resolves: rhbz#1546754 - The man page of sss_ssh_authorizedkeys can be enhanced to better explain how the keys are retrieved and how X.509 certificates can be used
+- Resolves: rhbz#1572790 - getgrgid/getpwuid fails in setups with multiple domains if the first domain uses mid_id/max_id
+- Resolves: rhbz#1561562 - sssd not honoring dyndns_server if the DNS update process is terminated with a signal
+- Resolves: rhbz#1583251 - home dir disappear in sssd cache on the IPA master for AD users
+- Resolves: rhbz#1514061 - ID override GID from Default Trust View is not properly resolved in case domain resolution order is set
+- Resolves: rhbz#1571466 - Utilizing domain_resolution_order in sssd.conf breaks SELinux user map
+- Resolves: rhbz#1571526 - SSSD with ID provider 'ad' should give a warning in case the ldap schema is manually changed to something different than 'ad'.
+
+* Thu May 31 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-25
+- Resolves: rhbz#1547782 - The SSSD IPA provider allocates information about external groups on a long lived memory context, causing memory growth of the sssd_be process
+
+* Sat May 19 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-24
+- Related: rhbz#1578291 - Samba can not register sss idmap module because it's using an outdated SMB_IDMAP_INTERFACE_VERSION
+
+* Fri May 18 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-23
+- Resolves: rhbz#1578291 - Samba can not register sss idmap module because it's using an outdated SMB_IDMAP_INTERFACE_VERSION
+
+* Fri May 18 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-22
+- Resolves: rhbz#1516266 - Give a more detailed debug and system-log message if krb5_init_context() failed
+- Resolves: rhbz#1503802 - Smartcard authentication fails if SSSD is offline and 'krb5_store_password_if_offline = True'
+- Resolves: rhbz#1385665 - Incorrect error code returned from krb5_child (updated)
+- Resolves: rhbz#1547234 - SSSD's GPO code ignores ad_site option
+- Resolves: rhbz#1459348 - extend sss-certmap man page regarding priority processing
+- Resolves: rhbz#1220767 - Group renaming issue when "id_provider = ldap" is set
+- Resolves: rhbz#1538555 - crash in nss_protocol_fill_netgrent. sssd_nss[19234]: segfault at 80 ip 000055612688c2a0 sp 00007ffddf9b9cd0 error 4 in sssd_nss[55612687e000+39000]
+
+* Wed Apr 25 2018 Jakub Hrozek <jhrozek@redhat.com> - 1.16.0-21
+- Resolves: rhbz#1565774 - After updating to RHEL 7.5 failing to clear the sssd cache
+
+* Fri Apr 20 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-20
+- Resolves: rhbz#1566782 - memory management issue in the sssd_nss_ex interface can cause the ns-slapd process on IPA server to crash
 
 * Wed Feb 21 2018 Fabiano Fidêncio <fidencio@redhat.com> - 1.16.0-19
 - Related: rhbzrhbz#1544943 - sssd goes offline when renewing expired ticket