diff --git a/.gitignore b/.gitignore
index 2d2eb03..0e4e65c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-SOURCES/freeipa-4.6.5.tar.gz
+SOURCES/freeipa-4.6.6.tar.gz
 SOURCES/header-logo.png
 SOURCES/login-screen-background.jpg
 SOURCES/product-name.png
diff --git a/.ipa.metadata b/.ipa.metadata
index 298fd0e..0dfcd18 100644
--- a/.ipa.metadata
+++ b/.ipa.metadata
@@ -1,4 +1,4 @@
-45d419f50412d016d194fb0e02a54251b26a7b35 SOURCES/freeipa-4.6.5.tar.gz
+2ed9f8319600bb22b7b252b1ed787883173d9ca4 SOURCES/freeipa-4.6.6.tar.gz
 77c318cf1f4fc25cf847de0692a77859a767c0e3 SOURCES/header-logo.png
 8727245558422bf966d60677568925f081b8e299 SOURCES/login-screen-background.jpg
 af82b7b7d327bd683c7d062a6f15713ea91ebedf SOURCES/product-name.png
diff --git a/SOURCES/0001-Coverity-fix-issue-in-ipa_extdom_extop.c.patch b/SOURCES/0001-Coverity-fix-issue-in-ipa_extdom_extop.c.patch
deleted file mode 100644
index 836750c..0000000
--- a/SOURCES/0001-Coverity-fix-issue-in-ipa_extdom_extop.c.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 5fb390bc2aed0f460e96c0e98dd57ecf01aec01c Mon Sep 17 00:00:00 2001
-From: Florence Blanc-Renaud <flo@redhat.com>
-Date: Thu, 21 Mar 2019 13:59:32 +0100
-Subject: [PATCH] Coverity: fix issue in ipa_extdom_extop.c
-
-Coverity found the following issue:
-Error: BAD_COMPARE (CWE-697): [#def1]
-freeipa-4.6.5/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c:121: null_misuse: Comparing pointer "threadnumber" against "NULL" using anything besides "==" or "!=" is likely to be incorrect.
-
-The comparison is using the pointer while it should use the pointed value.
-
-Fixes: https://pagure.io/freeipa/issue/7884
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
-index 3abaa411d2873dedb27ac83bc53d82677577e5b5..10d3f86ebad920fb9c051aa428cbd675b682f14a 100644
---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
-+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
-@@ -118,7 +118,7 @@ static int ipa_get_threadnumber(Slapi_ComponentId *plugin_id, size_t *threadnumb
-     *threadnumber = slapi_entry_attr_get_uint(search_entries[0],
-                                               NSSLAPD_THREADNUMBER);
- 
--    if (threadnumber <= 0) {
-+    if (*threadnumber <= 0) {
-         LOG_FATAL("No thread number found.\n");
-         ret = LDAP_OPERATIONS_ERROR;
-         goto done;
--- 
-2.20.1
-
diff --git a/SOURCES/0001-extdom-unify-error-code-handling.patch b/SOURCES/0001-extdom-unify-error-code-handling.patch
new file mode 100644
index 0000000..b2f6f72
--- /dev/null
+++ b/SOURCES/0001-extdom-unify-error-code-handling.patch
@@ -0,0 +1,352 @@
+From 574a615e61ca74b08e2bd7e1e820757f88150418 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 14 Jun 2019 11:13:54 +0200
+Subject: [PATCH 1/2] extdom: unify error code handling especially
+ LDAP_NO_SUCH_OBJECT
+
+A return code LDAP_NO_SUCH_OBJECT will tell SSSD on the IPA client to
+remove the searched object from the cache. As a consequence
+LDAP_NO_SUCH_OBJECT should only be returned if the object really does
+not exists otherwise the data of existing objects might be removed form
+the cache of the clients causing unexpected behaviour like
+authentication errors.
+
+Currently some code-paths use LDAP_NO_SUCH_OBJECT as default error code.
+With this patch LDAP_NO_SUCH_OBJECT is only returned if the related
+lookup functions return ENOENT. Timeout related error code will lead to
+LDAP_TIMELIMIT_EXCEEDED and LDAP_OPERATIONS_ERROR is used as default
+error code.
+
+Fixes: https://pagure.io/freeipa/issue/8044
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+---
+ .../ipa-extdom-extop/back_extdom_sss_idmap.c  |  4 +-
+ .../ipa-extdom-extop/ipa_extdom_common.c      | 77 ++++++++++++++-----
+ .../ipa-extdom-extop/ipa_extdom_extop.c       |  2 +
+ 3 files changed, 61 insertions(+), 22 deletions(-)
+
+diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c
+index 89c58ca2d..64b90e3ae 100644
+--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c
++++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c
+@@ -47,10 +47,10 @@ static enum nss_status __convert_sss_nss2nss_status(int errcode) {
+         return NSS_STATUS_SUCCESS;
+     case ENOENT:
+         return NSS_STATUS_NOTFOUND;
+-    case ETIME:
+-        /* fall-through */
+     case ERANGE:
+         return NSS_STATUS_TRYAGAIN;
++    case ETIME:
++        /* fall-through */
+     case ETIMEDOUT:
+         /* fall-through */
+     default:
+diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c
+index 1b93dce18..134b62377 100644
+--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c
++++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c
+@@ -523,7 +523,7 @@ int pack_ber_user(struct ipa_extdom_ctx *ctx,
+         if (strcasecmp(locat+1, domain_name) == 0  ) {
+             locat[0] = '\0';
+         } else {
+-            ret = LDAP_NO_SUCH_OBJECT;
++            ret = LDAP_INVALID_SYNTAX;
+             goto done;
+         }
+     }
+@@ -568,10 +568,12 @@ int pack_ber_user(struct ipa_extdom_ctx *ctx,
+             ret = getgrgid_r_wrapper(ctx,
+                                      groups[c], &grp, &buf, &buf_len);
+             if (ret != 0) {
+-                if (ret == ENOMEM || ret == ERANGE) {
+-                    ret = LDAP_OPERATIONS_ERROR;
+-                } else {
++                if (ret == ENOENT) {
+                     ret = LDAP_NO_SUCH_OBJECT;
++                } else if (ret == ETIMEDOUT) {
++                    ret = LDAP_TIMELIMIT_EXCEEDED;
++                } else {
++                    ret = LDAP_OPERATIONS_ERROR;
+                 }
+                 goto done;
+             }
+@@ -634,7 +636,7 @@ int pack_ber_group(enum response_types response_type,
+         if (strcasecmp(locat+1, domain_name) == 0  ) {
+             locat[0] = '\0';
+         } else {
+-            ret = LDAP_NO_SUCH_OBJECT;
++            ret = LDAP_INVALID_SYNTAX;
+             goto done;
+         }
+     }
+@@ -836,6 +838,8 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx,
+                             || id_type == SSS_ID_TYPE_BOTH)) {
+             if (ret == ENOENT) {
+                 ret = LDAP_NO_SUCH_OBJECT;
++            } else if (ret == ETIMEDOUT || ret == ETIME) {
++                ret = LDAP_TIMELIMIT_EXCEEDED;
+             } else {
+                 set_err_msg(req, "Failed to lookup SID by UID");
+                 ret = LDAP_OPERATIONS_ERROR;
+@@ -847,10 +851,12 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx,
+     } else {
+         ret = getpwuid_r_wrapper(ctx, uid, &pwd, &buf, &buf_len);
+         if (ret != 0) {
+-            if (ret == ENOMEM || ret == ERANGE) {
+-                ret = LDAP_OPERATIONS_ERROR;
+-            } else {
++            if (ret == ENOENT) {
+                 ret = LDAP_NO_SUCH_OBJECT;
++            } else if (ret == ETIMEDOUT) {
++                ret = LDAP_TIMELIMIT_EXCEEDED;
++            } else {
++                ret = LDAP_OPERATIONS_ERROR;
+             }
+             goto done;
+         }
+@@ -862,6 +868,8 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx,
+                 set_err_msg(req, "Failed to read original data");
+                 if (ret == ENOENT) {
+                     ret = LDAP_NO_SUCH_OBJECT;
++                } else if (ret == ETIMEDOUT || ret == ETIME) {
++                    ret = LDAP_TIMELIMIT_EXCEEDED;
+                 } else {
+                     ret = LDAP_OPERATIONS_ERROR;
+                 }
+@@ -907,6 +915,8 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx,
+         if (ret != 0 || id_type != SSS_ID_TYPE_GID) {
+             if (ret == ENOENT) {
+                 ret = LDAP_NO_SUCH_OBJECT;
++            } else if (ret == ETIMEDOUT || ret == ETIME) {
++                ret = LDAP_TIMELIMIT_EXCEEDED;
+             } else {
+                 set_err_msg(req, "Failed to lookup SID by GID");
+                 ret = LDAP_OPERATIONS_ERROR;
+@@ -918,10 +928,12 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx,
+     } else {
+         ret = getgrgid_r_wrapper(ctx, gid, &grp, &buf, &buf_len);
+         if (ret != 0) {
+-            if (ret == ENOMEM || ret == ERANGE) {
+-                ret = LDAP_OPERATIONS_ERROR;
+-            } else {
++            if (ret == ENOENT) {
+                 ret = LDAP_NO_SUCH_OBJECT;
++            } else if (ret == ETIMEDOUT) {
++                ret = LDAP_TIMELIMIT_EXCEEDED;
++            } else {
++                ret = LDAP_OPERATIONS_ERROR;
+             }
+             goto done;
+         }
+@@ -933,6 +945,8 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx,
+                 set_err_msg(req, "Failed to read original data");
+                 if (ret == ENOENT) {
+                     ret = LDAP_NO_SUCH_OBJECT;
++                } else if (ret == ETIMEDOUT || ret == ETIME) {
++                    ret = LDAP_TIMELIMIT_EXCEEDED;
+                 } else {
+                     ret = LDAP_OPERATIONS_ERROR;
+                 }
+@@ -976,6 +990,8 @@ static int handle_cert_request(struct ipa_extdom_ctx *ctx,
+     if (ret != 0) {
+         if (ret == ENOENT) {
+             ret = LDAP_NO_SUCH_OBJECT;
++        } else if (ret == ETIMEDOUT || ret == ETIME) {
++            ret = LDAP_TIMELIMIT_EXCEEDED;
+         } else {
+             set_err_msg(req, "Failed to lookup name by certificate");
+             ret = LDAP_OPERATIONS_ERROR;
+@@ -1020,6 +1036,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
+     if (ret != 0) {
+         if (ret == ENOENT) {
+             ret = LDAP_NO_SUCH_OBJECT;
++        } else if (ret == ETIMEDOUT || ret == ETIME) {
++            ret = LDAP_TIMELIMIT_EXCEEDED;
+         } else {
+             set_err_msg(req, "Failed to lookup name by SID");
+             ret = LDAP_OPERATIONS_ERROR;
+@@ -1057,10 +1075,12 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
+     case SSS_ID_TYPE_BOTH:
+         ret = getpwnam_r_wrapper(ctx, fq_name, &pwd, &buf, &buf_len);
+         if (ret != 0) {
+-            if (ret == ENOMEM || ret == ERANGE) {
+-                ret = LDAP_OPERATIONS_ERROR;
+-            } else {
++            if (ret == ENOENT) {
+                 ret = LDAP_NO_SUCH_OBJECT;
++            } else if (ret == ETIMEDOUT) {
++                ret = LDAP_TIMELIMIT_EXCEEDED;
++            } else {
++                ret = LDAP_OPERATIONS_ERROR;
+             }
+             goto done;
+         }
+@@ -1072,6 +1092,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
+                 set_err_msg(req, "Failed to read original data");
+                 if (ret == ENOENT) {
+                     ret = LDAP_NO_SUCH_OBJECT;
++                } else if (ret == ETIMEDOUT || ret == ETIME) {
++                    ret = LDAP_TIMELIMIT_EXCEEDED;
+                 } else {
+                     ret = LDAP_OPERATIONS_ERROR;
+                 }
+@@ -1089,10 +1111,12 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
+     case SSS_ID_TYPE_GID:
+         ret = getgrnam_r_wrapper(ctx, fq_name, &grp, &buf, &buf_len);
+         if (ret != 0) {
+-            if (ret == ENOMEM || ret == ERANGE) {
+-                ret = LDAP_OPERATIONS_ERROR;
+-            } else {
++            if (ret == ENOENT) {
+                 ret = LDAP_NO_SUCH_OBJECT;
++            } else if (ret == ETIMEDOUT) {
++                ret = LDAP_TIMELIMIT_EXCEEDED;
++            } else {
++                ret = LDAP_OPERATIONS_ERROR;
+             }
+             goto done;
+         }
+@@ -1104,6 +1128,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
+                 set_err_msg(req, "Failed to read original data");
+                 if (ret == ENOENT) {
+                     ret = LDAP_NO_SUCH_OBJECT;
++                } else if (ret == ETIMEDOUT || ret == ETIME) {
++                    ret = LDAP_TIMELIMIT_EXCEEDED;
+                 } else {
+                     ret = LDAP_OPERATIONS_ERROR;
+                 }
+@@ -1167,6 +1193,8 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx,
+         if (ret != 0) {
+             if (ret == ENOENT) {
+                 ret = LDAP_NO_SUCH_OBJECT;
++            } else if (ret == ETIMEDOUT || ret == ETIME) {
++                ret = LDAP_TIMELIMIT_EXCEEDED;
+             } else {
+                 set_err_msg(req, "Failed to lookup SID by name");
+                 ret = LDAP_OPERATIONS_ERROR;
+@@ -1190,6 +1218,8 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx,
+                     set_err_msg(req, "Failed to read original data");
+                     if (ret == ENOENT) {
+                         ret = LDAP_NO_SUCH_OBJECT;
++                    } else if (ret == ETIMEDOUT || ret == ETIME) {
++                        ret = LDAP_TIMELIMIT_EXCEEDED;
+                     } else {
+                         ret = LDAP_OPERATIONS_ERROR;
+                     }
+@@ -1205,6 +1235,9 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx,
+         } else if (ret == ENOMEM || ret == ERANGE) {
+             ret = LDAP_OPERATIONS_ERROR;
+             goto done;
++        } else if (ret == ETIMEDOUT) {
++            ret = LDAP_TIMELIMIT_EXCEEDED;
++            goto done;
+         } else { /* no user entry found */
+             /* according to the getpwnam() man page there are a couple of
+              * error codes which can indicate that the user was not found. To
+@@ -1212,10 +1245,12 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx,
+              * errors. */
+             ret = getgrnam_r_wrapper(ctx, fq_name, &grp, &buf, &buf_len);
+             if (ret != 0) {
+-                if (ret == ENOMEM || ret == ERANGE) {
+-                    ret = LDAP_OPERATIONS_ERROR;
+-                } else {
++                if (ret == ENOENT) {
+                     ret = LDAP_NO_SUCH_OBJECT;
++                } else if (ret == ETIMEDOUT) {
++                    ret = LDAP_TIMELIMIT_EXCEEDED;
++                } else {
++                    ret = LDAP_OPERATIONS_ERROR;
+                 }
+                 goto done;
+             }
+@@ -1226,6 +1261,8 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx,
+                                     || id_type == SSS_ID_TYPE_BOTH)) {
+                     if (ret == ENOENT) {
+                         ret = LDAP_NO_SUCH_OBJECT;
++                    } else if (ret == ETIMEDOUT || ret == ETIME) {
++                        ret = LDAP_TIMELIMIT_EXCEEDED;
+                     } else {
+                         set_err_msg(req, "Failed to read original data");
+                         ret = LDAP_OPERATIONS_ERROR;
+diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
+index 10d3f86eb..48fcecc1e 100644
+--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
++++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
+@@ -242,6 +242,8 @@ static int ipa_extdom_extop(Slapi_PBlock *pb)
+     if (ret != LDAP_SUCCESS) {
+         if (ret == LDAP_NO_SUCH_OBJECT) {
+             rc = LDAP_NO_SUCH_OBJECT;
++        } else if (ret == LDAP_TIMELIMIT_EXCEEDED) {
++            rc = LDAP_TIMELIMIT_EXCEEDED;
+         } else {
+             rc = LDAP_OPERATIONS_ERROR;
+             err_msg = "Failed to handle the request.\n";
+-- 
+2.21.0
+
+
+From 387ed98e59ba4df8d3fd435cfc84f055970c064e Mon Sep 17 00:00:00 2001
+From: Alexander Bokovoy <abokovoy@redhat.com>
+Date: Mon, 19 Aug 2019 10:15:50 +0300
+Subject: [PATCH 2/2] ipa-extdom-extop: test timed out getgrgid_r
+
+Simulate getgrgid_r() timeout when packing list of groups user is a
+member of in pack_ber_user().
+
+Related: https://pagure.io/freeipa/issue/8044
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+---
+ .../ipa_extdom_cmocka_tests.c                 | 29 +++++++++++++++++++
+ 1 file changed, 29 insertions(+)
+
+diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c
+index 29699cfa3..1fa4c6af8 100644
+--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c
++++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c
+@@ -493,6 +493,34 @@ void test_set_err_msg(void **state)
+ #define TEST_SID "S-1-2-3-4"
+ #define TEST_DOMAIN_NAME "DOMAIN"
+ 
++/* Always time out for test */
++static
++enum nss_status getgrgid_r_timeout(gid_t gid, struct group *result,
++                                   char *buffer, size_t buflen, int *errnop) {
++    return NSS_STATUS_UNAVAIL;
++}
++
++void test_pack_ber_user_timeout(void **state)
++{
++    int ret;
++    struct berval *resp_val = NULL;
++    struct test_data *test_data;
++    enum nss_status (*oldgetgrgid_r)(gid_t gid, struct group *result,
++                                     char *buffer, size_t buflen, int *errnop);
++
++    test_data = (struct test_data *) *state;
++
++    oldgetgrgid_r = test_data->ctx->nss_ctx->getgrgid_r;
++    test_data->ctx->nss_ctx->getgrgid_r = getgrgid_r_timeout;
++
++    ret = pack_ber_user(test_data->ctx, RESP_USER_GROUPLIST,
++                        TEST_DOMAIN_NAME, "member001", 12345, 54321,
++                        "gecos", "homedir", "shell", NULL, &resp_val);
++    test_data->ctx->nss_ctx->getgrgid_r = oldgetgrgid_r;
++    assert_int_equal(ret, LDAP_TIMELIMIT_EXCEEDED);
++    ber_bvfree(resp_val);
++}
++
+ char res_sid[] = {0x30, 0x0e, 0x0a, 0x01, 0x01, 0x04, 0x09, 0x53, 0x2d, 0x31, \
+                   0x2d, 0x32, 0x2d, 0x33, 0x2d, 0x34};
+ char res_nam[] = {0x30, 0x13, 0x0a, 0x01, 0x02, 0x30, 0x0e, 0x04, 0x06, 0x44, \
+@@ -614,6 +642,7 @@ void test_decode(void **state)
+ int main(int argc, const char *argv[])
+ {
+     const struct CMUnitTest tests[] = {
++        cmocka_unit_test(test_pack_ber_user_timeout),
+         cmocka_unit_test(test_getpwnam_r_wrapper),
+         cmocka_unit_test(test_getpwuid_r_wrapper),
+         cmocka_unit_test(test_getgrnam_r_wrapper),
+-- 
+2.21.0
+
diff --git a/SOURCES/0002-Use-unicode-strings-for-Python-2-version.patch b/SOURCES/0002-Use-unicode-strings-for-Python-2-version.patch
new file mode 100644
index 0000000..394dd1b
--- /dev/null
+++ b/SOURCES/0002-Use-unicode-strings-for-Python-2-version.patch
@@ -0,0 +1,26 @@
+From 56b3c4cf7cab07410e026ce695667a2aa0c4ce2d Mon Sep 17 00:00:00 2001
+From: Alexander Bokovoy <abokovoy@redhat.com>
+Date: Fri, 23 Aug 2019 11:49:53 +0300
+Subject: [PATCH] Use unicode strings for Python 2 version
+
+Related: https://pagure.io/freeipa/issue/6951
+---
+ ipaserver/install/adtrustinstance.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
+index 804a04530..67dadf9b9 100644
+--- a/ipaserver/install/adtrustinstance.py
++++ b/ipaserver/install/adtrustinstance.py
+@@ -131,7 +131,7 @@ def map_Guests_to_nobody():
+ 
+ 
+ def get_idmap_range(realm):
+-    idrange = api.Command.idrange_show('{}_id_range'.format(realm))['result']
++    idrange = api.Command.idrange_show(u'{}_id_range'.format(realm))['result']
+     range_start = int(idrange['ipabaseid'][0])
+     range_size = int(idrange['ipaidrangesize'][0])
+     range_fmt = '{} - {}'.format(range_start, range_start + range_size)
+-- 
+2.21.0
+
diff --git a/SOURCES/0002-Web-UI-topology-graph-Show-FQDN-for-nodes-if-they-ha.patch b/SOURCES/0002-Web-UI-topology-graph-Show-FQDN-for-nodes-if-they-ha.patch
deleted file mode 100644
index ba1a806..0000000
--- a/SOURCES/0002-Web-UI-topology-graph-Show-FQDN-for-nodes-if-they-ha.patch
+++ /dev/null
@@ -1,361 +0,0 @@
-From 4b853e8c2f57034c9a72b96fc028e66aa3175a07 Mon Sep 17 00:00:00 2001
-From: Serhii Tsymbaliuk <stsymbal@redhat.com>
-Date: Tue, 12 Feb 2019 10:44:33 +0100
-Subject: [PATCH] Web UI (topology graph): Show FQDN for nodes if they have no
- common DNS zone
-
-It allows to avoid confusion with identical short hostnames.
-
-There are two cases implemented:
-- no common DNS zone: graph shows FQDN for all nodes
-- all nodes have one common DNS zone: graph shows DN relatively to the common zone
-
-https://pagure.io/freeipa/issue/7206
-
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
----
- install/ui/src/freeipa/topology.js       |  64 +++++++++
- install/ui/src/freeipa/topology_graph.js |   3 +-
- install/ui/test/all_tests.html           |   4 +-
- install/ui/test/index.html               |   1 +
- install/ui/test/topology_tests.html      |  25 ++++
- install/ui/test/topology_tests.js        | 158 +++++++++++++++++++++++
- 6 files changed, 252 insertions(+), 3 deletions(-)
- create mode 100644 install/ui/test/topology_tests.html
- create mode 100644 install/ui/test/topology_tests.js
-
-diff --git a/install/ui/src/freeipa/topology.js b/install/ui/src/freeipa/topology.js
-index e98cb1e0ace1874056d3affa98c9518509f90558..fd7a2833abc04ffe7c3f8405bde4df0e6b942349 100644
---- a/install/ui/src/freeipa/topology.js
-+++ b/install/ui/src/freeipa/topology.js
-@@ -1374,6 +1374,33 @@ topology.TopologyGraphWidget = declare([Stateful, Evented], {
-         return deferred.promise;
-     },
- 
-+    _find_common_domain: function(nodes) {
-+        if (nodes.length < 2) {
-+            return '';
-+        }
-+
-+        var common_labels = null;
-+
-+        for (var i=0, l=nodes.length; i<l; i++) {
-+            var node = nodes[i];
-+            var labels = node.id.split('.').reverse();
-+
-+            if (common_labels === null) {
-+                common_labels = labels;
-+                continue;
-+            }
-+
-+            for (var j=0; j<common_labels.length; j++) {
-+                if (labels[j] !== common_labels[j]) {
-+                    common_labels = common_labels.slice(0, j);
-+                    break;
-+                }
-+            }
-+        }
-+
-+        return common_labels.reverse().join('.');
-+    },
-+
-     /**
-      * @param {Object} size - dict contains height and width value. (optional)
-      */
-@@ -1383,6 +1410,43 @@ topology.TopologyGraphWidget = declare([Stateful, Evented], {
-         if (IPA.domain_level < topology.required_domain_level) return;
- 
-         when(this._get_data()).then(function(data) {
-+            // remove common domain labels from node FQDN
-+            // Example #1:
-+            //   nodes:
-+            //    - master.ipa.example.com
-+            //    - replica.ipa.example.com
-+            //   common domain: ipa.example.com
-+            //   captions: master, replica
-+            //
-+            // Example #2:
-+            //   nodes:
-+            //    - master.net1.example.com
-+            //    - replica.net1.example.com
-+            //    - replica.net2.example.com
-+            //   common domain: example.com
-+            //   captions: master.net1, replica.net1, replica.net2
-+            //
-+            var common_domain = this._find_common_domain(data.nodes);
-+
-+            if (this.parent) {
-+                var title = this.parent.title;
-+                if (common_domain) {
-+                    title += ' (' + common_domain + ')';
-+                }
-+                this.parent.header.title_widget.update({text: title});
-+            }
-+
-+            for (var i=0,l=data.nodes.length; i<l; i++) {
-+                var node = data.nodes[i];
-+                if (l > 1 && common_domain.length > 0) {
-+                    node.caption = node.id.substring(
-+                        0, node.id.length - common_domain.length - 1
-+                    );
-+                } else {
-+                    node.caption = node.id;
-+                }
-+            }
-+
-             if (!this.graph) {
-                 this.graph = new topology_graph.TopoGraph({
-                     nodes: data.nodes,
-diff --git a/install/ui/src/freeipa/topology_graph.js b/install/ui/src/freeipa/topology_graph.js
-index 9f549133b516dbfe471080714845b457fd62ab1a..b736a22f63aa9a5685ac5840f60f9e2c89fb4525 100644
---- a/install/ui/src/freeipa/topology_graph.js
-+++ b/install/ui/src/freeipa/topology_graph.js
-@@ -180,7 +180,6 @@ topology_graph.TopoGraph = declare([Evented], {
-         this._target_node = null;
-         this.restart();
-     },
--
-     _create_svg: function(container) {
-         var self = this;
- 
-@@ -804,7 +803,7 @@ topology_graph.TopoGraph = declare([Evented], {
-             .attr('class', 'id')
-             .attr('fill', '#002235')
-             .text(function(d) {
--                return d.id.split('.')[0];
-+                return d.caption;
-             });
- 
-         // remove old nodes
-diff --git a/install/ui/test/all_tests.html b/install/ui/test/all_tests.html
-index cdb04b395a878db4338da7458b8f52f13514ead9..f85ae3390a923ad3083779e1ddfcdca6afa2377e 100644
---- a/install/ui/test/all_tests.html
-+++ b/install/ui/test/all_tests.html
-@@ -26,7 +26,8 @@
-             'test/utils_tests',
-             'test/build_tests',
-             'test/binding_tests',
--        ], function(om, ipa, details, entity, as, nav, cert, aci, wid, ip, ut, bt, bi){
-+            'test/topology_tests',
-+        ], function(om, ipa, details, entity, as, nav, cert, aci, wid, ip, ut, bt, bi, topo){
-             om();
-             ipa();
-             details();
-@@ -40,6 +41,7 @@
-             ut();
-             bt();
-             bi();
-+            topo();
-         });
-     </script>
- </head>
-diff --git a/install/ui/test/index.html b/install/ui/test/index.html
-index 89af3211cd9791ee3055ca85ddae6afdf5b9edcf..0fd5b83d696e7e368f5ca7d726c5e4301b05acfe 100644
---- a/install/ui/test/index.html
-+++ b/install/ui/test/index.html
-@@ -37,6 +37,7 @@
-         <li><a href="utils_tests.html">Utils Test Suite</a>
-         <li><a href="build_tests.html">Build Test Suite</a>
-         <li><a href="binding_tests.html">Binding Test Suite</a>
-+        <li><a href="topology_tests.html">Topology Test Suite</a>
-         </ul>
-     </div>
- 
-diff --git a/install/ui/test/topology_tests.html b/install/ui/test/topology_tests.html
-new file mode 100644
-index 0000000000000000000000000000000000000000..29ca44ddcc004efbdad9860276906b7111bb40b0
---- /dev/null
-+++ b/install/ui/test/topology_tests.html
-@@ -0,0 +1,25 @@
-+<!DOCTYPE html>
-+<html>
-+<head>
-+    <title>Topology Test Suite</title>
-+    <link rel="stylesheet" href="qunit.css" type="text/css" media="screen">
-+    <script type="text/javascript" src="qunit.js"></script>
-+    <script type="text/javascript" src="../js/libs/loader.js"></script>
-+    <script type="text/javascript" src="../js/libs/jquery.js"></script>
-+    <script type="text/javascript" src="../js/libs/jquery.ordered-map.js"></script>
-+    <script type="text/javascript" src="config.js"></script>
-+    <script type="text/javascript" src="../js/dojo/dojo.js"></script>
-+
-+    <script type="text/javascript">
-+        require(['test/topology_tests'], function(tests){ tests() });
-+    </script>
-+</head>
-+<body>
-+    <h1 id="qunit-header">Topology Test Suite</h1>
-+    <h2 id="qunit-banner"></h2>
-+    <div id="qunit-testrunner-toolbar"></div>
-+    <h2 id="qunit-userAgent"></h2>
-+    <ol id="qunit-tests"></ol>
-+    <div id="qunit-fixture"></div>
-+</body>
-+</html>
-diff --git a/install/ui/test/topology_tests.js b/install/ui/test/topology_tests.js
-new file mode 100644
-index 0000000000000000000000000000000000000000..6458a83f2794969e2916899975707b6c554ac314
---- /dev/null
-+++ b/install/ui/test/topology_tests.js
-@@ -0,0 +1,158 @@
-+/**
-+ * Copyright (C) 2019  FreeIPA Contributors see COPYING for license
-+ */
-+
-+define([
-+        'freeipa/ipa',
-+        'freeipa/topology',
-+        'freeipa/jquery'],
-+    function(IPA, topology, $) {
-+        return function() {
-+
-+var widget;
-+
-+function inject_data(widget, data) {
-+    widget._get_data = function() {
-+        return data;
-+    };
-+}
-+
-+QUnit.module('topology', {
-+    beforeEach: function(assert) {
-+        widget = new topology.TopologyGraphWidget(
-+            topology.topology_graph_facet_spec
-+        );
-+        widget.render();
-+    }
-+});
-+
-+QUnit.test('Testing TopoGraph nodes', function(assert) {
-+    var nodes = [
-+        { id: 'master.ipa.test' },
-+        { id: 'replica.ipa.test' }
-+    ];
-+
-+    var suffixes = [
-+        { cn: ['ca'] },
-+        { cn: ['domain'] }
-+    ];
-+
-+    inject_data(widget, { nodes: nodes, links: [], suffixes: suffixes });
-+
-+    widget.update();
-+
-+    assert.ok($('circle.node', widget.el).length === nodes.length,
-+        'Checking rendered nodes count');
-+
-+    assert.ok($('text.id:eq(0)', widget.el).text() === 'master',
-+        'Checking "master" node label');
-+    assert.ok($('text.id:eq(1)', widget.el).text() === 'replica',
-+        'Checking "replica" node label');
-+
-+    assert.ok($('text.suffix:eq(0)', widget.el).text() === 'ca',
-+        'Checking "ca" suffix');
-+    assert.ok($('text.suffix:eq(1)', widget.el).text() === 'domain',
-+        'Checking "domain" suffix');
-+});
-+
-+QUnit.test('Testing TopoGraph links', function(assert) {
-+    var nodes = [
-+        { id: 'master.ipa.test', targets: { 'replica.ipa.test': [] } },
-+        { id: 'replica.ipa.test' }
-+    ];
-+
-+    var suffixes = [
-+        { cn: ['ca'] },
-+        { cn: ['domain'] }
-+    ];
-+
-+    var links = [{
-+        source: 0,
-+        target: 1,
-+        left: false,
-+        right: true,
-+        suffix: suffixes[0]
-+    }];
-+
-+    inject_data(widget, { nodes: nodes, links: links, suffixes: suffixes });
-+    widget.update();
-+
-+    assert.ok($('circle.node', widget.el).length === nodes.length,
-+        'Checking rendered nodes count');
-+
-+    var rendered_links = $('path.link', widget.el).not('.dragline');
-+    assert.ok(rendered_links.length === 1,
-+        'Checking right direction link is rendered');
-+
-+    var marker = rendered_links.first().css('marker-end');
-+    assert.ok(marker && marker !== 'none',
-+        'Checking right direction link has proper marker');
-+
-+    links.push({
-+        source: 0,
-+        target: 1,
-+        left: true,
-+        right: false,
-+        suffix: suffixes[1]
-+    })
-+
-+    inject_data(widget, {
-+        nodes: nodes,
-+        links: links,
-+        suffixes: suffixes
-+    });
-+    widget.update();
-+
-+    rendered_links = $('path.link', widget.el).not('.dragline')
-+    assert.ok(rendered_links.length === 2,
-+        'Checking left direction link is rendered');
-+
-+    marker = rendered_links.last().css('marker-start');
-+    assert.ok(marker && marker !== 'none',
-+        'Checking left direction link has proper marker');
-+});
-+
-+QUnit.test('Testing TopoGraph for multiple DNS zones', function(assert) {
-+    var nodes = [
-+        { id: 'master.ipa.zone1' },
-+        { id: 'replica.ipa.zone1' },
-+        { id: 'master.ipa.zone2' },
-+        { id: 'master.ipa.zone1.common' },
-+        { id: 'replica.ipa.zone2.common' },
-+    ];
-+
-+    var suffixes = [
-+        { cn: ['ca'] },
-+        { cn: ['domain'] }
-+    ];
-+
-+    inject_data(widget, { nodes: nodes, links: [], suffixes: suffixes });
-+    widget.update();
-+
-+    $('text.id', widget.el).each(function(i) {
-+        assert.ok($(this).text() === nodes[i].id,
-+            'Checking node label "' + $(this).text() + '" is FQDN');
-+    });
-+
-+    nodes = nodes.filter(function(node) { return /\.common$/.test(node.id) });
-+
-+    inject_data(widget, { nodes: nodes, links: [], suffixes: suffixes });
-+    widget.update();
-+
-+    $('text.id', widget.el).each(function(i) {
-+        assert.ok($(this).text().indexOf('common') < 0,
-+            'Checking node label "' + $(this).text() + '" is relative');
-+    });
-+});
-+
-+QUnit.test('Testing TopoGraph with one node', function(assert) {
-+    var node = { id: 'master.ipa.test' };
-+
-+    inject_data(widget, { nodes: [node], links: [], suffixes: [] });
-+    widget.update();
-+
-+    assert.ok($('text.id:eq(0)', widget.el).text() === node.id,
-+        'Checking node label is FQDN');
-+});
-+
-+};});
--- 
-2.20.1
-
diff --git a/SOURCES/0003-ipa-replica-manage-fix-force-sync.patch b/SOURCES/0003-ipa-replica-manage-fix-force-sync.patch
deleted file mode 100644
index 60b4fbe..0000000
--- a/SOURCES/0003-ipa-replica-manage-fix-force-sync.patch
+++ /dev/null
@@ -1,45 +0,0 @@
-From 6c72f4241c70200d3d6637c254c07504aa19cdc9 Mon Sep 17 00:00:00 2001
-From: Florence Blanc-Renaud <flo@redhat.com>
-Date: Mon, 25 Mar 2019 14:22:59 +0100
-Subject: [PATCH] ipa-replica-manage: fix force-sync
-
-ipa-replica-manage force-sync --from <server> is performing a wrong check
-that may result in the tool looping on "No status yet".
-
-force-sync is adding a nsds5replicaupdateschedule attribute to the
-replication agreement in order to force replication to wake up. Note that
-this is not a re-initialization (re init drops the current db and reloads
-the entire db).
-
-In a second step, force-sync is checking the replication agreement by reading
-nsds5BeginReplicaRefresh, nsds5ReplicaLastInitStatus,
-nsds5ReplicaLastInitStart and nsds5ReplicaLastInitEnd. This is a wrong
-test as force-sync is not an init operation and does not touch these
-attributes.
-
-The tool should call wait_for_repl_update rather than wait_for_repl_init.
-This way, the check is done on the replication agreement attributes
-nsds5replicaUpdateInProgress, nsds5ReplicaLastUpdateStatus,
-nsds5ReplicaLastUpdateStart and nsds5ReplicaLastUpdateEnd.
-
-Fixes: https://pagure.io/freeipa/issue/7886
----
- install/tools/ipa-replica-manage | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage
-index cffed58b79f3e2cc41f8cf45b066f3843da01915..2a875b8fa58390c704d36b7d355ac79181021c35 100755
---- a/install/tools/ipa-replica-manage
-+++ b/install/tools/ipa-replica-manage
-@@ -1246,7 +1246,7 @@ def force_sync(realm, thishost, fromhost, dirman_passwd, nolookup=False):
-         repl = replication.ReplicationManager(realm, fromhost, dirman_passwd)
-         repl.force_sync(repl.conn, thishost)
-         agreement = repl.get_replication_agreement(thishost)
--        repl.wait_for_repl_init(repl.conn, agreement.dn)
-+        repl.wait_for_repl_update(repl.conn, agreement.dn)
-         ds.replica_manage_time_skew(prevent=True)
- 
- def show_DNA_ranges(hostname, master, realm, dirman_passwd, nextrange=False,
--- 
-2.20.1
-
diff --git a/SOURCES/0003-ipa_sam-remove-dependency-to-talloc_strackframe.h.patch b/SOURCES/0003-ipa_sam-remove-dependency-to-talloc_strackframe.h.patch
new file mode 100644
index 0000000..2b19a07
--- /dev/null
+++ b/SOURCES/0003-ipa_sam-remove-dependency-to-talloc_strackframe.h.patch
@@ -0,0 +1,76 @@
+From 5cceb47667c0665629bb474f73be1d2d8f1e1b5b Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 19 Feb 2019 12:30:40 +0100
+Subject: [PATCH] ipa_sam: remove dependency to talloc_strackframe.h
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Recent Samba versions removed some header files which did include
+non-public APIs. As a result talloc_strackframe.h and memory.h (for
+SAFE_FREE) are not available anymore. This patch replaces the use of the
+non-public APIs with public ones.
+
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+Reviewed-By: François Cami <fcami@redhat.com>
+(cherry picked from commit d1f5ed64e16d65b9df45cc0eac7d2724dcae7b67)
+---
+ daemons/ipa-sam/ipa_sam.c | 16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c
+index 2251f3ddc..755f44d68 100644
+--- a/daemons/ipa-sam/ipa_sam.c
++++ b/daemons/ipa-sam/ipa_sam.c
+@@ -19,7 +19,6 @@
+ #include <util/data_blob.h>
+ #include <util/time.h>
+ #include <util/debug.h>
+-#include <util/talloc_stack.h>
+ 
+ #ifndef _SAMBA_UTIL_H_
+ bool trim_string(char *s, const char *front, const char *back);
+@@ -881,9 +880,13 @@ static bool ipasam_uid_to_sid(struct pdb_methods *methods, uid_t uid,
+ 	struct dom_sid *user_sid = NULL;
+ 	int rc;
+ 	enum idmap_error_code err;
+-	TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ 	struct unixid id;
+ 
++	TALLOC_CTX *tmp_ctx = talloc_new(priv);
++	if (tmp_ctx == NULL) {
++		goto done;
++	}
++
+ 	/* Fast fail if we get a request for uidNumber=0 because it currently
+ 	 * will never exist in the directory
+ 	 * Saves an expensive LDAP call of which failure will never be cached
+@@ -968,9 +971,13 @@ static bool ipasam_gid_to_sid(struct pdb_methods *methods, gid_t gid,
+ 	size_t c;
+ 	int rc;
+ 	enum idmap_error_code err;
+-	TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ 	struct unixid id;
+ 
++	TALLOC_CTX *tmp_ctx = talloc_new(priv);
++	if (tmp_ctx == NULL) {
++		goto done;
++	}
++
+ 	filter = talloc_asprintf(tmp_ctx,
+ 				 "(|(&(gidNumber=%u)"
+ 				     "(objectClass=%s))"
+@@ -3749,7 +3756,8 @@ static void ipasam_free_private_data(void **vp)
+ 		(*ipasam_state)->result = NULL;
+ 	}
+ 	if ((*ipasam_state)->domain_dn != NULL) {
+-		SAFE_FREE((*ipasam_state)->domain_dn);
++		free((*ipasam_state)->domain_dn);
++		(*ipasam_state)->domain_dn = NULL;
+ 	}
+ 
+ 	*ipasam_state = NULL;
+-- 
+2.21.0
+
diff --git a/SOURCES/0004-Remove-ZERO_STRUCT-call.patch b/SOURCES/0004-Remove-ZERO_STRUCT-call.patch
new file mode 100644
index 0000000..4568d20
--- /dev/null
+++ b/SOURCES/0004-Remove-ZERO_STRUCT-call.patch
@@ -0,0 +1,37 @@
+From f4673e9656c16ff383cc6cf1caf523c913f2d3bd Mon Sep 17 00:00:00 2001
+From: Christian Heimes <cheimes@redhat.com>
+Date: Thu, 7 Feb 2019 12:11:42 +0100
+Subject: [PATCH 1/2] Remove ZERO_STRUCT() call
+
+ipa_sam uses Samba's macro ZERO_STRUCT() to safely zero out a block in
+memory. On F30 ZERO_STRUCT() is currently broken, because it uses the
+undefined C11 function memset_s().
+
+During investigation of the bug, it turned out that
+ZERO_STRUCT(td->security_identifier) is not needed. The whole td struct
+is allocated with talloc_zero(), so td->security_identifier is already
+zeroed.
+
+See: https://bugzilla.redhat.com/show_bug.cgi?id=1672231
+Signed-off-by: Christian Heimes <cheimes@redhat.com>
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+(cherry picked from commit 1355588768c7863234c518196f48527e119740e0)
+---
+ daemons/ipa-sam/ipa_sam.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c
+index 755f44d68..2f78f82f9 100644
+--- a/daemons/ipa-sam/ipa_sam.c
++++ b/daemons/ipa-sam/ipa_sam.c
+@@ -2266,7 +2266,6 @@ static bool fill_pdb_trusted_domain(TALLOC_CTX *mem_ctx,
+ 	if (dummy == NULL) {
+ 		DEBUG(9, ("Attribute %s not present.\n",
+ 			  LDAP_ATTRIBUTE_TRUST_SID));
+-		ZERO_STRUCT(td->security_identifier);
+ 	} else {
+ 		err = sss_idmap_sid_to_smb_sid(ipasam_state->idmap_ctx,
+ 					       dummy, &sid);
+-- 
+2.21.0
+
diff --git a/SOURCES/0004-Unify-and-simplify-LDAP-service-discovery.patch b/SOURCES/0004-Unify-and-simplify-LDAP-service-discovery.patch
deleted file mode 100644
index a90fffc..0000000
--- a/SOURCES/0004-Unify-and-simplify-LDAP-service-discovery.patch
+++ /dev/null
@@ -1,660 +0,0 @@
-From 04f68b7354cf1268019b08885eeb3a6915f314ef Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Thu, 12 Jul 2018 14:37:18 +0200
-Subject: [PATCH] Unify and simplify LDAP service discovery
-
-Move LDAP service discovery and service definitions from
-ipaserver.install to ipaserver. Simplify and unify different
-implementations in favor of a single implementation.
-
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Thomas Woerner <twoerner@redhat.com>
----
- install/tools/ipa-ca-install                |   9 +-
- install/tools/ipactl                        |   4 +-
- ipaserver/install/cainstance.py             |   3 +-
- ipaserver/install/ipa_kra_install.py        |  11 +-
- ipaserver/install/opendnssecinstance.py     |   3 +-
- ipaserver/install/server/replicainstall.py  |  18 +--
- ipaserver/install/service.py                |  65 +----------
- ipaserver/masters.py                        | 123 ++++++++++++++++++++
- ipaserver/plugins/cert.py                   |  10 +-
- ipaserver/plugins/dogtag.py                 |  99 ++++------------
- ipaserver/servroles.py                      |   9 +-
- ipatests/test_ipaserver/test_serverroles.py |   3 +-
- 12 files changed, 192 insertions(+), 165 deletions(-)
- create mode 100644 ipaserver/masters.py
-
-diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install
-index f78f43d94981d29939a247f3c492c5e7340298ea..dcdbe884f15b13b92ec68a11d9f00e3e28771b42 100755
---- a/install/tools/ipa-ca-install
-+++ b/install/tools/ipa-ca-install
-@@ -34,6 +34,7 @@ from ipaserver.install.installutils import check_creds, ReplicaConfig
- from ipaserver.install import dsinstance, ca
- from ipaserver.install import cainstance, service
- from ipaserver.install import custodiainstance
-+from ipaserver.masters import find_providing_server
- from ipapython import version
- from ipalib import api
- from ipalib.constants import DOMAIN_LEVEL_0
-@@ -211,8 +212,9 @@ def install_replica(safe_options, options, filename):
-         config.subject_base = attrs.get('ipacertificatesubjectbase')[0]
- 
-     if config.ca_host_name is None:
--        config.ca_host_name = \
--            service.find_providing_server('CA', api.Backend.ldap2, api.env.ca_host)
-+        config.ca_host_name = find_providing_server(
-+            'CA', api.Backend.ldap2, [api.env.ca_host]
-+        )
- 
-     options.realm_name = config.realm_name
-     options.domain_name = config.domain_name
-@@ -299,7 +301,8 @@ def promote(safe_options, options, filename):
-             paths.KRB5_KEYTAB,
-             ccache)
- 
--        ca_host = service.find_providing_server('CA', api.Backend.ldap2)
-+        ca_host = find_providing_server('CA', api.Backend.ldap2)
-+
-         if ca_host is None:
-             install_master(safe_options, options)
-         else:
-diff --git a/install/tools/ipactl b/install/tools/ipactl
-index ade91f7f75dab4fdf3b7fa73d2624a7395bc2a53..2767a26d1b70337d37dbcd87c707919579fe7e29 100755
---- a/install/tools/ipactl
-+++ b/install/tools/ipactl
-@@ -224,9 +224,9 @@ def get_config(dirsrv):
-         svc_list.append([order, name])
- 
-     ordered_list = []
--    for (order, svc) in sorted(svc_list):
-+    for order, svc in sorted(svc_list):
-         if svc in service.SERVICE_LIST:
--            ordered_list.append(service.SERVICE_LIST[svc][0])
-+            ordered_list.append(service.SERVICE_LIST[svc].systemd_name)
-     return ordered_list
- 
- def get_config_from_file():
-diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
-index e101087ac2d738eb95cc643bfb12faaf5e65f0be..f424e7cd76d24a5a633a4f4babf3e112537be92c 100644
---- a/ipaserver/install/cainstance.py
-+++ b/ipaserver/install/cainstance.py
-@@ -71,6 +71,7 @@ from ipaserver.install import replication
- from ipaserver.install import sysupgrade
- from ipaserver.install.dogtaginstance import DogtagInstance
- from ipaserver.plugins import ldap2
-+from ipaserver.masters import ENABLED_SERVICE
- 
- logger = logging.getLogger(__name__)
- 
-@@ -1304,7 +1305,7 @@ class CAInstance(DogtagInstance):
-             config = ['caRenewalMaster']
-         else:
-             config = []
--        self._ldap_enable(u'enabledService', "CA", self.fqdn, basedn, config)
-+        self._ldap_enable(ENABLED_SERVICE, "CA", self.fqdn, basedn, config)
- 
-     def setup_lightweight_ca_key_retrieval(self):
-         if sysupgrade.get_upgrade_state('dogtag', 'setup_lwca_key_retrieval'):
-diff --git a/ipaserver/install/ipa_kra_install.py b/ipaserver/install/ipa_kra_install.py
-index b536685f5f1f3fccab07fd37aa001958e2d38420..19260ac7f23a7c6f3a6328d4f146510a186b706e 100644
---- a/ipaserver/install/ipa_kra_install.py
-+++ b/ipaserver/install/ipa_kra_install.py
-@@ -41,6 +41,7 @@ from ipaserver.install.installutils import create_replica_config
- from ipaserver.install import dogtaginstance
- from ipaserver.install import kra
- from ipaserver.install.installutils import ReplicaConfig
-+from ipaserver.masters import find_providing_server
- 
- logger = logging.getLogger(__name__)
- 
-@@ -206,8 +207,14 @@ class KRAInstaller(KRAInstall):
-                 config.subject_base = attrs.get('ipacertificatesubjectbase')[0]
- 
-             if config.kra_host_name is None:
--                config.kra_host_name = service.find_providing_server(
--                    'KRA', api.Backend.ldap2, api.env.ca_host)
-+                config.kra_host_name = find_providing_server(
-+                    'KRA', api.Backend.ldap2, [api.env.ca_host]
-+                )
-+                if config.kra_host_name is None:
-+                    # all CA/KRA servers are down or unreachable.
-+                    raise admintool.ScriptError(
-+                        "Failed to find an active KRA server!"
-+                    )
-             custodia = custodiainstance.get_custodia_instance(
-                 config, custodiainstance.CustodiaModes.KRA_PEER)
-         else:
-diff --git a/ipaserver/install/opendnssecinstance.py b/ipaserver/install/opendnssecinstance.py
-index 0337bb22fea44f95ee9077423136353a991325db..d6725dff11599a8755a29b6707dc7b451258629f 100644
---- a/ipaserver/install/opendnssecinstance.py
-+++ b/ipaserver/install/opendnssecinstance.py
-@@ -15,6 +15,7 @@ from subprocess import CalledProcessError
- from ipalib.install import sysrestore
- from ipaserver.install import service
- from ipaserver.install import installutils
-+from ipaserver.masters import ENABLED_SERVICE
- from ipapython.dn import DN
- from ipapython import ipautil
- from ipaplatform import services
-@@ -45,7 +46,7 @@ def get_dnssec_key_masters(conn):
-     filter_attrs = {
-         u'cn': u'DNSSEC',
-         u'objectclass': u'ipaConfigObject',
--        u'ipaConfigString': [KEYMASTER, u'enabledService'],
-+        u'ipaConfigString': [KEYMASTER, ENABLED_SERVICE],
-     }
-     only_masters_f = conn.make_filter(filter_attrs, rules=conn.MATCH_ALL)
- 
-diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
-index b221e1291f973e7255263a39cfd680af1321598d..37ecbe4146fa908c30fb708037fcaa47af1a258b 100644
---- a/ipaserver/install/server/replicainstall.py
-+++ b/ipaserver/install/server/replicainstall.py
-@@ -46,6 +46,7 @@ from ipaserver.install.installutils import (
-     validate_mask)
- from ipaserver.install.replication import (
-     ReplicationManager, replica_conn_check)
-+from ipaserver.masters import find_providing_servers, find_providing_server
- import SSSDConfig
- from subprocess import CalledProcessError
- 
-@@ -1257,9 +1258,10 @@ def promote_check(installer):
-         if subject_base is not None:
-             config.subject_base = DN(subject_base)
- 
--        # Find if any server has a CA
--        ca_host = service.find_providing_server(
--                'CA', conn, config.ca_host_name)
-+        # Find any server with a CA
-+        ca_host = find_providing_server(
-+            'CA', conn, [config.ca_host_name]
-+        )
-         if ca_host is not None:
-             config.ca_host_name = ca_host
-             ca_enabled = True
-@@ -1280,14 +1282,16 @@ def promote_check(installer):
-                              "custom certificates.")
-                 raise ScriptError(rval=3)
- 
--        kra_host = service.find_providing_server(
--                'KRA', conn, config.kra_host_name)
-+        # Find any server with a KRA
-+        kra_host = find_providing_server(
-+            'KRA', conn, [config.kra_host_name]
-+        )
-         if kra_host is not None:
-             config.kra_host_name = kra_host
-             kra_enabled = True
-         else:
-             if options.setup_kra:
--                logger.error("There is no KRA server in the domain, "
-+                logger.error("There is no active KRA server in the domain, "
-                              "can't setup a KRA clone")
-                 raise ScriptError(rval=3)
-             kra_enabled = False
-@@ -1577,7 +1581,7 @@ def install(installer):
-     # Enable configured services and update DNS SRV records
-     service.enable_services(config.host_name)
-     api.Command.dns_update_system_records()
--    ca_servers = service.find_providing_servers('CA', api.Backend.ldap2, api)
-+    ca_servers = find_providing_servers('CA', api.Backend.ldap2, api=api)
-     api.Backend.ldap2.disconnect()
- 
-     # Everything installed properly, activate ipa service.
-diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
-index baefc0076990e67e56dfa68da48b56f4cd55849f..a030801175491f65dc83aa9d42afdb1dfdb65b0f 100644
---- a/ipaserver/install/service.py
-+++ b/ipaserver/install/service.py
-@@ -38,34 +38,15 @@ from ipapython import kerberos
- from ipalib import api, errors
- from ipaplatform import services
- from ipaplatform.paths import paths
-+from ipaserver.masters import (
-+    CONFIGURED_SERVICE, ENABLED_SERVICE, SERVICE_LIST
-+)
- 
- logger = logging.getLogger(__name__)
- 
- if six.PY3:
-     unicode = str
- 
--# The service name as stored in cn=masters,cn=ipa,cn=etc. In the tuple
--# the first value is the *nix service name, the second the start order.
--SERVICE_LIST = {
--    'KDC': ('krb5kdc', 10),
--    'KPASSWD': ('kadmin', 20),
--    'DNS': ('named', 30),
--    'HTTP': ('httpd', 40),
--    'KEYS': ('ipa-custodia', 41),
--    'NTP': ('ntpd', 45),
--    'CA': ('pki-tomcatd', 50),
--    'KRA': ('pki-tomcatd', 51),
--    'ADTRUST': ('smb', 60),
--    'EXTID': ('winbind', 70),
--    'OTPD': ('ipa-otpd', 80),
--    'DNSKeyExporter': ('ipa-ods-exporter', 90),
--    'DNSSEC': ('ods-enforcerd', 100),
--    'DNSKeySync': ('ipa-dnskeysyncd', 110),
--}
--
--CONFIGURED_SERVICE = u'configuredService'
--ENABLED_SERVICE = u'enabledService'
--
- 
- def print_msg(message, output_fd=sys.stdout):
-     logger.debug("%s", message)
-@@ -117,44 +98,6 @@ def add_principals_to_group(admin_conn, group, member_attr, principals):
-         pass
- 
- 
--def find_providing_servers(svcname, conn, api):
--    """
--    Find servers that provide the given service.
--
--    :param svcname: The service to find
--    :param conn: a connection to the LDAP server
--    :return: list of host names (possibly empty)
--
--    """
--    dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
--    query_filter = conn.make_filter({'objectClass': 'ipaConfigObject',
--                                     'ipaConfigString': ENABLED_SERVICE,
--                                     'cn': svcname}, rules='&')
--    try:
--        entries, _trunc = conn.find_entries(filter=query_filter, base_dn=dn)
--    except errors.NotFound:
--        return []
--    else:
--        return [entry.dn[1].value for entry in entries]
--
--
--def find_providing_server(svcname, conn, host_name=None, api=api):
--    """
--    Find a server that provides the given service.
--
--    :param svcname: The service to find
--    :param conn: a connection to the LDAP server
--    :param host_name: the preferred server
--    :return: the selected host name
--
--    """
--    servers = find_providing_servers(svcname, conn, api)
--    if len(servers) == 0:
--        return None
--    if host_name in servers:
--        return host_name
--    return servers[0]
--
- 
- def case_insensitive_attr_has_value(attr, value):
-     """
-@@ -618,7 +561,7 @@ class Service(object):
- 
-     def _ldap_enable(self, value, name, fqdn, ldap_suffix, config):
-         extra_config_opts = [
--            ' '.join([u'startOrder', unicode(SERVICE_LIST[name][1])])
-+            u'startOrder {}'.format(SERVICE_LIST[name].startorder),
-         ]
-         extra_config_opts.extend(config)
- 
-diff --git a/ipaserver/masters.py b/ipaserver/masters.py
-new file mode 100644
-index 0000000000000000000000000000000000000000..171c3abe0d6eea5aa6bcc642815eceae3ae885e7
---- /dev/null
-+++ b/ipaserver/masters.py
-@@ -0,0 +1,123 @@
-+#
-+# Copyright (C) 2018  FreeIPA Contributors see COPYING for license
-+#
-+"""Helpers services in for cn=masters,cn=ipa,cn=etc
-+"""
-+
-+from __future__ import absolute_import
-+
-+import collections
-+import logging
-+import random
-+
-+from ipapython.dn import DN
-+from ipalib import api
-+from ipalib import errors
-+
-+logger = logging.getLogger(__name__)
-+
-+# constants for ipaConfigString
-+CONFIGURED_SERVICE = u'configuredService'
-+ENABLED_SERVICE = u'enabledService'
-+
-+# The service name as stored in cn=masters,cn=ipa,cn=etc. The values are:
-+# 0: systemd service name
-+# 1: start order for system service
-+# 2: LDAP server entry CN, also used as SERVICE_LIST key
-+service_definition = collections.namedtuple(
-+    "service_definition",
-+    "systemd_name startorder service_entry"
-+)
-+
-+SERVICES = [
-+    service_definition('krb5kdc', 10, 'KDC'),
-+    service_definition('kadmin', 20, 'KPASSWD'),
-+    service_definition('named', 30, 'DNS'),
-+    service_definition('httpd', 40, 'HTTP'),
-+    service_definition('ipa-custodia', 41, 'KEYS'),
-+    service_definition('ntpd', 45, 'NTP'),
-+    service_definition('pki-tomcatd', 50, 'CA'),
-+    service_definition('pki-tomcatd', 51, 'KRA'),
-+    service_definition('smb', 60, 'ADTRUST'),
-+    service_definition('winbind', 70, 'EXTID'),
-+    service_definition('ipa-otpd', 80, 'OTPD'),
-+    service_definition('ipa-ods-exporter', 90, 'DNSKeyExporter'),
-+    service_definition('ods-enforcerd', 100, 'DNSSEC'),
-+    service_definition('ipa-dnskeysyncd', 110, 'DNSKeySync'),
-+]
-+
-+SERVICE_LIST = {s.service_entry: s for s in SERVICES}
-+
-+
-+def find_providing_servers(svcname, conn=None, preferred_hosts=(), api=api):
-+    """Find servers that provide the given service.
-+
-+    :param svcname: The service to find
-+    :param preferred_hosts: preferred servers
-+    :param conn: a connection to the LDAP server
-+    :param api: ipalib.API instance
-+    :return: list of host names in randomized order (possibly empty)
-+
-+    Preferred servers are moved to the front of the list if and only if they
-+    are found as providing servers.
-+    """
-+    assert isinstance(preferred_hosts, (tuple, list))
-+    if svcname not in SERVICE_LIST:
-+        raise ValueError("Unknown service '{}'.".format(svcname))
-+    if conn is None:
-+        conn = api.Backend.ldap2
-+
-+    dn = DN(api.env.container_masters, api.env.basedn)
-+    query_filter = conn.make_filter(
-+        {
-+            'objectClass': 'ipaConfigObject',
-+            'ipaConfigString': ENABLED_SERVICE,
-+            'cn': svcname
-+        },
-+        rules='&'
-+    )
-+    try:
-+        entries, _trunc = conn.find_entries(
-+            filter=query_filter,
-+            attrs_list=[],
-+            base_dn=dn
-+        )
-+    except errors.NotFound:
-+        return []
-+
-+    # unique list of host names, DNS is case insensitive
-+    servers = list(set(entry.dn[1].value.lower() for entry in entries))
-+    # shuffle the list like DNS SRV would randomize it
-+    random.shuffle(servers)
-+    # Move preferred hosts to front
-+    for host_name in reversed(preferred_hosts):
-+        host_name = host_name.lower()
-+        try:
-+            servers.remove(host_name)
-+        except ValueError:
-+            # preferred server not found, log and ignore
-+            logger.warning(
-+                "Lookup failed: Preferred host %s does not provide %s.",
-+                host_name, svcname
-+            )
-+        else:
-+            servers.insert(0, host_name)
-+    return servers
-+
-+
-+def find_providing_server(svcname, conn=None, preferred_hosts=(), api=api):
-+    """Find a server that provides the given service.
-+
-+    :param svcname: The service to find
-+    :param conn: a connection to the LDAP server
-+    :param host_name: the preferred server
-+    :param api: ipalib.API instance
-+    :return: the selected host name or None
-+    """
-+    servers = find_providing_servers(
-+        svcname, conn=conn, preferred_hosts=preferred_hosts, api=api
-+    )
-+    if not servers:
-+        return None
-+    else:
-+        return servers[0]
-diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py
-index da77f507cb2307eeec63acd0ab9d58c985ea8fe2..ff750e9d38ff98e0e1fa1c2eee5a3d0719da94bf 100644
---- a/ipaserver/plugins/cert.py
-+++ b/ipaserver/plugins/cert.py
-@@ -55,6 +55,7 @@ from ipalib import output
- from ipapython import dnsutil, kerberos
- from ipapython.dn import DN
- from ipaserver.plugins.service import normalize_principal, validate_realm
-+from ipaserver.masters import ENABLED_SERVICE, CONFIGURED_SERVICE
- 
- try:
-     import pyhbac
-@@ -297,19 +298,14 @@ def caacl_check(principal, ca, profile_id):
- def ca_kdc_check(api_instance, hostname):
-     master_dn = api_instance.Object.server.get_dn(unicode(hostname))
-     kdc_dn = DN(('cn', 'KDC'), master_dn)
--
-+    wanted = {ENABLED_SERVICE, CONFIGURED_SERVICE}
-     try:
-         kdc_entry = api_instance.Backend.ldap2.get_entry(
-             kdc_dn, ['ipaConfigString'])
--
--        ipaconfigstring = {val.lower() for val in kdc_entry['ipaConfigString']}
--
--        if 'enabledservice' not in ipaconfigstring \
--                and 'configuredservice' not in ipaconfigstring:
-+        if not wanted.intersection(kdc_entry['ipaConfigString']):
-             raise errors.NotFound(
-                 reason=_("enabledService/configuredService not in "
-                          "ipaConfigString kdc entry"))
--
-     except errors.NotFound:
-         raise errors.ACIError(
-             info=_("Host '%(hostname)s' is not an active KDC")
-diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py
-index 5a44f00c583cd4bae8211a511f907c4e179bb3f6..17e2225688c0c3878ef22e5979c65e30f971b5b3 100644
---- a/ipaserver/plugins/dogtag.py
-+++ b/ipaserver/plugins/dogtag.py
-@@ -255,6 +255,7 @@ from ipalib import Backend, api
- from ipapython.dn import DN
- import ipapython.cookie
- from ipapython import dogtag, ipautil, certdb
-+from ipaserver.masters import find_providing_server
- 
- if api.env.in_server:
-     import pki
-@@ -1208,56 +1209,6 @@ def parse_updateCRL_xml(doc):
-     return response
- 
- 
--def host_has_service(host, ldap2, service='CA'):
--    """
--    :param host: A host which might be a master for a service.
--    :param ldap2: connection to the local database
--    :param service: The service for which the host might be a master.
--    :return:   (true, false)
--
--    Check if a specified host is a master for a specified service.
--    """
--    base_dn = DN(('cn', host), ('cn', 'masters'), ('cn', 'ipa'),
--                 ('cn', 'etc'), api.env.basedn)
--    filter_attrs = {
--        'objectClass': 'ipaConfigObject',
--        'cn': service,
--        'ipaConfigString': 'enabledService',
--        }
--    query_filter = ldap2.make_filter(filter_attrs, rules='&')
--    try:
--        ent, _trunc = ldap2.find_entries(filter=query_filter, base_dn=base_dn)
--        if len(ent):
--            return True
--    except Exception:
--        pass
--    return False
--
--
--def select_any_master(ldap2, service='CA'):
--    """
--    :param ldap2: connection to the local database
--    :param service: The service for which we're looking for a master.
--    :return:   host as str
--
--    Select any host which is a master for a specified service.
--    """
--    base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
--                  api.env.basedn)
--    filter_attrs = {
--         'objectClass': 'ipaConfigObject',
--         'cn': service,
--         'ipaConfigString': 'enabledService',}
--    query_filter = ldap2.make_filter(filter_attrs, rules='&')
--    try:
--        ent, _trunc = ldap2.find_entries(filter=query_filter, base_dn=base_dn)
--        if len(ent):
--            entry = random.choice(ent)
--            return entry.dn[1].value
--    except Exception:
--        pass
--    return None
--
- #-------------------------------------------------------------------------------
- 
- from ipalib import Registry, errors, SkipPluginModule
-@@ -1265,7 +1216,6 @@ if api.env.ra_plugin != 'dogtag':
-     # In this case, abort loading this plugin module...
-     raise SkipPluginModule(reason='dogtag not selected as RA plugin')
- import os
--import random
- from ipaserver.plugins import rabase
- from ipalib.constants import TYPE_ERROR
- from ipalib import _
-@@ -1330,17 +1280,19 @@ class RestClient(Backend):
-         if self._ca_host is not None:
-             return self._ca_host
- 
--        ldap2 = self.api.Backend.ldap2
--        if host_has_service(api.env.ca_host, ldap2, "CA"):
--            object.__setattr__(self, '_ca_host', api.env.ca_host)
--        elif api.env.host != api.env.ca_host:
--            if host_has_service(api.env.host, ldap2, "CA"):
--                object.__setattr__(self, '_ca_host', api.env.host)
--        else:
--            object.__setattr__(self, '_ca_host', select_any_master(ldap2))
--        if self._ca_host is None:
--            object.__setattr__(self, '_ca_host', api.env.ca_host)
--        return self._ca_host
-+        preferred = [api.env.ca_host]
-+        if api.env.host != api.env.ca_host:
-+            preferred.append(api.env.host)
-+        ca_host = find_providing_server(
-+            'CA', conn=self.api.Backend.ldap2, preferred_hosts=preferred,
-+            api=self.api
-+        )
-+        if ca_host is None:
-+            # TODO: need during installation, CA is not yet set as enabled
-+            ca_host = api.env.ca_host
-+        # object is locked, need to use __setattr__()
-+        object.__setattr__(self, '_ca_host', ca_host)
-+        return ca_host
- 
-     def __enter__(self):
-         """Log into the REST API"""
-@@ -2082,9 +2034,7 @@ class kra(Backend):
-     """
- 
-     def __init__(self, api, kra_port=443):
--
-         self.kra_port = kra_port
--
-         super(kra, self).__init__(api)
- 
-     @property
-@@ -2095,17 +2045,18 @@ class kra(Backend):
- 
-         Select our KRA host.
-         """
--        ldap2 = self.api.Backend.ldap2
--        if host_has_service(api.env.ca_host, ldap2, "KRA"):
--            return api.env.ca_host
-+        preferred = [api.env.ca_host]
-         if api.env.host != api.env.ca_host:
--            if host_has_service(api.env.host, ldap2, "KRA"):
--                return api.env.host
--        host = select_any_master(ldap2, "KRA")
--        if host:
--            return host
--        else:
--            return api.env.ca_host
-+            preferred.append(api.env.host)
-+
-+        kra_host = find_providing_server(
-+            'KRA', self.api.Backend.ldap2, preferred_hosts=preferred,
-+            api=self.api
-+        )
-+        if kra_host is None:
-+            # TODO: need during installation, KRA is not yet set as enabled
-+            kra_host = api.env.ca_host
-+        return kra_host
- 
-     @contextlib.contextmanager
-     def get_client(self):
-diff --git a/ipaserver/servroles.py b/ipaserver/servroles.py
-index 994a59e35bb5d3a007e3d63bb273ba9ea552407d..af4e63710136a15e1673210c3e2207658698fbb5 100644
---- a/ipaserver/servroles.py
-+++ b/ipaserver/servroles.py
-@@ -79,7 +79,7 @@ import six
- 
- from ipalib import _, errors
- from ipapython.dn import DN
--
-+from ipaserver.masters import ENABLED_SERVICE
- 
- if six.PY3:
-     unicode = str
-@@ -483,11 +483,8 @@ class ServiceBasedRole(BaseServerRole):
-         :param entry: LDAPEntry of the service
-         :returns: True if the service entry is enabled, False otherwise
-         """
--        enabled_value = 'enabledservice'
--        ipaconfigstring_values = set(
--            e.lower() for e in entry.get('ipaConfigString', []))
--
--        return enabled_value in ipaconfigstring_values
-+        ipaconfigstring_values = set(entry.get('ipaConfigString', []))
-+        return ENABLED_SERVICE in ipaconfigstring_values
- 
-     def _get_services_by_masters(self, entries):
-         """
-diff --git a/ipatests/test_ipaserver/test_serverroles.py b/ipatests/test_ipaserver/test_serverroles.py
-index 76f1378ed5a94069cdef918d577e3658b78ecc43..e1bf0254dddfe03ade4fe72419b609de8e95b79a 100644
---- a/ipatests/test_ipaserver/test_serverroles.py
-+++ b/ipatests/test_ipaserver/test_serverroles.py
-@@ -16,6 +16,7 @@ import pytest
- from ipaplatform.paths import paths
- from ipalib import api, create_api, errors
- from ipapython.dn import DN
-+from ipaserver.masters import ENABLED_SERVICE
- 
- pytestmark = pytest.mark.needs_ipaapi
- 
-@@ -25,7 +26,7 @@ def _make_service_entry(ldap_backend, dn, enabled=True, other_config=None):
-         'objectClass': ['top', 'nsContainer', 'ipaConfigObject'],
-     }
-     if enabled:
--        mods.update({'ipaConfigString': ['enabledService']})
-+        mods.update({'ipaConfigString': [ENABLED_SERVICE]})
- 
-     if other_config is not None:
-         mods.setdefault('ipaConfigString', [])
--- 
-2.20.1
-
diff --git a/SOURCES/0005-Use-api.env.container_masters.patch b/SOURCES/0005-Use-api.env.container_masters.patch
deleted file mode 100644
index 97a8b44..0000000
--- a/SOURCES/0005-Use-api.env.container_masters.patch
+++ /dev/null
@@ -1,252 +0,0 @@
-From 3283ba88cdd7821a430132dec23a788ea4241f76 Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Wed, 27 Mar 2019 11:03:00 +0100
-Subject: [PATCH] Use api.env.container_masters
-
-Replace occurences of ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc')
-with api.env.container_masters.
-
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Thomas Woerner <twoerner@redhat.com>
----
- ipaserver/install/bindinstance.py              |  3 +--
- ipaserver/install/cainstance.py                |  7 +++----
- ipaserver/install/dns.py                       |  4 ++--
- ipaserver/install/ipa_backup.py                |  3 ++-
- ipaserver/install/ipa_restore.py               |  3 ++-
- ipaserver/install/krbinstance.py               |  6 +-----
- ipaserver/install/plugins/ca_renewal_master.py |  3 +--
- ipaserver/install/replication.py               |  3 +--
- ipaserver/install/server/upgrade.py            |  4 ++--
- ipaserver/install/service.py                   | 11 +++++------
- ipaserver/plugins/baseldap.py                  |  2 +-
- ipaserver/plugins/domainlevel.py               | 13 +++----------
- 12 files changed, 24 insertions(+), 38 deletions(-)
-
-diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
-index c175ca4f23b4f4440e1acaac2495276388daf3ae..6156ecdfbd1a62d5b1e0a26db47ef2b9a9448bc1 100644
---- a/ipaserver/install/bindinstance.py
-+++ b/ipaserver/install/bindinstance.py
-@@ -862,8 +862,7 @@ class BindInstance(service.Service):
- 
-     def __add_others(self):
-         entries = api.Backend.ldap2.get_entries(
--            DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
--               self.suffix),
-+            DN(api.env.container_masters, self.suffix),
-             api.Backend.ldap2.SCOPE_ONELEVEL, None, ['dn'])
- 
-         for entry in entries:
-diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
-index f424e7cd76d24a5a633a4f4babf3e112537be92c..2946b5cc2b4b8b708a060aa79d1b7ab0e7b4e651 100644
---- a/ipaserver/install/cainstance.py
-+++ b/ipaserver/install/cainstance.py
-@@ -1173,8 +1173,8 @@ class CAInstance(DogtagInstance):
-         if fqdn is None:
-             fqdn = api.env.host
- 
--        dn = DN(('cn', 'CA'), ('cn', fqdn), ('cn', 'masters'), ('cn', 'ipa'),
--                ('cn', 'etc'), api.env.basedn)
-+        dn = DN(('cn', 'CA'), ('cn', fqdn), api.env.container_masters,
-+                api.env.basedn)
-         renewal_filter = '(ipaConfigString=caRenewalMaster)'
-         try:
-             api.Backend.ldap2.get_entries(base_dn=dn, filter=renewal_filter,
-@@ -1188,8 +1188,7 @@ class CAInstance(DogtagInstance):
-         if fqdn is None:
-             fqdn = api.env.host
- 
--        base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
--                     api.env.basedn)
-+        base_dn = DN(api.env.container_masters, api.env.basedn)
-         filter = '(&(cn=CA)(ipaConfigString=caRenewalMaster))'
-         try:
-             entries = api.Backend.ldap2.get_entries(
-diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py
-index b17848a80c4300ed74aedc1e29a0dedbee79e6d9..930e038e4d7629563d2cea39fe581987dd0edfef 100644
---- a/ipaserver/install/dns.py
-+++ b/ipaserver/install/dns.py
-@@ -98,8 +98,8 @@ def _disable_dnssec():
-                                                api.env.basedn)
- 
-     conn = api.Backend.ldap2
--    dn = DN(('cn', 'DNSSEC'), ('cn', api.env.host), ('cn', 'masters'),
--            ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
-+    dn = DN(('cn', 'DNSSEC'), ('cn', api.env.host),
-+            api.env.container_masters, api.env.basedn)
-     try:
-         entry = conn.get_entry(dn)
-     except errors.NotFound:
-diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py
-index 789955a67dfc255285a2c82d9a8060495c3469e2..cef01d30454ea1adb8bf9c68f428b9555f1b9557 100644
---- a/ipaserver/install/ipa_backup.py
-+++ b/ipaserver/install/ipa_backup.py
-@@ -576,7 +576,8 @@ class Backup(admintool.AdminTool):
-         config.set('ipa', 'ipa_version', str(version.VERSION))
-         config.set('ipa', 'version', '1')
- 
--        dn = DN(('cn', api.env.host), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
-+        dn = DN(('cn', api.env.host), api.env.container_masters,
-+                api.env.basedn)
-         services_cns = []
-         try:
-             conn = self.get_connection()
-diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py
-index 8b2f5bef7c9b1b8e2e2bae4e88850cf18b67b889..bd065a038db4d523048f0566f65458402d801e18 100644
---- a/ipaserver/install/ipa_restore.py
-+++ b/ipaserver/install/ipa_restore.py
-@@ -507,7 +507,8 @@ class Restore(admintool.AdminTool):
-                                 master, e)
-                 continue
- 
--            master_dn = DN(('cn', master), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
-+            master_dn = DN(('cn', master), api.env.container_masters,
-+                           api.env.basedn)
-             try:
-                 services = repl.conn.get_entries(master_dn,
-                                                  repl.conn.SCOPE_ONELEVEL)
-diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py
-index aa9243dc69674a00f2e1bcdc3e71d44ae8862fbe..319eeb82bcbe61acd70b2943982b6fec6fa33f92 100644
---- a/ipaserver/install/krbinstance.py
-+++ b/ipaserver/install/krbinstance.py
-@@ -470,11 +470,7 @@ class KrbInstance(service.Service):
-         unadvertise enabled PKINIT feature in master's KDC entry in LDAP
-         """
-         ldap = api.Backend.ldap2
--        dn = DN(('cn', 'KDC'),
--                ('cn', self.fqdn),
--                ('cn', 'masters'),
--                ('cn', 'ipa'),
--                ('cn', 'etc'),
-+        dn = DN(('cn', 'KDC'), ('cn', self.fqdn), api.env.container_masters,
-                 self.suffix)
- 
-         entry = ldap.get_entry(dn, ['ipaConfigString'])
-diff --git a/ipaserver/install/plugins/ca_renewal_master.py b/ipaserver/install/plugins/ca_renewal_master.py
-index 618f51244019c2a77a9d0a93437f95c037f1a728..259bd5a991d39adb9f30fe5b22e59c7eef09cfc6 100644
---- a/ipaserver/install/plugins/ca_renewal_master.py
-+++ b/ipaserver/install/plugins/ca_renewal_master.py
-@@ -46,8 +46,7 @@ class update_ca_renewal_master(Updater):
-             return False, []
- 
-         ldap = self.api.Backend.ldap2
--        base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
--                     self.api.env.basedn)
-+        base_dn = DN(self.api.env.container_masters, self.api.env.basedn)
-         dn = DN(('cn', 'CA'), ('cn', self.api.env.host), base_dn)
-         filter = '(&(cn=CA)(ipaConfigString=caRenewalMaster))'
-         try:
-diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py
-index 70629b4528f033908c584bfaf0793cfa4ce259d4..8644b9ff618d28614a319d6da6a2041fea3c1c1f 100644
---- a/ipaserver/install/replication.py
-+++ b/ipaserver/install/replication.py
-@@ -1419,8 +1419,7 @@ class ReplicationManager(object):
- 
-         # delete master entry with all active services
-         try:
--            dn = DN(('cn', replica), ('cn', 'masters'), ('cn', 'ipa'),
--                    ('cn', 'etc'), self.suffix)
-+            dn = DN(('cn', replica), api.env.container_masters, self.suffix)
-             entries = self.conn.get_entries(dn, ldap.SCOPE_SUBTREE)
-             if entries:
-                 entries.sort(key=lambda x: len(x.dn), reverse=True)
-diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
-index 57c70ea9250bf6fcf027665304e02cc6def8e442..f4389d37909fc0b5aed960638de67243906b634d 100644
---- a/ipaserver/install/server/upgrade.py
-+++ b/ipaserver/install/server/upgrade.py
-@@ -1244,8 +1244,8 @@ def uninstall_dogtag_9(ds, http):
-         logger.debug('Dogtag is version 10 or above')
-         return
- 
--    dn = DN(('cn', 'CA'), ('cn', api.env.host), ('cn', 'masters'),
--            ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
-+    dn = DN(('cn', 'CA'), ('cn', api.env.host), api.env.container_masters,
-+            api.env.basedn)
-     try:
-         api.Backend.ldap2.delete_entry(dn)
-     except ipalib.errors.PublicError as e:
-diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
-index a030801175491f65dc83aa9d42afdb1dfdb65b0f..261eedc85be24478b99e5ae8886aec7bc23a80ed 100644
---- a/ipaserver/install/service.py
-+++ b/ipaserver/install/service.py
-@@ -134,8 +134,7 @@ def set_service_entry_config(name, fqdn, config_values,
-     assert isinstance(ldap_suffix, DN)
- 
-     entry_name = DN(
--        ('cn', name), ('cn', fqdn), ('cn', 'masters'),
--        ('cn', 'ipa'), ('cn', 'etc'), ldap_suffix)
-+        ('cn', name), ('cn', fqdn), api.env.container_masters, ldap_suffix)
- 
-     # enable disabled service
-     try:
-@@ -577,8 +576,8 @@ class Service(object):
-     def ldap_disable(self, name, fqdn, ldap_suffix):
-         assert isinstance(ldap_suffix, DN)
- 
--        entry_dn = DN(('cn', name), ('cn', fqdn), ('cn', 'masters'),
--                        ('cn', 'ipa'), ('cn', 'etc'), ldap_suffix)
-+        entry_dn = DN(('cn', name), ('cn', fqdn), api.env.container_masters,
-+                      ldap_suffix)
-         search_kw = {'ipaConfigString': ENABLED_SERVICE}
-         filter = api.Backend.ldap2.make_filter(search_kw)
-         try:
-@@ -611,8 +610,8 @@ class Service(object):
-         logger.debug("service %s startup entry disabled", name)
- 
-     def ldap_remove_service_container(self, name, fqdn, ldap_suffix):
--        entry_dn = DN(('cn', name), ('cn', fqdn), ('cn', 'masters'),
--                        ('cn', 'ipa'), ('cn', 'etc'), ldap_suffix)
-+        entry_dn = DN(('cn', name), ('cn', fqdn),
-+                      self.api.env.container_masters, ldap_suffix)
-         try:
-             api.Backend.ldap2.delete_entry(entry_dn)
-         except errors.NotFound:
-diff --git a/ipaserver/plugins/baseldap.py b/ipaserver/plugins/baseldap.py
-index 08ddc6d10d6431f51296bca9ae28aca8fa8586b2..25449b5aec72cbdbfb57527aa834cc69291398d6 100644
---- a/ipaserver/plugins/baseldap.py
-+++ b/ipaserver/plugins/baseldap.py
-@@ -497,7 +497,7 @@ def host_is_master(ldap, fqdn):
- 
-     Raises an exception if a master, otherwise returns nothing.
-     """
--    master_dn = DN(('cn', fqdn), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
-+    master_dn = DN(('cn', fqdn), api.env.container_masters, api.env.basedn)
-     try:
-         ldap.get_entry(master_dn, ['objectclass'])
-         raise errors.ValidationError(name='hostname', error=_('An IPA master host cannot be deleted or disabled'))
-diff --git a/ipaserver/plugins/domainlevel.py b/ipaserver/plugins/domainlevel.py
-index 306ca0a6d147b2c0dc7a91ee1aefc0e7a5c98048..0d36dc08c07612dc565417a66ab9c467eb7f0555 100644
---- a/ipaserver/plugins/domainlevel.py
-+++ b/ipaserver/plugins/domainlevel.py
-@@ -72,25 +72,18 @@ def check_conflict_entries(ldap, api, desired_value):
-     except errors.NotFound:
-         pass
- 
-+
- def get_master_entries(ldap, api):
-     """
-     Returns list of LDAPEntries representing IPA masters.
-     """
--
--    container_masters = DN(
--        ('cn', 'masters'),
--        ('cn', 'ipa'),
--        ('cn', 'etc'),
--        api.env.basedn
--    )
--
-+    dn = DN(api.env.container_masters, api.env.basedn)
-     masters, _dummy = ldap.find_entries(
-         filter="(cn=*)",
--        base_dn=container_masters,
-+        base_dn=dn,
-         scope=ldap.SCOPE_ONELEVEL,
-         paged_search=True,  # we need to make sure to get all of them
-     )
--
-     return masters
- 
- 
--- 
-2.20.1
-
diff --git a/SOURCES/0005-ipasam-use-SID-formatting-calls-to-libsss_idmap.patch b/SOURCES/0005-ipasam-use-SID-formatting-calls-to-libsss_idmap.patch
new file mode 100644
index 0000000..56ee540
--- /dev/null
+++ b/SOURCES/0005-ipasam-use-SID-formatting-calls-to-libsss_idmap.patch
@@ -0,0 +1,158 @@
+From 9cb4436694d2fa5f7a56fa774e5283f0b46cc18f Mon Sep 17 00:00:00 2001
+From: Alexander Bokovoy <abokovoy@redhat.com>
+Date: Sun, 31 Mar 2019 12:37:21 +0300
+Subject: [PATCH 2/2] ipasam: use SID formatting calls to libsss_idmap
+
+Samba 4.10 moved away to private libraries two functions we used to
+convert a binary SID structre to strings:
+ - sid_talloc_string()
+ - sid_string_dbg()
+
+We already used libsss_idmap to convert textual representation of SIDs
+to a binary one, use the reverse function too.
+
+libsss_idmap code operates on talloc structures, so we need to adopt a
+bit a place where sid_string_dbg() was used because it assumed a static
+buffer was provided by sid_string_dbg().
+
+Finally, sid_talloc_string()'s replacement moves allocated memory to the
+right context so that a memory will be freed earlier. Our SSSD idmap
+context is a long-living one while in all cases where we were using
+sid_talloc_string() we free the context much earlier.
+
+Resolves: https://pagure.io/freeipa/issue/7893
+Reviewed-By: Christian Heimes <cheimes@redhat.com>
+(cherry picked from commit 137af1d2c38925404dc92f70321ac0f5fb1cf5eb)
+---
+ daemons/ipa-sam/ipa_sam.c | 52 ++++++++++++++++++++++++++++-----------
+ 1 file changed, 37 insertions(+), 15 deletions(-)
+
+diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c
+index 2f78f82f9..851cbc39a 100644
+--- a/daemons/ipa-sam/ipa_sam.c
++++ b/daemons/ipa-sam/ipa_sam.c
+@@ -104,8 +104,6 @@ enum ndr_err_code ndr_pull_trustAuthInOutBlob(struct ndr_pull *ndr, int ndr_flag
+ bool sid_check_is_builtin(const struct dom_sid *sid); /* available in libpdb.so */
+ /* available in libpdb.so, renamed from sid_check_is_domain() in c43505b621725c9a754f0ee98318d451b093f2ed */
+ bool sid_linearize(char *outbuf, size_t len, const struct dom_sid *sid); /* available in libsmbconf.so */
+-char *sid_string_talloc(TALLOC_CTX *mem_ctx, const struct dom_sid *sid); /* available in libsmbconf.so */
+-char *sid_string_dbg(const struct dom_sid *sid); /* available in libsmbconf.so */
+ char *escape_ldap_string(TALLOC_CTX *mem_ctx, const char *s); /* available in libsmbconf.so */
+ bool secrets_store(const char *key, const void *data, size_t size); /* available in libpdb.so */
+ void idmap_cache_set_sid2unixid(const struct dom_sid *sid, struct unixid *unix_id); /* available in libsmbconf.so */
+@@ -261,6 +259,18 @@ static bool sid_compose(struct dom_sid *dst, const struct dom_sid *dom_sid,
+ 	return true;
+ }
+ 
++static char *sid_talloc_string(struct sss_idmap_ctx *ctx, void *final_ctx, const struct dom_sid *dom_sid)
++{
++	enum idmap_error_code ret;
++	char *result = NULL;
++	ret = sss_idmap_smb_sid_to_sid(ctx, discard_const(dom_sid), &result);
++	if (ret != IDMAP_SUCCESS) {
++		return NULL;
++	}
++
++	return talloc_move(final_ctx, &result);
++}
++
+ static bool is_null_sid(const struct dom_sid *sid)
+ {
+ 	size_t c;
+@@ -519,8 +529,18 @@ static bool ldapsam_extract_rid_from_entry(LDAP *ldap_struct,
+ 	}
+ 
+ 	if (dom_sid_compare_domain(sid, domain_sid) != 0) {
+-		DEBUG(10, ("SID %s is not in expected domain %s\n",
+-			   str, sid_string_dbg(domain_sid)));
++		char *debug_domain_sid = NULL;
++		err = sss_idmap_smb_sid_to_sid(idmap_ctx,
++					       discard_const(domain_sid),
++					       &debug_domain_sid);
++		if (err != IDMAP_SUCCESS) {
++			DEBUG(10, ("SID %s is not in expected domain.\n",
++				   str));
++		} else {
++			DEBUG(10, ("SID %s is not in expected domain %s\n",
++				   str, debug_domain_sid));
++			talloc_free(debug_domain_sid);
++		}
+ 		res = false;
+ 		goto done;
+ 	}
+@@ -589,7 +609,7 @@ static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods,
+ 		allsids = talloc_asprintf_append_buffer(
+ 			allsids, "(%s=%s)",
+ 			LDAP_ATTRIBUTE_SID,
+-			sid_string_talloc(mem_ctx, &sid));
++			sid_talloc_string(ipasam_state->idmap_ctx, mem_ctx, &sid));
+ 		if (allsids == NULL) {
+ 			goto done;
+ 		}
+@@ -790,7 +810,8 @@ static bool ldapsam_sid_to_id(struct pdb_methods *methods,
+ 	filter = talloc_asprintf(mem_ctx,
+ 				 "(&(%s=%s)"
+ 				 "(|(objectClass=%s)(objectClass=%s)))",
+-				 LDAP_ATTRIBUTE_SID, sid_string_talloc(mem_ctx, sid),
++				 LDAP_ATTRIBUTE_SID,
++				 sid_talloc_string(priv->idmap_ctx, mem_ctx, sid),
+ 				 LDAP_OBJ_GROUPMAP, LDAP_OBJ_SAMBASAMACCOUNT);
+ 	if (filter == NULL) {
+ 		DEBUG(5, ("talloc_asprintf failed\n"));
+@@ -936,7 +957,7 @@ static bool ipasam_uid_to_sid(struct pdb_methods *methods, uid_t uid,
+ 	err = sss_idmap_sid_to_smb_sid(priv->idmap_ctx,
+ 				       user_sid_string, &user_sid);
+ 	if (err != IDMAP_SUCCESS) {
+-		DEBUG(3, ("Error calling sid_string_talloc for sid '%s'\n",
++		DEBUG(3, ("Error creating sid structure for sid '%s'\n",
+ 			  user_sid_string));
+ 		goto done;
+ 	}
+@@ -1052,7 +1073,7 @@ found:
+ 	err = sss_idmap_sid_to_smb_sid(priv->idmap_ctx,
+ 				       group_sid_string, &group_sid);
+ 	if (err != IDMAP_SUCCESS) {
+-		DEBUG(3, ("Error calling sid_string_talloc for sid '%s'\n",
++		DEBUG(3, ("Error creating sid structure for sid '%s'\n",
+ 			  group_sid_string));
+ 		goto done;
+ 	}
+@@ -1595,11 +1616,11 @@ static bool ipasam_search_grouptype(struct pdb_methods *methods,
+ 	state->base = talloc_strdup(search, ipasam_state->base_dn);
+ 	state->connection = ipasam_state->ldap_state;
+ 	state->scope = LDAP_SCOPE_SUBTREE;
+-	state->filter =	talloc_asprintf(search, "(&(objectclass=%s)"
+-					"(%s=%s*))",
+-					 LDAP_OBJ_GROUPMAP,
+-					 LDAP_ATTRIBUTE_SID,
+-					 sid_string_talloc(search, sid));
++	state->filter =	talloc_asprintf(search, "(&(objectclass=%s)(%s=%s*))",
++					LDAP_OBJ_GROUPMAP, LDAP_ATTRIBUTE_SID,
++					sid_talloc_string(
++						ipasam_state->idmap_ctx,
++						search, sid));
+ 	state->attrs = talloc_attrs(search, "cn", LDAP_ATTRIBUTE_SID,
+ 				    "displayName", "description",
+ 				     NULL);
+@@ -2412,7 +2433,7 @@ static NTSTATUS ipasam_get_trusted_domain_by_sid(struct pdb_methods *methods,
+ 	char *sid_str;
+ 	bool ok;
+ 
+-	sid_str = sid_string_talloc(mem_ctx, sid);
++	sid_str = sid_talloc_string(ipasam_state->idmap_ctx, mem_ctx, sid);
+ 	if (sid_str == NULL) {
+ 		return NT_STATUS_NO_MEMORY;
+ 	}
+@@ -2593,7 +2614,8 @@ static NTSTATUS ipasam_set_trusted_domain(struct pdb_methods *methods,
+ 	if (!is_null_sid(&td->security_identifier)) {
+ 		smbldap_make_mod(priv2ld(ipasam_state), entry, &mods,
+ 				 LDAP_ATTRIBUTE_TRUST_SID,
+-				 sid_string_talloc(tmp_ctx, &td->security_identifier));
++				 sid_talloc_string(ipasam_state->idmap_ctx,
++						   tmp_ctx, &td->security_identifier));
+ 	}
+ 
+ 	if (td->trust_type != 0) {
+-- 
+2.21.0
+
diff --git a/SOURCES/0006-Consolidate-container_masters-queries.patch b/SOURCES/0006-Consolidate-container_masters-queries.patch
deleted file mode 100644
index ad86b7f..0000000
--- a/SOURCES/0006-Consolidate-container_masters-queries.patch
+++ /dev/null
@@ -1,316 +0,0 @@
-From 406a70cb9e481fb194bbbc67461f3cfd3c97a108 Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Wed, 27 Mar 2019 11:30:40 +0100
-Subject: [PATCH] Consolidate container_masters queries
-
-Replace manual queries of container_masters with new APIs get_masters()
-and is_service_enabled().
-
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Thomas Woerner <twoerner@redhat.com>
----
- ipaserver/install/bindinstance.py |  8 ++---
- ipaserver/install/ipa_restore.py  | 12 ++------
- ipaserver/masters.py              | 51 +++++++++++++++++++++++++++++++
- ipaserver/plugins/cert.py         | 15 +++------
- ipaserver/plugins/dns.py          | 49 ++++-------------------------
- ipaserver/plugins/user.py         | 15 ++-------
- ipaserver/plugins/vault.py        | 12 ++------
- 7 files changed, 70 insertions(+), 92 deletions(-)
-
-diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
-index 6156ecdfbd1a62d5b1e0a26db47ef2b9a9448bc1..940667db9c40559d5369188395bb18f2d1eac025 100644
---- a/ipaserver/install/bindinstance.py
-+++ b/ipaserver/install/bindinstance.py
-@@ -40,6 +40,7 @@ from ipaserver.dns_data_management import (
- from ipaserver.install import installutils
- from ipaserver.install import service
- from ipaserver.install import sysupgrade
-+from ipaserver.masters import get_masters
- from ipapython import ipautil
- from ipapython import dnsutil
- from ipapython.dnsutil import DNSName
-@@ -1037,13 +1038,8 @@ class BindInstance(service.Service):
-             cname_fqdn[cname] = fqdn
- 
-         # get FQDNs of all IPA masters
--        ldap = self.api.Backend.ldap2
-         try:
--            entries = ldap.get_entries(
--                DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
--                   self.api.env.basedn),
--                ldap.SCOPE_ONELEVEL, None, ['cn'])
--            masters = set(e['cn'][0] for e in entries)
-+            masters = set(get_masters(self.api.Backend.ldap2))
-         except errors.NotFound:
-             masters = set()
- 
-diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py
-index bd065a038db4d523048f0566f65458402d801e18..c7e996bbe284a7eb2d03fbedb4798d3b15f3dcc0 100644
---- a/ipaserver/install/ipa_restore.py
-+++ b/ipaserver/install/ipa_restore.py
-@@ -41,6 +41,7 @@ from ipaserver.install.replication import (wait_for_task, ReplicationManager,
-                                            get_cs_replication_manager)
- from ipaserver.install import installutils
- from ipaserver.install import dsinstance, httpinstance, cainstance, krbinstance
-+from ipaserver.masters import get_masters
- from ipapython import ipaldap
- import ipapython.errors
- from ipaplatform.constants import constants
-@@ -485,16 +486,7 @@ class Restore(admintool.AdminTool):
-             logger.error('Unable to get connection, skipping disabling '
-                          'agreements: %s', e)
-             return
--        masters = []
--        dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
--        try:
--            entries = conn.get_entries(dn, conn.SCOPE_ONELEVEL)
--        except Exception as e:
--            raise admintool.ScriptError(
--                "Failed to read master data: %s" % e)
--        else:
--            masters = [ent.single_value['cn'] for ent in entries]
--
-+        masters = get_masters(conn)
-         for master in masters:
-             if master == api.env.host:
-                 continue
-diff --git a/ipaserver/masters.py b/ipaserver/masters.py
-index 171c3abe0d6eea5aa6bcc642815eceae3ae885e7..6fa8f02332ceaa10ec30aa5142912f351fb58936 100644
---- a/ipaserver/masters.py
-+++ b/ipaserver/masters.py
-@@ -121,3 +121,54 @@ def find_providing_server(svcname, conn=None, preferred_hosts=(), api=api):
-         return None
-     else:
-         return servers[0]
-+
-+
-+def get_masters(conn=None, api=api):
-+    """Get all master hostnames
-+
-+    :param conn: a connection to the LDAP server
-+    :param api: ipalib.API instance
-+    :return: list of hostnames
-+    """
-+    if conn is None:
-+        conn = api.Backend.ldap2
-+
-+    dn = DN(api.env.container_masters, api.env.basedn)
-+    entries = conn.get_entries(dn, conn.SCOPE_ONELEVEL, None, ['cn'])
-+    return list(e['cn'][0] for e in entries)
-+
-+
-+def is_service_enabled(svcname, conn=None, api=api):
-+    """Check if service is enabled on any master
-+
-+    The check function only looks for presence of service entries. It
-+    ignores enabled/hidden flags.
-+
-+    :param svcname: The service to find
-+    :param conn: a connection to the LDAP server
-+    :param api: ipalib.API instance
-+    :return: True/False
-+    """
-+    if svcname not in SERVICE_LIST:
-+        raise ValueError("Unknown service '{}'.".format(svcname))
-+    if conn is None:
-+        conn = api.Backend.ldap2
-+
-+    dn = DN(api.env.container_masters, api.env.basedn)
-+    query_filter = conn.make_filter(
-+        {
-+            'objectClass': 'ipaConfigObject',
-+            'cn': svcname
-+        },
-+        rules='&'
-+    )
-+    try:
-+        conn.find_entries(
-+            filter=query_filter,
-+            attrs_list=[],
-+            base_dn=dn
-+        )
-+    except errors.NotFound:
-+        return False
-+    else:
-+        return True
-diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py
-index ff750e9d38ff98e0e1fa1c2eee5a3d0719da94bf..36a7a859292b2ddb9dd721e2bf786c6be130f323 100644
---- a/ipaserver/plugins/cert.py
-+++ b/ipaserver/plugins/cert.py
-@@ -55,7 +55,9 @@ from ipalib import output
- from ipapython import dnsutil, kerberos
- from ipapython.dn import DN
- from ipaserver.plugins.service import normalize_principal, validate_realm
--from ipaserver.masters import ENABLED_SERVICE, CONFIGURED_SERVICE
-+from ipaserver.masters import (
-+    ENABLED_SERVICE, CONFIGURED_SERVICE, is_service_enabled
-+)
- 
- try:
-     import pyhbac
-@@ -1908,14 +1910,5 @@ class ca_is_enabled(Command):
-     has_output = output.standard_value
- 
-     def execute(self, *args, **options):
--        base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
--                     self.api.env.basedn)
--        filter = '(&(objectClass=ipaConfigObject)(cn=CA))'
--        try:
--            self.api.Backend.ldap2.find_entries(
--                base_dn=base_dn, filter=filter, attrs_list=[])
--        except errors.NotFound:
--            result = False
--        else:
--            result = True
-+        result = is_service_enabled('CA', conn=self.api.Backend.ldap2)
-         return dict(result=result, value=pkey_to_value(None, options))
-diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py
-index 3c006c5701a426cc03971c9e3361dfd091770241..d6baa2fc1769701ac62b8c6d686fbed74ea3f002 100644
---- a/ipaserver/plugins/dns.py
-+++ b/ipaserver/plugins/dns.py
-@@ -86,6 +86,7 @@ from ipaserver.dns_data_management import (
-     IPASystemRecords,
-     IPADomainIsNotManagedByIPAError,
- )
-+from ipaserver.masters import find_providing_servers, is_service_enabled
- 
- if six.PY3:
-     unicode = str
-@@ -1593,19 +1594,7 @@ def dnssec_installed(ldap):
-     :param ldap: ldap connection
-     :return: True if DNSSEC was installed, otherwise False
-     """
--    dn = DN(api.env.container_masters, api.env.basedn)
--
--    filter_attrs = {
--        u'cn': u'DNSSEC',
--        u'objectclass': u'ipaConfigObject',
--    }
--    only_masters_f = ldap.make_filter(filter_attrs, rules=ldap.MATCH_ALL)
--
--    try:
--        ldap.find_entries(filter=only_masters_f, base_dn=dn)
--    except errors.NotFound:
--        return False
--    return True
-+    return is_service_enabled('DNSSEC', conn=ldap)
- 
- 
- def default_zone_update_policy(zone):
-@@ -3191,24 +3180,9 @@ class dnsrecord(LDAPObject):
-         return cliname
- 
-     def get_dns_masters(self):
--        ldap = self.api.Backend.ldap2
--        base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), self.api.env.basedn)
--        ldap_filter = '(&(objectClass=ipaConfigObject)(cn=DNS))'
--        dns_masters = []
--
--        try:
--            entries = ldap.find_entries(filter=ldap_filter, base_dn=base_dn)[0]
--
--            for entry in entries:
--                try:
--                    master = entry.dn[1]['cn']
--                    dns_masters.append(master)
--                except (IndexError, KeyError):
--                    pass
--        except errors.NotFound:
--            return []
--
--        return dns_masters
-+        return find_providing_servers(
-+            'DNS', self.api.Backend.ldap2, preferred_hosts=[api.env.host]
-+        )
- 
-     def get_record_entry_attrs(self, entry_attrs):
-         entry_attrs = entry_attrs.copy()
-@@ -4077,19 +4051,8 @@ class dns_is_enabled(Command):
-     NO_CLI = True
-     has_output = output.standard_value
- 
--    base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
--    filter = '(&(objectClass=ipaConfigObject)(cn=DNS))'
--
-     def execute(self, *args, **options):
--        ldap = self.api.Backend.ldap2
--        dns_enabled = False
--
--        try:
--            ldap.find_entries(filter=self.filter, base_dn=self.base_dn)
--            dns_enabled = True
--        except errors.EmptyResult:
--            dns_enabled = False
--
-+        dns_enabled = is_service_enabled('DNS', conn=self.api.Backend.ldap2)
-         return dict(result=dns_enabled, value=pkey_to_value(None, options))
- 
- 
-diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py
-index 1aa19ab3c2763983b2216e332013b45df1a4a496..980385dc83e93ec4a65726077b34917e21115efa 100644
---- a/ipaserver/plugins/user.py
-+++ b/ipaserver/plugins/user.py
-@@ -69,6 +69,7 @@ from ipapython.dn import DN
- from ipapython.ipaldap import LDAPClient
- from ipapython.ipautil import ipa_generate_password, TMP_PWD_ENTROPY_BITS
- from ipalib.capabilities import client_has_capability
-+from ipaserver.masters import get_masters
- 
- if six.PY3:
-     unicode = str
-@@ -1105,21 +1106,11 @@ class user_status(LDAPQuery):
-         attr_list = ['krbloginfailedcount', 'krblastsuccessfulauth', 'krblastfailedauth', 'nsaccountlock']
- 
-         disabled = False
--        masters = []
--        # Get list of masters
--        try:
--            masters, _truncated = ldap.find_entries(
--                None, ['*'], DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn),
--                ldap.SCOPE_ONELEVEL
--            )
--        except errors.NotFound:
--            # If this happens we have some pretty serious problems
--            logger.error('No IPA masters found!')
-+        masters = get_masters(ldap)
- 
-         entries = []
-         count = 0
--        for master in masters:
--            host = master['cn'][0]
-+        for host in masters:
-             if host == api.env.host:
-                 other_ldap = self.obj.backend
-             else:
-diff --git a/ipaserver/plugins/vault.py b/ipaserver/plugins/vault.py
-index 682f6bea74df024bd28e15157c9b809888d08c38..a2603217cc3b79c6ec891b4deadeea91364eeeb9 100644
---- a/ipaserver/plugins/vault.py
-+++ b/ipaserver/plugins/vault.py
-@@ -34,6 +34,7 @@ from .service import normalize_principal, validate_realm
- from ipalib import _, ngettext
- from ipapython import kerberos
- from ipapython.dn import DN
-+from ipaserver.masters import is_service_enabled
- 
- if api.env.in_server:
-     import pki.account
-@@ -1220,14 +1221,5 @@ class kra_is_enabled(Command):
-     has_output = output.standard_value
- 
-     def execute(self, *args, **options):
--        base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
--                     self.api.env.basedn)
--        filter = '(&(objectClass=ipaConfigObject)(cn=KRA))'
--        try:
--            self.api.Backend.ldap2.find_entries(
--                base_dn=base_dn, filter=filter, attrs_list=[])
--        except errors.NotFound:
--            result = False
--        else:
--            result = True
-+        result = is_service_enabled('KRA', conn=self.api.Backend.ldap2)
-         return dict(result=result, value=pkey_to_value(None, options))
--- 
-2.20.1
-
diff --git a/SOURCES/0006-user-stage-transfer-all-attributes-from-preserved-to.patch b/SOURCES/0006-user-stage-transfer-all-attributes-from-preserved-to.patch
new file mode 100644
index 0000000..a5276e5
--- /dev/null
+++ b/SOURCES/0006-user-stage-transfer-all-attributes-from-preserved-to.patch
@@ -0,0 +1,104 @@
+From 5731aa2850d150a90ad84ce5492cd5d8b154e413 Mon Sep 17 00:00:00 2001
+From: Florence Blanc-Renaud <flo@redhat.com>
+Date: Tue, 23 Jul 2019 09:31:53 +0200
+Subject: [PATCH] user-stage: transfer all attributes from preserved to stage
+ user
+
+The user-stage command is internally implemented as:
+- user_show(all=True) in order to read the user attributes
+- loop on the attributes defined as possible to add using stageuser-add and
+transform them into new options for stageuser_add (for instance stageuser-add
+provides the option --shell for the attribute loginshell, but there is no
+option for the attribute businesscategory).
+- call stageuser_add in order to create a new entry in the active users subtree
+- user-del to remove the previous entry in the staged users subtree
+
+The issue is in the 2nd step. Only the attributes with a stageuser-add option
+are processed.
+The logic of the code should be slightly modified, so that all the attributes
+read in the first step are processed:
+- if they correspond to an option of stageuser-add, process them like it's
+currently done. For instance if the entry contains displayname, then it
+should be processed as --displayName=value in the stageuser-add cmd
+- if they do not correspond to an option of stageuser-add, add them with
+--setattr=<attrname>=<attrvalue>
+
+Note that some attributes may need to be filtered, for instance user-show
+returns has_password or has_keytab, which do not correspond to attributes
+in the LDAP entry.
+
+Fixes: https://pagure.io/freeipa/issue/7597
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+---
+ ipaserver/plugins/user.py | 44 +++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 44 insertions(+)
+
+diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py
+index 980385dc83e93ec4a65726077b34917e21115efa..fbf7b11789c58377366f187211c4e403d0cf7ffe 100644
+--- a/ipaserver/plugins/user.py
++++ b/ipaserver/plugins/user.py
+@@ -919,7 +919,29 @@ class user_stage(LDAPMultiQuery):
+     has_output = output.standard_multi_delete
+     msg_summary = _('Staged user account "%(value)s"')
+ 
++    # when moving from preserved to stage, some attributes may be
++    # present in the preserved entry but cannot be provided to
++    # stageuser_add
++    # For instance: dn and uid are derived from LOGIN argument
++    #    has_keytab, has_password, preserved are virtual attributes
++    #    ipauniqueid, krbcanonicalname, sshpubkeyfp, krbextradata
++    #    are automatically generated
++    #    ipacertmapdata can only be provided with user_add_certmapdata
++    ignore_attrs = [u'dn', u'uid',
++                    u'has_keytab', u'has_password', u'preserved',
++                    u'ipauniqueid', u'krbcanonicalname',
++                    u'sshpubkeyfp', u'krbextradata',
++                    u'ipacertmapdata',
++                    u'nsaccountlock']
++
+     def execute(self, *keys, **options):
++
++        def _build_setattr_arg(key, val):
++            if isinstance(val, bytes):
++                return u"{}={}".format(key, val.decode('UTF-8'))
++            else:
++                return u"{}={}".format(key, val)
++
+         staged = []
+         failed = []
+ 
+@@ -940,8 +962,30 @@ class user_stage(LDAPMultiQuery):
+                     value = value[0]
+                 new_options[param.name] = value
+ 
++            # Some attributes may not be accessible through the Command
++            # options and need to be added with --setattr
++            set_attr = []
++            for userkey in user.keys():
++                if userkey in new_options or userkey in self.ignore_attrs:
++                    continue
++                value = user[userkey]
++
++                if isinstance(value, (list, tuple)):
++                    for val in value:
++                        set_attr.append(_build_setattr_arg(userkey, val))
++                else:
++                    set_attr.append(_build_setattr_arg(userkey, val))
++            if set_attr:
++                new_options[u'setattr'] = set_attr
++
+             try:
+                 self.api.Command.stageuser_add(*single_keys, **new_options)
++                # special handling for certmapdata
++                certmapdata = user.get(u'ipacertmapdata')
++                if certmapdata:
++                    self.api.Command.stageuser_add_certmapdata(
++                        *single_keys,
++                        ipacertmapdata=certmapdata)
+                 try:
+                     self.api.Command.user_del(*multi_keys, preserve=False)
+                 except errors.ExecutionError:
+-- 
+2.20.1
+
diff --git a/SOURCES/0007-Replace-hard-coded-paths-with-path-constants.patch b/SOURCES/0007-Replace-hard-coded-paths-with-path-constants.patch
deleted file mode 100644
index c84eb02..0000000
--- a/SOURCES/0007-Replace-hard-coded-paths-with-path-constants.patch
+++ /dev/null
@@ -1,570 +0,0 @@
-From f4995135a97531819503632e72f9910101f5ce61 Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Wed, 7 Feb 2018 17:18:07 +0100
-Subject: [PATCH] Replace hard-coded paths with path constants
-
-Several run() calls used hard-coded paths rather than pre-defined paths
-from ipaplatform.paths. The patch fixes all places that I was able to
-find with a simple search.
-
-The fix simplifies Darix's port of freeIPA on openSuSE.
-
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Rob Crittenden <rcritten@redhat.com>
-(cherry picked from commit 2391c75e3d7efcdc5c2f49defa5138fc7e6def06)
-
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- client/ipa-client-automount                   |  2 +-
- install/tools/ipa-adtrust-install             |  2 +-
- install/tools/ipa-ca-install                  |  2 +-
- install/tools/ipa-dns-install                 |  2 +-
- ipaclient/install/client.py                   | 10 ++++----
- ipaplatform/base/paths.py                     |  8 +++++++
- ipapython/kernel_keyring.py                   | 24 +++++++++++++------
- ipaserver/install/adtrustinstance.py          |  6 +++--
- ipaserver/install/installutils.py             | 17 +++++++++----
- ipaserver/install/ipa_backup.py               |  6 ++---
- ipaserver/install/ipa_restore.py              |  4 ++--
- ipaserver/install/krbinstance.py              |  2 +-
- ipatests/pytest_ipa/integration/__init__.py   |  3 ++-
- ipatests/test_integration/test_caless.py      |  2 +-
- ipatests/test_ipapython/test_ipautil.py       | 15 ++++++------
- .../test_caacl_profile_enforcement.py         |  3 ++-
- ipatests/test_xmlrpc/test_cert_plugin.py      |  2 +-
- 17 files changed, 70 insertions(+), 40 deletions(-)
-
-diff --git a/client/ipa-client-automount b/client/ipa-client-automount
-index ee55d655c9531c8fb7baebd0e7a99f3db484f7db..6c2816c410642967e95a7b1eb60583600a7f5fb0 100755
---- a/client/ipa-client-automount
-+++ b/client/ipa-client-automount
-@@ -92,7 +92,7 @@ def wait_for_sssd():
-     time.sleep(1)
-     while n < 10 and not found:
-         try:
--            ipautil.run(["getent", "passwd", "admin@%s" % api.env.realm])
-+            ipautil.run([paths.GETENT, "passwd", "admin@%s" % api.env.realm])
-             found = True
-         except Exception:
-             time.sleep(1)
-diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install
-index a870d136e242affe6627cd4c44a173a80a9ab1c6..9dbfadb6fae193e2f4a54b3a0e226e0a6b1fd26f 100755
---- a/install/tools/ipa-adtrust-install
-+++ b/install/tools/ipa-adtrust-install
-@@ -110,7 +110,7 @@ def read_admin_password(admin_name):
- 
- def ensure_admin_kinit(admin_name, admin_password):
-     try:
--        ipautil.run(['kinit', admin_name], stdin=admin_password+'\n')
-+        ipautil.run([paths.KINIT, admin_name], stdin=admin_password+'\n')
-     except ipautil.CalledProcessError:
-         print("There was error to automatically re-kinit your admin user "
-               "ticket.")
-diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install
-index dcdbe884f15b13b92ec68a11d9f00e3e28771b42..55182dc30e4736618f749e78db161fc7eefe37ac 100755
---- a/install/tools/ipa-ca-install
-+++ b/install/tools/ipa-ca-install
-@@ -352,7 +352,7 @@ def main():
-     api.Backend.ldap2.disconnect()
- 
-     # execute ipactl to refresh services status
--    ipautil.run(['ipactl', 'start', '--ignore-service-failures'],
-+    ipautil.run([paths.IPACTL, 'start', '--ignore-service-failures'],
-                 raiseonerr=False)
- 
- 
-diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install
-index 32a17d223ae2bdd9a1ded62defcc272a40d2627b..0e76a5ab93bd37c2f0c9c5ea4894023588697782 100755
---- a/install/tools/ipa-dns-install
-+++ b/install/tools/ipa-dns-install
-@@ -151,7 +151,7 @@ def main():
-     # Services are enabled in dns_installer.install()
- 
-     # execute ipactl to refresh services status
--    ipautil.run(['ipactl', 'start', '--ignore-service-failures'],
-+    ipautil.run([paths.IPACTL, 'start', '--ignore-service-failures'],
-                 raiseonerr=False)
- 
-     api.Backend.ldap2.disconnect()
-diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py
-index 80b572ce9b5a250c0c32a1d7fcd06ec53af32984..babebfc667c5a096fb2e0238de444ffa3ce62b77 100644
---- a/ipaclient/install/client.py
-+++ b/ipaclient/install/client.py
-@@ -1125,7 +1125,7 @@ def configure_sshd_config(fstore, options):
-         )
- 
-         for candidate in candidates:
--            args = ['sshd', '-t', '-f', os.devnull]
-+            args = [paths.SSHD, '-t', '-f', os.devnull]
-             for item in candidate.items():
-                 args.append('-o')
-                 args.append('%s=%s' % item)
-@@ -1157,7 +1157,7 @@ def configure_automount(options):
-     logger.info('\nConfiguring automount:')
- 
-     args = [
--        'ipa-client-automount', '--debug', '-U', '--location',
-+        paths.IPA_CLIENT_AUTOMOUNT, '--debug', '-U', '--location',
-         options.location
-     ]
- 
-@@ -2615,7 +2615,7 @@ def _install(options):
-                 subject_base = DN(subject_base)
- 
-             if options.principal is not None:
--                run(["kdestroy"], raiseonerr=False, env=env)
-+                run([paths.KDESTROY], raiseonerr=False, env=env)
- 
-             # Obtain the TGT. We do it with the temporary krb5.conf, so that
-             # only the KDC we're installing under is contacted.
-@@ -2954,7 +2954,7 @@ def _install(options):
-             # Particulary, SSSD might take longer than 6-8 seconds.
-             while n < 10 and not found:
-                 try:
--                    ipautil.run(["getent", "passwd", user])
-+                    ipautil.run([paths.GETENT, "passwd", user])
-                     found = True
-                 except Exception as e:
-                     time.sleep(1)
-@@ -3036,7 +3036,7 @@ def uninstall(options):
-     statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE)
- 
-     try:
--        run(["ipa-client-automount", "--uninstall", "--debug"])
-+        run([paths.IPA_CLIENT_AUTOMOUNT, "--uninstall", "--debug"])
-     except Exception as e:
-         logger.error(
-             "Unconfigured automount client failed: %s", str(e))
-diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
-index f1327daa11840bb9416cb0a12f2b5a1300b0374b..435d1b7de9083ee74e80da6fef5c3e3cdad654bb 100644
---- a/ipaplatform/base/paths.py
-+++ b/ipaplatform/base/paths.py
-@@ -25,6 +25,8 @@ This base platform module exports default filesystem paths.
- class BasePathNamespace(object):
-     BASH = "/bin/bash"
-     BIN_HOSTNAMECTL = "/bin/hostnamectl"
-+    ECHO = "/bin/echo"
-+    GZIP = "/usr/bin/gzip"
-     LS = "/bin/ls"
-     SH = "/bin/sh"
-     SYSTEMCTL = "/bin/systemctl"
-@@ -160,8 +162,10 @@ class BasePathNamespace(object):
-     GPG = "/usr/bin/gpg"
-     GPG_AGENT = "/usr/bin/gpg-agent"
-     IPA_GETCERT = "/usr/bin/ipa-getcert"
-+    KADMIN_LOCAL = '/usr/sbin/kadmin.local'
-     KDESTROY = "/usr/bin/kdestroy"
-     KINIT = "/usr/bin/kinit"
-+    KLIST = "/usr/bin/klist"
-     BIN_KVNO = "/usr/bin/kvno"
-     LDAPMODIFY = "/usr/bin/ldapmodify"
-     LDAPPASSWD = "/usr/bin/ldappasswd"
-@@ -207,6 +211,7 @@ class BasePathNamespace(object):
-     GROUPADD = "/usr/sbin/groupadd"
-     USERMOD = "/usr/sbin/usermod"
-     HTTPD = "/usr/sbin/httpd"
-+    IPA_CLIENT_AUTOMOUNT = "/usr/sbin/ipa-client-automount"
-     IPA_CLIENT_INSTALL = "/usr/sbin/ipa-client-install"
-     IPA_DNS_INSTALL = "/usr/sbin/ipa-dns-install"
-     SBIN_IPA_JOIN = "/usr/sbin/ipa-join"
-@@ -362,6 +367,9 @@ class BasePathNamespace(object):
-     IF_INET6 = '/proc/net/if_inet6'
-     AUTHCONFIG = None
-     IPA_SERVER_UPGRADE = '/usr/sbin/ipa-server-upgrade'
-+    KEYCTL = '/usr/bin/keyctl'
-+    GETENT = '/usr/bin/getent'
-+    SSHD = '/usr/sbin/sshd'
- 
- 
- paths = BasePathNamespace()
-diff --git a/ipapython/kernel_keyring.py b/ipapython/kernel_keyring.py
-index 4b7010e32e90a52fefb0ebbd4fec930ae82b7ea6..6ae1e74493810fa25093fe134447dd4ba0f5da74 100644
---- a/ipapython/kernel_keyring.py
-+++ b/ipapython/kernel_keyring.py
-@@ -23,6 +23,7 @@ import os
- import six
- 
- from ipapython.ipautil import run
-+from ipaplatform.paths import paths
- 
- # NOTE: Absolute path not required for keyctl since we reset the environment
- #       in ipautil.run.
-@@ -35,34 +36,38 @@ from ipapython.ipautil import run
- KEYRING = '@s'
- KEYTYPE = 'user'
- 
-+
- def dump_keys():
-     """
-     Dump all keys
-     """
--    result = run(['keyctl', 'list', KEYRING], raiseonerr=False,
-+    result = run([paths.KEYCTL, 'list', KEYRING], raiseonerr=False,
-                  capture_output=True)
-     return result.output
- 
-+
- def get_real_key(key):
-     """
-     One cannot request a key based on the description it was created with
-     so find the one we're looking for.
-     """
-     assert isinstance(key, six.string_types)
--    result = run(['keyctl', 'search', KEYRING, KEYTYPE, key],
-+    result = run([paths.KEYCTL, 'search', KEYRING, KEYTYPE, key],
-                  raiseonerr=False, capture_output=True)
-     if result.returncode:
-         raise ValueError('key %s not found' % key)
-     return result.raw_output.rstrip()
- 
-+
- def get_persistent_key(key):
-     assert isinstance(key, six.string_types)
--    result = run(['keyctl', 'get_persistent', KEYRING, key],
-+    result = run([paths.KEYCTL, 'get_persistent', KEYRING, key],
-                  raiseonerr=False, capture_output=True)
-     if result.returncode:
-         raise ValueError('persistent key %s not found' % key)
-     return result.raw_output.rstrip()
- 
-+
- def is_persistent_keyring_supported():
-     uid = os.geteuid()
-     try:
-@@ -72,6 +77,7 @@ def is_persistent_keyring_supported():
- 
-     return True
- 
-+
- def has_key(key):
-     """
-     Returns True/False whether the key exists in the keyring.
-@@ -83,6 +89,7 @@ def has_key(key):
-     except ValueError:
-         return False
- 
-+
- def read_key(key):
-     """
-     Read the keyring and return the value for key.
-@@ -91,13 +98,14 @@ def read_key(key):
-     """
-     assert isinstance(key, six.string_types)
-     real_key = get_real_key(key)
--    result = run(['keyctl', 'pipe', real_key], raiseonerr=False,
-+    result = run([paths.KEYCTL, 'pipe', real_key], raiseonerr=False,
-                  capture_output=True)
-     if result.returncode:
-         raise ValueError('keyctl pipe failed: %s' % result.error_log)
- 
-     return result.raw_output
- 
-+
- def update_key(key, value):
-     """
-     Update the keyring data. If they key doesn't exist it is created.
-@@ -106,13 +114,14 @@ def update_key(key, value):
-     assert isinstance(value, bytes)
-     if has_key(key):
-         real_key = get_real_key(key)
--        result = run(['keyctl', 'pupdate', real_key], stdin=value,
-+        result = run([paths.KEYCTL, 'pupdate', real_key], stdin=value,
-                      raiseonerr=False)
-         if result.returncode:
-             raise ValueError('keyctl pupdate failed: %s' % result.error_log)
-     else:
-         add_key(key, value)
- 
-+
- def add_key(key, value):
-     """
-     Add a key to the kernel keyring.
-@@ -121,18 +130,19 @@ def add_key(key, value):
-     assert isinstance(value, bytes)
-     if has_key(key):
-         raise ValueError('key %s already exists' % key)
--    result = run(['keyctl', 'padd', KEYTYPE, key, KEYRING],
-+    result = run([paths.KEYCTL, 'padd', KEYTYPE, key, KEYRING],
-                  stdin=value, raiseonerr=False)
-     if result.returncode:
-         raise ValueError('keyctl padd failed: %s' % result.error_log)
- 
-+
- def del_key(key):
-     """
-     Remove a key from the keyring
-     """
-     assert isinstance(key, six.string_types)
-     real_key = get_real_key(key)
--    result = run(['keyctl', 'unlink', real_key, KEYRING],
-+    result = run([paths.KEYCTL, 'unlink', real_key, KEYRING],
-                  raiseonerr=False)
-     if result.returncode:
-         raise ValueError('keyctl unlink failed: %s' % result.error_log)
-diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
-index 1f875c26fe909428ebf2e9c2acc9a8ad70de9a72..e787fccb9482809b180012ed8e7be2e5a6494f93 100644
---- a/ipaserver/install/adtrustinstance.py
-+++ b/ipaserver/install/adtrustinstance.py
-@@ -555,8 +555,10 @@ class ADTRUSTInstance(service.Service):
-     def clean_samba_keytab(self):
-         if os.path.exists(self.keytab):
-             try:
--                ipautil.run(["ipa-rmkeytab", "--principal", self.principal,
--                             "-k", self.keytab])
-+                ipautil.run([
-+                    paths.IPA_RMKEYTAB, "--principal", self.principal,
-+                    "-k", self.keytab
-+                ])
-             except ipautil.CalledProcessError as e:
-                 if e.returncode != 5:
-                     logger.critical("Failed to remove old key for %s",
-diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
-index 005fbeef37309ee3891e82ac0727adb031213da6..e110a5c3fc3e214736cb650f6da8a330eaa665a2 100644
---- a/ipaserver/install/installutils.py
-+++ b/ipaserver/install/installutils.py
-@@ -599,19 +599,26 @@ def get_directive(filename, directive, separator=' '):
-     fd.close()
-     return None
- 
-+
- def kadmin(command):
--    return ipautil.run(["kadmin.local", "-q", command,
--                        "-x", "ipa-setup-override-restrictions"],
--                       capture_output=True,
--                       capture_error=True)
-+    return ipautil.run(
-+        [
-+            paths.KADMIN_LOCAL, "-q", command,
-+            "-x", "ipa-setup-override-restrictions"
-+        ],
-+        capture_output=True,
-+        capture_error=True
-+    )
- 
- 
- def kadmin_addprinc(principal):
-     return kadmin("addprinc -randkey " + principal)
- 
-+
- def kadmin_modprinc(principal, options):
-     return kadmin("modprinc " + options + " " + principal)
- 
-+
- def create_keytab(path, principal):
-     try:
-         if os.path.isfile(path):
-@@ -832,7 +839,7 @@ def expand_replica_info(filename, password):
-     tarfile = top_dir+"/files.tar"
-     dir_path = top_dir + "/realm_info"
-     decrypt_file(filename, tarfile, password, top_dir)
--    ipautil.run(["tar", "xf", tarfile, "-C", top_dir])
-+    ipautil.run([paths.TAR, "xf", tarfile, "-C", top_dir])
-     os.remove(tarfile)
- 
-     return top_dir, dir_path
-diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py
-index cef01d30454ea1adb8bf9c68f428b9555f1b9557..db4b28c6deebd833855c32c5ff832dad3e5c741e 100644
---- a/ipaserver/install/ipa_backup.py
-+++ b/ipaserver/install/ipa_backup.py
-@@ -314,7 +314,7 @@ class Backup(admintool.AdminTool):
-                     dirsrv.stop(capture_output=False)
-             else:
-                 logger.info('Stopping IPA services')
--                run(['ipactl', 'stop'])
-+                run([paths.IPACTL, 'stop'])
- 
-             instance = installutils.realm_to_serverid(api.env.realm)
-             if os.path.exists(paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE %
-@@ -336,7 +336,7 @@ class Backup(admintool.AdminTool):
-                     dirsrv.start(capture_output=False)
-             else:
-                 logger.info('Starting IPA service')
--                run(['ipactl', 'start'])
-+                run([paths.IPACTL, 'start'])
- 
-             # Compress after services are restarted to minimize
-             # the unavailability window
-@@ -549,7 +549,7 @@ class Backup(admintool.AdminTool):
-         # Compress the archive. This is done separately, since 'tar' cannot
-         # append to a compressed archive.
-         if self.tarfile:
--            result = run(['gzip', self.tarfile], raiseonerr=False)
-+            result = run([paths.GZIP, self.tarfile], raiseonerr=False)
-             if result.returncode != 0:
-                 raise admintool.ScriptError(
-                     'gzip returned non-zero code %d '
-diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py
-index c7e996bbe284a7eb2d03fbedb4798d3b15f3dcc0..4941831585f473c4937b23b3f59d8ff99a654b0e 100644
---- a/ipaserver/install/ipa_restore.py
-+++ b/ipaserver/install/ipa_restore.py
-@@ -386,7 +386,7 @@ class Restore(admintool.AdminTool):
-                     dirsrv.start(capture_output=False)
-             else:
-                 logger.info('Stopping IPA services')
--                result = run(['ipactl', 'stop'], raiseonerr=False)
-+                result = run([paths.IPACTL, 'stop'], raiseonerr=False)
-                 if result.returncode not in [0, 6]:
-                     logger.warning('Stopping IPA failed: %s', result.error_log)
- 
-@@ -426,7 +426,7 @@ class Restore(admintool.AdminTool):
-                 gssproxy = services.service('gssproxy', api)
-                 gssproxy.reload_or_restart()
-                 logger.info('Starting IPA services')
--                run(['ipactl', 'start'])
-+                run([paths.IPACTL, 'start'])
-                 logger.info('Restarting SSSD')
-                 sssd = services.service('sssd', api)
-                 sssd.restart()
-diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py
-index 319eeb82bcbe61acd70b2943982b6fec6fa33f92..139803ffbe26a6197535e66b63ba566c2a917e01 100644
---- a/ipaserver/install/krbinstance.py
-+++ b/ipaserver/install/krbinstance.py
-@@ -346,7 +346,7 @@ class KrbInstance(service.Service):
-         MIN_KRB5KDC_WITH_WORKERS = "1.9"
-         cpus = os.sysconf('SC_NPROCESSORS_ONLN')
-         workers = False
--        result = ipautil.run(['klist', '-V'],
-+        result = ipautil.run([paths.KLIST, '-V'],
-                              raiseonerr=False, capture_output=True)
-         if result.returncode == 0:
-             verstr = result.output.split()[-1]
-diff --git a/ipatests/pytest_ipa/integration/__init__.py b/ipatests/pytest_ipa/integration/__init__.py
-index fb9990a15b8e28dbe27f2b9275e4877e00f25755..7c1eb2232e2362b8f691329d9a022391a0e79d91 100644
---- a/ipatests/pytest_ipa/integration/__init__.py
-+++ b/ipatests/pytest_ipa/integration/__init__.py
-@@ -31,6 +31,7 @@ import pytest
- from pytest_multihost import make_multihost_fixture
- 
- from ipapython import ipautil
-+from ipaplatform.paths import paths
- from ipatests.test_util import yield_fixture
- from .config import Config
- from .env_config import get_global_config
-@@ -150,7 +151,7 @@ def collect_logs(name, logs_dict, logfile_dir=None, beakerlib_plugin=None):
-             # delete from remote
-             host.run_command(['rm', '-f', tmpname])
-             # Unpack on the local side
--            ipautil.run(['tar', 'xJvf', 'logs.tar.xz'], cwd=dirname,
-+            ipautil.run([paths.TAR, 'xJvf', 'logs.tar.xz'], cwd=dirname,
-                         raiseonerr=False)
-             os.unlink(tarname)
- 
-diff --git a/ipatests/test_integration/test_caless.py b/ipatests/test_integration/test_caless.py
-index f93bdc976e03e23536c4cb2dc7401d44ddddcea1..ff8d95caa6fed00d3876f1d08e2170a9587a6d86 100644
---- a/ipatests/test_integration/test_caless.py
-+++ b/ipatests/test_integration/test_caless.py
-@@ -336,7 +336,7 @@ class CALessBase(IntegrationTest):
-                 with open(cert_fname) as cert:
-                     chain.write(cert.read())
- 
--        ipautil.run(["openssl", "pkcs12", "-export", "-out", filename,
-+        ipautil.run([paths.OPENSSL, "pkcs12", "-export", "-out", filename,
-                      "-inkey", key_fname, "-in", certchain_fname, "-passin",
-                      "pass:" + cls.cert_password, "-passout", "pass:" +
-                      password, "-name", nickname], cwd=cls.cert_dir)
-diff --git a/ipatests/test_ipapython/test_ipautil.py b/ipatests/test_ipapython/test_ipautil.py
-index e15b4f948e8c6f927ee5594780609dace0345d28..88b591e5cb173799c2d5dffddadcfe65958b7c6b 100644
---- a/ipatests/test_ipapython/test_ipautil.py
-+++ b/ipatests/test_ipapython/test_ipautil.py
-@@ -30,6 +30,7 @@ import pytest
- import six
- import tempfile
- 
-+from ipaplatform.paths import paths
- from ipalib.constants import IPAAPI_USER
- from ipapython import ipautil
- 
-@@ -419,7 +420,7 @@ class TestTimeParser(object):
- 
- 
- def test_run():
--    result = ipautil.run(['echo', 'foo\x02bar'],
-+    result = ipautil.run([paths.ECHO, 'foo\x02bar'],
-                          capture_output=True,
-                          capture_error=True)
-     assert result.returncode == 0
-@@ -430,7 +431,7 @@ def test_run():
- 
- 
- def test_run_no_capture_output():
--    result = ipautil.run(['echo', 'foo\x02bar'])
-+    result = ipautil.run([paths.ECHO, 'foo\x02bar'])
-     assert result.returncode == 0
-     assert result.output is None
-     assert result.raw_output == b'foo\x02bar\n'
-@@ -439,13 +440,13 @@ def test_run_no_capture_output():
- 
- 
- def test_run_bytes():
--    result = ipautil.run(['echo', b'\x01\x02'], capture_output=True)
-+    result = ipautil.run([paths.ECHO, b'\x01\x02'], capture_output=True)
-     assert result.returncode == 0
-     assert result.raw_output == b'\x01\x02\n'
- 
- 
- def test_run_decode():
--    result = ipautil.run(['echo', u'á'.encode('utf-8')],
-+    result = ipautil.run([paths.ECHO, u'á'.encode('utf-8')],
-                          encoding='utf-8', capture_output=True)
-     assert result.returncode == 0
-     if six.PY3:
-@@ -457,11 +458,11 @@ def test_run_decode():
- def test_run_decode_bad():
-     if six.PY3:
-         with pytest.raises(UnicodeDecodeError):
--            ipautil.run(['echo', b'\xa0\xa1'],
-+            ipautil.run([paths.ECHO, b'\xa0\xa1'],
-                         capture_output=True,
-                         encoding='utf-8')
-     else:
--        result = ipautil.run(['echo', '\xa0\xa1'],
-+        result = ipautil.run([paths.ECHO, '\xa0\xa1'],
-                              capture_output=True,
-                              encoding='utf-8')
-         assert result.returncode == 0
-@@ -469,7 +470,7 @@ def test_run_decode_bad():
- 
- 
- def test_backcompat():
--    result = out, err, rc = ipautil.run(['echo', 'foo\x02bar'],
-+    result = out, err, rc = ipautil.run([paths.ECHO, 'foo\x02bar'],
-                                         capture_output=True,
-                                         capture_error=True)
-     assert rc is result.returncode
-diff --git a/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py b/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py
-index 931f7aff344859ee62e8e195a5fa76a1b4807eb1..6ed6cbf34c62bb83b6ebaf84cc3b105d6f76aea6 100644
---- a/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py
-+++ b/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py
-@@ -18,6 +18,7 @@ from cryptography.hazmat.primitives import hashes, serialization
- from cryptography.hazmat.primitives.asymmetric import rsa
- 
- from ipalib import api, errors
-+from ipaplatform.paths import paths
- from ipatests.util import (
-     prepare_config, unlock_principal_password, change_principal,
-     host_keytab)
-@@ -50,7 +51,7 @@ def generate_user_csr(username, domain=None):
-         username=username)
- 
-     with tempfile.NamedTemporaryFile(mode='w') as csr_file:
--        run(['openssl', 'req', '-new', '-key', CERT_RSA_PRIVATE_KEY_PATH,
-+        run([paths.OPENSSL, 'req', '-new', '-key', CERT_RSA_PRIVATE_KEY_PATH,
-              '-out', csr_file.name,
-              '-config', prepare_config(
-                  CERT_OPENSSL_CONFIG_TEMPLATE, csr_values)])
-diff --git a/ipatests/test_xmlrpc/test_cert_plugin.py b/ipatests/test_xmlrpc/test_cert_plugin.py
-index 9001e7f0989764a904275d11c5d96afc53322054..16f2058b1a9a38ec76479a184a23214275f5f551 100644
---- a/ipatests/test_xmlrpc/test_cert_plugin.py
-+++ b/ipatests/test_xmlrpc/test_cert_plugin.py
-@@ -176,7 +176,7 @@ class test_cert(BaseCert):
-         result = api.Command.cert_show(sn, out=unicode(self.certfile))
-         with open(self.certfile, "rb") as f:
-             pem_cert = f.read().decode('ascii')
--        result = run(['openssl', 'x509', '-text'],
-+        result = run([paths.OPENSSL, 'x509', '-text'],
-                      stdin=pem_cert, capture_output=True)
-         assert _EXP_CRL_URI in result.output
-         assert _EXP_OCSP_URI in result.output
--- 
-2.20.1
-
diff --git a/SOURCES/0007-xmlrpc-test-add-test-for-preserved-stage-user.patch b/SOURCES/0007-xmlrpc-test-add-test-for-preserved-stage-user.patch
new file mode 100644
index 0000000..b82f87b
--- /dev/null
+++ b/SOURCES/0007-xmlrpc-test-add-test-for-preserved-stage-user.patch
@@ -0,0 +1,128 @@
+From bcfbeef0ca7f69ff50f40990e783d58fb9a83d30 Mon Sep 17 00:00:00 2001
+From: Florence Blanc-Renaud <flo@redhat.com>
+Date: Fri, 26 Jul 2019 15:44:58 +0200
+Subject: [PATCH] xmlrpc test: add test for preserved > stage user
+
+When moving a preserved user to the stage area, check that the
+custom attributes are not lost ( = the attr for which there is
+no specific user_stage option).
+
+Test scenario:
+- add a stage user with --setattr "businesscategory=value"
+- activate the user, check that businesscategory is still present
+- delete (preserve) the user, check that attr is still present
+- stage the user, check that attr is still present
+
+Related: https://pagure.io/freeipa/issue/7597
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+---
+ ipatests/test_xmlrpc/test_stageuser_plugin.py | 64 +++++++++++++++++++
+ .../test_xmlrpc/tracker/stageuser_plugin.py   |  5 +-
+ 2 files changed, 67 insertions(+), 2 deletions(-)
+
+diff --git a/ipatests/test_xmlrpc/test_stageuser_plugin.py b/ipatests/test_xmlrpc/test_stageuser_plugin.py
+index 9a869259d06a65722f019a19405baf53c03917e1..cc6a3b1a880acab1ffba06061be6eae229f80237 100644
+--- a/ipatests/test_xmlrpc/test_stageuser_plugin.py
++++ b/ipatests/test_xmlrpc/test_stageuser_plugin.py
+@@ -128,6 +128,17 @@ def stageduser_notposix(request):
+     return tracker.make_fixture(request)
+ 
+ 
++@pytest.fixture(scope='class')
++def stageduser_customattr(request):
++    tracker = StageUserTracker(u'customattr', u'customattr', u'customattr',
++                               setattr=u'businesscategory=BusinessCat')
++    tracker.track_create()
++    tracker.attrs.update(
++        businesscategory=[u'BusinessCat']
++    )
++    return tracker.make_fixture(request)
++
++
+ @pytest.fixture(scope='class')
+ def user(request):
+     tracker = UserTracker(u'auser1', u'active', u'user')
+@@ -573,6 +584,59 @@ class TestPreserved(XMLRPC_test):
+         stageduser.delete()
+ 
+ 
++@pytest.mark.tier1
++class TestCustomAttr(XMLRPC_test):
++    """Test for pagure ticket 7597
++
++    When a staged user is activated, preserved and finally staged again,
++    the custom attributes are lost.
++    """
++    def test_stageduser_customattr(self, stageduser_customattr):
++        # Create a staged user with attributes not accessible
++        # through the options
++        # --setattr is needed here
++        command = stageduser_customattr.make_create_command()
++        result = command()
++        stageduser_customattr.check_create(result, [u'businesscategory'])
++
++        # Activate the staged user
++        user_customattr = UserTracker(
++            stageduser_customattr.uid, stageduser_customattr.givenname,
++            stageduser_customattr.sn)
++        user_customattr.create_from_staged(stageduser_customattr)
++        user_customattr.attrs[u'businesscategory'] = [u'BusinessCat']
++
++        command = stageduser_customattr.make_activate_command()
++        result = command()
++        user_customattr.check_activate(result)
++
++        # Check that the user contains businesscategory
++        command = user_customattr.make_retrieve_command(all=True)
++        result = command()
++        assert 'BusinessCat' in result['result'][u'businesscategory']
++
++        # delete the user with --preserve
++        command = user_customattr.make_delete_command(no_preserve=False,
++                                                      preserve=True)
++        result = command()
++        user_customattr.check_delete(result)
++
++        # Check that the preserved user contains businesscategory
++        command = user_customattr.make_retrieve_command(all=True)
++        result = command()
++        assert 'BusinessCat' in result['result'][u'businesscategory']
++
++        # Move the user from preserved to stage
++        command = user_customattr.make_stage_command()
++        result = command()
++        stageduser_customattr.check_restore_preserved(result)
++
++        # Check that the stage user contains businesscategory
++        command = stageduser_customattr.make_retrieve_command(all=True)
++        result = command()
++        assert 'BusinessCat' in result['result'][u'businesscategory']
++
++
+ @pytest.mark.tier1
+ class TestManagers(XMLRPC_test):
+     def test_staged_manager(self, user, stageduser):
+diff --git a/ipatests/test_xmlrpc/tracker/stageuser_plugin.py b/ipatests/test_xmlrpc/tracker/stageuser_plugin.py
+index c2ab1d35c0b64980eae37f75db081b948c992b00..7609664ab4f3dc3d17b33c9ba4fa855f61a8b106 100644
+--- a/ipatests/test_xmlrpc/tracker/stageuser_plugin.py
++++ b/ipatests/test_xmlrpc/tracker/stageuser_plugin.py
+@@ -176,12 +176,13 @@ class StageUserTracker(KerberosAliasMixin, Tracker):
+ 
+         self.exists = True
+ 
+-    def check_create(self, result):
++    def check_create(self, result, extra_keys=()):
+         """ Check 'stageuser-add' command result """
++        expected = self.filter_attrs(self.create_keys | set(extra_keys))
+         assert_deepequal(dict(
+             value=self.uid,
+             summary=u'Added stage user "%s"' % self.uid,
+-            result=self.filter_attrs(self.create_keys),
++            result=self.filter_attrs(expected),
+         ), result)
+ 
+     def check_delete(self, result):
+-- 
+2.20.1
+
diff --git a/SOURCES/0008-Don-t-return-SSH-keys-with-ipa-host-find-pkey-only.patch b/SOURCES/0008-Don-t-return-SSH-keys-with-ipa-host-find-pkey-only.patch
new file mode 100644
index 0000000..216c128
--- /dev/null
+++ b/SOURCES/0008-Don-t-return-SSH-keys-with-ipa-host-find-pkey-only.patch
@@ -0,0 +1,31 @@
+From 6672b67ee145db6ed368b50a49bec00f49eccf91 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Thu, 1 Aug 2019 13:53:44 -0400
+Subject: [PATCH] Don't return SSH keys with ipa host-find --pkey-only
+
+This was introduced in 14ee02dcbd6cbb6c221ac7526e471a9fc58fcc82
+
+https://pagure.io/freeipa/issue/8029
+
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+---
+ ipaserver/plugins/host.py | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py
+index c74a3e58f8af6b33e284ba54b5763a684d91bac3..d6172599d30ec0b2c7b475e59dec22e111e79328 100644
+--- a/ipaserver/plugins/host.py
++++ b/ipaserver/plugins/host.py
+@@ -1050,7 +1050,8 @@ class host_find(LDAPSearch):
+                         (filter, hosts_filter), ldap.MATCH_ALL
+                     )
+ 
+-        add_sshpubkey_to_attrs_pre(self.context, attrs_list)
++        if not options.get('pkey_only', False):
++            add_sshpubkey_to_attrs_pre(self.context, attrs_list)
+ 
+         return (filter.replace('locality', 'l'), base_dn, scope)
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0008-Support-Samba-4.9.patch b/SOURCES/0008-Support-Samba-4.9.patch
deleted file mode 100644
index cccdcce..0000000
--- a/SOURCES/0008-Support-Samba-4.9.patch
+++ /dev/null
@@ -1,120 +0,0 @@
-From 9650b233bdbda82bcbb447a3fc94523655cabc39 Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Fri, 21 Sep 2018 10:57:23 +0300
-Subject: [PATCH] Support Samba 4.9
-
-Samba 4.9 became a bit more strict about creating a local NT token and a
-failure to resolve or create BUILTIN\Guests group will cause a rejection
-of the connection for a successfully authenticated one.
-
-Add a default mapping of the nobody group to BUILTIN\Guests.
-
-BUILTIN\Guests is a special group SID that is added to the NT token for
-authenticated users.
-
-For real guests there is 'guest account' option in smb.conf which
-defaults to 'nobody' user.
-
-This was implicit behavior before as 'guest account = nobody' by
-default would pick up 'nobody' group as well.
-
-Fixes: https://pagure.io/freeipa/issue/7705
-Reviewed-By: Rob Crittenden <rcritten@redhat.com>
-(cherry picked from commit 703497532abe4189835d0a02b32f9919c889bc1c)
-
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- .../updates/90-post_upgrade_plugins.update    |  1 +
- ipaserver/install/adtrustinstance.py          | 14 +++++++++++++
- ipaserver/install/plugins/adtrust.py          | 20 ++++++++++++++++++-
- 3 files changed, 34 insertions(+), 1 deletion(-)
-
-diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update
-index bbc3e29422fc0f139c2ca68a7033863e4c25f8cf..4e9378d9b567842e1cc9a8eeae819a931810895d 100644
---- a/install/updates/90-post_upgrade_plugins.update
-+++ b/install/updates/90-post_upgrade_plugins.update
-@@ -19,6 +19,7 @@ plugin: update_fix_duplicate_cacrt_in_ldap
- plugin: update_upload_cacrt
- # update_ra_cert_store has to be executed after update_ca_renewal_master
- plugin: update_ra_cert_store
-+plugin: update_mapping_Guests_to_nobody
- 
- # last
- # DNS version 1
-diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
-index e787fccb9482809b180012ed8e7be2e5a6494f93..d6b8f5cfa66c0cfbc6d47906703fc09c3e961a53 100644
---- a/ipaserver/install/adtrustinstance.py
-+++ b/ipaserver/install/adtrustinstance.py
-@@ -120,6 +120,15 @@ def make_netbios_name(s):
-     return ''.join([c for c in s.split('.')[0].upper() \
-                     if c in ALLOWED_NETBIOS_CHARS])[:15]
- 
-+
-+def map_Guests_to_nobody():
-+    env = {'LC_ALL': 'C'}
-+    args = [paths.NET, 'groupmap', 'add', 'sid=S-1-5-32-546',
-+            'unixgroup=nobody', 'type=builtin']
-+
-+    logger.debug("Map BUILTIN\\Guests to a group 'nobody'")
-+    ipautil.run(args, env=env, raiseonerr=False, capture_error=True)
-+
- class ADTRUSTInstance(service.Service):
- 
-     ATTR_SID = "ipaNTSecurityIdentifier"
-@@ -532,6 +541,9 @@ class ADTRUSTInstance(service.Service):
-             tmp_conf.flush()
-             ipautil.run([paths.NET, "conf", "import", tmp_conf.name])
- 
-+    def __map_Guests_to_nobody(self):
-+        map_Guests_to_nobody()
-+
-     def __setup_group_membership(self):
-         # Add the CIFS and host principals to the 'adtrust agents' group
-         # as 389-ds only operates with GroupOfNames, we have to use
-@@ -833,6 +845,8 @@ class ADTRUSTInstance(service.Service):
-                   self.__create_samba_domain_object)
-         self.step("creating samba config registry", self.__write_smb_registry)
-         self.step("writing samba config file", self.__write_smb_conf)
-+        self.step("map BUILTIN\\Guests to nobody group",
-+                  self.__map_Guests_to_nobody)
-         self.step("adding cifs Kerberos principal",
-                   self.request_service_keytab)
-         self.step("adding cifs and host Kerberos principals to the adtrust agents group", \
-diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
-index bec5a09c1c129b1129f31e3df59a2fa87aac0691..1f50bef891770c53a9086c7aa36d0ee1f088fbe6 100644
---- a/ipaserver/install/plugins/adtrust.py
-+++ b/ipaserver/install/plugins/adtrust.py
-@@ -23,7 +23,8 @@ from ipalib import Registry, errors
- from ipalib import Updater
- from ipapython.dn import DN
- from ipaserver.install import sysupgrade
--from ipaserver.install.adtrustinstance import ADTRUSTInstance
-+from ipaserver.install.adtrustinstance import (
-+    ADTRUSTInstance, map_Guests_to_nobody)
- 
- logger = logging.getLogger(__name__)
- 
-@@ -382,3 +383,20 @@ class update_tdo_gidnumber(Updater):
-             return False, ()
- 
-         return False, ()
-+
-+
-+@register()
-+class update_mapping_Guests_to_nobody(Updater):
-+    """
-+    Map BUILTIN\\Guests group to nobody
-+
-+    Samba 4.9 became more strict on availability of builtin Guests group
-+    """
-+    def execute(self, **options):
-+        # First, see if trusts are enabled on the server
-+        if not self.api.Command.adtrust_is_enabled()['result']:
-+            logger.debug('AD Trusts are not enabled on this server')
-+            return False, []
-+
-+        map_Guests_to_nobody()
-+        return False, []
--- 
-2.20.1
-
diff --git a/SOURCES/0009-Add-design-page-for-one-way-trust-to-AD-with-shared-.patch b/SOURCES/0009-Add-design-page-for-one-way-trust-to-AD-with-shared-.patch
deleted file mode 100644
index 78963c4..0000000
--- a/SOURCES/0009-Add-design-page-for-one-way-trust-to-AD-with-shared-.patch
+++ /dev/null
@@ -1,196 +0,0 @@
-From fd9e724513e4c574cfa3f2498fbdae0682ccb9a9 Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Tue, 19 Mar 2019 10:23:20 +0200
-Subject: [PATCH] Add design page for one-way trust to AD with shared secret
-
-(cherry picked from commit b3911ade55eec139e07f8b4ea83612f1b2794857)
-
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- .../oneway-trust-with-shared-secret.md        | 174 ++++++++++++++++++
- 1 file changed, 174 insertions(+)
- create mode 100644 doc/designs/adtrust/oneway-trust-with-shared-secret.md
-
-diff --git a/doc/designs/adtrust/oneway-trust-with-shared-secret.md b/doc/designs/adtrust/oneway-trust-with-shared-secret.md
-new file mode 100644
-index 0000000000000000000000000000000000000000..dc58a08941acea447f9234107ebcba775351089e
---- /dev/null
-+++ b/doc/designs/adtrust/oneway-trust-with-shared-secret.md
-@@ -0,0 +1,174 @@
-+# One-way trust with shared secret
-+
-+## Overview
-+
-+FreeIPA does support trust to an Active Directory forest. The trust can be
-+established using administrative credentials from the forest root domain or
-+using a so-called shared secret. In the latter case no administrative access is
-+given to the remote side of the trust and each administrator performs their
-+configuration separately: FreeIPA administrator configures IPA side, Active
-+Directory administrator adds IPA forest as a trusted one on the Active
-+Directory side.
-+
-+For trust to be active, one needs to validate it. Validation process includes a
-+sequences of DCE RPC calls that force a domain controller on the trusted side
-+to establish a so-called "secure channel" to a remote domain controller in the
-+trusting domain. This is an administrative operation and requires
-+administrative privileges to activate. If trust was established using a shared
-+secret, IPA side will lack ability to initiate a validation process.
-+
-+At the same time, FreeIPA 4.6 or earlier versions do not include functionality
-+to allow a remote validation from Active Directory to happen before trust
-+objects are created and SSSD can retrieve information from the Active Directory
-+side. Unfortunately, the latter is not possible until trust is validated.
-+
-+The purpose of this design is to extend FreeIPA setup to allow trust validation
-+to be initiated from Windows UI in case a shared secret is used to create a
-+trust agreement.
-+
-+## Use Cases
-+
-+As a FreeIPA administrator, I'd like to establish a trust between an Active
-+Directory forest and a FreeIPA deployment using a shared secret. As FreeIPA
-+administrator, I have no administrative access to Active Directory and would
-+like to delegate the operation to create trust on Active Directory side to my
-+counterpart in Active Directory forest.
-+
-+
-+## How to Use
-+
-+
-+1. Establish a one-way trust with a shared secret on IPA side:
-+   `ipa trust-add <ad-domain> --shared-secret`
-+
-+2. On Windows side, open Active Directory Domain and Trusts tool
-+   * Open properties for the Windows forest
-+   * Choose 'Trusts' tab and press 'New trust' button there
-+   * Navigate through the trust wizard by entering:
-+      *  IPA forest name, then 'next'
-+      *  Choose 'Forest trust' on the Trust Type page
-+      *  Choose 'One-way: incoming' on the Direction of Trust page
-+      *  Choose 'This domain only' on the Sides of Trust page
-+      *  Enter the same shared secret one was using in step (1) with 'ipa trust-add'
-+   *  Complete trust wizard
-+
-+3. Going back to the trust properties, one can now validate the trust from Windows side.
-+
-+One limitation is that it is not possible to retrieve forest trust information
-+about IPA realm by Active Directory domain controllers due to the fact that
-+Samba configuration used by IPA does not support a remote query for this
-+information. It is only available when Samba is used in Samba AD configuration.
-+
-+TODO: check whether it is possible to force to set forest trust information
-+from IPA side after both sides of trust are were configured.
-+
-+## Design
-+
-+There are two important parts of the solution. On IPA side, there is a module
-+to allow Samba to look up trusted domains and user/group information in IPA
-+LDAP. On the other side, there is support for POSIX identities of trusted
-+domain objects in SSSD.
-+
-+### FreeIPA module for Samba passdb interface
-+
-+FreeIPA provides a special module for Samba, `ipasam`, that looks up
-+information about trusted domains and user/group in FreeIPA LDAP. The module
-+also maintains trust-related information when trust is created via  DCE RPC
-+interfaces.
-+
-+When trust is created, `ipasam` module needs to create a set of Kerberos
-+principals to allow Kerberos KDC to issue cross-realm ticket granting tickets.
-+These principals will have the same keys as trusted domain objects on Active
-+Directory level.
-+
-+When a secure channel is established between two domain controllers from
-+separate trusted domains, both DCs rely on the trusted domain object account
-+credentials to be the same on both sides. However, since Samba has to perform
-+SMB to POSIX translation when running in POSIX environment, it also needs to
-+have a POSIX identity associated with the trusted domain object account.
-+
-+As result, `ipasam` module needs to maintain POSIX attributes for the trusted
-+domain object account, along with Kerberos principals associated with the
-+trust.
-+
-+### SSSD
-+
-+When Windows successfully authenticates to Samba, Samba needs a POSIX identity
-+to run `smbd` processes as the authenticated 'user'. `smbd` and `winbindd`
-+processes use standard system calls to resolve authenticated user to a system
-+one (`getpwnam_r()`) and if the call fails, whole Windows request is rejected.
-+
-+Given that trusted domain object accounts are associated with the cross-realm
-+Kerberos principals, they are located in a special subtree in FreeIPA LDAP:
-+`cn=trusts,$SUFFIX`. However, SSSD does not look by default in this subtree for
-+users. By default, SSSD configuration for user accounts looks in
-+`cn=users,cn=accounts,$SUFFIX` for `id_provider = ipa` and will not be able to
-+see trusted domain object accounts.
-+
-+Thus, to allow Windows to successfully validate a one-way shared incoming trust
-+to FreeIPA, SSSD needs to resolve trusted domain object accounts as POSIX users
-+on IPA master side.
-+
-+
-+## Implementation
-+
-+### FreeIPA `ipasam` module
-+
-+`ipasam` module needs to create and maintain POSIX identities of the trusted
-+domain object accounts.
-+
-+Following objects and their aliases are created and maintained by `ipasam`
-+module. In the description below `REMOTE` means Kerberos realm of the Active
-+Directory forest's root domain (e.g. `AD.EXAMPLE.COM`), `REMOTE-FLAT` is
-+NetBIOS name of the Active Directory forest's root domain (e.g. `AD`).
-+Correspondingly, `LOCAL` means FreeIPA Kerberos realm (e.g. `IPA.EXAMPLE.COM`)
-+and `LOCAL-FLAT` is the NetBIOS name of the FreeIPA primary domain (e.g.
-+`IPA`).
-+
-+  Principal | Description
-+  --------- | -----------
-+  krbtgt/REMOTE@LOCAL | Cross-realm principal representing Active Directory forest root domain
-+  REMOTE-FLAT$@LOCAL | Trusted domain object account for the Active Directory forest root domain
-+  krbtgt/REMOTE-FLAT@LOCAL | Alias to REMOTE-FLAT$ TDO
-+  krbtgt/LOCAL@REMOTE | Cross-realm principal representing IPA domain in Active Directory forest to allow crross-realm TGT issuance from IPA KDC side
-+  LOCAL-FLAT$@REMOTE | Trusted domain object account for IPA domain in Active Directory forest
-+  krbtgt/LOCAL-FLAT@REMOTE | Alias to LOCAL-FLAT$
-+
-+For inbound trust `ipasam` module creates following principals:
-+  * `krbtgt/LOCAL@REMOTE`, enabled by default
-+  * `LOCAL-FLAT$@REMOTE`, used by SSSD to talk to Active Directory domain
-+    controllers, with canonical name set to `LOCAL-FLAT$` because Kerberos KDC
-+    must use this salt when issuing tickets for this principal. The use of this
-+    principal is disabled on IPA side (IPA KDC does not issue tickets in this name)
-+    --- we only retrieve a keytab for the principal in SSSD.
-+
-+For outbound trust `ipasam` module creates following principals:
-+  * `krbtgt/REMOTE@LOCAL`, enabled by default.
-+  * `REMOTE-FLAT$@LOCAL`, enabled by default. Used by a remote AD DC to
-+    authenticate against Samba on IPA master. This principal will have POSIX
-+    identity associated.
-+
-+
-+### SSSD
-+
-+In IPA master mode, SSSD needs to start look into `cn=trusts,$SUFFIX` subtree
-+in addition to `cn=users,cn=accounts,$SUFFIX` subtree to find trusted domain
-+object accounts. This can be achieved either by explicitly adding a second
-+search base to `ldap_search_user_base` option in the `[domain/...]` section or
-+by automatically expanding a list of search bases when running in the IPA
-+master mode. The latter is already implemented in SSSD 1.16.3 and 2.1.0 with
-+https://pagure.io/SSSD/sssd/c/14faec9cd9437ef116ae054412d25ec2e820e409
-+
-+
-+Feature Management
-+------------------
-+
-+We already allow to create a shared secret-based trust to Active Directory. No
-+functional change is needed in either Web UI or CLI.
-+
-+Upgrade
-+-------
-+
-+During upgrade POSIX identities need to be created for existing trust
-+agreements.
-+
--- 
-2.20.1
-
diff --git a/SOURCES/0009-check-for-single-label-domains-only-during-server-in.patch b/SOURCES/0009-check-for-single-label-domains-only-during-server-in.patch
new file mode 100644
index 0000000..81a8177
--- /dev/null
+++ b/SOURCES/0009-check-for-single-label-domains-only-during-server-in.patch
@@ -0,0 +1,112 @@
+From 12d456a12d0029833059fe28d3bb1cea338fef16 Mon Sep 17 00:00:00 2001
+From: Florence Blanc-Renaud <flo@redhat.com>
+Date: Thu, 5 Sep 2019 15:49:05 +0200
+Subject: [PATCH] check for single-label domains only during server install
+
+The fix for https://pagure.io/freeipa/issue/7207 and
+https://pagure.io/freeipa/issue/7598 added checks against single-label
+domains in client, server and replica installs. This prevents client
+enrollment to existing topologies with single-label domain.
+
+This commit removes those fixes on ipa-4-6 branch. Server installation
+with single-label domain will still be refused, but client enrollment
+will succeed.
+
+Fixes: https://pagure.io/freeipa/issue/8058
+Reviewed-By: Francois Cami <fcami@redhat.com>
+---
+ ipalib/util.py                      |  5 +++--
+ ipaserver/install/server/install.py | 16 ++++++++--------
+ ipaserver/plugins/config.py         |  2 +-
+ ipaserver/plugins/realmdomains.py   |  2 +-
+ 4 files changed, 13 insertions(+), 12 deletions(-)
+
+diff --git a/ipalib/util.py b/ipalib/util.py
+index 1aa94d97b440110fe55584048d468b9c014ec67b..8b6ec564aa6299a6dd149e9afa1bdc04ac770bf2 100644
+--- a/ipalib/util.py
++++ b/ipalib/util.py
+@@ -406,14 +406,15 @@ def validate_dns_label(dns_label, allow_underscore=False, allow_slash=False):
+ 
+ def validate_domain_name(
+     domain_name, allow_underscore=False,
+-    allow_slash=False, entity='domain'
++    allow_slash=False, entity='domain',
++    check_sld=False
+ ):
+     if domain_name.endswith('.'):
+         domain_name = domain_name[:-1]
+ 
+     domain_name = domain_name.split(".")
+ 
+-    if len(domain_name) < 2:
++    if check_sld and len(domain_name) < 2:
+         raise ValueError(_(
+             'single label {}s are not supported'.format(entity)))
+ 
+diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
+index c1e593e467cdb856a4ab3251ee103f3da3386a82..5ea4f2e1cc80c995997888aaf44f500524beb796 100644
+--- a/ipaserver/install/server/install.py
++++ b/ipaserver/install/server/install.py
+@@ -471,25 +471,25 @@ def install_check(installer):
+         domain_name = read_domain_name(host_name[host_name.find(".")+1:],
+                                        not installer.interactive)
+         logger.debug("read domain_name: %s\n", domain_name)
+-        try:
+-            validate_domain_name(domain_name)
+-        except ValueError as e:
+-            raise ScriptError("Invalid domain name: %s" % unicode(e))
+     else:
+         domain_name = options.domain_name
+ 
+     domain_name = domain_name.lower()
++    try:
++        validate_domain_name(domain_name, check_sld=True)
++    except ValueError as e:
++        raise ScriptError("Invalid domain name: %s" % unicode(e))
+ 
+     if not options.realm_name:
+         realm_name = read_realm_name(domain_name, not installer.interactive)
+         logger.debug("read realm_name: %s\n", realm_name)
+ 
+-        try:
+-            validate_domain_name(realm_name, entity="realm")
+-        except ValueError as e:
+-            raise ScriptError("Invalid realm name: {}".format(unicode(e)))
+     else:
+         realm_name = options.realm_name.upper()
++    try:
++        validate_domain_name(realm_name, entity="realm", check_sld=True)
++    except ValueError as e:
++        raise ScriptError("Invalid realm name: {}".format(unicode(e)))
+ 
+     if not options.subject_base:
+         options.subject_base = installutils.default_subject_base(realm_name)
+diff --git a/ipaserver/plugins/config.py b/ipaserver/plugins/config.py
+index 58b48935c2c7471ff2ce0bb3f5ce92a9fb47a503..b6349f03b7347b696c4e38480440a31db6757de8 100644
+--- a/ipaserver/plugins/config.py
++++ b/ipaserver/plugins/config.py
+@@ -400,7 +400,7 @@ class config(LDAPObject):
+             )
+ 
+         try:
+-            validate_domain_name(domain)
++            validate_domain_name(domain, check_sld=True)
+         except ValueError as e:
+             raise errors.ValidationError(
+                 name=attr_name,
+diff --git a/ipaserver/plugins/realmdomains.py b/ipaserver/plugins/realmdomains.py
+index 80c5c298372f1c3f773150622c708f0286cc87a2..414dfae5090c4cd2e694bdfd3839a39783dd95fc 100644
+--- a/ipaserver/plugins/realmdomains.py
++++ b/ipaserver/plugins/realmdomains.py
+@@ -59,7 +59,7 @@ def _domain_name_normalizer(d):
+ 
+ def _domain_name_validator(ugettext, value):
+     try:
+-        validate_domain_name(value, allow_slash=False)
++        validate_domain_name(value, allow_slash=False, check_sld=True)
+     except ValueError as e:
+         return unicode(e)
+     return None
+-- 
+2.20.1
+
diff --git a/SOURCES/0010-Don-t-configure-KEYRING-ccache-in-containers.patch b/SOURCES/0010-Don-t-configure-KEYRING-ccache-in-containers.patch
new file mode 100644
index 0000000..f417ec0
--- /dev/null
+++ b/SOURCES/0010-Don-t-configure-KEYRING-ccache-in-containers.patch
@@ -0,0 +1,166 @@
+From 7e9d17ca027b377c54288eb06ead7602a2a5136b Mon Sep 17 00:00:00 2001
+From: Christian Heimes <cheimes@redhat.com>
+Date: Wed, 12 Dec 2018 17:32:06 +0100
+Subject: [PATCH] Don't configure KEYRING ccache in containers
+
+Kernel keyrings are not namespaced yet. Keyrings can leak into other
+containers. Therefore keyrings should not be used in containerized
+environment.
+
+Don't configure Kerberos to use KEYRING ccache backen when a container
+environment is detected by systemd-detect-virt --container.
+
+Fixes: https://pagure.io/freeipa/issue/7807
+Signed-off-by: Christian Heimes <cheimes@redhat.com>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+Reviewed-By: Tibor Dudlak <tdudlak@redhat.com>
+Reviewed-By: Oleg Kozlov <okozlov@redhat.com>
+Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
+---
+ ipaplatform/base/paths.py               |  1 +
+ ipaplatform/base/tasks.py               |  8 +++++++
+ ipaplatform/redhat/tasks.py             | 21 ++++++++++++++++
+ ipapython/kernel_keyring.py             | 10 +++++++-
+ ipatests/test_ipaplatform/test_tasks.py | 32 +++++++++++++++++++++++++
+ 5 files changed, 71 insertions(+), 1 deletion(-)
+ create mode 100644 ipatests/test_ipaplatform/test_tasks.py
+
+diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
+index 435d1b7de9083ee74e80da6fef5c3e3cdad654bb..0395e40b7fb624cd6f625a0cd959c4a216731f6d 100644
+--- a/ipaplatform/base/paths.py
++++ b/ipaplatform/base/paths.py
+@@ -30,6 +30,7 @@ class BasePathNamespace(object):
+     LS = "/bin/ls"
+     SH = "/bin/sh"
+     SYSTEMCTL = "/bin/systemctl"
++    SYSTEMD_DETECT_VIRT = "/bin/systemd-detect-virt"
+     TAR = "/bin/tar"
+     AUTOFS_LDAP_AUTH_CONF = "/etc/autofs_ldap_auth.conf"
+     ETC_DIRSRV = "/etc/dirsrv"
+diff --git a/ipaplatform/base/tasks.py b/ipaplatform/base/tasks.py
+index cd0427197aaecde0139781a564be443e59f3f9df..49c39e99b475cef2945354b2aaadf20239421d34 100644
+--- a/ipaplatform/base/tasks.py
++++ b/ipaplatform/base/tasks.py
+@@ -116,6 +116,14 @@ class BaseTaskNamespace(object):
+ 
+         raise NotImplementedError()
+ 
++    def detect_container(self):
++        """Check if running inside a container
++
++        :returns: container runtime or None
++        :rtype: str, None
++        """
++        raise NotImplementedError
++
+     def restore_hostname(self, fstore, statestore):
+         """
+         Restores the original hostname as backed up in the
+diff --git a/ipaplatform/redhat/tasks.py b/ipaplatform/redhat/tasks.py
+index 9ce0d8375c88cb3281149ef82c975d14f150e5a4..8f6dc9a0370c59a3d4a33e8699bbc8c228ca0e1d 100644
+--- a/ipaplatform/redhat/tasks.py
++++ b/ipaplatform/redhat/tasks.py
+@@ -30,6 +30,7 @@ import os
+ import socket
+ import traceback
+ import errno
++import subprocess
+ import sys
+ 
+ from ctypes.util import find_library
+@@ -168,6 +169,26 @@ class RedHatTaskNamespace(BaseTaskNamespace):
+                  "resolution to 'lo' interface. You might need to enable IPv6 "
+                  "on the interface 'lo' in sysctl.conf.")
+ 
++    def detect_container(self):
++        """Check if running inside a container
++
++        :returns: container runtime or None
++        :rtype: str, None
++        """
++        try:
++            output = subprocess.check_output(
++                [paths.SYSTEMD_DETECT_VIRT, '--container'],
++                stderr=subprocess.STDOUT
++            )
++        except subprocess.CalledProcessError as e:
++            if e.returncode == 1:
++                # No container runtime detected
++                return None
++            else:
++                raise
++        else:
++            return output.decode('utf-8').strip()
++
+     def restore_pre_ipa_client_configuration(self, fstore, statestore,
+                                              was_sssd_installed,
+                                              was_sssd_configured):
+diff --git a/ipapython/kernel_keyring.py b/ipapython/kernel_keyring.py
+index 6ae1e74493810fa25093fe134447dd4ba0f5da74..cd47108e5846bc2f78e45f222bdfbd0ca11b7d81 100644
+--- a/ipapython/kernel_keyring.py
++++ b/ipapython/kernel_keyring.py
+@@ -24,6 +24,7 @@ import six
+ 
+ from ipapython.ipautil import run
+ from ipaplatform.paths import paths
++from ipaplatform.tasks import tasks
+ 
+ # NOTE: Absolute path not required for keyctl since we reset the environment
+ #       in ipautil.run.
+@@ -68,7 +69,14 @@ def get_persistent_key(key):
+     return result.raw_output.rstrip()
+ 
+ 
+-def is_persistent_keyring_supported():
++def is_persistent_keyring_supported(check_container=True):
++    """Returns True if the kernel persistent keyring is supported.
++
++    If check_container is True and a containerized environment is detected,
++    return False. There is no support for keyring namespace isolation yet.
++    """
++    if check_container and tasks.detect_container() is not None:
++        return False
+     uid = os.geteuid()
+     try:
+         get_persistent_key(str(uid))
+diff --git a/ipatests/test_ipaplatform/test_tasks.py b/ipatests/test_ipaplatform/test_tasks.py
+new file mode 100644
+index 0000000000000000000000000000000000000000..524490c78defb6ce14bf76ea296a9a33db0cbf0a
+--- /dev/null
++++ b/ipatests/test_ipaplatform/test_tasks.py
+@@ -0,0 +1,32 @@
++#
++# Copyright (C) 2017  FreeIPA Contributors see COPYING for license
++#
++from __future__ import absolute_import
++
++import os
++
++from ipaplatform.tasks import tasks
++
++
++def test_detect_container():
++    container = None
++    # naive detection, may fail for OpenVZ and other container runtimes
++    if os.path.isfile('/run/systemd/container'):
++        with open('/run/systemd/container') as f:
++            container = f.read().strip()
++    elif os.geteuid() == 0:
++        with open('/proc/1/environ') as f:
++            environ = f.read()
++        for item in environ.split('\x00'):
++            if not item:
++                continue
++            k, v = item.split('=', 1)
++            if k == 'container':
++                container = v
++
++    detected = tasks.detect_container()
++    if container == 'oci':
++        # systemd doesn't know about podman
++        assert detected in {'container-other', container}
++    else:
++        assert detected == container
+-- 
+2.20.1
+
diff --git a/SOURCES/0010-trust-allow-trust-agents-to-read-POSIX-identities-of.patch b/SOURCES/0010-trust-allow-trust-agents-to-read-POSIX-identities-of.patch
deleted file mode 100644
index f07f1a1..0000000
--- a/SOURCES/0010-trust-allow-trust-agents-to-read-POSIX-identities-of.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 58478231b10a670bc8c8bf5a1a41a5e3cb075b3f Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Fri, 22 Mar 2019 18:50:30 +0200
-Subject: [PATCH] trust: allow trust agents to read POSIX identities of trust
-
-SSSD and Samba on IPA masters need to be able to look up POSIX
-attributes of trusted domain objects in order to allow Active Directory
-domain controllers from trusted forests to connect to LSA and NETLOGON
-pipes.
-
-We only have access to read POSIX attributes in cn=accounts,$SUFFIX
-subtree rather than whole $SUFFIX. Thus, add an ACI to trusts subtree.
-
-Fixes: https://pagure.io/freeipa/issue/6077
-(cherry picked from commit 8908b5085179d07cff45ebb11d498b872d28eee7)
-
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- install/updates/60-trusts.update | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/install/updates/60-trusts.update b/install/updates/60-trusts.update
-index 04c85ba77389b12415849ed81b8131c07b1c7a32..90201e1b4bfc01509da722303cb975a970131fb5 100644
---- a/install/updates/60-trusts.update
-+++ b/install/updates/60-trusts.update
-@@ -33,6 +33,7 @@ add:aci: (target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType ||
- replace:aci:(target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || ipaNTTrustAttributes || ipaNTTrustDirection || ipaNTTrustPartner || ipaNTFlatName || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming || ipaNTSecurityIdentifier || ipaNTTrustForestTrustInfo || ipaNTTrustPosixOffset || ipaNTSupportedEncryptionTypes || krbPrincipalName || krbLastPwdChange || krbTicketFlags || krbLoginFailedCount || krbExtraData || krbPrincipalKey")(version 3.0;acl "Allow trust system user to create and delete trust accounts and cross realm principals"; allow (read,write,add,delete) groupdn="ldap:///cn=adtrust agents,cn=sysaccounts,cn=etc,$SUFFIX";)::(target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || ipaNTTrustAttributes || ipaNTTrustDirection || ipaNTTrustPartner || ipaNTFlatName || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming || ipaNTSecurityIdentifier || ipaNTTrustForestTrustInfo || ipaNTTrustPosixOffset || ipaNTSupportedEncryptionTypes || ipaNTSIDBlacklistIncoming || ipaNTSIDBlacklistOutgoing || krbPrincipalName || krbLastPwdChange || krbTicketFlags || krbLoginFailedCount || krbExtraData || krbPrincipalKey")(version 3.0;acl "Allow trust system user to create and delete trust accounts and cross realm principals"; allow (read,write,add,delete) groupdn="ldap:///cn=adtrust agents,cn=sysaccounts,cn=etc,$SUFFIX";)
- replace:aci:(target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || ipaNTTrustAttributes || ipaNTTrustDirection || ipaNTTrustPartner || ipaNTFlatName || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming || ipaNTSecurityIdentifier || ipaNTTrustForestTrustInfo || ipaNTTrustPosixOffset || ipaNTSupportedEncryptionTypes")(version 3.0;acl "Allow trust admins manage trust accounts"; allow (read,write,add,delete) groupdn="ldap:///cn=trust admins,cn=groups,cn=accounts,$SUFFIX";)::(target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || ipaNTTrustAttributes || ipaNTTrustDirection || ipaNTTrustPartner || ipaNTFlatName || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming || ipaNTSecurityIdentifier || ipaNTTrustForestTrustInfo || ipaNTTrustPosixOffset || ipaNTSupportedEncryptionTypes || ipaNTSIDBlacklistIncoming || ipaNTSIDBlacklistOutgoing")(version 3.0;acl "Allow trust admins manage trust accounts"; allow (read,write,add,delete) groupdn="ldap:///cn=trust admins,cn=groups,cn=accounts,$SUFFIX";)
- add:aci: (target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || ipaNTTrustAttributes || ipaNTTrustDirection || ipaNTTrustPartner || ipaNTFlatName || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming || ipaNTSecurityIdentifier || ipaNTTrustForestTrustInfo || ipaNTTrustPosixOffset || ipaNTSupportedEncryptionTypes || ipaNTSIDBlacklistIncoming || ipaNTSIDBlacklistOutgoing")(version 3.0;acl "Allow trust admins manage trust accounts"; allow (read,write,add,delete) groupdn="ldap:///cn=trust admins,cn=groups,cn=accounts,$SUFFIX";)
-+add:aci: (targetattr = "cn || createtimestamp || description || displayname || entryusn || gecos || gidnumber || givenname || homedirectory || ipantsecurityidentifier || loginshell || modifytimestamp || objectclass || uid || uidnumber")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "Allow reading POSIX information about trusted domain objects";allow (compare,read,search) groupdn = "ldap:///cn=adtrust agents,cn=sysaccounts,cn=etc,$SUFFIX";)
- 
- # Samba user should be able to read NT passwords to authenticate
- # Add ipaNTHash to global ACIs, leave DNS tree out of global allow access rule
--- 
-2.20.1
-
diff --git a/SOURCES/0011-Add-container-environment-check-to-replicainstall.patch b/SOURCES/0011-Add-container-environment-check-to-replicainstall.patch
new file mode 100644
index 0000000..5eba40e
--- /dev/null
+++ b/SOURCES/0011-Add-container-environment-check-to-replicainstall.patch
@@ -0,0 +1,34 @@
+From 734a39d52cf738bfce7ad97deab74f368387a83b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Tibor=20Dudl=C3=A1k?= <tdudlak@redhat.com>
+Date: Tue, 10 Sep 2019 18:54:53 +0200
+Subject: [PATCH] Add container environment check to replicainstall
+
+Inside the container environment master's IP address
+does not resolve to its name.
+
+Resolves: https://pagure.io/freeipa/issue/6210
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+---
+ ipaserver/install/server/replicainstall.py | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
+index e13b7f18c4d4df7efde50ac9cb7d2f71bfa765cc..bd82a9d1483545d478e790a727e48eaa9ac22cfc 100644
+--- a/ipaserver/install/server/replicainstall.py
++++ b/ipaserver/install/server/replicainstall.py
+@@ -1134,7 +1134,11 @@ def promote_check(installer):
+                            "certificate")
+ 
+     installutils.verify_fqdn(config.host_name, options.no_host_dns)
+-    installutils.verify_fqdn(config.master_host_name, options.no_host_dns)
++    # Inside the container environment master's IP address does not
++    # resolve to its name. See https://pagure.io/freeipa/issue/6210
++    container_environment = tasks.detect_container() is not None
++    installutils.verify_fqdn(config.master_host_name, options.no_host_dns,
++                             local_hostname=not container_environment)
+ 
+     ccache = os.environ['KRB5CCNAME']
+     kinit_keytab('host/{env.host}@{env.realm}'.format(env=api.env),
+-- 
+2.20.1
+
diff --git a/SOURCES/0011-trusts-add-support-for-one-way-shared-secret-trust.patch b/SOURCES/0011-trusts-add-support-for-one-way-shared-secret-trust.patch
deleted file mode 100644
index 9e03c88..0000000
--- a/SOURCES/0011-trusts-add-support-for-one-way-shared-secret-trust.patch
+++ /dev/null
@@ -1,416 +0,0 @@
-From 4be3de451c8b2a6314c29df43e5ade17f39d8777 Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Fri, 22 Mar 2019 18:56:52 +0200
-Subject: [PATCH] trusts: add support for one-way shared secret trust
-
-Refactor ipa-sam code to generate principals with additional POSIX
-information so that FreeIPA is capable to establish trust when using a
-shared secret from Active Directory domain controller side.
-
-Trust verification process from Samba AD DC or Microsoft Windows AD DC
-side requires us to have a working local TDO object with POSIX
-attributes so that smbd would be able to map incoming authenticated
-Kerberos principal for the TDO to a local POSIX account.
-
-Note that FreeIPA stores TDO objects in a subtree of cn=trusts,$SUFFIX
-and thus SSSD is not able to see these POSIX accounts unless
-specifically instructed to do so via multiple search bases. The support
-for automatically enabling cn=trusts,$SUFFIX search base in IPA server
-mode was added to SSSD 1.16.3 and 2.1.0 with the commit
-https://pagure.io/SSSD/sssd/c/14faec9cd9437ef116ae054412d25ec2e820e409
-
-Fixes: https://pagure.io/freeipa/issue/6077
-(cherry picked from commit f30f7e380ef9d327ced3e1b0e5c800a8b1069097)
-
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- daemons/ipa-sam/ipa_sam.c | 232 +++++++++++++++++++++++++++++---------
- 1 file changed, 179 insertions(+), 53 deletions(-)
-
-diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c
-index 675a511f0febf13cc5e00b547c18a050ac534f2e..3cf878c3f99774f7715f776c31d70e2950f9451c 100644
---- a/daemons/ipa-sam/ipa_sam.c
-+++ b/daemons/ipa-sam/ipa_sam.c
-@@ -140,6 +140,7 @@ bool E_md4hash(const char *passwd, uint8_t p16[16]); /* available in libcliauth-
- #define LDAP_ATTRIBUTE_OBJECTCLASS "objectClass"
- #define LDAP_ATTRIBUTE_HOME_DRIVE "ipaNTHomeDirectoryDrive"
- #define LDAP_ATTRIBUTE_HOME_PATH "ipaNTHomeDirectory"
-+#define LDAP_ATTRIBUTE_HOMEDIRECTORY "homeDirectory"
- #define LDAP_ATTRIBUTE_LOGON_SCRIPT "ipaNTLogonScript"
- #define LDAP_ATTRIBUTE_PROFILE_PATH "ipaNTProfilePath"
- #define LDAP_ATTRIBUTE_SID_BLACKLIST_INCOMING "ipaNTSIDBlacklistIncoming"
-@@ -1797,9 +1798,10 @@ done:
- #define KRB_PRINC_CREATE_DISABLED           0x00000001
- #define KRB_PRINC_CREATE_AGENT_PERMISSION   0x00000002
- 
-+
- static bool set_krb_princ(struct ipasam_private *ipasam_state,
- 			  TALLOC_CTX *mem_ctx,
--			  const char *princ, const char *saltprinc,
-+			  const char *princ, const char *alias,
- 			  const char *pwd,
- 			  const char *base_dn,
- 			  uint32_t   create_flags)
-@@ -1857,14 +1859,15 @@ static bool set_krb_princ(struct ipasam_private *ipasam_state,
- 			 LDAP_ATTRIBUTE_KRB_CANONICAL, princ);
- 	smbldap_set_mod(&mods, LDAP_MOD_ADD,
- 			 LDAP_ATTRIBUTE_KRB_PRINCIPAL, princ);
--        if (saltprinc) {
--	    smbldap_set_mod(&mods, LDAP_MOD_ADD,
--			    LDAP_ATTRIBUTE_KRB_PRINCIPAL, saltprinc);
--        }
-+	if (alias) {
-+		smbldap_set_mod(&mods, LDAP_MOD_ADD,
-+				LDAP_ATTRIBUTE_KRB_PRINCIPAL, alias);
-+	}
- 
- 	if ((create_flags & KRB_PRINC_CREATE_DISABLED)) {
--		smbldap_make_mod(priv2ld(ipasam_state), entry, &mods,
--				LDAP_ATTRIBUTE_KRB_TICKET_FLAGS, __TALLOC_STRING_LINE2__(IPASAM_DISALLOW_ALL_TIX));
-+		smbldap_set_mod(&mods, LDAP_MOD_ADD,
-+				LDAP_ATTRIBUTE_KRB_TICKET_FLAGS,
-+				__TALLOC_STRING_LINE2__(IPASAM_DISALLOW_ALL_TIX));
- 	}
- 
- 	if ((create_flags & KRB_PRINC_CREATE_AGENT_PERMISSION)) {
-@@ -1877,18 +1880,19 @@ static bool set_krb_princ(struct ipasam_private *ipasam_state,
- 		smbldap_set_mod(&mods, LDAP_MOD_ADD,
- 				LDAP_ATTRIBUTE_OBJECTCLASS,
- 				LDAP_OBJ_IPAOPALLOW);
--		smbldap_make_mod(priv2ld(ipasam_state), entry, &mods,
--				LDAP_ATTRIBUTE_IPAOPALLOW, agent_dn);
-+		smbldap_set_mod(&mods, LDAP_MOD_ADD,
-+				LDAP_ATTRIBUTE_IPAOPALLOW,
-+				agent_dn);
- 		agent_dn = talloc_asprintf(mem_ctx, LDAP_CN_ADTRUST_ADMINS",%s", ipasam_state->base_dn);
- 		if (agent_dn == NULL) {
- 			DEBUG(1, ("error configuring cross realm principal data for trust admins!\n"));
- 			return false;
- 		}
--		smbldap_make_mod(priv2ld(ipasam_state), entry, &mods,
--				LDAP_ATTRIBUTE_IPAOPALLOW, agent_dn);
-+		smbldap_set_mod(&mods, LDAP_MOD_ADD,
-+				LDAP_ATTRIBUTE_IPAOPALLOW,
-+				agent_dn);
- 	}
- 
--
- 	if (entry == NULL) {
- 		ret = smbldap_add(ipasam_state->ldap_state, dn, mods);
- 	} else {
-@@ -1899,7 +1903,7 @@ static bool set_krb_princ(struct ipasam_private *ipasam_state,
- 		return false;
- 	}
- 
--	ret = set_cross_realm_pw(ipasam_state, saltprinc ? saltprinc : princ, pwd);
-+	ret = set_cross_realm_pw(ipasam_state, princ, pwd);
- 	if (ret != 0) {
- 		DEBUG(1, ("set_cross_realm_pw failed.\n"));
- 		return false;
-@@ -1941,18 +1945,21 @@ enum princ_mod {
- };
- 
- static bool handle_cross_realm_princs(struct ipasam_private *ipasam_state,
--				      const char *domain, const char *pwd,
-+				      const char *domain, const char *flat_name,
-+				      const char *pwd_incoming,
-+				      const char *pwd_outgoing,
- 				      uint32_t trust_direction,
- 				      enum princ_mod mod)
- {
- 	char *trusted_dn;
- 	char *princ_l;
- 	char *princ_r;
--	char *princ_tdo;
--	char *saltprinc_tdo;
-+	char *princ_r_tdo, *princ_l_tdo;
- 	char *remote_realm;
- 	bool ok;
-+        int failed = 0;
- 	TALLOC_CTX *tmp_ctx;
-+	const char *r_tdo_alias, *l_tdo_alias;
- 
- 	tmp_ctx = talloc_new(NULL);
- 	if (tmp_ctx == NULL) {
-@@ -1967,46 +1974,111 @@ static bool handle_cross_realm_princs(struct ipasam_private *ipasam_state,
- 
- 	trusted_dn = trusted_domain_dn(tmp_ctx, ipasam_state, domain);
- 
--	princ_l = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", remote_realm,
--			ipasam_state->realm);
--	princ_r = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s",
--			ipasam_state->realm, remote_realm);
-+	princ_l = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s",
-+				  remote_realm, ipasam_state->realm);
-+	princ_l_tdo = talloc_asprintf(tmp_ctx, "%s$@%s",
-+				      flat_name, ipasam_state->realm);
-+	l_tdo_alias = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s",
-+				      flat_name, ipasam_state->realm);
- 
--	princ_tdo = talloc_asprintf(tmp_ctx, "%s$@%s",
--			ipasam_state->flat_name, remote_realm);
-+	princ_r = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s",
-+				  ipasam_state->realm, remote_realm);
-+	princ_r_tdo = talloc_asprintf(tmp_ctx, "%s$@%s",
-+				      ipasam_state->flat_name, remote_realm);
- 
--	saltprinc_tdo = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s",
-+	r_tdo_alias = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s",
- 			ipasam_state->flat_name, remote_realm);
- 
--	if (trusted_dn == NULL || princ_l == NULL ||
--	    princ_r == NULL || princ_tdo == NULL || saltprinc_tdo == NULL) {
-+	if (trusted_dn == NULL || princ_l == NULL || princ_l_tdo == NULL ||
-+		l_tdo_alias == NULL || princ_r == NULL || princ_r_tdo == NULL ||
-+		r_tdo_alias == NULL) {
- 		ok = false;
- 		goto done;
- 	}
- 
- 	switch (mod) {
- 		case SET_PRINC:
--			/* Create Kerberos principal for inbound trust, enabled by default */
--			ok   = set_krb_princ(ipasam_state, tmp_ctx, princ_r, NULL, pwd, trusted_dn, KRB_PRINC_CREATE_DEFAULT);
--			/* Create Kerberos principal corresponding to TDO in AD for SSSD usage, disabled by default */
--			ok |= set_krb_princ(ipasam_state, tmp_ctx, princ_tdo, saltprinc_tdo, pwd, trusted_dn,
--					    KRB_PRINC_CREATE_DISABLED | KRB_PRINC_CREATE_AGENT_PERMISSION);
--			if ((trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) != 0) {
--				/* Create Kerberos principal for outbound trust, enabled by default */
--				ok |= set_krb_princ(ipasam_state, tmp_ctx, princ_l, NULL, pwd, trusted_dn, KRB_PRINC_CREATE_DEFAULT);
-+			/* We must use two sets by two principals here because
-+			 * they are used for different needs and must have
-+			 * different salts */
-+
-+			failed = 0;
-+			/* INBOUND TRUST */
-+			if ((trust_direction & LSA_TRUST_DIRECTION_INBOUND) != 0) {
-+				/* First: krbtgt/<OUR REALM>@<REMOTE REALM>, enabled by default
-+				 * in case of the inboud trust */
-+				failed += !set_krb_princ(ipasam_state, tmp_ctx, princ_r, NULL,
-+							 pwd_outgoing, trusted_dn,
-+							 KRB_PRINC_CREATE_DEFAULT);
-+
-+				/* Second: <OUR FLATNAME$>@<REMOTE REALM> is only used
-+				 * for SSSD to be able to talk to AD DCs but it has to
-+				 * have canonical name set to <OUR FLATNAME>$ because
-+				 * this is the salt used by AD DCs when using this
-+				 * principal, otherwise authentication will fail.
-+				 *
-+				 * *disable* use of this principal on our side as it is
-+				 * only used to retrieve trusted domain credentials by
-+				 * AD Trust Agents across the IPA topology */
-+				failed += !set_krb_princ(ipasam_state, tmp_ctx,
-+							 r_tdo_alias, princ_r_tdo,
-+							 pwd_incoming, trusted_dn,
-+							 (KRB_PRINC_CREATE_DISABLED |
-+							  KRB_PRINC_CREATE_AGENT_PERMISSION));
-+
-+	                        ok = (failed == 0);
-+				if (!ok) {
-+					goto done;
-+				}
- 			}
--			if (!ok) {
--				goto done;
-+
-+			failed = 0;
-+			/* OUTBOUND TRUST */
-+			if ((trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) != 0) {
-+				/* First: krbtgt/<REMOTE REALM>@<OUR REALM>, enabled by default */
-+				failed += !set_krb_princ(ipasam_state, tmp_ctx,
-+							 princ_l, NULL,
-+							 pwd_outgoing, trusted_dn,
-+							 KRB_PRINC_CREATE_DEFAULT);
-+
-+				/* Second: <REMOTE FLAT NAME>$@<OUR REALM>, enabled by default
-+				 * as it is used for a remote DC to authenticate against IPA Samba
-+				 *
-+				 * A local account for the outbound trust must have
-+				 * POSIX and SMB identities associated with our domain but we associate
-+				 * them with the trust domain object itself */
-+				failed += !set_krb_princ(ipasam_state, tmp_ctx,
-+							 princ_l_tdo, l_tdo_alias,
-+							 pwd_incoming, trusted_dn,
-+							 KRB_PRINC_CREATE_DEFAULT);
-+
-+	                        ok = (failed == 0);
-+				if (!ok) {
-+					goto done;
-+				}
- 			}
- 			break;
- 		case DEL_PRINC:
--			ok  = del_krb_princ(ipasam_state, tmp_ctx, princ_r, trusted_dn);
--			ok |= del_krb_princ(ipasam_state, tmp_ctx, princ_tdo, trusted_dn);
--			if ((trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) != 0) {
--				ok |= del_krb_princ(ipasam_state, tmp_ctx, princ_l, trusted_dn);
-+			failed = 0;
-+			if ((trust_direction & LSA_TRUST_DIRECTION_INBOUND) != 0) {
-+				failed += !del_krb_princ(ipasam_state, tmp_ctx, princ_r, trusted_dn);
-+				failed += !del_krb_princ(ipasam_state, tmp_ctx, princ_r_tdo, trusted_dn);
-+
-+	                        ok = (failed == 0);
-+				if (!ok) {
-+					goto done;
-+				}
- 			}
--			if (!ok) {
--				goto done;
-+
-+			failed = 0;
-+			if ((trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) != 0) {
-+				failed += !del_krb_princ(ipasam_state, tmp_ctx, princ_l, trusted_dn);
-+				failed += !del_krb_princ(ipasam_state, tmp_ctx, princ_l_tdo, trusted_dn);
-+
-+	                        ok = (failed == 0);
-+				if (!ok) {
-+					goto done;
-+				}
- 			}
- 			break;
- 		default:
-@@ -2022,16 +2094,22 @@ done:
- }
- 
- static bool set_cross_realm_princs(struct ipasam_private *ipasam_state,
--				   const char *domain, const char *pwd, uint32_t trust_direction)
-+				   const char *domain, const char* flat_name,
-+				   const char *pwd_incoming, const char *pwd_outgoing,
-+				   uint32_t trust_direction)
- {
--	return handle_cross_realm_princs(ipasam_state, domain, pwd, trust_direction, SET_PRINC);
-+	return handle_cross_realm_princs(ipasam_state, domain, flat_name,
-+					 pwd_incoming,
-+					 pwd_outgoing,
-+					 trust_direction, SET_PRINC);
- }
- 
- static bool del_cross_realm_princs(struct ipasam_private *ipasam_state,
--				   const char *domain)
-+				   const char *domain, const char *flat_name)
- {
- 	uint32_t trust_direction = LSA_TRUST_DIRECTION_INBOUND | LSA_TRUST_DIRECTION_OUTBOUND;
--	return handle_cross_realm_princs(ipasam_state, domain, NULL, trust_direction, DEL_PRINC);
-+	return handle_cross_realm_princs(ipasam_state, domain, flat_name,
-+					 NULL, NULL, trust_direction, DEL_PRINC);
- }
- 
- static bool get_trusted_domain_int(struct ipasam_private *ipasam_state,
-@@ -2439,8 +2517,8 @@ static NTSTATUS ipasam_set_trusted_domain(struct pdb_methods *methods,
- 	int ret, i, count;
- 	NTSTATUS status;
- 	TALLOC_CTX *tmp_ctx;
--	char *trustpw;
--	char *sid;
-+	char *trustpw_incoming, *trustpw_outgoing;
-+	char *sid, *tda_name;
- 	char **in_blacklist = NULL;
- 	char **out_blacklist = NULL;
- 	uint32_t enctypes, trust_offset;
-@@ -2465,6 +2543,8 @@ static NTSTATUS ipasam_set_trusted_domain(struct pdb_methods *methods,
- 				 LDAP_OBJ_TRUSTED_DOMAIN);
- 		smbldap_make_mod(priv2ld(ipasam_state), entry, &mods, "objectClass",
- 				 LDAP_OBJ_ID_OBJECT);
-+		smbldap_make_mod(priv2ld(ipasam_state), entry, &mods, "objectClass",
-+				 LDAP_OBJ_POSIXACCOUNT);
- 	}
- 
- 	if (entry != NULL) {
-@@ -2477,12 +2557,23 @@ static NTSTATUS ipasam_set_trusted_domain(struct pdb_methods *methods,
- 		smbldap_make_mod(priv2ld(ipasam_state), entry, &mods,
- 		                 LDAP_ATTRIBUTE_GIDNUMBER,
- 				 ipasam_state->fallback_primary_group_gid_str);
-+		smbldap_make_mod(priv2ld(ipasam_state), entry, &mods,
-+		                 LDAP_ATTRIBUTE_HOMEDIRECTORY,
-+				 "/dev/null");
- 	}
- 
- 	if (td->netbios_name != NULL) {
-+		tda_name = talloc_asprintf(tmp_ctx, "%s$", td->netbios_name);
-+		if (!tda_name) {
-+			status = NT_STATUS_UNSUCCESSFUL;
-+			goto done;
-+		}
- 		smbldap_make_mod(priv2ld(ipasam_state), entry, &mods,
- 				 LDAP_ATTRIBUTE_FLAT_NAME,
- 				 td->netbios_name);
-+		smbldap_make_mod(priv2ld(ipasam_state), entry, &mods,
-+				 LDAP_ATTRIBUTE_UID,
-+				 tda_name);
- 	}
- 
- 	if (td->domain_name != NULL) {
-@@ -2618,13 +2709,38 @@ static NTSTATUS ipasam_set_trusted_domain(struct pdb_methods *methods,
- 
- 	if (entry == NULL) { /* FIXME: allow password updates here */
- 		status = get_trust_pwd(tmp_ctx, &td->trust_auth_incoming,
--				       &trustpw, NULL);
-+				       &trustpw_incoming, NULL);
- 		if (!NT_STATUS_IS_OK(status)) {
- 			goto done;
- 		}
--		res = set_cross_realm_princs(ipasam_state, td->domain_name,
--					     trustpw, td->trust_direction);
--		memset(trustpw, 0, strlen(trustpw));
-+		status = get_trust_pwd(tmp_ctx, &td->trust_auth_outgoing,
-+				       &trustpw_outgoing, NULL);
-+		if (!NT_STATUS_IS_OK(status)) {
-+			goto done;
-+		}
-+		res = set_cross_realm_princs(ipasam_state, td->domain_name, td->netbios_name,
-+					     trustpw_incoming, trustpw_outgoing,
-+					     td->trust_direction);
-+		{
-+			/* Replace memset() use by an explicit loop to avoid
-+			 * both compile time and link time optimisations.
-+			 * We could have used memset_s() from C++11 but it is
-+			 * currently not implemented by GCC or glibc.
-+			 */
-+			volatile char *p = (void *) trustpw_incoming;
-+			volatile char *q = (void *) trustpw_outgoing;
-+			size_t plen = strlen(trustpw_incoming);
-+			size_t qlen = strlen(trustpw_outgoing);
-+
-+			while (plen--) {
-+				*p++ = '\0';
-+			}
-+
-+			while (qlen--) {
-+				*q++ = '\0';
-+			}
-+		}
-+
- 		if (!res) {
- 			DEBUG(1, ("error writing cross realm principals!\n"));
- 			status = NT_STATUS_UNSUCCESSFUL;
-@@ -2693,7 +2809,7 @@ static NTSTATUS ipasam_del_trusted_domain(struct pdb_methods *methods,
- 		talloc_get_type_abort(methods->private_data, struct ipasam_private);
- 	LDAPMessage *entry = NULL;
- 	char *dn;
--	const char *domain_name;
-+	const char *domain_name, *flat_name;
- 	TALLOC_CTX *tmp_ctx;
- 	NTSTATUS status;
- 
-@@ -2731,7 +2847,17 @@ static NTSTATUS ipasam_del_trusted_domain(struct pdb_methods *methods,
- 		goto done;
- 	}
- 
--	if (!del_cross_realm_princs(ipasam_state, domain_name)) {
-+	flat_name = get_single_attribute(tmp_ctx, priv2ld(ipasam_state), entry,
-+					 LDAP_ATTRIBUTE_FLAT_NAME);
-+	if (flat_name == NULL) {
-+		DEBUG(1, ("Attribute %s not present.\n",
-+			  LDAP_ATTRIBUTE_FLAT_NAME));
-+		status = NT_STATUS_INVALID_PARAMETER;
-+		goto done;
-+	}
-+
-+
-+	if (!del_cross_realm_princs(ipasam_state, domain_name, flat_name)) {
- 		DEBUG(1, ("error deleting cross realm principals!\n"));
- 		status = NT_STATUS_UNSUCCESSFUL;
- 		goto done;
--- 
-2.20.1
-
diff --git a/SOURCES/0012-add-default-access-control-when-migrating-trust-obje.patch b/SOURCES/0012-add-default-access-control-when-migrating-trust-obje.patch
new file mode 100644
index 0000000..bad7801
--- /dev/null
+++ b/SOURCES/0012-add-default-access-control-when-migrating-trust-obje.patch
@@ -0,0 +1,55 @@
+From 06eb54e3e8e645a64d915602a64834cc26bc8924 Mon Sep 17 00:00:00 2001
+From: Alexander Bokovoy <abokovoy@redhat.com>
+Date: Tue, 10 Sep 2019 13:39:39 +0300
+Subject: [PATCH] add default access control when migrating trust objects
+
+It looks like for some cases we do not have proper set up keytab
+retrieval configuration in the old trusted domain object. This mostly
+affects two-way trust cases. In such cases, create default configuration
+as ipasam would have created when trust was established.
+
+Resolves: https://pagure.io/freeipa/issue/8067
+
+Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
+Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
+---
+ ipaserver/install/plugins/adtrust.py | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
+index 12596d5bfe71c16a2cb87acb755a88051676e3e5..0dd2c840899abe3b51b9308d38a9d0f4d1fb2f9b 100644
+--- a/ipaserver/install/plugins/adtrust.py
++++ b/ipaserver/install/plugins/adtrust.py
+@@ -28,6 +28,9 @@ logger = logging.getLogger(__name__)
+ register = Registry()
+ 
+ DEFAULT_ID_RANGE_SIZE = 200000
++trust_read_keys_template = \
++    ["cn=adtrust agents,cn=sysaccounts,cn=etc,{basedn}",
++     "cn=trust admins,cn=groups,cn=accounts,{basedn}"]
+ 
+ 
+ @register()
+@@ -575,8 +578,15 @@ class update_tdo_to_new_layout(Updater):
+                     'krbprincipalkey')
+                 entry_data['krbextradata'] = en.single_value.get(
+                     'krbextradata')
+-                entry_data['ipaAllowedToPerform;read_keys'] = en.get(
+-                    'ipaAllowedToPerform;read_keys', [])
++                read_keys = en.get('ipaAllowedToPerform;read_keys', [])
++                if not read_keys:
++                    # Old style, no ipaAllowedToPerform;read_keys in the entry,
++                    # use defaults that ipasam should have set when creating a
++                    # trust
++                    read_keys = list(map(
++                        lambda x: x.format(basedn=self.api.env.basedn),
++                        trust_read_keys_template))
++                entry_data['ipaAllowedToPerform;read_keys'] = read_keys
+ 
+         entry.update(entry_data)
+         try:
+-- 
+2.20.1
+
diff --git a/SOURCES/0012-upgrade-upgrade-existing-trust-agreements-to-new-lay.patch b/SOURCES/0012-upgrade-upgrade-existing-trust-agreements-to-new-lay.patch
deleted file mode 100644
index d6a0c1e..0000000
--- a/SOURCES/0012-upgrade-upgrade-existing-trust-agreements-to-new-lay.patch
+++ /dev/null
@@ -1,443 +0,0 @@
-From baf93c9bdfcb761ab469efdb2a1ba4ae8485f165 Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Fri, 22 Mar 2019 19:02:16 +0200
-Subject: [PATCH] upgrade: upgrade existing trust agreements to new layout
-
-Existing trust agreements will lack required Kerberos principals and
-POSIX attributes expected to allow Active Directory domain controllers
-to query IPA master over LSA and NETLOGON RPC pipes.
-
-Upgrade code is split into two parts:
- - upgrade trusted domain object to have proper POSIX attributes
- - generate required Kerberos principals for AD DC communication
-
-Fixes: https://pagure.io/freeipa/issue/6077
-(cherry picked from commit 090e09df130f27fb30a986529ef0944383e668e1)
-
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- ipaserver/install/plugins/adtrust.py | 371 ++++++++++++++++++++++++---
- 1 file changed, 329 insertions(+), 42 deletions(-)
-
-diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
-index 1f50bef891770c53a9086c7aa36d0ee1f088fbe6..1461e000dc855a21665eb5ea0cfe4a47df419344 100644
---- a/ipaserver/install/plugins/adtrust.py
-+++ b/ipaserver/install/plugins/adtrust.py
-@@ -1,30 +1,27 @@
--# Authors:
--#   Martin Kosek <mkosek@redhat.com>
--#
--# Copyright (C) 2012  Red Hat
--# see file 'COPYING' for use and warranty information
--#
--# 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/>.
-+# Copyright (C) 2012-2019  FreeIPA Contributors see COPYING for license
- 
-+from __future__ import absolute_import
- import logging
- 
- from ipalib import Registry, errors
- from ipalib import Updater
- from ipapython.dn import DN
-+from ipapython import ipautil
-+from ipaplatform.paths import paths
- from ipaserver.install import sysupgrade
- from ipaserver.install.adtrustinstance import (
-     ADTRUSTInstance, map_Guests_to_nobody)
-+from ipaserver.dcerpc_common import TRUST_BIDIRECTIONAL
-+
-+try:
-+    from samba.ndr import ndr_unpack
-+    from samba.dcerpc import lsa, drsblobs
-+except ImportError:
-+    # If samba.ndr is not available, this machine is not provisioned
-+    # for serving a trust to Active Directory. As result, it does
-+    # not matter what ndr_unpack does but we save on pylint checks
-+    def ndr_unpack(x):
-+        raise NotImplementedError
- 
- logger = logging.getLogger(__name__)
- 
-@@ -325,6 +322,28 @@ class update_sids(Updater):
-         return False, ()
- 
- 
-+def get_gidNumber(ldap, env):
-+    # Read the gidnumber of the fallback group and returns a list with it
-+    dn = DN(('cn', ADTRUSTInstance.FALLBACK_GROUP_NAME),
-+            env.container_group,
-+            env.basedn)
-+
-+    try:
-+        entry = ldap.get_entry(dn, ['gidnumber'])
-+        gidNumber = entry.get('gidnumber')
-+    except errors.NotFound:
-+        logger.error("%s not found",
-+                     ADTRUSTInstance.FALLBACK_GROUP_NAME)
-+        return None
-+
-+    if gidNumber is None:
-+        logger.error("%s does not have a gidnumber",
-+                     ADTRUSTInstance.FALLBACK_GROUP_NAME)
-+        return None
-+
-+    return gidNumber
-+
-+
- @register()
- class update_tdo_gidnumber(Updater):
-     """
-@@ -340,43 +359,55 @@ class update_tdo_gidnumber(Updater):
-             logger.debug('AD Trusts are not enabled on this server')
-             return False, []
- 
--        # Read the gidnumber of the fallback group
--        dn = DN(('cn', ADTRUSTInstance.FALLBACK_GROUP_NAME),
--                self.api.env.container_group,
--                self.api.env.basedn)
--
--        try:
--            entry = ldap.get_entry(dn, ['gidnumber'])
--            gidNumber = entry.get('gidnumber')
--        except errors.NotFound:
--            logger.error("%s not found",
--                         ADTRUSTInstance.FALLBACK_GROUP_NAME)
--            return False, ()
--
-+        gidNumber = get_gidNumber(ldap, self.api.env)
-         if not gidNumber:
-             logger.error("%s does not have a gidnumber",
-                          ADTRUSTInstance.FALLBACK_GROUP_NAME)
-             return False, ()
- 
--        # For each trusted domain object, add gidNumber
-+        # For each trusted domain object, add posix attributes
-+        # to allow use of a trusted domain account by AD DCs
-+        # to authenticate against our Samba instance
-         try:
-             tdos = ldap.get_entries(
-                 DN(self.api.env.container_adtrusts, self.api.env.basedn),
-                 scope=ldap.SCOPE_ONELEVEL,
--                filter="(objectclass=ipaNTTrustedDomain)",
--                attrs_list=['gidnumber'])
-+                filter="(&(objectclass=ipaNTTrustedDomain)"
-+                       "(objectclass=ipaIDObject))",
-+                attrs_list=['gidnumber', 'uidnumber', 'objectclass',
-+                            'ipantsecurityidentifier',
-+                            'ipaNTTrustDirection'
-+                            'uid', 'cn', 'ipantflatname'])
-             for tdo in tdos:
-                 # if the trusted domain object does not contain gidnumber,
-                 # add the default fallback group gidnumber
-                 if not tdo.get('gidnumber'):
--                    try:
--                        tdo['gidnumber'] = gidNumber
--                        ldap.update_entry(tdo)
--                        logger.debug("Added gidnumber %s to %s",
--                                     gidNumber, tdo.dn)
--                    except Exception:
--                        logger.warning(
--                            "Failed to add gidnumber to %s", tdo.dn)
-+                    tdo['gidnumber'] = gidNumber
-+
-+                # Generate uidNumber and ipaNTSecurityIdentifier if
-+                # uidNumber is missing. We rely on sidgen plugin here
-+                # to generate ipaNTSecurityIdentifier.
-+                if not tdo.get('uidnumber'):
-+                    tdo['uidnumber'] = ['-1']
-+
-+                if 'posixAccount' not in tdo.get('objectclass'):
-+                    tdo['objectclass'].extend(['posixAccount'])
-+                # Based on the flat name of a TDO,
-+                # add user name FLATNAME$ (note dollar sign)
-+                # to allow SSSD to map this TDO to a POSIX account
-+                if not tdo.get('uid'):
-+                    tdo['uid'] = ["{flatname}$".format(
-+                                  flatname=tdo.single_value['ipantflatname'])]
-+                if not tdo.get('homedirectory'):
-+                    tdo['homedirectory'] = ['/dev/null']
-+
-+                # Store resulted entry
-+                try:
-+                    ldap.update_entry(tdo)
-+                except errors.ExecutionError as e:
-+                    logger.warning(
-+                        "Failed to update trusted domain object %s", tdo.dn)
-+                    logger.debug("Exception during TDO update: %s", str(e))
- 
-         except errors.NotFound:
-             logger.debug("No trusted domain object to update")
-@@ -400,3 +431,259 @@ class update_mapping_Guests_to_nobody(Updater):
- 
-         map_Guests_to_nobody()
-         return False, []
-+
-+
-+@register()
-+class update_tdo_to_new_layout(Updater):
-+    """
-+    Transform trusted domain objects into a new layout
-+
-+    There are now two Kerberos principals per direction of trust:
-+
-+    INBOUND:
-+     - krbtgt/<OUR REALM>@<REMOTE REALM>, enabled by default
-+
-+     - <OUR FLATNAME$>@<REMOTE REALM>, disabled by default on our side
-+       as it is only used by SSSD to retrieve TDO creds when operating
-+       as an AD Trust agent across IPA topology
-+
-+    OUTBOUND:
-+     - krbtgt/<REMOTE REALM>@<OUR REALM>, enabled by default
-+
-+     - <REMOTE FLATNAME$>@<OUR REALM>, enabled by default and
-+       used by remote trusted DCs to authenticate against us
-+
-+       This principal also has krbtgt/<REMOTE FLATNAME>@<OUR REALM> defined
-+       as a Kerberos principal alias. This is due to how Kerberos
-+       key salt is derived for cross-realm principals on AD side
-+
-+    Finally, Samba requires <REMOTE FLATNAME$> account to also possess POSIX
-+    and SMB identities. We ensure this by making the trusted domain object to
-+    be this account with 'uid' and 'cn' attributes being '<REMOTE FLATNAME$>'
-+    and uidNumber/gidNumber generated automatically. Also, we ensure the
-+    trusted domain object is given a SID.
-+
-+    The update to <REMOTE FLATNAME$> POSIX/SMB identities is done through
-+    the update plugin update_tdo_gidnumber.
-+    """
-+    tgt_principal_template = "krbtgt/{remote}@{local}"
-+    nbt_principal_template = "{nbt}$@{realm}"
-+    trust_filter = \
-+        "(&(objectClass=ipaNTTrustedDomain)(objectClass=ipaIDObject))"
-+    trust_attrs = ("ipaNTFlatName", "ipaNTTrustPartner", "ipaNTTrustDirection",
-+                   "cn", "ipaNTTrustAttributes", "ipaNTAdditionalSuffixes",
-+                   "ipaNTTrustedDomainSID", "ipaNTTrustType",
-+                   "ipaNTTrustAuthIncoming", "ipaNTTrustAuthOutgoing")
-+    change_password_template = \
-+        "change_password -pw {password} " \
-+        "-e aes256-cts-hmac-sha1-96,aes128-cts-hmac-sha1-96 " \
-+        "{principal}"
-+
-+    KRB_PRINC_CREATE_DEFAULT = 0x00000000
-+    KRB_PRINC_CREATE_DISABLED = 0x00000001
-+    KRB_PRINC_CREATE_AGENT_PERMISSION = 0x00000002
-+    KRB_PRINC_CREATE_IDENTITY = 0x00000004
-+    KRB_PRINC_MUST_EXIST = 0x00000008
-+
-+    # This is a flag for krbTicketFlags attribute
-+    # to disallow creating any tickets using this principal
-+    KRB_DISALLOW_ALL_TIX = 0x00000040
-+
-+    def retrieve_trust_password(self, packed):
-+        # The structure of the trust secret is described at
-+        # https://github.com/samba-team/samba/blob/master/
-+        # librpc/idl/drsblobs.idl#L516-L569
-+        # In our case in LDAP TDO object stores
-+        # `struct trustAuthInOutBlob` that has `count` and
-+        # the `current` of `AuthenticationInformationArray` struct
-+        # which has own `count` and `array` of `AuthenticationInformation`
-+        # structs that have `AuthType` field which should be equal to
-+        # `LSA_TRUST_AUTH_TYPE_CLEAR`.
-+        # Then AuthInfo field would contain a password as an array of bytes
-+        assert(packed.count != 0)
-+        assert(packed.current.count != 0)
-+        assert(packed.current.array[0].AuthType == lsa.TRUST_AUTH_TYPE_CLEAR)
-+        clear_value = packed.current.array[0].AuthInfo.password
-+
-+        return ''.join(map(chr, clear_value))
-+
-+    def set_krb_principal(self, principals, password, trustdn, flags=None):
-+
-+        ldap = self.api.Backend.ldap2
-+
-+        if isinstance(principals, (list, tuple)):
-+            trust_principal = principals[0]
-+            aliases = principals[1:]
-+        else:
-+            trust_principal = principals
-+            aliases = []
-+
-+        try:
-+            entry = ldap.get_entry(
-+                DN(('krbprincipalname', trust_principal), trustdn))
-+            dn = entry.dn
-+            action = ldap.update_entry
-+            logger.debug("Updating Kerberos principal entry for %s",
-+                         trust_principal)
-+        except errors.NotFound:
-+            # For a principal that must exist, we re-raise the exception
-+            # to let the caller to handle this situation
-+            if flags & self.KRB_PRINC_MUST_EXIST:
-+                raise
-+
-+            dn = DN(('krbprincipalname', trust_principal), trustdn)
-+            entry = ldap.make_entry(dn)
-+            logger.debug("Adding Kerberos principal entry for %s",
-+                         trust_principal)
-+            action = ldap.add_entry
-+
-+        entry_data = {
-+            'objectclass':
-+                ['krbPrincipal', 'krbPrincipalAux',
-+                 'krbTicketPolicyAux', 'top'],
-+            'krbcanonicalname': [trust_principal],
-+            'krbprincipalname': [trust_principal],
-+        }
-+
-+        entry_data['krbprincipalname'].extend(aliases)
-+
-+        if flags & self.KRB_PRINC_CREATE_DISABLED:
-+            flg = int(entry.single_value.get('krbticketflags', 0))
-+            entry_data['krbticketflags'] = flg | self.KRB_DISALLOW_ALL_TIX
-+
-+        if flags & self.KRB_PRINC_CREATE_AGENT_PERMISSION:
-+            entry_data['objectclass'].extend(['ipaAllowedOperations'])
-+
-+        entry.update(entry_data)
-+        try:
-+            action(entry)
-+        except errors.EmptyModlist:
-+            logger.debug("No update was required for Kerberos principal %s",
-+                         trust_principal)
-+
-+        # If entry existed, no need to set Kerberos keys on it
-+        if action == ldap.update_entry:
-+            logger.debug("No need to update Kerberos keys for "
-+                         "existing Kerberos principal %s",
-+                         trust_principal)
-+            return
-+
-+        # Now that entry is updated, set its Kerberos keys.
-+        #
-+        # It would be a complication to use ipa-getkeytab LDAP extended control
-+        # here because we would need to encode the request in ASN.1 sequence
-+        # and we don't have the code to do so exposed in Python bindings.
-+        # Instead, as we run on IPA master, we can use kadmin.local for that
-+        # directly.
-+        # We pass the command as a stdin to both avoid shell interpolation
-+        # of the passwords and also to avoid its exposure to other processes
-+        # Since we don't want to record the output, make also a redacted log
-+        change_password = self.change_password_template.format(
-+            password=password,
-+            principal=trust_principal)
-+
-+        redacted = self.change_password_template.format(
-+            password='<REDACTED OUT>',
-+            principal=trust_principal)
-+        logger.debug("Updating Kerberos keys for %s with the following "
-+                     "kadmin command:\n\t%s", trust_principal, redacted)
-+
-+        ipautil.run([paths.KADMIN_LOCAL, "-x",
-+                    "ipa-setup-override-restrictions"],
-+                    stdin=change_password, skip_output=True)
-+
-+    def execute(self, **options):
-+        # First, see if trusts are enabled on the server
-+        if not self.api.Command.adtrust_is_enabled()['result']:
-+            logger.debug('AD Trusts are not enabled on this server')
-+            return False, []
-+
-+        ldap = self.api.Backend.ldap2
-+        gidNumber = get_gidNumber(ldap, self.api.env)
-+        if gidNumber is None:
-+            return False, []
-+
-+        result = self.api.Command.trustconfig_show()['result']
-+        our_nbt_name = result.get('ipantflatname', [None])[0]
-+        if not our_nbt_name:
-+            return False, []
-+
-+        trusts_dn = self.api.env.container_adtrusts + self.api.env.basedn
-+
-+        trusts = ldap.get_entries(
-+            base_dn=trusts_dn,
-+            scope=ldap.SCOPE_ONELEVEL,
-+            filter=self.trust_filter,
-+            attrs_list=self.trust_attrs)
-+
-+        # For every trust, retrieve its principals and convert
-+        for t_entry in trusts:
-+            t_dn = t_entry.dn
-+            logger.debug('Processing trust domain object %s', str(t_dn))
-+            t_realm = t_entry.single_value.get('ipaNTTrustPartner').upper()
-+            direction = int(t_entry.single_value.get('ipaNTTrustDirection'))
-+            passwd_incoming = self.retrieve_trust_password(
-+                ndr_unpack(drsblobs.trustAuthInOutBlob,
-+                           t_entry.single_value.get('ipaNTTrustAuthIncoming')))
-+            passwd_outgoing = self.retrieve_trust_password(
-+                ndr_unpack(drsblobs.trustAuthInOutBlob,
-+                           t_entry.single_value.get('ipaNTTrustAuthOutgoing')))
-+            # For outbound and inbound trusts, process four principals total
-+            if (direction & TRUST_BIDIRECTIONAL) == TRUST_BIDIRECTIONAL:
-+                # 1. OUTBOUND: krbtgt/<REMOTE REALM>@<OUR REALM> must exist
-+                trust_principal = self.tgt_principal_template.format(
-+                    remote=t_realm, local=self.api.env.realm)
-+                try:
-+                    self.set_krb_principal(trust_principal,
-+                                           passwd_outgoing,
-+                                           t_dn,
-+                                           flags=self.KRB_PRINC_CREATE_DEFAULT)
-+                except errors.NotFound:
-+                    # It makes no sense to convert this one, skip the trust
-+                    # completely, better to re-establish one
-+                    logger.error(
-+                        "Broken trust to AD: %s not found, "
-+                        "please re-establish the trust to %s",
-+                        trust_principal, t_realm)
-+                    continue
-+
-+                # 2. Create <REMOTE FLATNAME$>@<OUR REALM>
-+                nbt_name = t_entry.single_value.get('ipaNTFlatName')
-+                nbt_principal = self.nbt_principal_template.format(
-+                    nbt=nbt_name, realm=self.api.env.realm)
-+                tgt_principal = self.tgt_principal_template.format(
-+                    remote=nbt_name, local=self.api.env.realm)
-+                self.set_krb_principal([nbt_principal, tgt_principal],
-+                                       passwd_incoming,
-+                                       t_dn,
-+                                       flags=self.KRB_PRINC_CREATE_DEFAULT)
-+
-+            # 3. INBOUND: krbtgt/<OUR REALM>@<REMOTE REALM> must exist
-+            trust_principal = self.tgt_principal_template.format(
-+                remote=self.api.env.realm, local=t_realm)
-+            try:
-+                self.set_krb_principal(trust_principal, passwd_outgoing,
-+                                       t_dn,
-+                                       flags=self.KRB_PRINC_CREATE_DEFAULT)
-+            except errors.NotFound:
-+                # It makes no sense to convert this one, skip the trust
-+                # completely, better to re-establish one
-+                logger.error(
-+                    "Broken trust to AD: %s not found, "
-+                    "please re-establish the trust to %s",
-+                    trust_principal, t_realm)
-+                continue
-+
-+            # 4. Create <OUR FLATNAME$>@<REMOTE REALM>, disabled
-+            nbt_principal = self.nbt_principal_template.format(
-+                nbt=our_nbt_name, realm=t_realm)
-+            tgt_principal = self.tgt_principal_template.format(
-+                remote=our_nbt_name, local=t_realm)
-+            self.set_krb_principal([nbt_principal, tgt_principal],
-+                                   passwd_incoming,
-+                                   t_dn,
-+                                   flags=self.KRB_PRINC_CREATE_DEFAULT |
-+                                   self.KRB_PRINC_CREATE_AGENT_PERMISSION |
-+                                   self.KRB_PRINC_CREATE_DISABLED)
-+
-+        return False, []
--- 
-2.20.1
-
diff --git a/SOURCES/0013-adtrust-add-default-read_keys-permission-for-TDO-obj.patch b/SOURCES/0013-adtrust-add-default-read_keys-permission-for-TDO-obj.patch
new file mode 100644
index 0000000..6868b4c
--- /dev/null
+++ b/SOURCES/0013-adtrust-add-default-read_keys-permission-for-TDO-obj.patch
@@ -0,0 +1,105 @@
+From 847e3d053fc5243a9fce7af673cb138983a3255c Mon Sep 17 00:00:00 2001
+From: Alexander Bokovoy <abokovoy@redhat.com>
+Date: Thu, 12 Sep 2019 11:21:51 +0300
+Subject: [PATCH] adtrust: add default read_keys permission for TDO objects
+
+If trusted domain object (TDO) is lacking ipaAllowedToPerform;read_keys
+attribute values, it cannot be used by SSSD to retrieve TDO keys and the
+whole communication with Active Directory domain controllers will not be
+possible.
+
+This seems to affect trusts which were created before
+ipaAllowedToPerform;read_keys permission granting was introduced
+(FreeIPA 4.2). Add back the default setting for the permissions which
+grants access to trust agents and trust admins.
+
+Resolves: https://pagure.io/freeipa/issue/8067
+
+Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
+Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
+---
+ .../updates/90-post_upgrade_plugins.update    |  1 +
+ ipaserver/install/plugins/adtrust.py          | 56 +++++++++++++++++++
+ 2 files changed, 57 insertions(+)
+
+diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update
+index 6cd87a4226e34839ba7625fa03893cd8fb902386..e3afb3423ccaf1598bc0a0e982a5264781fd81a4 100644
+--- a/install/updates/90-post_upgrade_plugins.update
++++ b/install/updates/90-post_upgrade_plugins.update
+@@ -12,6 +12,7 @@ plugin: update_default_range
+ plugin: update_default_trust_view
+ plugin: update_tdo_gidnumber
+ plugin: update_tdo_to_new_layout
++plugin: update_tdo_default_read_keys_permissions
+ plugin: update_ca_renewal_master
+ plugin: update_idrange_type
+ plugin: update_pacs
+diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
+index 0dd2c840899abe3b51b9308d38a9d0f4d1fb2f9b..fca83aa6df2cc3fafca91f2ed55339dba016a1fa 100644
+--- a/ipaserver/install/plugins/adtrust.py
++++ b/ipaserver/install/plugins/adtrust.py
+@@ -727,3 +727,59 @@ class update_tdo_to_new_layout(Updater):
+                                    self.KRB_PRINC_CREATE_DISABLED)
+ 
+         return False, []
++
++
++@register()
++class update_tdo_default_read_keys_permissions(Updater):
++    trust_filter = \
++        "(&(objectClass=krbPrincipal)(krbPrincipalName=krbtgt/{nbt}@*))"
++
++    def execute(self, **options):
++        ldap = self.api.Backend.ldap2
++
++        # First, see if trusts are enabled on the server
++        if not self.api.Command.adtrust_is_enabled()['result']:
++            logger.debug('AD Trusts are not enabled on this server')
++            return False, []
++
++        result = self.api.Command.trustconfig_show()['result']
++        our_nbt_name = result.get('ipantflatname', [None])[0]
++        if not our_nbt_name:
++            return False, []
++
++        trusts_dn = self.api.env.container_adtrusts + self.api.env.basedn
++        trust_filter = self.trust_filter.format(nbt=our_nbt_name)
++
++        # We might be in a situation when no trusts exist yet
++        # In such case there is nothing to upgrade but we have to catch
++        # an exception or it will abort the whole upgrade process
++        try:
++            tdos = ldap.get_entries(
++                base_dn=trusts_dn,
++                scope=ldap.SCOPE_SUBTREE,
++                filter=trust_filter,
++                attrs_list=['*'])
++        except errors.EmptyResult:
++            tdos = []
++
++        for tdo in tdos:
++            updates = dict()
++            oc = tdo.get('objectClass', [])
++            if 'ipaAllowedOperations' not in oc:
++                updates['objectClass'] = oc + ['ipaAllowedOperations']
++
++            read_keys = tdo.get('ipaAllowedToPerform;read_keys', [])
++            if not read_keys:
++                read_keys_values = list(map(
++                    lambda x: x.format(basedn=self.api.env.basedn),
++                    trust_read_keys_template))
++                updates['ipaAllowedToPerform;read_keys'] = read_keys_values
++
++            tdo.update(updates)
++            try:
++                ldap.update_entry(tdo)
++            except errors.EmptyModlist:
++                logger.debug("No update was required for TDO %s",
++                             tdo.single_value.get('krbCanonicalName'))
++
++        return False, []
+-- 
+2.20.1
+
diff --git a/SOURCES/0013-upgrade-add-trust-upgrade-to-actual-upgrade-code.patch b/SOURCES/0013-upgrade-add-trust-upgrade-to-actual-upgrade-code.patch
deleted file mode 100644
index 86aebcf..0000000
--- a/SOURCES/0013-upgrade-add-trust-upgrade-to-actual-upgrade-code.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 25166da75410026b9b634535caacb7747cd88cd1 Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Fri, 22 Mar 2019 19:08:33 +0200
-Subject: [PATCH] upgrade: add trust upgrade to actual upgrade code
-
-Fixes: https://pagure.io/freeipa/issue/6077
-(cherry picked from commit f51f90e4b4bac032e076ab0f6cb3dfecb5ae12ce)
-
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- install/updates/90-post_upgrade_plugins.update | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update
-index 4e9378d9b567842e1cc9a8eeae819a931810895d..a9f5f6a924d330b924d9adb8b7eee728258f27c6 100644
---- a/install/updates/90-post_upgrade_plugins.update
-+++ b/install/updates/90-post_upgrade_plugins.update
-@@ -11,6 +11,7 @@ plugin: update_sids
- plugin: update_default_range
- plugin: update_default_trust_view
- plugin: update_tdo_gidnumber
-+plugin: update_tdo_to_new_layout
- plugin: update_ca_renewal_master
- plugin: update_idrange_type
- plugin: update_pacs
--- 
-2.20.1
-
diff --git a/SOURCES/0014-Disable-deprecated-lambda-check-in-adtrust-upgrade-c.patch b/SOURCES/0014-Disable-deprecated-lambda-check-in-adtrust-upgrade-c.patch
new file mode 100644
index 0000000..4f0f10f
--- /dev/null
+++ b/SOURCES/0014-Disable-deprecated-lambda-check-in-adtrust-upgrade-c.patch
@@ -0,0 +1,38 @@
+From 78c4838bcf3528018b06d73d1b82bde7f575f2db Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Mon, 16 Sep 2019 09:38:19 -0400
+Subject: [PATCH] Disable deprecated-lambda check in adtrust upgrade code
+
+It is interesting that we don't have this problem with newer
+Python and pylint versions. Ignoring to try to keep the code
+more in line with newer releases.
+
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
+---
+ ipaserver/install/plugins/adtrust.py | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
+index fca83aa6df2cc3fafca91f2ed55339dba016a1fa..950b7b9c82f1b0e115675ff8093d1bd02e913ae2 100644
+--- a/ipaserver/install/plugins/adtrust.py
++++ b/ipaserver/install/plugins/adtrust.py
+@@ -583,6 +583,7 @@ class update_tdo_to_new_layout(Updater):
+                     # Old style, no ipaAllowedToPerform;read_keys in the entry,
+                     # use defaults that ipasam should have set when creating a
+                     # trust
++                    # pylint: disable=deprecated-lambda
+                     read_keys = list(map(
+                         lambda x: x.format(basedn=self.api.env.basedn),
+                         trust_read_keys_template))
+@@ -770,6 +771,7 @@ class update_tdo_default_read_keys_permissions(Updater):
+ 
+             read_keys = tdo.get('ipaAllowedToPerform;read_keys', [])
+             if not read_keys:
++                # pylint: disable=deprecated-lambda
+                 read_keys_values = list(map(
+                     lambda x: x.format(basedn=self.api.env.basedn),
+                     trust_read_keys_template))
+-- 
+2.20.1
+
diff --git a/SOURCES/0014-RFE-ipa-client-should-setup-openldap-for-GSSAPI.patch b/SOURCES/0014-RFE-ipa-client-should-setup-openldap-for-GSSAPI.patch
deleted file mode 100644
index b2e2e77..0000000
--- a/SOURCES/0014-RFE-ipa-client-should-setup-openldap-for-GSSAPI.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-From 8cdf6a3dd64d36f40a9107dad2ab2d9a470f58b5 Mon Sep 17 00:00:00 2001
-From: amitkuma <amitkuma@redhat.com>
-Date: Tue, 16 Jan 2018 17:34:08 +0530
-Subject: [PATCH] RFE: ipa client should setup openldap for GSSAPI
-
-The IPA client installer currently edits /etc/openldap/ldap.conf, setting up
-the client to consume LDAP data from IPA.  It currently sets:
-URI
-BASE
-TLS_CACERT
-
-This PR makes ipa-client to add this AV pair:
-SASL_MECH GSSAPI
-
-Resolves: https://pagure.io/freeipa/issue/7366
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- ipaclient/install/client.py | 14 ++++++++++++--
- 1 file changed, 12 insertions(+), 2 deletions(-)
-
-diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py
-index babebfc667c5a096fb2e0238de444ffa3ce62b77..ca404ab80fd1586e7098950545a343fa6812ca39 100644
---- a/ipaclient/install/client.py
-+++ b/ipaclient/install/client.py
-@@ -523,8 +523,12 @@ def configure_openldap_conf(fstore, cli_basedn, cli_server):
-         {
-             'name': 'comment',
-             'type': 'comment',
--            'value': '   URI, BASE and TLS_CACERT have been added if they '
--                     'were not set.'
-+            'value': '   URI, BASE, TLS_CACERT and SASL_MECH'
-+        },
-+        {
-+            'name': 'comment',
-+            'type': 'comment',
-+            'value': '   have been added if they were not set.'
-         },
-         {
-             'name': 'comment',
-@@ -575,6 +579,12 @@ def configure_openldap_conf(fstore, cli_basedn, cli_server):
-             'type': 'option',
-             'value': paths.IPA_CA_CRT
-         },
-+        {
-+            'action': 'addifnotset',
-+            'name': 'SASL_MECH',
-+            'type': 'option',
-+            'value': 'GSSAPI'
-+        },
-     ]
- 
-     target_fname = paths.OPENLDAP_LDAP_CONF
--- 
-2.20.1
-
diff --git a/SOURCES/0015-Add-uniqueness-constraint-on-CA-ACL-name.patch b/SOURCES/0015-Add-uniqueness-constraint-on-CA-ACL-name.patch
deleted file mode 100644
index f689e9b..0000000
--- a/SOURCES/0015-Add-uniqueness-constraint-on-CA-ACL-name.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 4145fbdb5428b11274344cfc97eb2fe5ba9537a5 Mon Sep 17 00:00:00 2001
-From: Fraser Tweedale <ftweedal@redhat.com>
-Date: Thu, 7 Dec 2017 12:52:54 +1100
-Subject: [PATCH] Add uniqueness constraint on CA ACL name
-
-It is possible to add caacl entries with same "name" (cn).  The
-command is supposed to prevent this but direct LDAP operations allow
-it and doing that will cause subsequent errors.
-
-Enable the DS uniqueness constraint plugin for the cn attribute in
-CA ACL entries.
-
-Fixes: https://pagure.io/freeipa/issue/7304
-Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- install/updates/10-uniqueness.update | 17 +++++++++++++++++
- 1 file changed, 17 insertions(+)
-
-diff --git a/install/updates/10-uniqueness.update b/install/updates/10-uniqueness.update
-index 050bfd55ec2e6a09c44700ae40757ee1d72c136f..77facba195cb5a1564818010f97afdd15d65a274 100644
---- a/install/updates/10-uniqueness.update
-+++ b/install/updates/10-uniqueness.update
-@@ -92,3 +92,20 @@ add:uniqueness-across-all-subtrees: on
- dn: cn=ipaUniqueID uniqueness,cn=plugins,cn=config
- add:uniqueness-exclude-subtrees: cn=staged users,cn=accounts,cn=provisioning,$SUFFIX
- add:uniqueness-across-all-subtrees: on
-+
-+dn: cn=caacl name uniqueness,cn=plugins,cn=config
-+default:objectClass: top
-+default:objectClass: nsSlapdPlugin
-+default:objectClass: extensibleObject
-+default:cn: caacl name uniqueness
-+default:nsslapd-pluginDescription: Enforce unique attribute values
-+default:nsslapd-pluginPath: libattr-unique-plugin
-+default:nsslapd-pluginInitfunc: NSUniqueAttr_Init
-+default:nsslapd-pluginType: preoperation
-+default:nsslapd-pluginEnabled: on
-+default:uniqueness-attribute-name: cn
-+default:uniqueness-subtrees: cn=caacls,cn=ca,$SUFFIX
-+default:nsslapd-plugin-depends-on-type: database
-+default:nsslapd-pluginId: NSUniqueAttr
-+default:nsslapd-pluginVersion: 1.1.0
-+default:nsslapd-pluginVendor: Fedora Project
--- 
-2.20.1
-
diff --git a/SOURCES/0015-Fix-segfault-in-ipadb_parse_ldap_entry.patch b/SOURCES/0015-Fix-segfault-in-ipadb_parse_ldap_entry.patch
new file mode 100644
index 0000000..0dd39f3
--- /dev/null
+++ b/SOURCES/0015-Fix-segfault-in-ipadb_parse_ldap_entry.patch
@@ -0,0 +1,49 @@
+From 480f8a40e9ff8d7f344faac1a9af64972cf2288a Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Thu, 5 Sep 2019 13:00:27 -0400
+Subject: [PATCH] Fix segfault in ipadb_parse_ldap_entry()
+
+lcontext may be NULL here, probably due to a restarted 389ds.  Based on
+a patch by Rob Crittenden.
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+---
+ daemons/ipa-kdb/ipa_kdb_principals.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c
+index b27612258bbe198154dea5b5d79e551caf9857d1..0fe8e396b9bc011b77b183851389f6c57c70a2c9 100644
+--- a/daemons/ipa-kdb/ipa_kdb_principals.c
++++ b/daemons/ipa-kdb/ipa_kdb_principals.c
+@@ -21,7 +21,9 @@
+  */
+ 
+ #include "ipa_kdb.h"
++#include "ipa_krb5.h"
+ #include <unicase.h>
++#include <syslog.h>
+ 
+ /*
+  * During TGS request search by ipaKrbPrincipalName (case-insensitive)
+@@ -554,6 +556,17 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
+         return KRB5_KDB_DBNOTINITED;
+     }
+     lcontext = ipactx->lcontext;
++    if (!lcontext) {
++        krb5_klog_syslog(LOG_INFO,
++                         "No LDAP connection in ipadb_parse_ldap_entry(); retrying...\n");
++        ret = ipadb_get_connection(ipactx);
++        if (ret != 0) {
++            krb5_klog_syslog(LOG_ERR,
++                             "No LDAP connection on retry in ipadb_parse_ldap_entry()!\n");
++            kerr = KRB5_KDB_INTERNAL_ERROR;
++            goto done;
++        }
++    }
+ 
+     entry->magic = KRB5_KDB_MAGIC_NUMBER;
+     entry->len = KRB5_KDB_V1_BASE_LENGTH;
+-- 
+2.20.1
+
diff --git a/SOURCES/0016-Add-sysadm_r-to-default-SELinux-user-map-order.patch b/SOURCES/0016-Add-sysadm_r-to-default-SELinux-user-map-order.patch
deleted file mode 100644
index 99f519e..0000000
--- a/SOURCES/0016-Add-sysadm_r-to-default-SELinux-user-map-order.patch
+++ /dev/null
@@ -1,69 +0,0 @@
-From dfb0b27748aebb307fa3ab72aa1c43a71da1d78e Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= <fcami@redhat.com>
-Date: Fri, 9 Nov 2018 17:30:32 +0100
-Subject: [PATCH] Add sysadm_r to default SELinux user map order
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-It is a standard SELinux user role included in RHEL (like
-user_r, staff_r, guest_r) and used quite often.
-
-Fixes: https://pagure.io/freeipa/issue/7658
-Signed-off-by: François Cami <fcami@redhat.com>
-Reviewed-By: Rob Crittenden <rcritten@redhat.com>
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- install/share/bootstrap-template.ldif      | 2 +-
- install/ui/test/data/ipa_init.json         | 2 +-
- ipatests/test_xmlrpc/test_config_plugin.py | 8 ++++++--
- 3 files changed, 8 insertions(+), 4 deletions(-)
-
-diff --git a/install/share/bootstrap-template.ldif b/install/share/bootstrap-template.ldif
-index 1b80794e66a5986d049195885ae1c9d6380eec81..6cd17e37ef147169b65709a56b0fa7312889c262 100644
---- a/install/share/bootstrap-template.ldif
-+++ b/install/share/bootstrap-template.ldif
-@@ -425,7 +425,7 @@ ipaDefaultEmailDomain: $DOMAIN
- ipaMigrationEnabled: FALSE
- ipaConfigString: AllowNThash
- ipaConfigString: KDC:Disable Last Success
--ipaSELinuxUserMapOrder: guest_u:s0$$xguest_u:s0$$user_u:s0$$staff_u:s0-s0:c0.c1023$$unconfined_u:s0-s0:c0.c1023
-+ipaSELinuxUserMapOrder: guest_u:s0$$xguest_u:s0$$user_u:s0$$staff_u:s0-s0:c0.c1023$$sysadm_u:s0-s0:c0.c1023$$unconfined_u:s0-s0:c0.c1023
- ipaSELinuxUserMapDefault: unconfined_u:s0-s0:c0.c1023
- 
- dn: cn=cosTemplates,cn=accounts,$SUFFIX
-diff --git a/install/ui/test/data/ipa_init.json b/install/ui/test/data/ipa_init.json
-index dd4b84cc920408ec8fa0bb92e9d6debc67cede7e..52f6ab191e05b314fcbeaa4786230e5ae2ebea4b 100644
---- a/install/ui/test/data/ipa_init.json
-+++ b/install/ui/test/data/ipa_init.json
-@@ -863,7 +863,7 @@
-                   "ipausers"
-                ],
-                "ipaselinuxusermaporder" : [
--                  "guest_u:s0$xguest_u:s0$user_u:s0$staff_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023"
-+                  "guest_u:s0$xguest_u:s0$user_u:s0$staff_u:s0-s0:c0.c1023$sysadm_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023"
-                ],
-                "ca_renewal_master_server" : [
-                   "vm.example.com"
-diff --git a/ipatests/test_xmlrpc/test_config_plugin.py b/ipatests/test_xmlrpc/test_config_plugin.py
-index a277eab7eeb44590f982510564e92935c444c744..bd5a62acbed6a6c29bbf5fcbd041ef59bb0363bd 100644
---- a/ipatests/test_xmlrpc/test_config_plugin.py
-+++ b/ipatests/test_xmlrpc/test_config_plugin.py
-@@ -148,8 +148,12 @@ class test_config(Declarative):
- 
-         dict(
-             desc='Try to set new selinux order and invalid default user',
--            command=('config_mod', [],
--                dict(ipaselinuxusermaporder=u'xguest_u:s0$guest_u:s0$user_u:s0-s0:c0.c1023$staff_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023',
-+            command=(
-+                'config_mod', [],
-+                dict(
-+                    ipaselinuxusermaporder=u'xguest_u:s0$guest_u:s0'
-+                    u'$user_u:s0-s0:c0.c1023$staff_u:s0-s0:c0.c1023'
-+                    u'$sysadm_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023',
-                     ipaselinuxusermapdefault=u'unknown_u:s0')),
-             expected=errors.ValidationError(name='ipaselinuxusermapdefault',
-                 error='SELinux user map default user not in order list'),
--- 
-2.20.1
-
diff --git a/SOURCES/0016-ipa-restore-Restore-ownership-and-perms-on-389-ds-lo.patch b/SOURCES/0016-ipa-restore-Restore-ownership-and-perms-on-389-ds-lo.patch
new file mode 100644
index 0000000..c375293
--- /dev/null
+++ b/SOURCES/0016-ipa-restore-Restore-ownership-and-perms-on-389-ds-lo.patch
@@ -0,0 +1,42 @@
+From 24f33237eda1fddd82010b88fe1e8033a4c27976 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Fri, 20 Sep 2019 15:36:36 -0400
+Subject: [PATCH] ipa-restore: Restore ownership and perms on 389-ds log
+ directory
+
+Previously it would end up being owned by root:root mode 0755
+instead of dirsrv:dirsrv mode 0770.
+
+https://pagure.io/freeipa/issue/7725
+
+Signed-off-by: Rob Crittenden <rcritten@redhat.com>
+Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
+Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
+---
+ ipaserver/install/ipa_restore.py | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py
+index 4941831585f473c4937b23b3f59d8ff99a654b0e..917f516c8fa414b23dcb451c9105c59e0afeec51 100644
+--- a/ipaserver/install/ipa_restore.py
++++ b/ipaserver/install/ipa_restore.py
+@@ -592,11 +592,15 @@ class Restore(admintool.AdminTool):
+             logger.info("Waiting for LDIF to finish")
+             wait_for_task(conn, dn)
+         else:
++            template_dir = paths.VAR_LOG_DIRSRV_INSTANCE_TEMPLATE % instance
+             try:
+-                os.makedirs(paths.VAR_LOG_DIRSRV_INSTANCE_TEMPLATE % instance)
++                os.makedirs(template_dir)
+             except OSError as e:
+                 pass
+ 
++            os.chown(template_dir, pent.pw_uid, pent.pw_gid)
++            os.chmod(template_dir, 0o770)
++
+             args = [paths.LDIF2DB,
+                     '-Z', instance,
+                     '-i', ldiffile,
+-- 
+2.20.1
+
diff --git a/SOURCES/0017-Extend-CALessBase-installer_server-to-accept-extra_a.patch b/SOURCES/0017-Extend-CALessBase-installer_server-to-accept-extra_a.patch
deleted file mode 100644
index ae49738..0000000
--- a/SOURCES/0017-Extend-CALessBase-installer_server-to-accept-extra_a.patch
+++ /dev/null
@@ -1,55 +0,0 @@
-From 853b56f4096734c47a26cf11767a7d6d582b11eb Mon Sep 17 00:00:00 2001
-From: Rob Crittenden <rcritten@redhat.com>
-Date: Mon, 25 Jun 2018 17:04:16 -0400
-Subject: [PATCH] Extend CALessBase::installer_server to accept extra_args
-
-Allow callers to pass abitrary extra arguments to the installer.
-
-This is useful when using a CALess installation in order to
-speed up tests that require a full install but do not require
-a full PKI.
-
-Reviewed-By: Rob Crittenden <rcritten@redhat.com>
-Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- ipatests/test_integration/test_caless.py | 16 +++++++++++-----
- 1 file changed, 11 insertions(+), 5 deletions(-)
-
-diff --git a/ipatests/test_integration/test_caless.py b/ipatests/test_integration/test_caless.py
-index ff8d95caa6fed00d3876f1d08e2170a9587a6d86..1ebe8fa368b88e949c0bd30bfc3999bf15c4df66 100644
---- a/ipatests/test_integration/test_caless.py
-+++ b/ipatests/test_integration/test_caless.py
-@@ -171,7 +171,7 @@ class CALessBase(IntegrationTest):
-                        http_pin=_DEFAULT, dirsrv_pin=_DEFAULT, pkinit_pin=None,
-                        root_ca_file='root.pem', pkinit_pkcs12_exists=False,
-                        pkinit_pkcs12='server-kdc.p12', unattended=True,
--                       stdin_text=None):
-+                       stdin_text=None, extra_args=None):
-         """Install a CA-less server
- 
-         Return value is the remote ipa-server-install command
-@@ -179,10 +179,16 @@ class CALessBase(IntegrationTest):
-         if host is None:
-             host = cls.master
- 
--        extra_args = ['--http-cert-file', http_pkcs12,
--                      '--dirsrv-cert-file', dirsrv_pkcs12,
--                      '--ca-cert-file', root_ca_file,
--                      '--ip-address', host.ip]
-+        std_args = [
-+            '--http-cert-file', http_pkcs12,
-+            '--dirsrv-cert-file', dirsrv_pkcs12,
-+            '--ca-cert-file', root_ca_file,
-+            '--ip-address', host.ip
-+        ]
-+        if extra_args:
-+            extra_args.extend(std_args)
-+        else:
-+            extra_args = std_args
- 
-         if http_pin is _DEFAULT:
-             http_pin = cls.cert_password
--- 
-2.20.1
-
diff --git a/SOURCES/0017-replica-install-enforce-server-arg.patch b/SOURCES/0017-replica-install-enforce-server-arg.patch
new file mode 100644
index 0000000..014e04f
--- /dev/null
+++ b/SOURCES/0017-replica-install-enforce-server-arg.patch
@@ -0,0 +1,123 @@
+From 6953cecad70fc183ca4a8eddc467a7efa7ff83d3 Mon Sep 17 00:00:00 2001
+From: Florence Blanc-Renaud <flo@redhat.com>
+Date: Mon, 9 Sep 2019 12:58:48 +0200
+Subject: [PATCH] replica install: enforce --server arg
+
+When the --server option is provided to ipa-replica-install (1-step
+install), make sure that the server offers all the required roles
+(CA, KRA). If it's not the case, refuse the installation.
+
+Note that the --server option is ignored when promoting from client to
+replica (2-step install with ipa-client-install and ipa-replica-install),
+meaning that the existing behavior is not changed in this use case:
+by default the host specified in default.conf as server is used for
+enrollment, but if it does not provide a required role, another host can
+be picked for CA or KRA setup.
+
+Fixes: https://pagure.io/freeipa/issue/7566
+Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+Reviewed-By: Mohammad Rizwan Yusuf <myusuf@redhat.com>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+Reviewed-By: Mohammad Rizwan Yusuf <myusuf@redhat.com>
+---
+ install/tools/man/ipa-replica-install.1    |  4 ++-
+ ipaserver/install/server/replicainstall.py | 36 ++++++++++++++++++++--
+ 2 files changed, 37 insertions(+), 3 deletions(-)
+
+diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1
+index a1284135ac67de2b67b322aec3f6bbfb05f1a8ec..12764b8994a04bf56e80492bdcc66578a1f991e0 100644
+--- a/install/tools/man/ipa-replica-install.1
++++ b/install/tools/man/ipa-replica-install.1
+@@ -51,7 +51,7 @@ One Time Password for joining a machine to the IPA realm.
+ Path to host keytab.
+ .TP
+ \fB\-\-server\fR
+-The fully qualified domain name of the IPA server to enroll to.
++The fully qualified domain name of the IPA server to enroll to. The IPA server must provide the CA role if \fB\-\-setup-ca\fR option is specified, and the KRA role if \fB\-\-setup-kra\fR option is specified.
+ .TP
+ \fB\-n\fR, \fB\-\-domain\fR=\fIDOMAIN\fR
+ The primary DNS domain of an existing IPA deployment, e.g. example.com.
+@@ -281,3 +281,5 @@ path.
+ 1 if an error occurred
+ 
+ 3 if the host exists in the IPA server or a replication agreement to the remote master already exists
++
++4 if the remote master specified for enrollment does not provide required services such as CA or KRA
+diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
+index bd82a9d1483545d478e790a727e48eaa9ac22cfc..14e8b2c3a76525c6ec2a16ca26fa032aab694a59 100644
+--- a/ipaserver/install/server/replicainstall.py
++++ b/ipaserver/install/server/replicainstall.py
+@@ -1024,6 +1024,8 @@ def promote_check(installer):
+             print("IPA client is already configured on this system, ignoring "
+                   "the --domain, --server, --realm, --hostname, --password "
+                   "and --keytab options.")
++            # Make sure options.server is not used
++            options.server = None
+ 
+     sstore = sysrestore.StateFile(paths.SYSRESTORE)
+ 
+@@ -1269,8 +1271,15 @@ def promote_check(installer):
+             config.subject_base = DN(subject_base)
+ 
+         # Find any server with a CA
++        # The order of preference is
++        # 1. the first server specified in --server, if any
++        # 2. the server specified in the config file
++        # 3. any other
++        preferred_cas = [config.ca_host_name]
++        if options.server:
++            preferred_cas.insert(0, options.server)
+         ca_host = find_providing_server(
+-            'CA', conn, [config.ca_host_name]
++            'CA', conn, preferred_cas
+         )
+         if ca_host is not None:
+             config.ca_host_name = ca_host
+@@ -1279,6 +1288,14 @@ def promote_check(installer):
+                 logger.error("Certificates could not be provided when "
+                              "CA is present on some master.")
+                 raise ScriptError(rval=3)
++            if options.setup_ca and options.server and \
++               ca_host != options.server:
++                # Installer was provided with a specific master
++                # but this one doesn't provide CA
++                logger.error("The specified --server %s does not provide CA, "
++                             "please provide a server with the CA role",
++                             options.server)
++                raise ScriptError(rval=4)
+         else:
+             if options.setup_ca:
+                 logger.error("The remote master does not have a CA "
+@@ -1293,12 +1310,27 @@ def promote_check(installer):
+                 raise ScriptError(rval=3)
+ 
+         # Find any server with a KRA
++        # The order of preference is
++        # 1. the first server specified in --server, if any
++        # 2. the server specified in the config file
++        # 3. any other
++        preferred_kras = [config.kra_host_name]
++        if options.server:
++            preferred_kras.insert(0, options.server)
+         kra_host = find_providing_server(
+-            'KRA', conn, [config.kra_host_name]
++            'KRA', conn, preferred_kras
+         )
+         if kra_host is not None:
+             config.kra_host_name = kra_host
+             kra_enabled = True
++            if options.setup_kra and options.server and \
++               kra_host != options.server:
++                # Installer was provided with a specific master
++                # but this one doesn't provide KRA
++                logger.error("The specified --server %s does not provide KRA, "
++                             "please provide a server with the KRA role",
++                             options.server)
++                raise ScriptError(rval=4)
+         else:
+             if options.setup_kra:
+                 logger.error("There is no active KRA server in the domain, "
+-- 
+2.20.1
+
diff --git a/SOURCES/0018-Log-INFO-message-when-LDAP-connection-fails-on-start.patch b/SOURCES/0018-Log-INFO-message-when-LDAP-connection-fails-on-start.patch
new file mode 100644
index 0000000..01c3822
--- /dev/null
+++ b/SOURCES/0018-Log-INFO-message-when-LDAP-connection-fails-on-start.patch
@@ -0,0 +1,94 @@
+From 349014688322df67509f44d51f232237e2a7ca7d Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Fri, 2 Aug 2019 15:55:20 -0400
+Subject: [PATCH] Log INFO message when LDAP connection fails on startup
+
+Since krb5_klog_syslog() always needs parameters from syslog.h, move the
+include into ipa_krb5.h.
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+Reviewed-By: Christian Heimes <cheimes@redhat.com>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+---
+ daemons/ipa-kdb/ipa_kdb.c          | 6 ++++--
+ daemons/ipa-kdb/ipa_kdb_audit_as.c | 1 -
+ daemons/ipa-kdb/ipa_kdb_certauth.c | 1 -
+ daemons/ipa-kdb/ipa_kdb_mspac.c    | 1 -
+ util/ipa_krb5.h                    | 1 +
+ 5 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c
+index c90f8d9caf247874c6bda58eb33c7733c4709b02..0dcc74263263423da6b1f4d8441ee149bce24c58 100644
+--- a/daemons/ipa-kdb/ipa_kdb.c
++++ b/daemons/ipa-kdb/ipa_kdb.c
+@@ -24,6 +24,7 @@
+ #include <sys/utsname.h>
+ 
+ #include "ipa_kdb.h"
++#include "ipa_krb5.h"
+ 
+ #define IPADB_GLOBAL_CONFIG_CACHE_TIME 60
+ 
+@@ -586,8 +587,9 @@ static krb5_error_code ipadb_init_module(krb5_context kcontext,
+ 
+     ret = ipadb_get_connection(ipactx);
+     if (ret != 0) {
+-        /* not a fatal failure, as the LDAP server may be temporarily down */
+-        /* TODO: spam syslog with this error */
++        /* Not a fatal failure, as the LDAP server may be temporarily down. */
++        krb5_klog_syslog(LOG_INFO,
++                         "Didn't connect to LDAP on startup: %d", ret);
+     }
+ 
+     kerr = krb5_db_set_context(kcontext, ipactx);
+diff --git a/daemons/ipa-kdb/ipa_kdb_audit_as.c b/daemons/ipa-kdb/ipa_kdb_audit_as.c
+index c68a67aa2a0ca9a2dc9e7a2d39c60d8b105fcc06..77748a75d6b16ee4d080a5f53213cc58c81660dc 100644
+--- a/daemons/ipa-kdb/ipa_kdb_audit_as.c
++++ b/daemons/ipa-kdb/ipa_kdb_audit_as.c
+@@ -20,7 +20,6 @@
+  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <syslog.h>
+ #include "ipa_kdb.h"
+ #include "ipa_pwd.h"
+ 
+diff --git a/daemons/ipa-kdb/ipa_kdb_certauth.c b/daemons/ipa-kdb/ipa_kdb_certauth.c
+index 82589f2f92096400b2f586a65eec962229c3daf7..47911aa3ded56efe4d47acb78d94ccdbcdca7339 100644
+--- a/daemons/ipa-kdb/ipa_kdb_certauth.c
++++ b/daemons/ipa-kdb/ipa_kdb_certauth.c
+@@ -39,7 +39,6 @@
+ 
+ #include <errno.h>
+ //#include <krb5/certauth_plugin.h>
+-#include <syslog.h>
+ #include <sss_certmap.h>
+ 
+ #include "ipa_krb5.h"
+diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
+index 329a5c11586ccd7004dd17e503133f9fda7e8395..74cbb77cccb45188f7bd8a1a33085f8ef964930f 100644
+--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
+@@ -25,7 +25,6 @@
+ #include "ipa_kdb.h"
+ #include "ipa_mspac.h"
+ #include <talloc.h>
+-#include <syslog.h>
+ #include <unicase.h>
+ #include "util/time.h"
+ #include "gen_ndr/ndr_krb5pac.h"
+diff --git a/util/ipa_krb5.h b/util/ipa_krb5.h
+index 60a8ced5d8a63532254b3703801d2aeb9ff45892..b039c1a7f3d0bc215376f8f1dd2ac93e75a0c626 100644
+--- a/util/ipa_krb5.h
++++ b/util/ipa_krb5.h
+@@ -3,6 +3,7 @@
+ #include <lber.h>
+ #include <krb5/krb5.h>
+ #include <kdb.h>
++#include <syslog.h>
+ 
+ struct krb_key_salt {
+     krb5_enctype enctype;
+-- 
+2.20.1
+
diff --git a/SOURCES/0018-Skip-zone-overlap-check-with-auto-reverse.patch b/SOURCES/0018-Skip-zone-overlap-check-with-auto-reverse.patch
deleted file mode 100644
index 1251db9..0000000
--- a/SOURCES/0018-Skip-zone-overlap-check-with-auto-reverse.patch
+++ /dev/null
@@ -1,188 +0,0 @@
-From 85bc681683a8a5d71b9cfaf9c70e0f388732f285 Mon Sep 17 00:00:00 2001
-From: Justin Stephenson <jstephen@redhat.com>
-Date: Wed, 27 Dec 2017 16:32:47 -0500
-Subject: [PATCH] Skip zone overlap check with auto-reverse
-
-Skip the existing reverse zone overlap check during DNS installation
-when both --auto-reverse and --allow-zone-overlap arguments are
-provided.
-
-https://pagure.io/freeipa/issue/7239
-
-Reviewed-By: Rob Crittenden <rcritten@redhat.com>
-Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- ipaserver/install/bindinstance.py             | 18 ++--
- .../test_integration/test_installation.py     | 95 +++++++++++++++++++
- 2 files changed, 105 insertions(+), 8 deletions(-)
-
-diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
-index 940667db9c40559d5369188395bb18f2d1eac025..4de2c6442175a64f4048a93b2006a6d5c6b2a045 100644
---- a/ipaserver/install/bindinstance.py
-+++ b/ipaserver/install/bindinstance.py
-@@ -304,7 +304,7 @@ def read_reverse_zone(default, ip_address, allow_zone_overlap=False):
-     return normalize_zone(zone)
- 
- 
--def get_auto_reverse_zones(ip_addresses):
-+def get_auto_reverse_zones(ip_addresses, allow_zone_overlap=False):
-     auto_zones = []
-     for ip in ip_addresses:
-         if ipautil.reverse_record_exists(ip):
-@@ -312,12 +312,13 @@ def get_auto_reverse_zones(ip_addresses):
-             logger.info("Reverse record for IP address %s already exists", ip)
-             continue
-         default_reverse = get_reverse_zone_default(ip)
--        try:
--            dnsutil.check_zone_overlap(default_reverse)
--        except ValueError:
--            logger.info("Reverse zone %s for IP address %s already exists",
--                        default_reverse, ip)
--            continue
-+        if not allow_zone_overlap:
-+            try:
-+                dnsutil.check_zone_overlap(default_reverse)
-+            except ValueError:
-+                logger.info("Reverse zone %s for IP address %s already exists",
-+                            default_reverse, ip)
-+                continue
-         auto_zones.append((ip, default_reverse))
-     return auto_zones
- 
-@@ -488,7 +489,8 @@ def check_reverse_zones(ip_addresses, reverse_zones, options, unattended,
-             ips_missing_reverse.append(ip)
- 
-     # create reverse zone for IP addresses that does not have one
--    for (ip, rz) in get_auto_reverse_zones(ips_missing_reverse):
-+    for (ip, rz) in get_auto_reverse_zones(ips_missing_reverse,
-+                                           options.allow_zone_overlap):
-         if options.auto_reverse:
-             logger.info("Reverse zone %s will be created", rz)
-             checked_reverse_zones.append(rz)
-diff --git a/ipatests/test_integration/test_installation.py b/ipatests/test_integration/test_installation.py
-index 4cd8a3e33927b7522e9b2a8908a8c179daaa1280..7e6c728102e29753ec7b56cedea734dd18b8bb8c 100644
---- a/ipatests/test_integration/test_installation.py
-+++ b/ipatests/test_integration/test_installation.py
-@@ -9,6 +9,7 @@ installed.
- 
- from __future__ import absolute_import
- 
-+import os
- import pytest
- from ipalib.constants import DOMAIN_LEVEL_0
- from ipaplatform.constants import constants
-@@ -16,9 +17,46 @@ from ipaplatform.paths import paths
- from ipatests.pytest_ipa.integration.env_config import get_global_config
- from ipatests.test_integration.base import IntegrationTest
- from ipatests.pytest_ipa.integration import tasks
-+from ipatests.test_integration.test_caless import CALessBase, ipa_certs_cleanup
- 
- config = get_global_config()
- 
-+
-+def create_broken_resolv_conf(master):
-+    # Force a broken resolv.conf to simulate a bad response to
-+    # reverse zone lookups
-+    master.run_command([
-+        '/usr/bin/mv',
-+        paths.RESOLV_CONF,
-+        '%s.sav' % paths.RESOLV_CONF
-+    ])
-+
-+    contents = "# Set as broken by ipatests\nnameserver 127.0.0.2\n"
-+    master.put_file_contents(paths.RESOLV_CONF, contents)
-+
-+
-+def restore_resolv_conf(master):
-+    if os.path.exists('%s.sav' % paths.RESOLV_CONF):
-+        master.run_command([
-+            '/usr/bin/mv',
-+            '%s.sav' % paths.RESOLV_CONF,
-+            paths.RESOLV_CONF
-+        ])
-+
-+
-+def server_install_setup(func):
-+    def wrapped(*args):
-+        master = args[0].master
-+        create_broken_resolv_conf(master)
-+        try:
-+            func(*args)
-+        finally:
-+            tasks.uninstall_master(master, clean=False)
-+            restore_resolv_conf(master)
-+            ipa_certs_cleanup(master)
-+    return wrapped
-+
-+
- class InstallTestBase1(IntegrationTest):
- 
-     num_replicas = 3
-@@ -226,6 +264,63 @@ class TestInstallWithCA_DNS2(InstallTestBase2):
-         super(TestInstallWithCA_DNS2, self).test_replica2_ipa_kra_install()
- 
- 
-+class TestInstallWithCA_DNS3(CALessBase):
-+    """
-+    Test an install with a bad DNS resolver configured to force a
-+    timeout trying to verify the existing zones. In the case of a reverse
-+    zone it is skipped unless --allow-zone-overlap is set regardless of
-+    the value of --auto-reverse. Confirm that --allow-zone-overlap
-+    lets the reverse zone be created.
-+
-+    ticket 7239
-+    """
-+
-+    @server_install_setup
-+    def test_number_of_zones(self):
-+        """There should be two zones: one forward, one reverse"""
-+
-+        self.create_pkcs12('ca1/server')
-+        self.prepare_cacert('ca1')
-+
-+        self.install_server(extra_args=['--allow-zone-overlap'])
-+
-+        result = self.master.run_command([
-+            'ipa', 'dnszone-find'])
-+
-+        assert "in-addr.arpa." in result.stdout_text
-+
-+        assert "returned 2" in result.stdout_text
-+
-+
-+class TestInstallWithCA_DNS4(CALessBase):
-+    """
-+    Test an install with a bad DNS resolver configured to force a
-+    timeout trying to verify the existing zones. In the case of a reverse
-+    zone it is skipped unless --allow-zone-overlap is set regardless of
-+    the value of --auto-reverse. Confirm that without --allow-reverse-zone
-+    only the forward zone is created.
-+
-+    ticket 7239
-+    """
-+
-+    @server_install_setup
-+    def test_number_of_zones(self):
-+        """There should be one zone, a forward because rev timed-out"""
-+
-+        self.create_pkcs12('ca1/server')
-+        self.prepare_cacert('ca1')
-+
-+        # no zone overlap by default
-+        self.install_server()
-+
-+        result = self.master.run_command([
-+            'ipa', 'dnszone-find'])
-+
-+        assert "in-addr.arpa." not in result.stdout_text
-+
-+        assert "returned 1" in result.stdout_text
-+
-+
- @pytest.mark.cs_acceptance
- class TestInstallWithCA_KRA_DNS1(InstallTestBase1):
- 
--- 
-2.20.1
-
diff --git a/SOURCES/0019-Add-hidden-replica-feature.patch b/SOURCES/0019-Add-hidden-replica-feature.patch
deleted file mode 100644
index 9048ce4..0000000
--- a/SOURCES/0019-Add-hidden-replica-feature.patch
+++ /dev/null
@@ -1,390 +0,0 @@
-From fc64de3f833ab63f2b2ee8984db95866b3f718a7 Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Fri, 22 Mar 2019 15:14:06 +0100
-Subject: [PATCH] Add hidden replica feature
-
-A hidden replica is a replica that does not advertise its services via
-DNS SRV records, ipa-ca DNS entry, or LDAP. Clients do not auto-select a
-hidden replica, but are still free to explicitly connect to it.
-
-Fixes: https://pagure.io/freeipa/issue/7892
-Co-authored-by: Francois Cami <fcami@redhat.com>:
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Thomas Woerner <twoerner@redhat.com>
-Reviewed-By: Francois Cami <fcami@redhat.com>
----
- API.txt                                    |  2 +-
- install/tools/ipactl                       | 12 ++++-
- ipaserver/install/server/__init__.py       |  7 +++
- ipaserver/install/server/replicainstall.py | 11 ++++-
- ipaserver/install/service.py               | 57 +++++++++++++++++-----
- ipaserver/masters.py                       | 46 ++++++++++++-----
- ipaserver/plugins/serverrole.py            |  2 +-
- ipaserver/servroles.py                     | 27 +++++++---
- 8 files changed, 131 insertions(+), 33 deletions(-)
-
-diff --git a/API.txt b/API.txt
-index b9dc35fb5752ce04f58aa8c4c3e89c7299f34cd7..2135300183e3dc2126309e8f892e79fe6b5178fb 100644
---- a/API.txt
-+++ b/API.txt
-@@ -4443,7 +4443,7 @@ option: Flag('raw', autofill=True, cli_name='raw', default=False)
- option: Str('role_servrole?', autofill=False, cli_name='role')
- option: Str('server_server?', autofill=False, cli_name='server')
- option: Int('sizelimit?', autofill=False)
--option: StrEnum('status?', autofill=False, cli_name='status', default=u'enabled', values=[u'enabled', u'configured', u'absent'])
-+option: StrEnum('status?', autofill=False, cli_name='status', default=u'enabled', values=[u'enabled', u'configured', u'hidden', u'absent'])
- option: Int('timelimit?', autofill=False)
- option: Str('version?')
- output: Output('count', type=[<type 'int'>])
-diff --git a/install/tools/ipactl b/install/tools/ipactl
-index 2767a26d1b70337d37dbcd87c707919579fe7e29..f40ea5a6df74f04ec7e6e8959d731553651a81d3 100755
---- a/install/tools/ipactl
-+++ b/install/tools/ipactl
-@@ -29,6 +29,7 @@ import ldapurl
- from ipaserver.install import service, installutils
- from ipaserver.install.dsinstance import config_dirname
- from ipaserver.install.installutils import is_ipa_configured, ScriptError
-+from ipaserver.masters import ENABLED_SERVICE, HIDDEN_SERVICE
- from ipalib import api, errors
- from ipapython.ipaldap import LDAPClient
- from ipapython.ipautil import wait_for_open_ports, wait_for_open_socket
-@@ -162,7 +163,16 @@ def version_check():
- 
- def get_config(dirsrv):
-     base = DN(('cn', api.env.host), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
--    srcfilter = '(ipaConfigString=enabledService)'
-+    srcfilter = LDAPClient.combine_filters(
-+        [
-+            LDAPClient.make_filter({'objectClass': 'ipaConfigObject'}),
-+            LDAPClient.make_filter(
-+                {'ipaConfigString': [ENABLED_SERVICE, HIDDEN_SERVICE]},
-+                rules=LDAPClient.MATCH_ANY
-+            ),
-+        ],
-+        rules=LDAPClient.MATCH_ALL
-+    )
-     attrs = ['cn', 'ipaConfigString']
-     if not dirsrv.is_running():
-         raise IpactlError("Failed to get list of services to probe status:\n" +
-diff --git a/ipaserver/install/server/__init__.py b/ipaserver/install/server/__init__.py
-index b6c01d0971b827dc1547adcfff48fbcb545f4b18..f20b3dac4c7f79454a2b8871409319578ee2eb9e 100644
---- a/ipaserver/install/server/__init__.py
-+++ b/ipaserver/install/server/__init__.py
-@@ -240,6 +240,13 @@ class ServerInstallInterface(ServerCertificateInstallInterface,
-     )
-     master_password = master_install_only(master_password)
- 
-+    hidden_replica = knob(
-+        None,
-+        cli_names='--hidden-replica',
-+        description="Install a hidden replica",
-+    )
-+    hidden_replica = replica_install_only(hidden_replica)
-+
-     domain_level = knob(
-         int, constants.MAX_DOMAIN_LEVEL,
-         description="IPA domain level",
-diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
-index 37ecbe4146fa908c30fb708037fcaa47af1a258b..7178238bfb996f987b5e3beaebe05fa104ada089 100644
---- a/ipaserver/install/server/replicainstall.py
-+++ b/ipaserver/install/server/replicainstall.py
-@@ -1055,6 +1055,7 @@ def promote_check(installer):
-     config.setup_kra = options.setup_kra
-     config.dir = installer._top_dir
-     config.basedn = api.env.basedn
-+    config.hidden_replica = options.hidden_replica
- 
-     http_pkcs12_file = None
-     http_pkcs12_info = None
-@@ -1579,8 +1580,16 @@ def install(installer):
-         remove_replica_info_dir(installer)
- 
-     # Enable configured services and update DNS SRV records
--    service.enable_services(config.host_name)
-+    if options.hidden_replica:
-+        # Set services to hidden
-+        service.hide_services(config.host_name)
-+    else:
-+        # Enable configured services
-+        service.enable_services(config.host_name)
-+    # update DNS SRV records. Although it's only really necessary in
-+    # enabled-service case, also perform update in hidden replica case.
-     api.Command.dns_update_system_records()
-+
-     ca_servers = find_providing_servers('CA', api.Backend.ldap2, api=api)
-     api.Backend.ldap2.disconnect()
- 
-diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
-index 261eedc85be24478b99e5ae8886aec7bc23a80ed..6d7997c559f8d748f00dd9df28371c53bc12ee21 100644
---- a/ipaserver/install/service.py
-+++ b/ipaserver/install/service.py
-@@ -39,7 +39,7 @@ from ipalib import api, errors
- from ipaplatform import services
- from ipaplatform.paths import paths
- from ipaserver.masters import (
--    CONFIGURED_SERVICE, ENABLED_SERVICE, SERVICE_LIST
-+    CONFIGURED_SERVICE, ENABLED_SERVICE, HIDDEN_SERVICE, SERVICE_LIST
- )
- 
- logger = logging.getLogger(__name__)
-@@ -180,7 +180,7 @@ def set_service_entry_config(name, fqdn, config_values,
- 
- 
- def enable_services(fqdn):
--    """Change all configured services to enabled
-+    """Change all services to enabled state
- 
-     Server.ldap_configure() only marks a service as configured. Services
-     are enabled at the very end of installation.
-@@ -189,15 +189,46 @@ def enable_services(fqdn):
- 
-     :param fqdn: hostname of server
-     """
-+    _set_services_state(fqdn, ENABLED_SERVICE)
-+
-+
-+def hide_services(fqdn):
-+    """Change all services to hidden state
-+
-+    Note: DNS records must be updated with dns_update_system_records, too.
-+
-+    :param fqdn: hostname of server
-+    """
-+    _set_services_state(fqdn, HIDDEN_SERVICE)
-+
-+
-+def _set_services_state(fqdn, dest_state):
-+    """Change all services of a host
-+
-+    :param fqdn: hostname of server
-+    :param dest_state: destination state
-+    """
-     ldap2 = api.Backend.ldap2
-     search_base = DN(('cn', fqdn), api.env.container_masters, api.env.basedn)
--    search_filter = ldap2.make_filter(
--        {
--            'objectClass': 'ipaConfigObject',
--            'ipaConfigString': CONFIGURED_SERVICE
--        },
--        rules='&'
-+
-+    source_states = {
-+        CONFIGURED_SERVICE.lower(),
-+        ENABLED_SERVICE.lower(),
-+        HIDDEN_SERVICE.lower()
-+    }
-+    source_states.remove(dest_state.lower())
-+
-+    search_filter = ldap2.combine_filters(
-+        [
-+            ldap2.make_filter({'objectClass': 'ipaConfigObject'}),
-+            ldap2.make_filter(
-+                {'ipaConfigString': list(source_states)},
-+                rules=ldap2.MATCH_ANY
-+            ),
-+        ],
-+        rules=ldap2.MATCH_ALL
-     )
-+
-     entries = ldap2.get_entries(
-         search_base,
-         filter=search_filter,
-@@ -208,10 +239,10 @@ def enable_services(fqdn):
-         name = entry['cn']
-         cfgstrings = entry.setdefault('ipaConfigString', [])
-         for value in list(cfgstrings):
--            if value.lower() == CONFIGURED_SERVICE.lower():
-+            if value.lower() in source_states:
-                 cfgstrings.remove(value)
--        if not case_insensitive_attr_has_value(cfgstrings, ENABLED_SERVICE):
--            cfgstrings.append(ENABLED_SERVICE)
-+        if not case_insensitive_attr_has_value(cfgstrings, dest_state):
-+            cfgstrings.append(dest_state)
- 
-         try:
-             ldap2.update_entry(entry)
-@@ -221,7 +252,9 @@ def enable_services(fqdn):
-             logger.exception("failed to set service %s config values", name)
-             raise
-         else:
--            logger.debug("Enabled service %s for %s", name, fqdn)
-+            logger.debug(
-+                "Set service %s for %s to %s", name, fqdn, dest_state
-+            )
- 
- 
- class Service(object):
-diff --git a/ipaserver/masters.py b/ipaserver/masters.py
-index 6fa8f02332ceaa10ec30aa5142912f351fb58936..76c1a9594d8b5f88c503a08b84a17e14ac320df3 100644
---- a/ipaserver/masters.py
-+++ b/ipaserver/masters.py
-@@ -19,6 +19,7 @@ logger = logging.getLogger(__name__)
- # constants for ipaConfigString
- CONFIGURED_SERVICE = u'configuredService'
- ENABLED_SERVICE = u'enabledService'
-+HIDDEN_SERVICE = u'hiddenService'
- 
- # The service name as stored in cn=masters,cn=ipa,cn=etc. The values are:
- # 0: systemd service name
-@@ -68,30 +69,53 @@ def find_providing_servers(svcname, conn=None, preferred_hosts=(), api=api):
-         conn = api.Backend.ldap2
- 
-     dn = DN(api.env.container_masters, api.env.basedn)
--    query_filter = conn.make_filter(
--        {
--            'objectClass': 'ipaConfigObject',
--            'ipaConfigString': ENABLED_SERVICE,
--            'cn': svcname
--        },
--        rules='&'
-+
-+    query_filter = conn.combine_filters(
-+        [
-+            conn.make_filter(
-+                {
-+                    'objectClass': 'ipaConfigObject',
-+                    'cn': svcname
-+                },
-+                rules=conn.MATCH_ALL,
-+            ),
-+            conn.make_filter(
-+                {
-+                    'ipaConfigString': [ENABLED_SERVICE, HIDDEN_SERVICE]
-+                },
-+                rules=conn.MATCH_ANY
-+            ),
-+        ],
-+        rules=conn.MATCH_ALL
-     )
-+
-     try:
-         entries, _trunc = conn.find_entries(
-             filter=query_filter,
--            attrs_list=[],
-+            attrs_list=['ipaConfigString'],
-             base_dn=dn
-         )
-     except errors.NotFound:
-         return []
- 
--    # unique list of host names, DNS is case insensitive
--    servers = list(set(entry.dn[1].value.lower() for entry in entries))
-+    # DNS is case insensitive
-+    preferred_hosts = list(host_name.lower() for host_name in preferred_hosts)
-+    servers = []
-+    for entry in entries:
-+        servername = entry.dn[1].value.lower()
-+        cfgstrings = entry.get('ipaConfigString', [])
-+        # always consider enabled services
-+        if ENABLED_SERVICE in cfgstrings:
-+            servers.append(servername)
-+        # use hidden services on preferred hosts
-+        elif HIDDEN_SERVICE in cfgstrings and servername in preferred_hosts:
-+            servers.append(servername)
-+    # unique list of host names
-+    servers = list(set(servers))
-     # shuffle the list like DNS SRV would randomize it
-     random.shuffle(servers)
-     # Move preferred hosts to front
-     for host_name in reversed(preferred_hosts):
--        host_name = host_name.lower()
-         try:
-             servers.remove(host_name)
-         except ValueError:
-diff --git a/ipaserver/plugins/serverrole.py b/ipaserver/plugins/serverrole.py
-index 199978000ce8cf783bda50c46b7c9fa109f70ad6..1f6d2dca518d374d7bd07e96019610e3ef6430be 100644
---- a/ipaserver/plugins/serverrole.py
-+++ b/ipaserver/plugins/serverrole.py
-@@ -70,7 +70,7 @@ class server_role(Object):
-             cli_name='status',
-             label=_('Role status'),
-             doc=_('Status of the role'),
--            values=(u'enabled', u'configured', u'absent'),
-+            values=(u'enabled', u'configured', u'hidden', u'absent'),
-             default=u'enabled',
-             flags={'virtual_attribute', 'no_create', 'no_update'}
-         )
-diff --git a/ipaserver/servroles.py b/ipaserver/servroles.py
-index af4e63710136a15e1673210c3e2207658698fbb5..02a22e77dbb615f735660c53d1b2eb7da022591d 100644
---- a/ipaserver/servroles.py
-+++ b/ipaserver/servroles.py
-@@ -79,7 +79,7 @@ import six
- 
- from ipalib import _, errors
- from ipapython.dn import DN
--from ipaserver.masters import ENABLED_SERVICE
-+from ipaserver.masters import ENABLED_SERVICE, HIDDEN_SERVICE
- 
- if six.PY3:
-     unicode = str
-@@ -87,6 +87,7 @@ if six.PY3:
- 
- ENABLED = u'enabled'
- CONFIGURED = u'configured'
-+HIDDEN = u'hidden'
- ABSENT = u'absent'
- 
- 
-@@ -190,6 +191,7 @@ class BaseServerRole(LDAPBasedProperty):
-         :returns: * 'enabled' if the role is enabled on the master
-                   * 'configured' if it is not enabled but has
-                     been configured by installer
-+                  * 'hidden' if the role is not advertised
-                   * 'absent' otherwise
-         """
-         ldap2 = api_instance.Backend.ldap2
-@@ -442,7 +444,7 @@ class SingleValuedServerAttribute(ServerAttribute):
-         return masters
- 
- 
--_Service = namedtuple('Service', ['name', 'enabled'])
-+_Service = namedtuple('Service', ['name', 'enabled', 'hidden'])
- 
- 
- class ServiceBasedRole(BaseServerRole):
-@@ -470,8 +472,9 @@ class ServiceBasedRole(BaseServerRole):
-         entry_cn = entry['cn'][0]
- 
-         enabled = self._is_service_enabled(entry)
-+        hidden = self._is_service_hidden(entry)
- 
--        return _Service(name=entry_cn, enabled=enabled)
-+        return _Service(name=entry_cn, enabled=enabled, hidden=hidden)
- 
-     def _is_service_enabled(self, entry):
-         """
-@@ -486,6 +489,15 @@ class ServiceBasedRole(BaseServerRole):
-         ipaconfigstring_values = set(entry.get('ipaConfigString', []))
-         return ENABLED_SERVICE in ipaconfigstring_values
- 
-+    def _is_service_hidden(self, entry):
-+        """Determine if service is hidden
-+
-+        :param entry: LDAPEntry of the service
-+        :returns: True if the service entry is enabled, False otherwise
-+        """
-+        ipaconfigstring_values = set(entry.get('ipaConfigString', []))
-+        return HIDDEN_SERVICE in ipaconfigstring_values
-+
-     def _get_services_by_masters(self, entries):
-         """
-         given list of entries, return a dictionary keyed by master FQDNs which
-@@ -509,9 +521,12 @@ class ServiceBasedRole(BaseServerRole):
-             except ValueError:
-                 continue
- 
--            status = (
--                ENABLED if all(s.enabled for s in services) else
--                CONFIGURED)
-+            if all(s.enabled for s in services):
-+                status = ENABLED
-+            elif all(s.hidden for s in services):
-+                status = HIDDEN
-+            else:
-+                status = CONFIGURED
- 
-             result.append(self.create_role_status_dict(master, status))
- 
--- 
-2.20.1
-
diff --git a/SOURCES/0019-Fix-NULL-pointer-dereference-in-maybe_require_preaut.patch b/SOURCES/0019-Fix-NULL-pointer-dereference-in-maybe_require_preaut.patch
new file mode 100644
index 0000000..f5cb38f
--- /dev/null
+++ b/SOURCES/0019-Fix-NULL-pointer-dereference-in-maybe_require_preaut.patch
@@ -0,0 +1,30 @@
+From e3206de9fb0d25691b35568723ad67a60ca01165 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Wed, 4 Sep 2019 13:48:14 -0400
+Subject: [PATCH] Fix NULL pointer dereference in maybe_require_preauth()
+
+ipadb_get_global_config() is permitted to return NULL.
+
+Signed-off-by: Robbie Harwood <rharwood@redhat.com>
+Reviewed-By: Christian Heimes <cheimes@redhat.com>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+---
+ daemons/ipa-kdb/ipa_kdb_principals.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c
+index 0fe8e396b9bc011b77b183851389f6c57c70a2c9..259a0d2563f4b9c038b041781b2580fe72d7ed7e 100644
+--- a/daemons/ipa-kdb/ipa_kdb_principals.c
++++ b/daemons/ipa-kdb/ipa_kdb_principals.c
+@@ -1070,7 +1070,7 @@ static krb5_flags maybe_require_preauth(struct ipadb_context *ipactx,
+     struct ipadb_e_data *ied;
+ 
+     config = ipadb_get_global_config(ipactx);
+-    if (config->disable_preauth_for_spns) {
++    if (config && config->disable_preauth_for_spns) {
+         ied = (struct ipadb_e_data *)entry->e_data;
+         if (ied && ied->ipa_user != true) {
+             /* not a user, assume SPN */
+-- 
+2.20.1
+
diff --git a/SOURCES/0020-Handle-missing-LWCA-certificate-or-chain.patch b/SOURCES/0020-Handle-missing-LWCA-certificate-or-chain.patch
new file mode 100644
index 0000000..81001b4
--- /dev/null
+++ b/SOURCES/0020-Handle-missing-LWCA-certificate-or-chain.patch
@@ -0,0 +1,196 @@
+From f830f450c0c5818090eba9f9f0e0cec5551a1cef Mon Sep 17 00:00:00 2001
+From: Fraser Tweedale <ftweedal@redhat.com>
+Date: Thu, 30 May 2019 20:57:10 +1000
+Subject: [PATCH] Handle missing LWCA certificate or chain
+
+If lightweight CA key replication has not completed, requests for
+the certificate or chain will return 404**.  This can occur in
+normal operation, and should be a temporary condition.  Detect this
+case and handle it by simply omitting the 'certificate' and/or
+'certificate_out' fields in the response, and add a warning message
+to the response.
+
+Also update the client-side plugin that handles the
+--certificate-out option.  Because the CLI will automatically print
+the warning message, if the expected field is missing from the
+response, just ignore it and continue processing.
+
+** after the Dogtag NullPointerException gets fixed!
+
+Part of: https://pagure.io/freeipa/issue/7964
+
+Reviewed-By: Christian Heimes <cheimes@redhat.com>
+Reviewed-By: Fraser Tweedale <ftweedal@redhat.com>
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+---
+ ipaclient/plugins/ca.py | 19 +++++++++++---
+ ipalib/messages.py      |  9 +++++++
+ ipaserver/plugins/ca.py | 57 +++++++++++++++++++++++++++++++----------
+ 3 files changed, 68 insertions(+), 17 deletions(-)
+
+diff --git a/ipaclient/plugins/ca.py b/ipaclient/plugins/ca.py
+index f0e7d5ced0d3d9318e34aba84cbc37cf42b9410d..ab47ae85df398e1dc40191691a26639eb3772493 100644
+--- a/ipaclient/plugins/ca.py
++++ b/ipaclient/plugins/ca.py
+@@ -33,13 +33,24 @@ class WithCertOutArgs(MethodOverride):
+                                              error=str(e))
+ 
+         result = super(WithCertOutArgs, self).forward(*keys, **options)
++
+         if filename:
++            # if result certificate / certificate_chain not present in result,
++            # it means Dogtag did not provide it (probably due to LWCA key
++            # replication lag or failure.  The server transmits a warning
++            # message in this case, which the client automatically prints.
++            # So in this section we just ignore it and move on.
++            certs = None
+             if options.get('chain', False):
+-                certs = result['result']['certificate_chain']
++                if 'certificate_chain' in result['result']:
++                    certs = result['result']['certificate_chain']
+             else:
+-                certs = [base64.b64decode(result['result']['certificate'])]
+-            certs = (x509.load_der_x509_certificate(cert) for cert in certs)
+-            x509.write_certificate_list(certs, filename)
++                if 'certificate' in result['result']:
++                    certs = [base64.b64decode(result['result']['certificate'])]
++            if certs:
++                x509.write_certificate_list(
++                    (x509.load_der_x509_certificate(cert) for cert in certs),
++                    filename)
+ 
+         return result
+ 
+diff --git a/ipalib/messages.py b/ipalib/messages.py
+index 9e2c990d6db8ee41daf3fba6085eed8355dccbe7..646662795648b5a44a5ce25b7610982d5500cfac 100644
+--- a/ipalib/messages.py
++++ b/ipalib/messages.py
+@@ -487,6 +487,15 @@ class FailedToAddHostDNSRecords(PublicMessage):
+                "%(reason)s")
+ 
+ 
++class LightweightCACertificateNotAvailable(PublicMessage):
++    """
++    **13031** Certificate is not available
++    """
++    errno = 13031
++    type = "error"
++    format = _("The certificate for %(ca)s is not available on this server.")
++
++
+ def iter_messages(variables, base):
+     """Return a tuple with all subclasses
+     """
+diff --git a/ipaserver/plugins/ca.py b/ipaserver/plugins/ca.py
+index 88e7ec2a9f50a3c4f90947c8e3d38e327627a878..c8f1630c65d55ee9e820ea50ef34e08f92c66f4a 100644
+--- a/ipaserver/plugins/ca.py
++++ b/ipaserver/plugins/ca.py
+@@ -6,7 +6,7 @@ import base64
+ 
+ import six
+ 
+-from ipalib import api, errors, output, Bytes, DNParam, Flag, Str
++from ipalib import api, errors, messages, output, Bytes, DNParam, Flag, Str
+ from ipalib.constants import IPA_CA_CN
+ from ipalib.plugable import Registry
+ from ipapython.dn import ATTR_NAME_BY_OID
+@@ -163,28 +163,53 @@ class ca(LDAPObject):
+ 
+ 
+ def set_certificate_attrs(entry, options, want_cert=True):
++    """
++    Set certificate attributes into the entry.  Depending on
++    options, this may contact Dogtag to retrieve certificate or
++    chain.  If the retrieval fails with 404 (which can occur under
++    normal operation due to lightweight CA key replication delay),
++    return a message object that should be set in the response.
++
++    """
+     try:
+         ca_id = entry['ipacaid'][0]
+     except KeyError:
+-        return
++        return None
+     full = options.get('all', False)
+     want_chain = options.get('chain', False)
+ 
+     want_data = want_cert or want_chain or full
+     if not want_data:
+-        return
++        return None
++
++    msg = None
+ 
+     with api.Backend.ra_lightweight_ca as ca_api:
+         if want_cert or full:
+-            der = ca_api.read_ca_cert(ca_id)
+-            entry['certificate'] = base64.b64encode(der).decode('ascii')
++            try:
++                der = ca_api.read_ca_cert(ca_id)
++                entry['certificate'] = base64.b64encode(der).decode('ascii')
++            except errors.HTTPRequestError as e:
++                if e.status == 404:  # pylint: disable=no-member
++                    msg = messages.LightweightCACertificateNotAvailable(
++                        ca=entry['cn'][0])
++                else:
++                    raise e
+ 
+         if want_chain or full:
+-            pkcs7_der = ca_api.read_ca_chain(ca_id)
+-            certs = x509.pkcs7_to_certs(pkcs7_der, x509.DER)
+-            ders = [cert.public_bytes(x509.Encoding.DER) for cert in certs]
+-            entry['certificate_chain'] = ders
+-
++            try:
++                pkcs7_der = ca_api.read_ca_chain(ca_id)
++                certs = x509.pkcs7_to_certs(pkcs7_der, x509.DER)
++                ders = [cert.public_bytes(x509.Encoding.DER) for cert in certs]
++                entry['certificate_chain'] = ders
++            except errors.HTTPRequestError as e:
++                if e.status == 404:  # pylint: disable=no-member
++                    msg = messages.LightweightCACertificateNotAvailable(
++                        ca=entry['cn'][0])
++                else:
++                    raise e
++
++    return msg
+ 
+ @register()
+ class ca_find(LDAPSearch):
+@@ -198,7 +223,9 @@ class ca_find(LDAPSearch):
+         result = super(ca_find, self).execute(*keys, **options)
+         if not options.get('pkey_only', False):
+             for entry in result['result']:
+-                set_certificate_attrs(entry, options, want_cert=False)
++                msg = set_certificate_attrs(entry, options, want_cert=False)
++                if msg:
++                    self.add_message(msg)
+         return result
+ 
+ 
+@@ -220,7 +247,9 @@ class ca_show(LDAPRetrieve):
+     def execute(self, *keys, **options):
+         ca_enabled_check(self.api)
+         result = super(ca_show, self).execute(*keys, **options)
+-        set_certificate_attrs(result['result'], options)
++        msg = set_certificate_attrs(result['result'], options)
++        if msg:
++            self.add_message(msg)
+         return result
+ 
+ 
+@@ -284,7 +313,9 @@ class ca_add(LDAPCreate):
+         return dn
+ 
+     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+-        set_certificate_attrs(entry_attrs, options)
++        msg = set_certificate_attrs(entry_attrs, options)
++        if msg:
++            self.add_message(msg)
+         return dn
+ 
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0020-ipatests-Exercise-hidden-replica-feature.patch b/SOURCES/0020-ipatests-Exercise-hidden-replica-feature.patch
deleted file mode 100644
index fbb0dc9..0000000
--- a/SOURCES/0020-ipatests-Exercise-hidden-replica-feature.patch
+++ /dev/null
@@ -1,150 +0,0 @@
-From f643289f42a0d537da2e8ab6be4727d0bc679690 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= <fcami@redhat.com>
-Date: Fri, 22 Mar 2019 19:29:01 +0100
-Subject: [PATCH] ipatests: Exercise hidden replica feature
-
-A hidden replica is a replica that does not advertise its services via
-DNS SRV records, ipa-ca DNS entry, or LDAP. Clients do not auto-select a
-hidden replica, but are still free to explicitly connect to it.
-
-Fixes: https://pagure.io/freeipa/issue/7892
-Co-authored-by: Francois Cami <fcami@redhat.com>
-Signed-off-by: Francois Cami <fcami@redhat.com>
-Reviewed-By: Thomas Woerner <twoerner@redhat.com>
-Reviewed-By: Francois Cami <fcami@redhat.com>
----
- .../test_replica_promotion.py                 | 114 ++++++++++++++++++
- 1 file changed, 114 insertions(+)
-
-diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py
-index 6608b23f7fb37948d54c21c88d572527356e7335..80890bf05cb242fe09af77aa27b411ac6194e2d6 100644
---- a/ipatests/test_integration/test_replica_promotion.py
-+++ b/ipatests/test_integration/test_replica_promotion.py
-@@ -17,6 +17,10 @@ from ipatests.pytest_ipa.integration.env_config import get_global_config
- from ipalib.constants import (
-     DOMAIN_LEVEL_0, DOMAIN_LEVEL_1, DOMAIN_SUFFIX_NAME, IPA_CA_NICKNAME)
- from ipaplatform.paths import paths
-+from ipatests.test_integration.test_backup_and_restore import backup
-+from ipatests.test_integration.test_dns_locations import (
-+    resolve_records_from_server
-+)
- 
- config = get_global_config()
- 
-@@ -795,3 +799,113 @@ class TestReplicaInForwardZone(IntegrationTest):
-             # Restore /etc/hosts on master and replica
-             restore_etc_hosts(master)
-             restore_etc_hosts(replica)
-+
-+
-+class TestHiddenReplicaPromotion(IntegrationTest):
-+    """
-+    Test hidden replica features
-+    """
-+
-+    topology = 'star'
-+    num_replicas = 1
-+
-+    @classmethod
-+    def install(cls, mh):
-+        tasks.install_master(cls.master, setup_dns=True, setup_kra=True)
-+
-+    @replicas_cleanup
-+    def test_hidden_replica_install(self):
-+        self.replicas[0].run_command([
-+            'ipa-client-install',
-+            '-p', 'admin',
-+            '-w', self.master.config.admin_password,
-+            '--domain', self.master.domain.name,
-+            '--realm', self.master.domain.realm,
-+            '--server', self.master.hostname,
-+            '-U'
-+        ])
-+        self.replicas[0].run_command([
-+            'ipa-replica-install', '-w',
-+            self.master.config.admin_password,
-+            '-n', self.master.domain.name,
-+            '-r', self.master.domain.realm,
-+            '--server', self.master.hostname,
-+            '--setup-ca',
-+            '--setup-dns', '--no-forwarders',
-+            '--hidden-replica',
-+            '--setup-kra',
-+            '-U'
-+        ])
-+        expected_txt = 'hidden'
-+        result = self.replicas[0].run_command([
-+            'ipa', 'ipa server-role-find',
-+            '--server', self.replicas[0].hostname
-+        ])
-+        assert expected_txt in result.stdout
-+        dnsrecords = {
-+            '.'.join(('_kerberos._udp', self.master.domain.name)): 'SRV',
-+            '.'.join(('_kerberos._tcp', self.master.domain.name)): 'SRV',
-+            '.'.join(('_ldap._tcp', self.master.domain.name)): 'SRV',
-+            self.master.domain.name: 'NS'
-+        }
-+        nameserver = self.master.ip
-+        results = []
-+        for record in dnsrecords:
-+            srvr = resolve_records_from_server(
-+                record, dnsrecords[record], nameserver
-+            )
-+            results.extend(re.findall(
-+                '|'.join((self.master.hostname, self.replicas[0].hostname)),
-+                srvr)
-+            )
-+        assert self.master.hostname in results
-+        assert self.replicas[0].hostname not in results
-+
-+    def test_hidden_replica_promote(self):
-+        self.replicas[0].run_command([
-+            'ipa', 'server-mod', '--state=enabled'
-+        ])
-+        unexpected_txt = 'hidden'
-+        result = self.replicas[0].run_command([
-+            'ipa', 'ipa server-role-find',
-+            '--server', self.replicas[0].hostname
-+        ])
-+        assert unexpected_txt not in result.stdout
-+
-+    def test_hidden_replica_demote(self):
-+        self.replicas[0].run_command([
-+            'ipa', 'server-mod', '--state=hidden'
-+        ])
-+        expected_txt = 'hidden'
-+        result = self.replicas[0].run_command([
-+            'ipa', 'ipa server-role-find',
-+            '--server', self.replicas[0].hostname
-+        ])
-+        assert expected_txt in result.stdout
-+
-+    def test_hidden_replica_backup_and_restore(self):
-+        """
-+        Exercises backup+restore and hidden replica uninstall
-+        """
-+        # set expectations
-+        expected_txt = 'hidden'
-+        result = self.replicas[0].run_command([
-+            'ipa', 'ipa server-role-find',
-+            '--server', self.replicas[0].hostname
-+        ])
-+        assert expected_txt in result.stdout
-+        # backup
-+        backup_path = backup(self.replicas[0])
-+        # uninstall
-+        result = self.replicas[0].run_command([
-+            'ipa-server-uninstall', '-U', 'hidden-replica'
-+        ])
-+        # restore
-+        dirman_password = self.master.config.dirman_password
-+        self.replicas[0].run_command(
-+            ['ipa-restore', backup_path], stdin_text=dirman_password + '\nyes'
-+        )
-+        # check that the resulting server can be promoted to enabled
-+        self.replicas[0].run_command([
-+            'ipa', 'server-mod', '--state=enabled'
-+        ])
--- 
-2.20.1
-
diff --git a/SOURCES/0021-Fix-CustodiaClient-ccache-handling.patch b/SOURCES/0021-Fix-CustodiaClient-ccache-handling.patch
new file mode 100644
index 0000000..ca91578
--- /dev/null
+++ b/SOURCES/0021-Fix-CustodiaClient-ccache-handling.patch
@@ -0,0 +1,275 @@
+From 384225411c41c74157eccbe1ae8d1800026f413e Mon Sep 17 00:00:00 2001
+From: Christian Heimes <cheimes@redhat.com>
+Date: Wed, 12 Jun 2019 22:02:52 +0200
+Subject: [PATCH] Fix CustodiaClient ccache handling
+
+A CustodiaClient object has to the process environment a bit, e.g. set
+up GSSAPI credentials. To reuse the credentials in libldap connections,
+it is also necessary to set up a custom ccache store and to set the
+environment variable KRBCCNAME temporarily.
+
+Fixes: https://pagure.io/freeipa/issue/7964
+Co-Authored-By: Fraser Tweedale <ftweedal@redhat.com>
+Signed-off-by: Christian Heimes <cheimes@redhat.com>
+Reviewed-By: Christian Heimes <cheimes@redhat.com>
+Reviewed-By: Fraser Tweedale <ftweedal@redhat.com>
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+---
+ install/tools/ipa-pki-retrieve-key |  33 ++++---
+ ipaserver/secrets/client.py        | 143 ++++++++++++++++-------------
+ 2 files changed, 100 insertions(+), 76 deletions(-)
+
+diff --git a/install/tools/ipa-pki-retrieve-key b/install/tools/ipa-pki-retrieve-key
+index 5056682c3cdaa734be2dadcffd7de0b2d80afaf9..192022b9b40f076e88fd95d5cc8cf8305901dcf5 100755
+--- a/install/tools/ipa-pki-retrieve-key
++++ b/install/tools/ipa-pki-retrieve-key
+@@ -2,9 +2,8 @@
+ 
+ from __future__ import print_function
+ 
++import argparse
+ import os
+-import sys
+-import traceback
+ 
+ from ipalib import constants
+ from ipalib.config import Env
+@@ -16,27 +15,37 @@ def main():
+     env = Env()
+     env._finalize()
+ 
+-    keyname = "ca_wrapped/" + sys.argv[1]
+-    servername = sys.argv[2]
++    parser = argparse.ArgumentParser("ipa-pki-retrieve-key")
++    parser.add_argument("keyname", type=str)
++    parser.add_argument("servername", type=str)
++
++    args = parser.parse_args()
++    keyname = "ca_wrapped/{}".format(args.keyname)
+ 
+     service = constants.PKI_GSSAPI_SERVICE_NAME
+     client_keyfile = os.path.join(paths.PKI_TOMCAT, service + '.keys')
+     client_keytab = os.path.join(paths.PKI_TOMCAT, service + '.keytab')
+ 
++    for filename in [client_keyfile, client_keytab]:
++        if not os.access(filename, os.R_OK):
++            parser.error(
++                "File '{}' missing or not readable.\n".format(filename)
++            )
++
+     # pylint: disable=no-member
+     client = CustodiaClient(
+-        client_service='%s@%s' % (service, env.host), server=servername,
+-        realm=env.realm, ldap_uri="ldaps://" + env.host,
+-        keyfile=client_keyfile, keytab=client_keytab,
+-        )
++        client_service="{}@{}".format(service, env.host),
++        server=args.servername,
++        realm=env.realm,
++        ldap_uri="ldaps://" + env.host,
++        keyfile=client_keyfile,
++        keytab=client_keytab,
++    )
+ 
+     # Print the response JSON to stdout; it is already in the format
+     # that Dogtag's ExternalProcessKeyRetriever expects
+     print(client.fetch_key(keyname, store=False))
+ 
+ 
+-try:
++if __name__ == '__main__':
+     main()
+-except BaseException:
+-    traceback.print_exc()
+-    sys.exit(1)
+diff --git a/ipaserver/secrets/client.py b/ipaserver/secrets/client.py
+index 16e7856185aa9786007d3b7f8be0652f70fb4518..40df6c4e69cd673dd8e3c36fbf33f2cda8544a67 100644
+--- a/ipaserver/secrets/client.py
++++ b/ipaserver/secrets/client.py
+@@ -1,93 +1,106 @@
+ # Copyright (C) 2015  IPA Project Contributors, see COPYING for license
+ 
+ from __future__ import print_function, absolute_import
++
++import contextlib
++import os
++from base64 import b64encode
++
++
+ # pylint: disable=relative-import
+ from custodia.message.kem import KEMClient, KEY_USAGE_SIG, KEY_USAGE_ENC
+ # pylint: enable=relative-import
+ from jwcrypto.common import json_decode
+ from jwcrypto.jwk import JWK
++from ipalib.krb_utils import krb5_format_service_principal_name
+ from ipaserver.secrets.kem import IPAKEMKeys
+-from ipaserver.secrets.store import iSecStore
++from ipaserver.secrets.store import IPASecStore
+ from ipaplatform.paths import paths
+-from base64 import b64encode
+-import ldapurl
+ import gssapi
+-import os
+-import urllib3
+ import requests
+ 
+ 
+-class CustodiaClient(object):
+-
+-    def _client_keys(self):
+-        return self.ikk.server_keys
+-
+-    def _server_keys(self, server, realm):
+-        principal = 'host/%s@%s' % (server, realm)
+-        sk = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_SIG)))
+-        ek = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_ENC)))
+-        return (sk, ek)
+-
+-    def _ldap_uri(self, realm):
+-        dashrealm = '-'.join(realm.split('.'))
+-        socketpath = paths.SLAPD_INSTANCE_SOCKET_TEMPLATE % (dashrealm,)
+-        return 'ldapi://' + ldapurl.ldapUrlEscape(socketpath)
+-
+-    def _keystore(self, realm, ldap_uri, auth_type):
+-        config = dict()
+-        if ldap_uri is None:
+-            config['ldap_uri'] = self._ldap_uri(realm)
+-        else:
+-            config['ldap_uri'] = ldap_uri
+-        if auth_type is not None:
+-            config['auth_type'] = auth_type
++@contextlib.contextmanager
++def ccache_env(ccache):
++    """Temporarily set KRB5CCNAME environment variable
++    """
++    orig_ccache = os.environ.get('KRB5CCNAME')
++    os.environ['KRB5CCNAME'] = ccache
++    try:
++        yield
++    finally:
++        os.environ.pop('KRB5CCNAME', None)
++        if orig_ccache is not None:
++            os.environ['KRB5CCNAME'] = orig_ccache
+ 
+-        return iSecStore(config)
+ 
+-    def __init__(
+-            self, client_service, keyfile, keytab, server, realm,
+-            ldap_uri=None, auth_type=None):
++class CustodiaClient(object):
++    def __init__(self, client_service, keyfile, keytab, server, realm,
++                 ldap_uri=None, auth_type=None):
++        if client_service.endswith(realm) or "@" not in client_service:
++            raise ValueError(
++                "Client service name must be a GSS name (service@host), "
++                "not '{}'.".format(client_service)
++            )
+         self.client_service = client_service
+         self.keytab = keytab
+-
+-        # Init creds immediately to make sure they are valid.  Creds
+-        # can also be re-inited by _auth_header to avoid expiry.
+-        #
+-        self.creds = self.init_creds()
+-
+-        self.service_name = gssapi.Name('HTTP@%s' % (server,),
+-                                        gssapi.NameType.hostbased_service)
+         self.server = server
++        self.realm = realm
++        self.ldap_uri = ldap_uri
++        self.auth_type = auth_type
++        self.service_name = gssapi.Name(
++            'HTTP@{}'.format(server), gssapi.NameType.hostbased_service
++        )
++        self.keystore = IPASecStore()
++        # use in-process MEMORY ccache. Handler process don't need a TGT.
++        token = b64encode(os.urandom(8)).decode('ascii')
++        self.ccache = 'MEMORY:Custodia_{}'.format(token)
++
++        with ccache_env(self.ccache):
++            # Init creds immediately to make sure they are valid.  Creds
++            # can also be re-inited by _auth_header to avoid expiry.
++            self.creds = self._init_creds()
++
++            self.ikk = IPAKEMKeys(
++                {'server_keys': keyfile, 'ldap_uri': ldap_uri}
++            )
++            self.kemcli = KEMClient(
++                self._server_keys(), self._client_keys()
++            )
+ 
+-        self.ikk = IPAKEMKeys({'server_keys': keyfile, 'ldap_uri': ldap_uri})
+-
+-        self.kemcli = KEMClient(self._server_keys(server, realm),
+-                                self._client_keys())
+-
+-        self.keystore = self._keystore(realm, ldap_uri, auth_type)
+-
+-        # FIXME: Remove warnings about missing subjAltName for the
+-        #        requests module
+-        urllib3.disable_warnings()
++    def _client_keys(self):
++        return self.ikk.server_keys
+ 
+-    def init_creds(self):
+-        name = gssapi.Name(self.client_service,
+-                           gssapi.NameType.hostbased_service)
+-        store = {'client_keytab': self.keytab,
+-                 'ccache': 'MEMORY:Custodia_%s' % b64encode(
+-                     os.urandom(8)).decode('ascii')}
++    def _server_keys(self):
++        principal = krb5_format_service_principal_name(
++            'host', self.server, self.realm
++        )
++        sk = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_SIG)))
++        ek = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_ENC)))
++        return sk, ek
++
++    def _init_creds(self):
++        name = gssapi.Name(
++            self.client_service, gssapi.NameType.hostbased_service
++        )
++        store = {
++            'client_keytab': self.keytab,
++            'ccache': self.ccache
++        }
+         return gssapi.Credentials(name=name, store=store, usage='initiate')
+ 
+     def _auth_header(self):
+-        if not self.creds or self.creds.lifetime < 300:
+-            self.creds = self.init_creds()
+-        ctx = gssapi.SecurityContext(name=self.service_name, creds=self.creds)
++        if self.creds.lifetime < 300:
++            self.creds = self._init_creds()
++        ctx = gssapi.SecurityContext(
++            name=self.service_name,
++            creds=self.creds
++        )
+         authtok = ctx.step()
+         return {'Authorization': 'Negotiate %s' % b64encode(
+             authtok).decode('ascii')}
+ 
+     def fetch_key(self, keyname, store=True):
+-
+         # Prepare URL
+         url = 'https://%s/ipa/keys/%s' % (self.server, keyname)
+ 
+@@ -99,9 +112,11 @@ class CustodiaClient(object):
+         headers = self._auth_header()
+ 
+         # Perform request
+-        r = requests.get(url, headers=headers,
+-                         verify=paths.IPA_CA_CRT,
+-                         params={'type': 'kem', 'value': request})
++        r = requests.get(
++            url, headers=headers,
++            verify=paths.IPA_CA_CRT,
++            params={'type': 'kem', 'value': request}
++        )
+         r.raise_for_status()
+         reply = r.json()
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0021-Simplify-and-improve-tests.patch b/SOURCES/0021-Simplify-and-improve-tests.patch
deleted file mode 100644
index 699780f..0000000
--- a/SOURCES/0021-Simplify-and-improve-tests.patch
+++ /dev/null
@@ -1,212 +0,0 @@
-From a88af3d2f21b6a949885981aa82ff87a1336f40c Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Mon, 25 Mar 2019 08:17:28 +0100
-Subject: [PATCH] Simplify and improve tests
-
-Move tests for DNS and roles into helper methods to make them reusable.
-
-Fixes: https://pagure.io/freeipa/issue/7892
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Thomas Woerner <twoerner@redhat.com>
-Reviewed-By: Francois Cami <fcami@redhat.com>
----
- .../test_replica_promotion.py                 | 147 +++++++++---------
- 1 file changed, 70 insertions(+), 77 deletions(-)
-
-diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py
-index 80890bf05cb242fe09af77aa27b411ac6194e2d6..a4f3e402ce5d6f74af4bd6fed9376f0f039f297a 100644
---- a/ipatests/test_integration/test_replica_promotion.py
-+++ b/ipatests/test_integration/test_replica_promotion.py
-@@ -19,8 +19,11 @@ from ipalib.constants import (
- from ipaplatform.paths import paths
- from ipatests.test_integration.test_backup_and_restore import backup
- from ipatests.test_integration.test_dns_locations import (
--    resolve_records_from_server
-+    resolve_records_from_server, IPA_DEFAULT_MASTER_SRV_REC
- )
-+from ipapython.dnsutil import DNSName
-+from ipalib.constants import IPA_CA_RECORD
-+
- 
- config = get_global_config()
- 
-@@ -802,110 +805,100 @@ class TestReplicaInForwardZone(IntegrationTest):
- 
- 
- class TestHiddenReplicaPromotion(IntegrationTest):
-+    """Test hidden replica features
-     """
--    Test hidden replica features
--    """
--
-     topology = 'star'
-     num_replicas = 1
- 
-     @classmethod
-     def install(cls, mh):
-         tasks.install_master(cls.master, setup_dns=True, setup_kra=True)
-+        tasks.install_replica(
-+            cls.master, cls.replicas[0],
-+            setup_dns=True, setup_kra=True,
-+            extra_args=('--hidden-replica',)
-+        )
- 
--    @replicas_cleanup
--    def test_hidden_replica_install(self):
--        self.replicas[0].run_command([
--            'ipa-client-install',
--            '-p', 'admin',
--            '-w', self.master.config.admin_password,
--            '--domain', self.master.domain.name,
--            '--realm', self.master.domain.realm,
--            '--server', self.master.hostname,
--            '-U'
--        ])
--        self.replicas[0].run_command([
--            'ipa-replica-install', '-w',
--            self.master.config.admin_password,
--            '-n', self.master.domain.name,
--            '-r', self.master.domain.realm,
--            '--server', self.master.hostname,
--            '--setup-ca',
--            '--setup-dns', '--no-forwarders',
--            '--hidden-replica',
--            '--setup-kra',
--            '-U'
--        ])
--        expected_txt = 'hidden'
--        result = self.replicas[0].run_command([
--            'ipa', 'ipa server-role-find',
--            '--server', self.replicas[0].hostname
--        ])
--        assert expected_txt in result.stdout
--        dnsrecords = {
--            '.'.join(('_kerberos._udp', self.master.domain.name)): 'SRV',
--            '.'.join(('_kerberos._tcp', self.master.domain.name)): 'SRV',
--            '.'.join(('_ldap._tcp', self.master.domain.name)): 'SRV',
--            self.master.domain.name: 'NS'
--        }
--        nameserver = self.master.ip
--        results = []
--        for record in dnsrecords:
--            srvr = resolve_records_from_server(
--                record, dnsrecords[record], nameserver
--            )
--            results.extend(re.findall(
--                '|'.join((self.master.hostname, self.replicas[0].hostname)),
--                srvr)
-+    def _check_dnsrecords(self, hosts_expected, hosts_unexpected=()):
-+        domain = DNSName(self.master.domain.name).make_absolute()
-+        rset = [
-+            (rname, 'SRV')
-+            for rname, _port in IPA_DEFAULT_MASTER_SRV_REC
-+        ]
-+        rset.append((DNSName(IPA_CA_RECORD), 'A'))
-+
-+        for rname, rtype in rset:
-+            name_abs = rname.derelativize(domain)
-+            query = resolve_records_from_server(
-+                name_abs, rtype, self.master.ip
-             )
--        assert self.master.hostname in results
--        assert self.replicas[0].hostname not in results
-+            txt = query.to_text()
-+            for host in hosts_expected:
-+                value = host.hostname if rtype == 'SRV' else host.ip
-+                assert value in txt
-+            for host in hosts_unexpected:
-+                value = host.hostname if rtype == 'SRV' else host.ip
-+                assert value not in txt
-+
-+    def _check_server_role(self, host, status):
-+        roles = [u'IPA master', u'CA server', u'KRA server', u'DNS server']
-+        for role in roles:
-+            result = self.master.run_command([
-+                'ipa', 'server-role-find',
-+                '--server', host.hostname,
-+                '--role', role
-+            ])
-+            expected = 'Role status: {}'.format(status)
-+            assert expected in result.stdout_text
-+
-+    def test_hidden_replica_install(self):
-+        # TODO: check that all services are running on hidden replica
-+        self._check_server_role(self.master, 'enabled')
-+        self._check_server_role(self.replicas[0], 'hidden')
-+        self._check_dnsrecords([self.master], [self.replicas[0]])
- 
-     def test_hidden_replica_promote(self):
-         self.replicas[0].run_command([
--            'ipa', 'server-mod', '--state=enabled'
-+            'ipa', 'server-state',
-+            self.replicas[0].hostname, '--state=enabled'
-         ])
--        unexpected_txt = 'hidden'
-+        self._check_server_role(self.replicas[0], 'enabled')
-+        self._check_dnsrecords([self.master, self.replicas[0]])
-         result = self.replicas[0].run_command([
--            'ipa', 'ipa server-role-find',
--            '--server', self.replicas[0].hostname
--        ])
--        assert unexpected_txt not in result.stdout
-+            'ipa', 'server-state',
-+            self.replicas[0].hostname, '--state=enabled'
-+        ], raiseonerr=False)
-+        assert result.returncode == 1
-+        assert 'no modifications to be performed' in result.stderr_text
- 
-     def test_hidden_replica_demote(self):
-         self.replicas[0].run_command([
--            'ipa', 'server-mod', '--state=hidden'
-+            'ipa', 'server-state',
-+            self.replicas[0].hostname, '--state=hidden'
-         ])
--        expected_txt = 'hidden'
--        result = self.replicas[0].run_command([
--            'ipa', 'ipa server-role-find',
--            '--server', self.replicas[0].hostname
--        ])
--        assert expected_txt in result.stdout
-+        self._check_server_role(self.replicas[0], 'hidden')
-+        self._check_dnsrecords([self.master], [self.replicas[0]])
- 
-     def test_hidden_replica_backup_and_restore(self):
-+        """Exercises backup+restore and hidden replica uninstall
-         """
--        Exercises backup+restore and hidden replica uninstall
--        """
--        # set expectations
--        expected_txt = 'hidden'
--        result = self.replicas[0].run_command([
--            'ipa', 'ipa server-role-find',
--            '--server', self.replicas[0].hostname
--        ])
--        assert expected_txt in result.stdout
-+        self._check_server_role(self.replicas[0], 'hidden')
-         # backup
-         backup_path = backup(self.replicas[0])
-         # uninstall
--        result = self.replicas[0].run_command([
--            'ipa-server-uninstall', '-U', 'hidden-replica'
--        ])
-+        tasks.uninstall_replica(self.master, self.replicas[0])
-         # restore
-         dirman_password = self.master.config.dirman_password
-         self.replicas[0].run_command(
--            ['ipa-restore', backup_path], stdin_text=dirman_password + '\nyes'
-+            ['ipa-restore', backup_path],
-+            stdin_text=dirman_password + '\nyes'
-         )
-+        # check that role is still hidden
-+        self._check_server_role(self.replicas[0], 'hidden')
-+        self._check_dnsrecords([self.master], [self.replicas[0]])
-         # check that the resulting server can be promoted to enabled
-         self.replicas[0].run_command([
--            'ipa', 'server-mod', '--state=enabled'
-+            'ipa', 'server-mod', self.replicas[0].hostname, '--state=enabled'
-         ])
-+        self._check_server_role(self.replicas[0], 'enabled')
-+        self._check_dnsrecords([self.master, self.replicas[0]])
--- 
-2.20.1
-
diff --git a/SOURCES/0022-CustodiaClient-use-ldapi-when-ldap_uri-not-specified.patch b/SOURCES/0022-CustodiaClient-use-ldapi-when-ldap_uri-not-specified.patch
new file mode 100644
index 0000000..db4220c
--- /dev/null
+++ b/SOURCES/0022-CustodiaClient-use-ldapi-when-ldap_uri-not-specified.patch
@@ -0,0 +1,43 @@
+From 531b0b66a74b100986ba086fc134fb5f2e587c69 Mon Sep 17 00:00:00 2001
+From: Fraser Tweedale <ftweedal@redhat.com>
+Date: Wed, 19 Jun 2019 19:11:39 +1000
+Subject: [PATCH] CustodiaClient: use ldapi when ldap_uri not specified
+
+Reinstate ldap_uri selection behaviour that was lost during the
+refactor in the previous commit.  This is required because, on the
+ipa-4-7 branch at least, the IPASecStore needs to use LDAPI to set
+the Directory Manager passphrase digest.  Use LDAPI when the
+ldap_uri has not been explicity specified.
+
+Part of: https://pagure.io/freeipa/issue/7964
+
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+---
+ ipaserver/secrets/client.py | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/ipaserver/secrets/client.py b/ipaserver/secrets/client.py
+index 40df6c4e69cd673dd8e3c36fbf33f2cda8544a67..4c03ef8e4140dd507156d88941600a234b71184e 100644
+--- a/ipaserver/secrets/client.py
++++ b/ipaserver/secrets/client.py
+@@ -13,6 +13,7 @@ from custodia.message.kem import KEMClient, KEY_USAGE_SIG, KEY_USAGE_ENC
+ from jwcrypto.common import json_decode
+ from jwcrypto.jwk import JWK
+ from ipalib.krb_utils import krb5_format_service_principal_name
++from ipaserver.install.installutils import realm_to_ldapi_uri
+ from ipaserver.secrets.kem import IPAKEMKeys
+ from ipaserver.secrets.store import IPASecStore
+ from ipaplatform.paths import paths
+@@ -46,7 +47,7 @@ class CustodiaClient(object):
+         self.keytab = keytab
+         self.server = server
+         self.realm = realm
+-        self.ldap_uri = ldap_uri
++        self.ldap_uri = ldap_uri or realm_to_ldapi_uri(realm)
+         self.auth_type = auth_type
+         self.service_name = gssapi.Name(
+             'HTTP@{}'.format(server), gssapi.NameType.hostbased_service
+-- 
+2.20.1
+
diff --git a/SOURCES/0022-Implement-server-state-state-enabled-hidden.patch b/SOURCES/0022-Implement-server-state-state-enabled-hidden.patch
deleted file mode 100644
index 6b4b812..0000000
--- a/SOURCES/0022-Implement-server-state-state-enabled-hidden.patch
+++ /dev/null
@@ -1,129 +0,0 @@
-From 483fea9c199d76f1e759241ad32c990f5e0eaabc Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Mon, 25 Mar 2019 08:36:53 +0100
-Subject: [PATCH] Implement server-state --state=enabled/hidden
-
-server-state modified the hidden / enabled flags of all configured
-services of a server. Since the command does not directly modify the
-server LDAP entry, the command has to be implemented as a dedicated plugin.
-
-Fixes: https://pagure.io/freeipa/issue/7892
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Thomas Woerner <twoerner@redhat.com>
-Reviewed-By: Francois Cami <fcami@redhat.com>
----
- API.txt                     |  9 ++++++
- ipaserver/plugins/server.py | 58 +++++++++++++++++++++++++++++++++++--
- 2 files changed, 65 insertions(+), 2 deletions(-)
-
-diff --git a/API.txt b/API.txt
-index 2135300183e3dc2126309e8f892e79fe6b5178fb..222e30915ccc1fb4a6f3ce228669453f346fdde4 100644
---- a/API.txt
-+++ b/API.txt
-@@ -4471,6 +4471,14 @@ option: Str('version?')
- output: Entry('result')
- output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
- output: PrimaryKey('value')
-+command: server_state/1
-+args: 1,2,3
-+arg: Str('cn', cli_name='name')
-+option: StrEnum('state', values=[u'enabled', u'hidden'])
-+option: Str('version?')
-+output: Output('result', type=[<type 'bool'>])
-+output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
-+output: PrimaryKey('value')
- command: service_add/1
- args: 1,13,3
- arg: Principal('krbcanonicalname', cli_name='canonical_principal')
-@@ -6900,6 +6908,7 @@ default: server_role/1
- default: server_role_find/1
- default: server_role_show/1
- default: server_show/1
-+default: server_state/1
- default: service/1
- default: service_add/1
- default: service_add_cert/1
-diff --git a/ipaserver/plugins/server.py b/ipaserver/plugins/server.py
-index e265883e3637938e3df5ecf132f4add62413a997..0d144d13bca66b65de64328139fd7126eea24c89 100644
---- a/ipaserver/plugins/server.py
-+++ b/ipaserver/plugins/server.py
-@@ -12,7 +12,7 @@ import ldap
- import time
- 
- from ipalib import api, crud, errors, messages
--from ipalib import Int, Flag, Str, DNSNameParam
-+from ipalib import Int, Flag, Str, StrEnum, DNSNameParam
- from ipalib.plugable import Registry
- from .baseldap import (
-     LDAPSearch,
-@@ -28,8 +28,9 @@ from ipaplatform import services
- from ipapython.dn import DN
- from ipapython.dnsutil import DNSName
- from ipaserver import topology
--from ipaserver.servroles import ENABLED
-+from ipaserver.servroles import ENABLED, HIDDEN
- from ipaserver.install import bindinstance, dnskeysyncinstance
-+from ipaserver.install.service import hide_services, enable_services
- 
- __doc__ = _("""
- IPA servers
-@@ -949,3 +950,56 @@ class server_conncheck(crud.PKQuery):
-                                  messages.ExternalCommandOutput(line=line))
- 
-         return result
-+
-+
-+@register()
-+class server_state(crud.PKQuery):
-+    __doc__ = _("Set enabled/hidden state of a server.")
-+
-+    takes_options = (
-+        StrEnum(
-+            'state',
-+            values=(u'enabled', u'hidden'),
-+            label=_('State'),
-+            doc=_('Server state'),
-+            flags={'virtual_attribute', 'no_create', 'no_search'},
-+        ),
-+    )
-+
-+    msg_summary = _('Changed server state of "%(value)s".')
-+
-+    has_output = output.standard_boolean
-+
-+    def execute(self, *keys, **options):
-+        fqdn = keys[0]
-+        if options['state'] == u'enabled':
-+            to_status = ENABLED
-+            from_status = HIDDEN
-+        else:
-+            to_status = HIDDEN
-+            from_status = ENABLED
-+
-+        roles = self.api.Command.server_role_find(
-+            server_server=fqdn,
-+            status=from_status,
-+            include_master=True,
-+        )['result']
-+        from_roles = [r[u'role_servrole'] for r in roles]
-+        if not from_roles:
-+            # no server role is in source status
-+            raise errors.EmptyModlist
-+
-+        if to_status == ENABLED:
-+            enable_services(fqdn)
-+        else:
-+            hide_services(fqdn)
-+
-+        # update system roles
-+        result = self.api.Command.dns_update_system_records()
-+        if not result.get('value'):
-+            self.add_message(messages.AutomaticDNSRecordsUpdateFailed())
-+
-+        return {
-+            'value': fqdn,
-+            'result': True,
-+        }
--- 
-2.20.1
-
diff --git a/SOURCES/0023-Consider-hidden-servers-as-role-provider.patch b/SOURCES/0023-Consider-hidden-servers-as-role-provider.patch
deleted file mode 100644
index d847594..0000000
--- a/SOURCES/0023-Consider-hidden-servers-as-role-provider.patch
+++ /dev/null
@@ -1,45 +0,0 @@
-From d5538488447a42110c2b6f77ffdc80d4c6e0e61e Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Mon, 25 Mar 2019 15:58:07 +0100
-Subject: [PATCH] Consider hidden servers as role provider
-
-Hidden services are now considered as associated role providers, too. This
-fixes the issue of:
-
-    invalid 'PKINIT enabled server': all masters must have IPA
-    master role enabled
-
-and similar issues with CA and DNS.
-
-Fixes: https://pagure.io/freeipa/issue/7892
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Thomas Woerner <twoerner@redhat.com>
-Reviewed-By: Francois Cami <fcami@redhat.com>
----
- ipaserver/servroles.py | 7 ++++---
- 1 file changed, 4 insertions(+), 3 deletions(-)
-
-diff --git a/ipaserver/servroles.py b/ipaserver/servroles.py
-index 02a22e77dbb615f735660c53d1b2eb7da022591d..9c963be53527bb955ebf2b8cec7960f0d90717a4 100644
---- a/ipaserver/servroles.py
-+++ b/ipaserver/servroles.py
-@@ -338,12 +338,13 @@ class ServerAttribute(LDAPBasedProperty):
-         ldap.update_entry(service_entry)
- 
-     def _get_assoc_role_providers(self, api_instance):
--        """
--        get list of all servers on which the associated role is enabled
-+        """get list of all servers on which the associated role is enabled
-+
-+        Consider a hidden server as a valid provider for a role.
-         """
-         return [
-             r[u'server_server'] for r in self.associated_role.status(
--                api_instance) if r[u'status'] == ENABLED]
-+                api_instance) if r[u'status'] in {ENABLED, HIDDEN}]
- 
-     def _remove(self, api_instance, masters):
-         """
--- 
-2.20.1
-
diff --git a/SOURCES/0023-CustodiaClient-fix-IPASecStore-config-on-ipa-4-7.patch b/SOURCES/0023-CustodiaClient-fix-IPASecStore-config-on-ipa-4-7.patch
new file mode 100644
index 0000000..66f78ae
--- /dev/null
+++ b/SOURCES/0023-CustodiaClient-fix-IPASecStore-config-on-ipa-4-7.patch
@@ -0,0 +1,41 @@
+From 457131218990e7c6a9de21de0e3fb9e9ecf6a6fe Mon Sep 17 00:00:00 2001
+From: Fraser Tweedale <ftweedal@redhat.com>
+Date: Tue, 30 Jul 2019 16:21:35 +1000
+Subject: [PATCH] CustodiaClient: fix IPASecStore config on ipa-4-7
+
+The backport of a Custodia client fix for f30 and related refactors
+and improvements, to the ipa-4-7 branch, had no conflicts.  But
+there is a change on newer branches that broke the backport.  The
+running of Custodia handlers in separate processes simplified the
+configuration of the ISecStore.  For ipa-4-7 we need to continue to
+explicitly configure it, so restore the old configuration behaviour.
+
+Part of: https://pagure.io/freeipa/issue/7964
+
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+---
+ ipaserver/secrets/client.py | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/ipaserver/secrets/client.py b/ipaserver/secrets/client.py
+index 4c03ef8e4140dd507156d88941600a234b71184e..2363b081dbbf3671e8147497bb52811825bdf1a4 100644
+--- a/ipaserver/secrets/client.py
++++ b/ipaserver/secrets/client.py
+@@ -52,7 +52,12 @@ class CustodiaClient(object):
+         self.service_name = gssapi.Name(
+             'HTTP@{}'.format(server), gssapi.NameType.hostbased_service
+         )
+-        self.keystore = IPASecStore()
++
++        config = {'ldap_uri': self.ldap_uri}
++        if auth_type is not None:
++            config['auth_type'] = auth_type
++        self.keystore = IPASecStore(config)
++
+         # use in-process MEMORY ccache. Handler process don't need a TGT.
+         token = b64encode(os.urandom(8)).decode('ascii')
+         self.ccache = 'MEMORY:Custodia_{}'.format(token)
+-- 
+2.20.1
+
diff --git a/SOURCES/0024-Bump-krb5-min-version.patch b/SOURCES/0024-Bump-krb5-min-version.patch
new file mode 100644
index 0000000..4da8584
--- /dev/null
+++ b/SOURCES/0024-Bump-krb5-min-version.patch
@@ -0,0 +1,34 @@
+From fc937b3b5ecc2743546cd2e0fa0193c390113579 Mon Sep 17 00:00:00 2001
+From: Fraser Tweedale <ftweedal@redhat.com>
+Date: Wed, 25 Sep 2019 16:43:25 +1000
+Subject: [PATCH] Bump krb5 min version
+
+krb5-1.15.1-36 introduced a ccache behavioural change that broke
+lightweight CA key replication.  The preceding commits (backported
+from the ipa-4-7 branch) fix this issue but this commit ensure that
+the correct version of krb5 is used with the updated FreeIPA code.
+
+Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1755223
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+---
+ freeipa.spec.in | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/freeipa.spec.in b/freeipa.spec.in
+index 4cca8b5159e8e38f79bad8df8af76ac7b8ed5387..0f96778f758cb21c01e31ff35e70c79f020aa2d3 100644
+--- a/freeipa.spec.in
++++ b/freeipa.spec.in
+@@ -49,8 +49,8 @@
+ 
+ %global alt_name ipa
+ %if 0%{?rhel}
+-# 1.15.1-7: certauth (http://krbdev.mit.edu/rt/Ticket/Display.html?id=8561)
+-%global krb5_version 1.15.1-4
++# 1.15.1-36: https://bugzilla.redhat.com/show_bug.cgi?id=1755223
++%global krb5_version 1.15.1-36
+ # 0.7.16: https://github.com/drkjam/netaddr/issues/71
+ %global python_netaddr_version 0.7.5-8
+ # Require 4.7.0 which brings Python 3 bindings
+-- 
+2.20.1
+
diff --git a/SOURCES/0024-Improve-config-show-to-show-hidden-servers.patch b/SOURCES/0024-Improve-config-show-to-show-hidden-servers.patch
deleted file mode 100644
index e2e34f5..0000000
--- a/SOURCES/0024-Improve-config-show-to-show-hidden-servers.patch
+++ /dev/null
@@ -1,246 +0,0 @@
-From ae9ab0545ff06b60df4b66c0ebccb7baa79b8898 Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Mon, 25 Mar 2019 15:59:51 +0100
-Subject: [PATCH] Improve config-show to show hidden servers
-
-config-show only used to show enabled servers. Now also show hidden
-servers on separate lines. Additionally include information about
-KRA and DNS servers.
-
-The augmented config-show output makes it easier to diagnose a cluster
-and simplifies sanity checks.
-
-Fixes: https://pagure.io/freeipa/issue/7892
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Thomas Woerner <twoerner@redhat.com>
-Reviewed-By: Francois Cami <fcami@redhat.com>
----
- ipaserver/plugins/config.py                   | 56 +++++++++++++++++--
- ipaserver/plugins/serverroles.py              | 25 ++++++---
- ipaserver/servroles.py                        |  6 ++
- .../test_replica_promotion.py                 | 23 ++++++++
- 4 files changed, 97 insertions(+), 13 deletions(-)
-
-diff --git a/ipaserver/plugins/config.py b/ipaserver/plugins/config.py
-index fff58ac656f4fad3491dfa9f95c22b7d54a6da56..58b48935c2c7471ff2ce0bb3f5ce92a9fb47a503 100644
---- a/ipaserver/plugins/config.py
-+++ b/ipaserver/plugins/config.py
-@@ -249,6 +249,18 @@ class config(LDAPObject):
-             doc=_('List of all IPA masters'),
-             flags={'virtual_attribute', 'no_create', 'no_update'}
-         ),
-+        Str(
-+            'ipa_master_hidden_server*',
-+            label=_('Hidden IPA masters'),
-+            doc=_('List of all hidden IPA masters'),
-+            flags={'virtual_attribute', 'no_create', 'no_update'}
-+        ),
-+        Str(
-+            'pkinit_server_server*',
-+            label=_('IPA master capable of PKINIT'),
-+            doc=_('IPA master which can process PKINIT requests'),
-+            flags={'virtual_attribute', 'no_create', 'no_update'}
-+        ),
-         Str(
-             'ca_server_server*',
-             label=_('IPA CA servers'),
-@@ -261,6 +273,12 @@ class config(LDAPObject):
-             doc=_('IPA servers with enabled NTP'),
-             flags={'virtual_attribute', 'no_create', 'no_update'}
-         ),
-+        Str(
-+            'ca_server_hidden_server*',
-+            label=_('Hidden IPA CA servers'),
-+            doc=_('Hidden IPA servers configured as certificate authority'),
-+            flags={'virtual_attribute', 'no_create', 'no_update'}
-+        ),
-         Str(
-             'ca_renewal_master_server?',
-             label=_('IPA CA renewal master'),
-@@ -268,9 +286,15 @@ class config(LDAPObject):
-             flags={'virtual_attribute', 'no_create'}
-         ),
-         Str(
--            'pkinit_server_server*',
--            label=_('IPA master capable of PKINIT'),
--            doc=_('IPA master which can process PKINIT requests'),
-+            'kra_server_server*',
-+            label=_('IPA KRA servers'),
-+            doc=_('IPA servers configured as key recovery agent'),
-+            flags={'virtual_attribute', 'no_create', 'no_update'}
-+        ),
-+        Str(
-+            'kra_server_hidden_server*',
-+            label=_('Hidden IPA KRA servers'),
-+            doc=_('Hidden IPA servers configured as key recovery agent'),
-             flags={'virtual_attribute', 'no_create', 'no_update'}
-         ),
-         Str(
-@@ -279,7 +303,25 @@ class config(LDAPObject):
-             label=_('Domain resolution order'),
-             doc=_('colon-separated list of domains used for short name'
-                   ' qualification')
--        )
-+        ),
-+        Str(
-+            'dns_server_server*',
-+            label=_('IPA DNS servers'),
-+            doc=_('IPA servers configured as domain name server'),
-+            flags={'virtual_attribute', 'no_create', 'no_update'}
-+        ),
-+        Str(
-+            'dns_server_hidden_server*',
-+            label=_('Hidden IPA DNS servers'),
-+            doc=_('Hidden IPA servers configured as domain name server'),
-+            flags={'virtual_attribute', 'no_create', 'no_update'}
-+        ),
-+        Str(
-+            'dnssec_key_master_server?',
-+            label=_('IPA DNSSec key master'),
-+            doc=_('DNSec key master'),
-+            flags={'virtual_attribute', 'no_create', 'no_update'}
-+        ),
-     )
- 
-     def get_dn(self, *keys, **kwargs):
-@@ -560,7 +602,8 @@ class config_mod(LDAPUpdate):
- 
-     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
-         self.obj.show_servroles_attributes(
--            entry_attrs, "CA server", "IPA master", "NTP server", **options)
-+            entry_attrs, "CA server", "KRA server", "IPA master",
-+            "NTP server", "DNS server", **options)
-         return dn
- 
- 
-@@ -570,5 +613,6 @@ class config_show(LDAPRetrieve):
- 
-     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
-         self.obj.show_servroles_attributes(
--            entry_attrs, "CA server", "IPA master", "NTP server", **options)
-+            entry_attrs, "CA server", "KRA server", "IPA master",
-+            "NTP server", "DNS server", **options)
-         return dn
-diff --git a/ipaserver/plugins/serverroles.py b/ipaserver/plugins/serverroles.py
-index 0abf48ae5295be5f622bf8c90d32e7adff5e6cf7..5bba84972a5828b6c7230d0d0d858e6683e5986b 100644
---- a/ipaserver/plugins/serverroles.py
-+++ b/ipaserver/plugins/serverroles.py
-@@ -45,7 +45,9 @@ import six
- from ipalib import errors, _
- from ipalib.backend import Backend
- from ipalib.plugable import Registry
--from ipaserver.servroles import (attribute_instances, ENABLED, role_instances)
-+from ipaserver.servroles import (
-+    attribute_instances, ENABLED, HIDDEN, role_instances
-+)
- from ipaserver.servroles import SingleValuedServerAttribute
- 
- 
-@@ -81,17 +83,26 @@ class serverroles(Backend):
-             raise errors.NotFound(
-                 reason=_("{role}: role not found".format(role=role_name)))
- 
--    def _get_enabled_masters(self, role_name):
-+    def _get_masters(self, role_name, include_hidden):
-         result = {}
-         role = self._get_role(role_name)
-+        role_states = role.status(self.api, server=None)
- 
-         enabled_masters = [
--            r[u'server_server'] for r in role.status(self.api, server=None) if
--            r[u'status'] == ENABLED]
--
-+            r[u'server_server'] for r in role_states if
-+            r[u'status'] == ENABLED
-+        ]
-         if enabled_masters:
-             result.update({role.attr_name: enabled_masters})
- 
-+        if include_hidden and role.attr_name_hidden is not None:
-+            hidden_masters = [
-+                r[u'server_server'] for r in role_states if
-+                r[u'status'] == HIDDEN
-+            ]
-+            if hidden_masters:
-+                result.update({role.attr_name_hidden: hidden_masters})
-+
-         return result
- 
-     def _get_assoc_attributes(self, role_name):
-@@ -131,8 +142,8 @@ class serverroles(Backend):
-         return self._get_role(role_servrole).status(
-             self.api, server=server_server)
- 
--    def config_retrieve(self, servrole):
--        result = self._get_enabled_masters(servrole)
-+    def config_retrieve(self, servrole, include_hidden=True):
-+        result = self._get_masters(servrole, include_hidden=include_hidden)
- 
-         try:
-             assoc_attributes = self._get_assoc_attributes(servrole)
-diff --git a/ipaserver/servroles.py b/ipaserver/servroles.py
-index 9c963be53527bb955ebf2b8cec7960f0d90717a4..0988cbdd7eac599ef26c89a015523b2d92e9502f 100644
---- a/ipaserver/servroles.py
-+++ b/ipaserver/servroles.py
-@@ -104,6 +104,12 @@ class LDAPBasedProperty(object):
-     def __init__(self, attr_name, name):
-         self.attr_name = attr_name
-         self.name = name
-+        # for hidden services, insert hidden before '_server' suffix
-+        if attr_name.endswith(u'_server'):
-+            parts = attr_name.rsplit(u'_', 1)
-+            self.attr_name_hidden = u'{}_hidden_server'.format(parts[0])
-+        else:
-+            self.attr_name_hidden = None
- 
- 
- @six.add_metaclass(abc.ABCMeta)
-diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py
-index a4f3e402ce5d6f74af4bd6fed9376f0f039f297a..3be2ea95fa2325edfc74cbb902ce0a5966aa82d7 100644
---- a/ipatests/test_integration/test_replica_promotion.py
-+++ b/ipatests/test_integration/test_replica_promotion.py
-@@ -851,11 +851,32 @@ class TestHiddenReplicaPromotion(IntegrationTest):
-             expected = 'Role status: {}'.format(status)
-             assert expected in result.stdout_text
- 
-+    def _check_config(self, enabled=(), hidden=()):
-+        enabled = {host.hostname for host in enabled}
-+        hidden = {host.hostname for host in hidden}
-+        services = [
-+            'IPA masters', 'IPA CA servers', 'IPA KRA servers',
-+            'IPA DNS servers'
-+        ]
-+
-+        result = self.master.run_command(['ipa', 'config-show'])
-+        values = {}
-+        for line in result.stdout_text.split('\n'):
-+            if ':' not in line:
-+                continue
-+            k, v = line.split(':', 1)
-+            values[k.strip()] = {item.strip() for item in v.split(',')}
-+
-+        for service in services:
-+            assert values[service] == enabled
-+            assert values['Hidden {}'.format(service)] == hidden
-+
-     def test_hidden_replica_install(self):
-         # TODO: check that all services are running on hidden replica
-         self._check_server_role(self.master, 'enabled')
-         self._check_server_role(self.replicas[0], 'hidden')
-         self._check_dnsrecords([self.master], [self.replicas[0]])
-+        self._check_config([self.master], [self.replicas[0]])
- 
-     def test_hidden_replica_promote(self):
-         self.replicas[0].run_command([
-@@ -864,6 +885,8 @@ class TestHiddenReplicaPromotion(IntegrationTest):
-         ])
-         self._check_server_role(self.replicas[0], 'enabled')
-         self._check_dnsrecords([self.master, self.replicas[0]])
-+        self._check_config([self.master, self.replicas[0]])
-+
-         result = self.replicas[0].run_command([
-             'ipa', 'server-state',
-             self.replicas[0].hostname, '--state=enabled'
--- 
-2.20.1
-
diff --git a/SOURCES/0025-More-test-fixes.patch b/SOURCES/0025-More-test-fixes.patch
deleted file mode 100644
index f1559ca..0000000
--- a/SOURCES/0025-More-test-fixes.patch
+++ /dev/null
@@ -1,78 +0,0 @@
-From 9c62af973d71cabaf8d93216717468385ac2abbe Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Mon, 25 Mar 2019 18:36:19 +0100
-Subject: [PATCH] More test fixes
-
-Fixes: https://pagure.io/freeipa/issue/7892
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Thomas Woerner <twoerner@redhat.com>
-Reviewed-By: Francois Cami <fcami@redhat.com>
----
- .../test_integration/test_replica_promotion.py | 18 +++++++++++++-----
- 1 file changed, 13 insertions(+), 5 deletions(-)
-
-diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py
-index 3be2ea95fa2325edfc74cbb902ce0a5966aa82d7..9ce0074ea0df276b4800b306530d04c8274ece69 100644
---- a/ipatests/test_integration/test_replica_promotion.py
-+++ b/ipatests/test_integration/test_replica_promotion.py
-@@ -843,7 +843,7 @@ class TestHiddenReplicaPromotion(IntegrationTest):
-     def _check_server_role(self, host, status):
-         roles = [u'IPA master', u'CA server', u'KRA server', u'DNS server']
-         for role in roles:
--            result = self.master.run_command([
-+            result = self.replicas[0].run_command([
-                 'ipa', 'server-role-find',
-                 '--server', host.hostname,
-                 '--role', role
-@@ -859,7 +859,7 @@ class TestHiddenReplicaPromotion(IntegrationTest):
-             'IPA DNS servers'
-         ]
- 
--        result = self.master.run_command(['ipa', 'config-show'])
-+        result = self.replicas[0].run_command(['ipa', 'config-show'])
-         values = {}
-         for line in result.stdout_text.split('\n'):
-             if ':' not in line:
-@@ -868,8 +868,9 @@ class TestHiddenReplicaPromotion(IntegrationTest):
-             values[k.strip()] = {item.strip() for item in v.split(',')}
- 
-         for service in services:
--            assert values[service] == enabled
--            assert values['Hidden {}'.format(service)] == hidden
-+            hservice = 'Hidden {}'.format(service)
-+            assert values.get(service, set()) == enabled
-+            assert values.get(hservice, set()) == hidden
- 
-     def test_hidden_replica_install(self):
-         # TODO: check that all services are running on hidden replica
-@@ -909,19 +910,26 @@ class TestHiddenReplicaPromotion(IntegrationTest):
-         # backup
-         backup_path = backup(self.replicas[0])
-         # uninstall
--        tasks.uninstall_replica(self.master, self.replicas[0])
-+        tasks.uninstall_master(self.replicas[0])
-         # restore
-         dirman_password = self.master.config.dirman_password
-         self.replicas[0].run_command(
-             ['ipa-restore', backup_path],
-             stdin_text=dirman_password + '\nyes'
-         )
-+        # give replication some time
-+        time.sleep(5)
-+
-         # check that role is still hidden
-+        tasks.kinit_admin(self.replicas[0])
-+        self._check_config([self.master], [self.replicas[0]])
-         self._check_server_role(self.replicas[0], 'hidden')
-         self._check_dnsrecords([self.master], [self.replicas[0]])
-+
-         # check that the resulting server can be promoted to enabled
-         self.replicas[0].run_command([
-             'ipa', 'server-mod', self.replicas[0].hostname, '--state=enabled'
-         ])
-+        self._check_config([self.master, self.replicas[0]])
-         self._check_server_role(self.replicas[0], 'enabled')
-         self._check_dnsrecords([self.master, self.replicas[0]])
--- 
-2.20.1
-
diff --git a/SOURCES/0025-ipa-backup-fix-python2-issue-with-os.mkdir.patch b/SOURCES/0025-ipa-backup-fix-python2-issue-with-os.mkdir.patch
new file mode 100644
index 0000000..a60d5d6
--- /dev/null
+++ b/SOURCES/0025-ipa-backup-fix-python2-issue-with-os.mkdir.patch
@@ -0,0 +1,44 @@
+From 5badb4233cb59a6045e544576ebabff94c02131e Mon Sep 17 00:00:00 2001
+From: Florence Blanc-Renaud <flo@redhat.com>
+Date: Wed, 16 Oct 2019 17:02:38 +0200
+Subject: [PATCH] ipa-backup: fix python2 issue with os.mkdir
+
+Python2 and python3 have different interfaces for os.mkdir:
+python2: os.mkdir(path[, mode])
+python3: os.mkdir(path, mode=0o777, *, dir_fd=None)
+
+ipa-backup is using the python3 format, which breaks deployments using
+python2. The fix consists in using os.mkdir(path, 0o700) instead of
+os.mkdir(path, mode=0o700).
+
+Fixes: https://pagure.io/freeipa/issue/8099
+Reviewed-By: Alexander Bokovoy <abbra@users.noreply.github.com>
+---
+ ipaserver/install/ipa_backup.py | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py
+index 96f3d7e1c6abdc6a4f3080810a8ea3bd8211d16b..496bbd8925972a6e1dbdd00c01b62f2e2c4398d6 100644
+--- a/ipaserver/install/ipa_backup.py
++++ b/ipaserver/install/ipa_backup.py
+@@ -289,7 +289,7 @@ class Backup(admintool.AdminTool):
+         os.chown(self.top_dir, pent.pw_uid, pent.pw_gid)
+         os.chmod(self.top_dir, 0o750)
+         self.dir = os.path.join(self.top_dir, "ipa")
+-        os.mkdir(self.dir, mode=0o750)
++        os.mkdir(self.dir, 0o750)
+         os.chown(self.dir, pent.pw_uid, pent.pw_gid)
+         self.tarfile = None
+ 
+@@ -663,7 +663,7 @@ class Backup(admintool.AdminTool):
+             filename = os.path.join(backup_dir, "ipa-full.tar")
+ 
+         try:
+-            os.mkdir(backup_dir, mode=0o700)
++            os.mkdir(backup_dir, 0o700)
+         except (OSError, IOError) as e:
+             raise admintool.ScriptError(
+                 'Could not create backup directory: %s' % e
+-- 
+2.20.1
+
diff --git a/SOURCES/0026-Do-not-run-trust-upgrade-code-if-master-lacks-Samba-.patch b/SOURCES/0026-Do-not-run-trust-upgrade-code-if-master-lacks-Samba-.patch
new file mode 100644
index 0000000..31d5953
--- /dev/null
+++ b/SOURCES/0026-Do-not-run-trust-upgrade-code-if-master-lacks-Samba-.patch
@@ -0,0 +1,43 @@
+From 5701d4f75c780d778fccefdb1ec911d4f1fccd8e Mon Sep 17 00:00:00 2001
+From: Alexander Bokovoy <abokovoy@redhat.com>
+Date: Sun, 17 Nov 2019 19:37:03 +0200
+Subject: [PATCH] Do not run trust upgrade code if master lacks Samba bindings
+
+If a replica has no Samba bindings but there are trust agreements
+configured on some trust controller, skip trust upgrade code on this
+replica.
+
+Resolves: https://pagure.io/freeipa/issue/8001
+Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
+Reviewed-By: Thomas Woerner <twoerner@redhat.com>
+---
+ ipaserver/install/plugins/adtrust.py | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
+index 950b7b9c82f1b0e115675ff8093d1bd02e913ae2..c0de12eca903a6635f4b53b0806a0ba07170b7c6 100644
+--- a/ipaserver/install/plugins/adtrust.py
++++ b/ipaserver/install/plugins/adtrust.py
+@@ -23,6 +23,8 @@ except ImportError:
+     def ndr_unpack(x):
+         raise NotImplementedError
+ 
++    drsblobs = None
++
+ logger = logging.getLogger(__name__)
+ 
+ register = Registry()
+@@ -633,6 +635,10 @@ class update_tdo_to_new_layout(Updater):
+             logger.debug('AD Trusts are not enabled on this server')
+             return False, []
+ 
++        # If we have no Samba bindings, this master is not a trust controller
++        if drsblobs is None:
++            return False, []
++
+         ldap = self.api.Backend.ldap2
+         gidNumber = get_gidNumber(ldap, self.api.env)
+         if gidNumber is None:
+-- 
+2.23.0
+
diff --git a/SOURCES/0026-Don-t-allow-to-hide-last-server-for-a-role.patch b/SOURCES/0026-Don-t-allow-to-hide-last-server-for-a-role.patch
deleted file mode 100644
index 53e180e..0000000
--- a/SOURCES/0026-Don-t-allow-to-hide-last-server-for-a-role.patch
+++ /dev/null
@@ -1,118 +0,0 @@
-From ec58278fa7fc6d0b5ae8340c4054005a7864086f Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Tue, 26 Mar 2019 13:10:23 +0100
-Subject: [PATCH] Don't allow to hide last server for a role
-
-DNSSec key master and CA renewal master can't be hidden. There must be
-at least one enabled server available for each role, too.
-
-Fixes: https://pagure.io/freeipa/issue/7892
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Thomas Woerner <twoerner@redhat.com>
-Reviewed-By: Francois Cami <fcami@redhat.com>
----
- ipaserver/plugins/server.py                   | 30 ++++++++++++++++++
- .../test_replica_promotion.py                 | 31 +++++++++++++++++++
- 2 files changed, 61 insertions(+)
-
-diff --git a/ipaserver/plugins/server.py b/ipaserver/plugins/server.py
-index 0d144d13bca66b65de64328139fd7126eea24c89..bfd1406ff826aea97195aa08ca35018e35cac18c 100644
---- a/ipaserver/plugins/server.py
-+++ b/ipaserver/plugins/server.py
-@@ -970,6 +970,35 @@ class server_state(crud.PKQuery):
- 
-     has_output = output.standard_boolean
- 
-+    def _check_hide_server(self, fqdn):
-+        result = self.api.Command.config_show()['result']
-+        err = []
-+        # single value entries
-+        if result.get("ca_renewal_master_server") == fqdn:
-+            err.append(_("Cannot hide CA renewal master."))
-+        if result.get("dnssec_key_master_server") == fqdn:
-+            err.append(_("Cannot hide DNSSec key master."))
-+        # multi value entries, only fail if we are the last one
-+        checks = [
-+            ("ca_server_server", "CA"),
-+            ("dns_server_server", "DNS"),
-+            ("ipa_master_server", "IPA"),
-+            ("kra_server_server", "KRA"),
-+        ]
-+        for key, name in checks:
-+            values = result.get(key, [])
-+            if values == [fqdn]:  # fqdn is the only entry
-+                err.append(
-+                    _("Cannot hide last enabled %(name)s server.") % {
-+                        'name': name
-+                    }
-+                )
-+        if err:
-+            raise errors.ValidationError(
-+                name=fqdn,
-+                error=' '.join(str(e) for e in err)
-+            )
-+
-     def execute(self, *keys, **options):
-         fqdn = keys[0]
-         if options['state'] == u'enabled':
-@@ -992,6 +1021,7 @@ class server_state(crud.PKQuery):
-         if to_status == ENABLED:
-             enable_services(fqdn)
-         else:
-+            self._check_hide_server(fqdn)
-             hide_services(fqdn)
- 
-         # update system roles
-diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py
-index 9ce0074ea0df276b4800b306530d04c8274ece69..bf028bf7dc58abb6455ba1659f2d19bede69daa2 100644
---- a/ipatests/test_integration/test_replica_promotion.py
-+++ b/ipatests/test_integration/test_replica_promotion.py
-@@ -812,7 +812,15 @@ class TestHiddenReplicaPromotion(IntegrationTest):
- 
-     @classmethod
-     def install(cls, mh):
-+        # master with DNSSEC master
-         tasks.install_master(cls.master, setup_dns=True, setup_kra=True)
-+        cls.master.run_command([
-+            "ipa-dns-install",
-+            "--dnssec-master",
-+            "--forwarder", cls.master.config.dns_forwarder,
-+            "-U",
-+        ])
-+        # hidden replica with CA and DNS
-         tasks.install_replica(
-             cls.master, cls.replicas[0],
-             setup_dns=True, setup_kra=True,
-@@ -879,6 +887,29 @@ class TestHiddenReplicaPromotion(IntegrationTest):
-         self._check_dnsrecords([self.master], [self.replicas[0]])
-         self._check_config([self.master], [self.replicas[0]])
- 
-+    def test_hide_master_fails(self):
-+        # verify state
-+        self._check_config([self.master], [self.replicas[0]])
-+        # nothing to do
-+        result = self.master.run_command([
-+            'ipa', 'server-state',
-+            self.master.hostname, '--state=enabled'
-+        ], raiseonerr=False)
-+        assert result.returncode == 1
-+        assert "no modifications to be performed" in result.stderr_text
-+        # hiding the last master fails
-+        result = self.master.run_command([
-+            'ipa', 'server-state',
-+            self.master.hostname, '--state=hidden'
-+        ], raiseonerr=False)
-+        assert result.returncode == 1
-+        keys = [
-+            "CA renewal master", "DNSSec key master", "CA server",
-+            "KRA server", "DNS server", "IPA server"
-+        ]
-+        for key in keys:
-+            assert key in result.stderr_text
-+
-     def test_hidden_replica_promote(self):
-         self.replicas[0].run_command([
-             'ipa', 'server-state',
--- 
-2.20.1
-
diff --git a/SOURCES/0027-Make-sure-to-have-storage-space-for-tag.patch b/SOURCES/0027-Make-sure-to-have-storage-space-for-tag.patch
new file mode 100644
index 0000000..b994893
--- /dev/null
+++ b/SOURCES/0027-Make-sure-to-have-storage-space-for-tag.patch
@@ -0,0 +1,39 @@
+From 3384e4b799409eb669a779406cabbb1ed1bf783f Mon Sep 17 00:00:00 2001
+From: Simo Sorce <simo@redhat.com>
+Date: Mon, 16 Sep 2019 11:12:25 -0400
+Subject: [PATCH] Make sure to have storage space for tag
+
+ber_scanf expects a pointer to a ber_tag_t to return the tag pointed at
+by "t", if that is not provided the pointer will be store in whatever
+memory location is pointed by the stack at that time causeing a crash.
+
+Note that this is effectively unused code because in ipa-kdb the only
+party that can write a key_data structure to be stored is te kdb_driver
+itself and we never encode these s2kparam data.
+
+But we need to handle this for future proofing.
+
+Fixes #8071
+
+Signed-off-by: Simo Sorce <simo@redhat.com>
+Reviewed-By: Christian Heimes <cheimes@redhat.com>
+---
+ util/ipa_krb5.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/util/ipa_krb5.c b/util/ipa_krb5.c
+index a27cd4a4e538c738c6ab2157a4daabf8fea7661c..c09c3daa505655f2e5292a79c03683faa75ad244 100644
+--- a/util/ipa_krb5.c
++++ b/util/ipa_krb5.c
+@@ -554,7 +554,7 @@ int ber_decode_krb5_key_data(struct berval *encoded, int *m_kvno,
+         retag = ber_peek_tag(be, &setlen);
+         if (retag == (LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 2)) {
+             /* not supported yet, skip */
+-            retag = ber_scanf(be, "t[x]}");
++            retag = ber_scanf(be, "t[x]}", &tag);
+         } else {
+             retag = ber_scanf(be, "}");
+         }
+-- 
+2.23.0
+
diff --git a/SOURCES/0027-Synchronize-hidden-state-from-IPA-master-role.patch b/SOURCES/0027-Synchronize-hidden-state-from-IPA-master-role.patch
deleted file mode 100644
index ba3a6c8..0000000
--- a/SOURCES/0027-Synchronize-hidden-state-from-IPA-master-role.patch
+++ /dev/null
@@ -1,118 +0,0 @@
-From d0327f33d3bc426db5c8dd86666e680da6a44b61 Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Tue, 26 Mar 2019 13:27:35 +0100
-Subject: [PATCH] Synchronize hidden state from IPA master role
-
-ipa-{adtrust|ca|dns|kra}-install on a hidden replica also installs the
-new service as hidden service.
-
-Fixes: https://pagure.io/freeipa/issue/7892
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Thomas Woerner <twoerner@redhat.com>
-Reviewed-By: Francois Cami <fcami@redhat.com>
----
- install/tools/ipa-adtrust-install             |  2 +-
- install/tools/ipa-ca-install                  |  2 +-
- ipaserver/install/ipa_kra_install.py          |  2 +-
- ipaserver/install/service.py                  | 22 +++++++++++++++++++
- .../test_replica_promotion.py                 |  4 +++-
- 5 files changed, 28 insertions(+), 4 deletions(-)
-
-diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install
-index 9dbfadb6fae193e2f4a54b3a0e226e0a6b1fd26f..19bd21866119b4a23f5a6a02cc8ea37c8f5d36ea 100755
---- a/install/tools/ipa-adtrust-install
-+++ b/install/tools/ipa-adtrust-install
-@@ -213,7 +213,7 @@ def main():
-     adtrust.install(True, options, fstore, api)
- 
-     # Enable configured services and update DNS SRV records
--    service.enable_services(api.env.host)
-+    service.sync_services_state(api.env.host)
-     api.Command.dns_update_system_records()
- 
-     print("""
-diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install
-index 55182dc30e4736618f749e78db161fc7eefe37ac..dda7a0527b07695c51140c437a2699c8634f2724 100755
---- a/install/tools/ipa-ca-install
-+++ b/install/tools/ipa-ca-install
-@@ -347,7 +347,7 @@ def main():
-     api.Backend.ldap2.connect()
- 
-     # Enable configured services and update DNS SRV records
--    service.enable_services(api.env.host)
-+    service.sync_services_state(api.env.host)
-     api.Command.dns_update_system_records()
-     api.Backend.ldap2.disconnect()
- 
-diff --git a/ipaserver/install/ipa_kra_install.py b/ipaserver/install/ipa_kra_install.py
-index 19260ac7f23a7c6f3a6328d4f146510a186b706e..006bc92bec581e1983f11bfd75498b5484f2567a 100644
---- a/ipaserver/install/ipa_kra_install.py
-+++ b/ipaserver/install/ipa_kra_install.py
-@@ -239,6 +239,6 @@ class KRAInstaller(KRAInstall):
-         api.Backend.ldap2.connect()
- 
-         # Enable configured services and update DNS SRV records
--        service.enable_services(api.env.host)
-+        service.sync_services_state(api.env.host)
-         api.Command.dns_update_system_records()
-         api.Backend.ldap2.disconnect()
-diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
-index 6d7997c559f8d748f00dd9df28371c53bc12ee21..8948f64c2ec2db4cd013699e07dd94d5dba6c043 100644
---- a/ipaserver/install/service.py
-+++ b/ipaserver/install/service.py
-@@ -41,6 +41,7 @@ from ipaplatform.paths import paths
- from ipaserver.masters import (
-     CONFIGURED_SERVICE, ENABLED_SERVICE, HIDDEN_SERVICE, SERVICE_LIST
- )
-+from ipaserver.servroles import HIDDEN
- 
- logger = logging.getLogger(__name__)
- 
-@@ -202,6 +203,27 @@ def hide_services(fqdn):
-     _set_services_state(fqdn, HIDDEN_SERVICE)
- 
- 
-+def sync_services_state(fqdn):
-+    """Synchronize services state from IPA master role state
-+
-+    Hide all services if the IPA master role state is in hidden state.
-+    Otherwise enable all services.
-+
-+    :param fqdn: hostname of server
-+    """
-+    result = api.Command.server_role_find(
-+        server_server=fqdn,
-+        role_servrole='IPA master',
-+        status=HIDDEN
-+    )
-+    if result['count']:
-+        # one hidden server role
-+        hide_services(fqdn)
-+    else:
-+        # IPA master is either enabled or configured, enable all
-+        enable_services(fqdn)
-+
-+
- def _set_services_state(fqdn, dest_state):
-     """Change all services of a host
- 
-diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py
-index bf028bf7dc58abb6455ba1659f2d19bede69daa2..df71972a2ba3ad503011a558295bd38f587faf44 100644
---- a/ipatests/test_integration/test_replica_promotion.py
-+++ b/ipatests/test_integration/test_replica_promotion.py
-@@ -823,9 +823,11 @@ class TestHiddenReplicaPromotion(IntegrationTest):
-         # hidden replica with CA and DNS
-         tasks.install_replica(
-             cls.master, cls.replicas[0],
--            setup_dns=True, setup_kra=True,
-+            setup_dns=True, setup_kra=False,
-             extra_args=('--hidden-replica',)
-         )
-+        # manually install KRA to verify that hidden state is synced
-+        tasks.install_kra(cls.replicas[0])
- 
-     def _check_dnsrecords(self, hosts_expected, hosts_unexpected=()):
-         domain = DNSName(self.master.domain.name).make_absolute()
--- 
-2.20.1
-
diff --git a/SOURCES/0028-CVE-2019-10195-Don-t-log-passwords-embedded-in-comma.patch b/SOURCES/0028-CVE-2019-10195-Don-t-log-passwords-embedded-in-comma.patch
new file mode 100644
index 0000000..80fd778
--- /dev/null
+++ b/SOURCES/0028-CVE-2019-10195-Don-t-log-passwords-embedded-in-comma.patch
@@ -0,0 +1,147 @@
+From 4b391a87700b3bee23a241e6ede28d19fcfca3d3 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Tue, 2 Jul 2019 13:44:48 -0400
+Subject: [PATCH] CVE-2019-10195: Don't log passwords embedded in commands in
+ calls using batch
+
+A raw batch request was fully logged which could expose parameters
+we don't want logged, like passwords.
+
+Override _repr_iter to use the individual commands to log the
+values so that values are properly obscured.
+
+In case of errors log the full value on when the server is in
+debug mode.
+
+Reported by Jamison Bennett from Cloudera
+
+Signed-off-by: Rob Crittenden <rcritten@redhat.com>
+Reviewed-by:  Florence Blanc-Renaud <frenaud@redhat.com>
+---
+ ipaserver/plugins/batch.py | 96 ++++++++++++++++++++++++++++----------
+ 1 file changed, 72 insertions(+), 24 deletions(-)
+
+diff --git a/ipaserver/plugins/batch.py b/ipaserver/plugins/batch.py
+index 2794db895a014a6129654889289815d4286cf7f4..9df367d16234d1840a2e5297cdd5c3c59fa4828f 100644
+--- a/ipaserver/plugins/batch.py
++++ b/ipaserver/plugins/batch.py
+@@ -92,35 +92,82 @@ class batch(Command):
+         Output('results', (list, tuple), doc='')
+     )
+ 
++    def _validate_request(self, request):
++        """
++        Check that an individual request in a batch is parseable and the
++        commands exists.
++        """
++        if 'method' not in request:
++            raise errors.RequirementError(name='method')
++        if 'params' not in request:
++            raise errors.RequirementError(name='params')
++        name = request['method']
++        if (name not in self.api.Command or
++                isinstance(self.api.Command[name], Local)):
++            raise errors.CommandError(name=name)
++
++        # If params are not formated as a tuple(list, dict)
++        # the following lines will raise an exception
++        # that triggers an internal server error
++        # Raise a ConversionError instead to report the issue
++        # to the client
++        try:
++            a, kw = request['params']
++            newkw = dict((str(k), v) for k, v in kw.items())
++            api.Command[name].args_options_2_params(*a, **newkw)
++        except (AttributeError, ValueError, TypeError):
++            raise errors.ConversionError(
++                name='params',
++                error=_(u'must contain a tuple (list, dict)'))
++        except Exception as e:
++            raise errors.ConversionError(
++                name='params',
++                error=str(e))
++
++    def _repr_iter(self, **params):
++        """
++        Iterate through the request and use the Command _repr_intr so
++        that sensitive information (passwords) is not exposed.
++
++        In case of a malformatted request redact the entire thing.
++        """
++        exceptions = False
++        for arg in (params.get('methods', [])):
++            try:
++                self._validate_request(arg)
++            except Exception:
++                # redact the whole request since we don't know what's in it
++                exceptions = True
++                yield u'********'
++                continue
++
++            name = arg['method']
++            a, kw = arg['params']
++            newkw = dict((str(k), v) for k, v in kw.items())
++            param = api.Command[name].args_options_2_params(
++                *a, **newkw)
++
++            yield '{}({})'.format(
++                api.Command[name].name,
++                ', '.join(api.Command[name]._repr_iter(**param))
++            )
++
++        if exceptions:
++            logger.debug('batch: %s',
++                         ', '.join(super(batch, self)._repr_iter(**params)))
++
+     def execute(self, methods=None, **options):
+         results = []
+         for arg in (methods or []):
+             params = dict()
+             name = None
+             try:
+-                if 'method' not in arg:
+-                    raise errors.RequirementError(name='method')
+-                if 'params' not in arg:
+-                    raise errors.RequirementError(name='params')
++                self._validate_request(arg)
+                 name = arg['method']
+-                if (name not in self.api.Command or
+-                        isinstance(self.api.Command[name], Local)):
+-                    raise errors.CommandError(name=name)
+-
+-                # If params are not formated as a tuple(list, dict)
+-                # the following lines will raise an exception
+-                # that triggers an internal server error
+-                # Raise a ConversionError instead to report the issue
+-                # to the client
+-                try:
+-                    a, kw = arg['params']
+-                    newkw = dict((str(k), v) for k, v in kw.items())
+-                    params = api.Command[name].args_options_2_params(
+-                        *a, **newkw)
+-                except (AttributeError, ValueError, TypeError):
+-                    raise errors.ConversionError(
+-                        name='params',
+-                        error=_(u'must contain a tuple (list, dict)'))
++                a, kw = arg['params']
++                newkw = dict((str(k), v) for k, v in kw.items())
++                params = api.Command[name].args_options_2_params(
++                    *a, **newkw)
+                 newkw.setdefault('version', options['version'])
+ 
+                 result = api.Command[name](*a, **newkw)
+@@ -132,8 +179,9 @@ class batch(Command):
+                 )
+                 result['error']=None
+             except Exception as e:
+-                if isinstance(e, errors.RequirementError) or \
+-                    isinstance(e, errors.CommandError):
++                if (isinstance(e, errors.RequirementError) or
++                        isinstance(e, errors.CommandError) or
++                        isinstance(e, errors.ConversionError)):
+                     logger.info(
+                         '%s: batch: %s',
+                         context.principal,  # pylint: disable=no-member
+-- 
+2.23.0
+
diff --git a/SOURCES/0028-Test-replica-installation-from-hidden-replica.patch b/SOURCES/0028-Test-replica-installation-from-hidden-replica.patch
deleted file mode 100644
index 35e9db8..0000000
--- a/SOURCES/0028-Test-replica-installation-from-hidden-replica.patch
+++ /dev/null
@@ -1,183 +0,0 @@
-From 4850c91e063ddc0968a451ba9654c587f29a73d8 Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Tue, 26 Mar 2019 16:43:55 +0100
-Subject: [PATCH] Test replica installation from hidden replica
-
-Exercise ipa-replica-install with a hidden replica as source server and
-creation of replication agreements between a hidden and an enabled
-replica.
-
-Reviewed-By: Thomas Woerner <twoerner@redhat.com>
-Reviewed-By: Francois Cami <fcami@redhat.com>
----
- ipatests/pytest_ipa/integration/tasks.py      | 22 ++++--
- .../test_replica_promotion.py                 | 73 +++++++++++++++----
- 2 files changed, 74 insertions(+), 21 deletions(-)
-
-diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py
-index 1f0509189d2e3b3ad7402dd042d61e4ad4f97ed5..46506e4eee09dd1981777c8facef7c1938e07605 100644
---- a/ipatests/pytest_ipa/integration/tasks.py
-+++ b/ipatests/pytest_ipa/integration/tasks.py
-@@ -691,28 +691,38 @@ def sync_time(host, server):
-     host.run_command(['ntpdate', server.hostname])
- 
- 
--def connect_replica(master, replica, domain_level=None):
-+def connect_replica(master, replica, domain_level=None,
-+                    database=DOMAIN_SUFFIX_NAME):
-     if domain_level is None:
-         domain_level = master.config.domain_level
-     if domain_level == DOMAIN_LEVEL_0:
--        replica.run_command(['ipa-replica-manage', 'connect', master.hostname])
-+        if database == DOMAIN_SUFFIX_NAME:
-+            cmd = 'ipa-replica-manage'
-+        else:
-+            cmd = 'ipa-csreplica-manage'
-+        replica.run_command([cmd, 'connect', master.hostname])
-     else:
-         kinit_admin(master)
--        master.run_command(["ipa", "topologysegment-add", DOMAIN_SUFFIX_NAME,
-+        master.run_command(["ipa", "topologysegment-add", database,
-                             "%s-to-%s" % (master.hostname, replica.hostname),
-                             "--leftnode=%s" % master.hostname,
-                             "--rightnode=%s" % replica.hostname
-                             ])
- 
- 
--def disconnect_replica(master, replica, domain_level=None):
-+def disconnect_replica(master, replica, domain_level=None,
-+                       database=DOMAIN_SUFFIX_NAME):
-     if domain_level is None:
-         domain_level = master.config.domain_level
-     if domain_level == DOMAIN_LEVEL_0:
--        replica.run_command(['ipa-replica-manage', 'disconnect', master.hostname])
-+        if database == DOMAIN_SUFFIX_NAME:
-+            cmd = 'ipa-replica-manage'
-+        else:
-+            cmd = 'ipa-csreplica-manage'
-+        replica.run_command([cmd, 'disconnect', master.hostname])
-     else:
-         kinit_admin(master)
--        master.run_command(["ipa", "topologysegment-del", DOMAIN_SUFFIX_NAME,
-+        master.run_command(["ipa", "topologysegment-del", database,
-                             "%s-to-%s" % (master.hostname, replica.hostname),
-                             "--continue"
-                             ])
-diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py
-index df71972a2ba3ad503011a558295bd38f587faf44..f9cc3d833072666fed348795c414e3840615ac70 100644
---- a/ipatests/test_integration/test_replica_promotion.py
-+++ b/ipatests/test_integration/test_replica_promotion.py
-@@ -15,7 +15,8 @@ from ipatests.pytest_ipa.integration.tasks import (
-     assert_error, replicas_cleanup)
- from ipatests.pytest_ipa.integration.env_config import get_global_config
- from ipalib.constants import (
--    DOMAIN_LEVEL_0, DOMAIN_LEVEL_1, DOMAIN_SUFFIX_NAME, IPA_CA_NICKNAME)
-+    DOMAIN_LEVEL_0, DOMAIN_LEVEL_1, DOMAIN_SUFFIX_NAME, IPA_CA_NICKNAME,
-+    CA_SUFFIX_NAME)
- from ipaplatform.paths import paths
- from ipatests.test_integration.test_backup_and_restore import backup
- from ipatests.test_integration.test_dns_locations import (
-@@ -807,8 +808,8 @@ class TestReplicaInForwardZone(IntegrationTest):
- class TestHiddenReplicaPromotion(IntegrationTest):
-     """Test hidden replica features
-     """
--    topology = 'star'
--    num_replicas = 1
-+    topology = None
-+    num_replicas = 2
- 
-     @classmethod
-     def install(cls, mh):
-@@ -850,8 +851,12 @@ class TestHiddenReplicaPromotion(IntegrationTest):
-                 value = host.hostname if rtype == 'SRV' else host.ip
-                 assert value not in txt
- 
--    def _check_server_role(self, host, status):
--        roles = [u'IPA master', u'CA server', u'KRA server', u'DNS server']
-+    def _check_server_role(self, host, status, kra=True, dns=True):
-+        roles = [u'IPA master', u'CA server']
-+        if kra:
-+            roles.append(u'KRA server')
-+        if dns:
-+            roles.append(u'DNS server')
-         for role in roles:
-             result = self.replicas[0].run_command([
-                 'ipa', 'server-role-find',
-@@ -936,6 +941,52 @@ class TestHiddenReplicaPromotion(IntegrationTest):
-         self._check_server_role(self.replicas[0], 'hidden')
-         self._check_dnsrecords([self.master], [self.replicas[0]])
- 
-+    def test_replica_from_hidden(self):
-+        # install a replica from a hidden replica
-+        self._check_server_role(self.replicas[0], 'hidden')
-+        tasks.install_replica(
-+            master=self.replicas[0],
-+            replica=self.replicas[1],
-+            setup_dns=True
-+        )
-+        self._check_server_role(self.replicas[0], 'hidden')
-+        self._check_server_role(
-+            self.replicas[1], 'enabled', kra=False, dns=False
-+        )
-+        self._check_dnsrecords(
-+            [self.master, self.replicas[1]], [self.replicas[0]]
-+        )
-+        # hide the new replica
-+        self.replicas[0].run_command([
-+            'ipa', 'server-state',
-+            self.replicas[1].hostname, '--state=hidden'
-+        ])
-+        # and establish replication agreements from master
-+        tasks.connect_replica(
-+            master=self.master,
-+            replica=self.replicas[1],
-+        )
-+        tasks.connect_replica(
-+            master=self.master,
-+            replica=self.replicas[1],
-+            database=CA_SUFFIX_NAME,
-+        )
-+        # remove replication agreements again
-+        tasks.disconnect_replica(
-+            master=self.master,
-+            replica=self.replicas[1],
-+        )
-+        tasks.disconnect_replica(
-+            master=self.master,
-+            replica=self.replicas[1],
-+            database=CA_SUFFIX_NAME,
-+        )
-+        # and uninstall
-+        tasks.uninstall_replica(
-+            master=self.replicas[0],
-+            replica=self.replicas[1],
-+        )
-+
-     def test_hidden_replica_backup_and_restore(self):
-         """Exercises backup+restore and hidden replica uninstall
-         """
-@@ -950,19 +1001,11 @@ class TestHiddenReplicaPromotion(IntegrationTest):
-             ['ipa-restore', backup_path],
-             stdin_text=dirman_password + '\nyes'
-         )
-+
-         # give replication some time
-         time.sleep(5)
--
--        # check that role is still hidden
-         tasks.kinit_admin(self.replicas[0])
--        self._check_config([self.master], [self.replicas[0]])
--        self._check_server_role(self.replicas[0], 'hidden')
--        self._check_dnsrecords([self.master], [self.replicas[0]])
- 
--        # check that the resulting server can be promoted to enabled
--        self.replicas[0].run_command([
--            'ipa', 'server-mod', self.replicas[0].hostname, '--state=enabled'
--        ])
-+        # FIXME: restore turns hidden replica into enabled replica
-         self._check_config([self.master, self.replicas[0]])
-         self._check_server_role(self.replicas[0], 'enabled')
--        self._check_dnsrecords([self.master, self.replicas[0]])
--- 
-2.20.1
-
diff --git a/SOURCES/0029-Add-design-draft.patch b/SOURCES/0029-Add-design-draft.patch
deleted file mode 100644
index 6dff1da..0000000
--- a/SOURCES/0029-Add-design-draft.patch
+++ /dev/null
@@ -1,179 +0,0 @@
-From 451eb489193538c9ead259919669b3ca3658cbd8 Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Tue, 26 Mar 2019 16:45:02 +0100
-Subject: [PATCH] Add design draft
-
-The design draft explains implementation details, limitations, and API
-changes for the new feature.
-
-Fixes: https://pagure.io/freeipa/issue/7892
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Thomas Woerner <twoerner@redhat.com>
-Reviewed-By: Francois Cami <fcami@redhat.com>
----
- doc/designs/hidden-replicas.md | 153 +++++++++++++++++++++++++++++++++
- 1 file changed, 153 insertions(+)
- create mode 100644 doc/designs/hidden-replicas.md
-
-diff --git a/doc/designs/hidden-replicas.md b/doc/designs/hidden-replicas.md
-new file mode 100644
-index 0000000000000000000000000000000000000000..1abc73612cbf2e5636d7076b5c6f50eb0ecbce4c
---- /dev/null
-+++ b/doc/designs/hidden-replicas.md
-@@ -0,0 +1,153 @@
-+# Hidden replicas
-+
-+**TECH PREVIEW**
-+
-+## Overview
-+
-+A hidden replica is an IPA master server that is not advertised to
-+clients or other masters. Hidden replicas have all services running
-+and available, but none of the services has any DNS SRV records or
-+enabled LDAP server roles. This makes hidden replicas invisible for
-+service discovery.
-+
-+* IPA clients and SSSD ignore hidden replicas and don't consider them
-+  during installation or daily operations.
-+* Kerberos clients with ``dns_lookup_kdc = True`` do not auto-discover
-+  hidden replicas.
-+* Certmonger does not use a hidden replica to renew certificates.
-+* Masters without a CA or KRA instance never use CA or KRA services
-+  of a hidden replica.
-+
-+By default, only services on a hidden replica use other services on
-+the same machine, e.g. local LDAP and Kerberos services.
-+
-+## Limitations
-+
-+It's critical to understand that hidden replicas have limitations. Most
-+importantly, hidden replicas are just concealed, but not isolated and
-+secluded. Other machines merely don't see hidden replicas, when they
-+use standard mechanisms to discover IPA servers. Other machines are
-+able to find hidden replicas if they know what to look for. Any machine
-+is able to use services on a hidden replica, when they are explicitly
-+configured to do so.
-+
-+* Hidden replicas are neither firewalled nor do they have any ACLs in
-+  place to prevent connections from other machines. All IPA TCP and
-+  UDP ports must be open for at least all other IPA servers.
-+* There must be at least one regular, non-hidden server available and
-+  online for each service (IPA master, DNS, CA, KRA). If DNS locations
-+  are used, there should be at least one regular replica in each
-+  location.
-+* As of now, a hidden replica cannot be a *CA renewal master* or
-+  a *DNSSEC key master*. The restriction may be lifted in the future.
-+* Hard-coded server names and explicit configurations like
-+  ``ipa-client-install --server=$HOST``, SSSD config, or ``ca_host``
-+  setting in ``/etc/ipa/default.conf`` override auto-discovery.
-+* The process of demoting a regular replica to hidden replica or
-+  promotion from hidden to regular replica is not instantaneous. It
-+  takes a while until the changes have been replicated and cached
-+  settings are refreshed.
-+
-+## Use Cases
-+
-+Hidden replicas are primarily designed for dedicated services that may
-+otherwise disrupt clients. For example a full backup requires a
-+complete shutdown of all IPA services. Since a hidden replica is not
-+used by any clients by default, a temporary shutdown does not affect
-+clients.
-+
-+Other use cases include operations that put a high load on the IPA
-+API or LDAP server, like mass imports or extensive queries.
-+
-+## How to Use
-+
-+### installation of a hidden replica
-+
-+A new hidden replica can be installed with
-+``ipa-replica-install --hidden-replica``.
-+
-+### demotion / promotion of hidden replicas
-+
-+A new command ``ipa server-state`` can be used to modify the state of a
-+replica. An existing replica can be demoted to a hidden replica by
-+executing ``ipa server-state $HOST --state=hidden``. The command
-+``ipa server-state $HOST --state=enable`` turns a hidden replica
-+into an enabled, visible replica.
-+
-+A *CA renewal master* or *DNSSEC key master* can't be demoted to hidden
-+replica. First the services must be moved to another replica with
-+``ipa-dns-install --dnssec-master`` and
-+``ipa config-mod --ca-renewal-master-server=$HOST``.
-+
-+### query status
-+
-+The ``ipa config-show`` command now shows additional information about
-+DNS and KRA as well as hidden servers:
-+
-+```
-+$ ipa config-show
-+  ...
-+  IPA masters: server1.ipa.example
-+  Hidden IPA masters: hidden1.ipa.example
-+  IPA master capable of PKINIT: hidden1.ipa.example, server1.ipa.example
-+  IPA CA servers: server1.ipa.example
-+  Hidden IPA CA servers: hidden1.ipa.example
-+  IPA CA renewal master: server1.ipa.example
-+  IPA KRA servers: server1.ipa.example
-+  Hidden IPA KRA servers: hidden1.ipa.example
-+  IPA DNS servers: server1.ipa.example
-+  Hidden IPA DNS servers: hidden1.ipa.example
-+  IPA DNSSec key master: server1.ipa.example
-+$ ipa server-role-find --server=hidden1.ipa.example --include-master
-+----------------------
-+6 server roles matched
-+----------------------
-+  Server name: hidden1.ipa.example
-+  Role name: AD trust agent
-+  Role status: absent
-+
-+  Server name: hidden1.ipa.example
-+  Role name: AD trust controller
-+  Role status: absent
-+
-+  Server name: hidden1.ipa.example
-+  Role name: CA server
-+  Role status: hidden
-+
-+  Server name: hidden1.ipa.example
-+  Role name: DNS server
-+  Role status: hidden
-+
-+  Server name: hidden1.ipa.example
-+  Role name: IPA master
-+  Role status: hidden
-+
-+  Server name: hidden1.ipa.example
-+  Role name: KRA server
-+  Role status: hidden
-+----------------------------
-+Number of entries returned 6
-+----------------------------
-+```
-+
-+## Implementation
-+
-+The status of a service is stored in LDAP inside the
-+``cn=masters,cn=ipa,cn=etc,$SUFFIX`` subtree. The subtree contains
-+entries for each IPA master. Each entry holds a bunch of sub entries
-+for services. For example
-+``cn=CA,cn=hidden1.ipa.example,cn=masters,cn=ipa,cn=etc,$SUFFIX`` is
-+the container for the *CA* service on the IPA master
-+*hidden1.ipa.example*. During the installation process the service
-+entries are created with multi-valued attribute ``ipaConfigString``
-+set to ``configuredService``. At the end of the installation,
-+``configuredService`` is either replaced with ``enabledService`` for a
-+standard, enabled, and visible replica. Or it is set to
-+``hiddenService`` for hidden, unadvertised replicas.
-+
-+Auto-discovery ignores any and all hidden services. The
-+``dns-update-system-records`` does not create SRV records for hidden
-+services. The ``find_providing_servers`` API ignores hidden services
-+except for preferred hosts. CA and KRA service discovery use the
-+current host or explicit ``ca_host`` option from
-+``/etc/ipa/default.conf`` as preferred host.
--- 
-2.20.1
-
diff --git a/SOURCES/0029-trust-upgrade-ensure-that-host-is-member-of-adtrust-.patch b/SOURCES/0029-trust-upgrade-ensure-that-host-is-member-of-adtrust-.patch
new file mode 100644
index 0000000..422aaed
--- /dev/null
+++ b/SOURCES/0029-trust-upgrade-ensure-that-host-is-member-of-adtrust-.patch
@@ -0,0 +1,110 @@
+From 4fd15ef7c4059e8010e54b014795f20ba459fc3f Mon Sep 17 00:00:00 2001
+From: Florence Blanc-Renaud <flo@redhat.com>
+Date: Tue, 3 Dec 2019 12:56:22 +0100
+Subject: [PATCH] trust upgrade: ensure that host is member of adtrust agents
+
+After an upgrade, the group cn=adtrust agents may be missing some members.
+Each ad trust controller must appear twice as member:
+- krbprincipalname=cifs/hostname@realm,cn=services,cn=accounts,basedn
+- fqdn=hostname,cn=computers,cn=accounts,basedn
+
+Add an upgrade plugin that builds a list of hostnames from the cifs
+principals and adds if needed fqdn=hostname...
+
+Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1778777
+Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
+Reviewed-By: Alexander Bokovoy <abbra@users.noreply.github.com>
+Reviewed-By: Alexander Bokovoy <abbra@users.noreply.github.com>
+---
+ .../updates/90-post_upgrade_plugins.update    |  1 +
+ ipaserver/install/plugins/adtrust.py          | 55 +++++++++++++++++++
+ 2 files changed, 56 insertions(+)
+
+diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update
+index e3afb3423ccaf1598bc0a0e982a5264781fd81a4..4ba8b845276c60c719fe8fcef9c457aa2deba61f 100644
+--- a/install/updates/90-post_upgrade_plugins.update
++++ b/install/updates/90-post_upgrade_plugins.update
+@@ -13,6 +13,7 @@ plugin: update_default_trust_view
+ plugin: update_tdo_gidnumber
+ plugin: update_tdo_to_new_layout
+ plugin: update_tdo_default_read_keys_permissions
++plugin: update_adtrust_agents_members
+ plugin: update_ca_renewal_master
+ plugin: update_idrange_type
+ plugin: update_pacs
+diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
+index c0de12eca903a6635f4b53b0806a0ba07170b7c6..dd6c25e9f14b161bda3bce5cc8ed260fae109db4 100644
+--- a/ipaserver/install/plugins/adtrust.py
++++ b/ipaserver/install/plugins/adtrust.py
+@@ -8,9 +8,11 @@ from ipalib import Updater
+ from ipapython.dn import DN
+ from ipapython import ipautil
+ from ipaplatform.paths import paths
++from ipaserver.install import service
+ from ipaserver.install import sysupgrade
+ from ipaserver.install.adtrustinstance import (
+     ADTRUSTInstance, map_Guests_to_nobody)
++
+ from ipaserver.dcerpc_common import TRUST_BIDIRECTIONAL
+ 
+ try:
+@@ -791,3 +793,56 @@ class update_tdo_default_read_keys_permissions(Updater):
+                              tdo.single_value.get('krbCanonicalName'))
+ 
+         return False, []
++
++
++@register()
++class update_adtrust_agents_members(Updater):
++    """ Ensure that each adtrust agent is a member of the adtrust agents group
++
++    cn=adtrust agents,cn=sysaccounts,cn=etc,$BASEDN must contain:
++    - member: krbprincipalname=cifs/master@realm,cn=services,cn=accounts,base
++    - member: fqdn=master,cn=computers,cn=accounts,base
++    """
++    def execute(self, **options):
++        ldap = self.api.Backend.ldap2
++
++        # First, see if trusts are enabled on the server
++        if not self.api.Command.adtrust_is_enabled()['result']:
++            logger.debug('AD Trusts are not enabled on this server')
++            return False, []
++
++        agents_dn = DN(
++            ('cn', 'adtrust agents'), ('cn', 'sysaccounts'),
++            ('cn', 'etc'), self.api.env.basedn)
++
++        try:
++            agents_entry = ldap.get_entry(agents_dn, ['member'])
++        except errors.NotFound:
++            logger.error("No adtrust agents group found")
++            return False, []
++
++        # Build a list of agents from the cifs/.. members
++        agents_list = []
++        members = agents_entry.get('member', [])
++        suffix = '@{}'.format(self.api.env.realm).lower()
++
++        for amember in members:
++            if amember[0].attr.lower() == 'krbprincipalname':
++                # Extract krbprincipalname=cifs/hostname@realm from the DN
++                value = amember[0].value
++                if (value.lower().startswith('cifs/') and
++                        value.lower().endswith(suffix)):
++                    # 5 = length of 'cifs/'
++                    hostname = value[5:-len(suffix)]
++                    agents_list.append(DN(('fqdn', hostname),
++                                       self.api.env.container_host,
++                                       self.api.env.basedn))
++
++        # Add the fqdn=hostname... to the group
++        service.add_principals_to_group(
++            ldap,
++            agents_dn,
++            "member",
++            agents_list)
++
++        return False, []
+-- 
+2.23.0
+
diff --git a/SOURCES/0030-Don-t-fail-if-config-show-does-not-return-servers.patch b/SOURCES/0030-Don-t-fail-if-config-show-does-not-return-servers.patch
deleted file mode 100644
index 3358ee3..0000000
--- a/SOURCES/0030-Don-t-fail-if-config-show-does-not-return-servers.patch
+++ /dev/null
@@ -1,60 +0,0 @@
-From a9b0d9b109d0f35adbf45ef8d158f276014c7c8b Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Tue, 26 Mar 2019 20:09:27 +0100
-Subject: [PATCH] Don't fail if config-show does not return servers
-
-When uninstalling a cluster and only hidden servers are left,
-config-show can return a result set without ipa_master_server entry.
-
-Fixes: https://pagure.io/freeipa/issue/7892
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Thomas Woerner <twoerner@redhat.com>
-Reviewed-By: Francois Cami <fcami@redhat.com>
----
- ipaserver/install/ca.py     | 2 +-
- ipaserver/plugins/pkinit.py | 2 +-
- ipaserver/plugins/server.py | 2 +-
- 3 files changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
-index 716f3b3dc1fc81438b74d4fa393f7f17d6d2a802..09b3c09e758775de77cdf4ac5cae755183aa8f8c 100644
---- a/ipaserver/install/ca.py
-+++ b/ipaserver/install/ca.py
-@@ -106,7 +106,7 @@ def uninstall_check(options):
- 
-     # skip the checks if the host is the last master
-     ipa_config = api.Command.config_show()['result']
--    ipa_masters = ipa_config['ipa_master_server']
-+    ipa_masters = ipa_config.get('ipa_master_server', [])
-     if len(ipa_masters) <= 1:
-         return
- 
-diff --git a/ipaserver/plugins/pkinit.py b/ipaserver/plugins/pkinit.py
-index 8853938460073f69f6e6242c5ae5c362b3faf4f7..6d42a9af11f2079054e59416f3930fbae5b65555 100644
---- a/ipaserver/plugins/pkinit.py
-+++ b/ipaserver/plugins/pkinit.py
-@@ -91,7 +91,7 @@ class pkinit_status(Search):
-         if server is not None:
-             servers = [server]
-         else:
--            servers = ipa_master_config['ipa_master_server']
-+            servers = ipa_master_config.get('ipa_master_server', [])
- 
-         pkinit_servers = ipa_master_config.get('pkinit_server_server')
-         if pkinit_servers is None:
-diff --git a/ipaserver/plugins/server.py b/ipaserver/plugins/server.py
-index bfd1406ff826aea97195aa08ca35018e35cac18c..ee9c2ba7440dce276213bb97eaca621e1ef33efe 100644
---- a/ipaserver/plugins/server.py
-+++ b/ipaserver/plugins/server.py
-@@ -482,7 +482,7 @@ class server_del(LDAPDelete):
- 
-         ipa_config = self.api.Command.config_show()['result']
- 
--        ipa_masters = ipa_config['ipa_master_server']
-+        ipa_masters = ipa_config.get('ipa_master_server', [])
- 
-         # skip these checks if the last master is being removed
-         if len(ipa_masters) <= 1:
--- 
-2.20.1
-
diff --git a/SOURCES/0031-Extract-ca_renewal-cert-update-subroutine.patch b/SOURCES/0031-Extract-ca_renewal-cert-update-subroutine.patch
deleted file mode 100644
index 8044f47..0000000
--- a/SOURCES/0031-Extract-ca_renewal-cert-update-subroutine.patch
+++ /dev/null
@@ -1,89 +0,0 @@
-From 474c13d1543608c8c4da06957295215bbcd5b67c Mon Sep 17 00:00:00 2001
-From: Fraser Tweedale <ftweedal@redhat.com>
-Date: Fri, 22 Mar 2019 13:37:45 +1100
-Subject: [PATCH] Extract ca_renewal cert update subroutine
-
-When the CA renewal master renews certificates that are shared
-across CA replicas, it puts them in LDAP for the other CA replicas
-to see.  The code to create/update these entries lives in the
-dogtag-ipa-ca-renew-agent renewal helper, but it will be useful for
-the ipa-cert-fix program too.  Extract it to a subroutine in the
-cainstance module.
-
-Part of: https://pagure.io/freeipa/issue/7885
-
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
----
- .../dogtag-ipa-ca-renew-agent-submit          | 16 +-----------
- ipaserver/install/cainstance.py               | 26 +++++++++++++++++++
- 2 files changed, 27 insertions(+), 15 deletions(-)
-
-diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit
-index c33404c18c0022af6b801d25cac1eb0bec019cdf..c2ba9cb842ba835948925a8e415d1e25fe8ee139 100755
---- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit
-+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit
-@@ -270,23 +270,9 @@ def store_cert(**kwargs):
-         return (REJECTED, "New certificate requests not supported")
-     cert = x509.load_pem_x509_certificate(cert.encode('ascii'))
- 
--    dn = DN(('cn', nickname), ('cn', 'ca_renewal'),
--            ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
-     try:
-         with ldap_connect() as conn:
--            try:
--                entry = conn.get_entry(dn, ['usercertificate'])
--                entry['usercertificate'] = [cert]
--                conn.update_entry(entry)
--            except errors.NotFound:
--                entry = conn.make_entry(
--                    dn,
--                    objectclass=['top', 'pkiuser', 'nscontainer'],
--                    cn=[nickname],
--                    usercertificate=[cert])
--                conn.add_entry(entry)
--            except errors.EmptyModlist:
--                pass
-+            cainstance.update_ca_renewal_entry(conn, nickname, cert)
-     except Exception as e:
-         attempts += 1
-         if attempts < 10:
-diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
-index 2946b5cc2b4b8b708a060aa79d1b7ab0e7b4e651..527ad0a1f492050d452336105cc5cf3c645af693 100644
---- a/ipaserver/install/cainstance.py
-+++ b/ipaserver/install/cainstance.py
-@@ -1711,6 +1711,32 @@ def update_authority_entry(cert):
-     return __update_entry_from_cert(make_filter, make_entry, cert)
- 
- 
-+def update_ca_renewal_entry(conn, nickname, cert):
-+    """
-+    Update the ca_renewal entry for the given nickname.
-+
-+    :param conn: A *connected* LDAP handle
-+    :param nickname: NSSDB nickname
-+    :param cert: python-cryptography X509Certificate
-+
-+    """
-+    dn = DN(('cn', nickname), ('cn', 'ca_renewal'),
-+            ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
-+    try:
-+        entry = conn.get_entry(dn, ['usercertificate'])
-+        entry['usercertificate'] = [cert]
-+        conn.update_entry(entry)
-+    except errors.NotFound:
-+        entry = conn.make_entry(
-+            dn,
-+            objectclass=['top', 'pkiuser', 'nscontainer'],
-+            cn=[nickname],
-+            usercertificate=[cert])
-+        conn.add_entry(entry)
-+    except errors.EmptyModlist:
-+        pass
-+
-+
- def ensure_ldap_profiles_container():
-     ensure_entry(
-         DN(('ou', 'certificateProfiles'), ('ou', 'ca'), ('o', 'ipaca')),
--- 
-2.20.1
-
diff --git a/SOURCES/0032-cainstance-add-function-to-determine-ca_renewal-nick.patch b/SOURCES/0032-cainstance-add-function-to-determine-ca_renewal-nick.patch
deleted file mode 100644
index df1d189..0000000
--- a/SOURCES/0032-cainstance-add-function-to-determine-ca_renewal-nick.patch
+++ /dev/null
@@ -1,85 +0,0 @@
-From d868e27dfe7ab9955faebf0a08be3b41971bf816 Mon Sep 17 00:00:00 2001
-From: Fraser Tweedale <ftweedal@redhat.com>
-Date: Fri, 22 Mar 2019 15:22:21 +1100
-Subject: [PATCH] cainstance: add function to determine ca_renewal nickname
-
-The ipa-cert-fix program needs to know where to put shared
-certificates.  Extract the logic that computes the nickname from
-dogtag-ipa-ca-renew-agent to new subroutine
-cainstance.get_ca_renewal_nickname().
-
-Part of: https://pagure.io/freeipa/issue/7885
-
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
----
- .../dogtag-ipa-ca-renew-agent-submit          | 16 ++----------
- ipaserver/install/cainstance.py               | 26 +++++++++++++++++++
- 2 files changed, 28 insertions(+), 14 deletions(-)
-
-diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit
-index c2ba9cb842ba835948925a8e415d1e25fe8ee139..31b4a1b7fc23567e91f8aa9938ce4e0941a84a8c 100755
---- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit
-+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit
-@@ -85,20 +85,8 @@ def get_nickname():
- 
-     ca_subject_dn = ca.lookup_ca_subject(api, subject_base)
- 
--    nickname_by_subject_dn = {
--        DN(ca_subject_dn): 'caSigningCert cert-pki-ca',
--        DN('CN=CA Audit', subject_base): 'auditSigningCert cert-pki-ca',
--        DN('CN=OCSP Subsystem', subject_base): 'ocspSigningCert cert-pki-ca',
--        DN('CN=CA Subsystem', subject_base): 'subsystemCert cert-pki-ca',
--        DN('CN=KRA Audit', subject_base): 'auditSigningCert cert-pki-kra',
--        DN('CN=KRA Transport Certificate', subject_base):
--            'transportCert cert-pki-kra',
--        DN('CN=KRA Storage Certificate', subject_base):
--            'storageCert cert-pki-kra',
--        DN('CN=IPA RA', subject_base): 'ipaCert',
--    }
--
--    return nickname_by_subject_dn.get(DN(subject))
-+    return cainstance.get_ca_renewal_nickname(
-+        subject_base, ca_subject_dn, DN(subject))
- 
- 
- def is_replicated():
-diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
-index 527ad0a1f492050d452336105cc5cf3c645af693..b4f6262b2c41e2da7992c403154a476aa3b82dd1 100644
---- a/ipaserver/install/cainstance.py
-+++ b/ipaserver/install/cainstance.py
-@@ -1711,6 +1711,32 @@ def update_authority_entry(cert):
-     return __update_entry_from_cert(make_filter, make_entry, cert)
- 
- 
-+def get_ca_renewal_nickname(subject_base, ca_subject_dn, sdn):
-+    """
-+    Get the nickname for storage in the cn_renewal container.
-+
-+    :param subject_base: Certificate subject base
-+    :param ca_subject_dn: IPA CA subject DN
-+    :param sdn: Subject DN
-+    :return: string, or None if nickname cannot be determined.
-+
-+    """
-+    assert isinstance(sdn, DN)
-+    nickname_by_subject_dn = {
-+        DN(ca_subject_dn): 'caSigningCert cert-pki-ca',
-+        DN('CN=CA Audit', subject_base): 'auditSigningCert cert-pki-ca',
-+        DN('CN=OCSP Subsystem', subject_base): 'ocspSigningCert cert-pki-ca',
-+        DN('CN=CA Subsystem', subject_base): 'subsystemCert cert-pki-ca',
-+        DN('CN=KRA Audit', subject_base): 'auditSigningCert cert-pki-kra',
-+        DN('CN=KRA Transport Certificate', subject_base):
-+            'transportCert cert-pki-kra',
-+        DN('CN=KRA Storage Certificate', subject_base):
-+            'storageCert cert-pki-kra',
-+        DN('CN=IPA RA', subject_base): 'ipaCert',
-+    }
-+    return nickname_by_subject_dn.get(sdn)
-+
-+
- def update_ca_renewal_entry(conn, nickname, cert):
-     """
-     Update the ca_renewal entry for the given nickname.
--- 
-2.20.1
-
diff --git a/SOURCES/0033-constants-add-ca_renewal-container.patch b/SOURCES/0033-constants-add-ca_renewal-container.patch
deleted file mode 100644
index f0d798f..0000000
--- a/SOURCES/0033-constants-add-ca_renewal-container.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From dc96bc41bbff6b0f596649e992df53734278e24f Mon Sep 17 00:00:00 2001
-From: Fraser Tweedale <ftweedal@redhat.com>
-Date: Tue, 26 Mar 2019 19:43:25 +1100
-Subject: [PATCH] constants: add ca_renewal container
-
-Part of: https://pagure.io/freeipa/issue/7885
-
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
----
- ipalib/constants.py             | 1 +
- ipaserver/install/cainstance.py | 3 +--
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/ipalib/constants.py b/ipalib/constants.py
-index 7ff9c6aed32debd609db2650420994aa32e2466c..678a708aa19b682046b570fdce1804ea58865c88 100644
---- a/ipalib/constants.py
-+++ b/ipalib/constants.py
-@@ -129,6 +129,7 @@ DEFAULT_CONFIG = (
-     ('container_sysaccounts', DN(('cn', 'sysaccounts'), ('cn', 'etc'))),
-     ('container_certmap', DN(('cn', 'certmap'))),
-     ('container_certmaprules', DN(('cn', 'certmaprules'), ('cn', 'certmap'))),
-+    ('container_ca_renewal', DN(('cn', 'ca_renewal'), ('cn', 'ipa'), ('cn', 'etc'))),
- 
-     # Ports, hosts, and URIs:
-     # Following values do not have any reasonable default.
-diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
-index b4f6262b2c41e2da7992c403154a476aa3b82dd1..1f22d120478a6d4019663281d3191a27a5ee09ea 100644
---- a/ipaserver/install/cainstance.py
-+++ b/ipaserver/install/cainstance.py
-@@ -1746,8 +1746,7 @@ def update_ca_renewal_entry(conn, nickname, cert):
-     :param cert: python-cryptography X509Certificate
- 
-     """
--    dn = DN(('cn', nickname), ('cn', 'ca_renewal'),
--            ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
-+    dn = DN(('cn', nickname), api.env.container_ca_renewal, api.env.basedn)
-     try:
-         entry = conn.get_entry(dn, ['usercertificate'])
-         entry['usercertificate'] = [cert]
--- 
-2.20.1
-
diff --git a/SOURCES/0034-Add-ipa-cert-fix-tool.patch b/SOURCES/0034-Add-ipa-cert-fix-tool.patch
deleted file mode 100644
index bfd021b..0000000
--- a/SOURCES/0034-Add-ipa-cert-fix-tool.patch
+++ /dev/null
@@ -1,363 +0,0 @@
-From 0a65f076441cfbbf659e109ea6de026504261dba Mon Sep 17 00:00:00 2001
-From: Fraser Tweedale <ftweedal@redhat.com>
-Date: Fri, 22 Mar 2019 16:53:53 +1100
-Subject: [PATCH] Add ipa-cert-fix tool
-
-The ipa-cert-fix tool wraps `pki-server cert-fix`, performing
-additional certificate requests for non-Dogtag IPA certificates and
-performing additional actions.  In particular:
-
-- Run cert-fix with arguments particular to the IPA deployment.
-
-- Update IPA RA certificate in the ipara user entry (if renewed).
-
-- Add shared certificates (if renewed) to the ca_renewal LDAP
-  container for replication.
-
-- Become the CA renewal master if shared certificates were renewed.
-  This ensures other CA replicas, including the previous CA renewal
-  master if not the current host, pick up those new certificates
-  when Certmonger attempts to renew them.
-
-Fixes: https://pagure.io/freeipa/issue/7885
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
----
- freeipa.spec.in                   |   2 +
- install/tools/Makefile.am         |   1 +
- install/tools/ipa-cert-fix        |   8 +
- ipaserver/install/ipa_cert_fix.py | 276 ++++++++++++++++++++++++++++++
- 4 files changed, 287 insertions(+)
- create mode 100755 install/tools/ipa-cert-fix
- create mode 100644 ipaserver/install/ipa_cert_fix.py
-
-diff --git a/freeipa.spec.in b/freeipa.spec.in
-index 34394b5caa811bffc677da9644120c90a09b1e81..775394619ab0eb682935c0d28fe434bcf8248a01 100644
---- a/freeipa.spec.in
-+++ b/freeipa.spec.in
-@@ -995,6 +995,7 @@ install/tools/ipa-adtrust-install
- install/tools/ipa-backup
- install/tools/ipa-ca-install
- install/tools/ipa-cacert-manage
-+install/tools/ipa-cert-fix
- install/tools/ipa-compat-manage
- install/tools/ipa-crlgen-manage
- install/tools/ipa-csreplica-manage
-@@ -1383,6 +1384,7 @@ fi
- %{_sbindir}/ipa-winsync-migrate
- %{_sbindir}/ipa-pkinit-manage
- %{_sbindir}/ipa-crlgen-manage
-+%{_sbindir}/ipa-cert-fix
- %{_libexecdir}/certmonger/dogtag-ipa-ca-renew-agent-submit
- %{_libexecdir}/certmonger/ipa-server-guard
- %dir %{_libexecdir}/ipa
-diff --git a/install/tools/Makefile.am b/install/tools/Makefile.am
-index 9dcd76762f678684b421ce4a7b7b27e673a3ff94..6cdfd109552bff2effbcfabe77ff8bf44c1c60da 100644
---- a/install/tools/Makefile.am
-+++ b/install/tools/Makefile.am
-@@ -30,6 +30,7 @@ dist_sbin_SCRIPTS =		\
- 	ipa-winsync-migrate	\
- 	ipa-pkinit-manage	\
- 	ipa-crlgen-manage	\
-+	ipa-cert-fix		\
- 	$(NULL)
- 
- appdir = $(libexecdir)/ipa/
-diff --git a/install/tools/ipa-cert-fix b/install/tools/ipa-cert-fix
-new file mode 100755
-index 0000000000000000000000000000000000000000..e1fc6f056a2a02ee350a2b09433be6cef46e514a
---- /dev/null
-+++ b/install/tools/ipa-cert-fix
-@@ -0,0 +1,8 @@
-+#! /usr/bin/python2 -E
-+#
-+# Copyright (C) 2019  FreeIPA Contributors see COPYING for license
-+#
-+
-+from ipaserver.install.ipa_cert_fix import IPACertFix
-+
-+IPACertFix.run_cli()
-diff --git a/ipaserver/install/ipa_cert_fix.py b/ipaserver/install/ipa_cert_fix.py
-new file mode 100644
-index 0000000000000000000000000000000000000000..3d9070eac1e7dc03840215dffeb4d73f4d3d0a47
---- /dev/null
-+++ b/ipaserver/install/ipa_cert_fix.py
-@@ -0,0 +1,276 @@
-+#
-+# Copyright (C) 2019  FreeIPA Contributors see COPYING for license
-+#
-+
-+# ipa-cert-fix performs the following steps:
-+#
-+# 1. Confirm running as root (AdminTool.validate_options does this)
-+#
-+# 2. Confirm that DS is up.
-+#
-+# 3. Determine which of following certs (if any) need renewing
-+#     - IPA RA
-+#     - Apache HTTPS
-+#     - 389 LDAPS
-+#     - Kerberos KDC (PKINIT)
-+#
-+# 4. Execute `pki-server cert-fix` with relevant options,
-+#    including `--extra-cert SERIAL` for each cert from #3.
-+#
-+# 5. Print details of renewed certificates.
-+#
-+# 6. Install renewed certs from #3 in relevant places
-+#
-+# 7. ipactl restart
-+
-+from __future__ import print_function, absolute_import
-+
-+import datetime
-+from enum import Enum
-+import logging
-+import shutil
-+
-+from ipalib import api
-+from ipalib import x509
-+from ipaplatform.paths import paths
-+from ipapython.admintool import AdminTool
-+from ipapython.certdb import NSSDatabase, EMPTY_TRUST_FLAGS
-+from ipapython.dn import DN
-+from ipaserver.install import ca, cainstance, dsinstance, installutils
-+from ipaserver.install.installutils import is_ipa_configured
-+from ipapython import ipautil
-+
-+msg = """
-+                          WARNING
-+
-+ipa-cert-fix is intended for recovery when expired certificates
-+prevent the normal operation of FreeIPA.  It should ONLY be used
-+in such scenarios, and backup of the system, especially certificates
-+and keys, is STRONGLY RECOMMENDED.
-+
-+"""
-+
-+logger = logging.getLogger(__name__)
-+
-+
-+class IPACertType(Enum):
-+    IPARA = "IPA RA"
-+    HTTPS = "Apache HTTPS"
-+    LDAPS = "LDAP"
-+    KDC = "KDC"
-+
-+
-+class IPACertFix(AdminTool):
-+    command_name = "ipa-cert-fix"
-+    usage = "%prog"
-+    description = "Renew expired certificates."
-+
-+    def validate_options(self):
-+        super(IPACertFix, self).validate_options(needs_root=True)
-+
-+    def run(self):
-+        if not is_ipa_configured():
-+            print("IPA is not configured.")
-+            return 0  # not really an error
-+
-+        if not cainstance.is_ca_installed_locally():
-+            print("CA is not installed on this server.")
-+            return 0  # not really an error
-+
-+        try:
-+            ipautil.run(['pki-server', 'cert-fix', '--help'], raiseonerr=True)
-+        except ipautil.CalledProcessError:
-+            print(
-+                "The 'pki-server cert-fix' command is not available; "
-+                "cannot proceed."
-+            )
-+            return 1
-+
-+        api.bootstrap(in_server=True, confdir=paths.ETC_IPA)
-+        api.finalize()
-+        api.Backend.ldap2.connect()  # ensure DS is up
-+
-+        subject_base = dsinstance.DsInstance().find_subject_base()
-+        if not subject_base:
-+            raise RuntimeError("Cannot determine certificate subject base.")
-+
-+        ca_subject_dn = ca.lookup_ca_subject(api, subject_base)
-+
-+        now = datetime.datetime.now() + datetime.timedelta(weeks=2)
-+        certs, extra_certs = expired_certs(now)
-+
-+        if not certs and not extra_certs:
-+            print("Nothing to do.")
-+            return 0
-+
-+        print(msg)
-+
-+        print_intentions(certs, extra_certs)
-+
-+        response = ipautil.user_input('Enter "yes" to proceed')
-+        if response.lower() != 'yes':
-+            print("Not proceeding.")
-+            return 0
-+        print("Proceeding.")
-+
-+        run_cert_fix(certs, extra_certs)
-+
-+        replicate_dogtag_certs(subject_base, ca_subject_dn, certs)
-+        install_ipa_certs(subject_base, ca_subject_dn, extra_certs)
-+
-+        if any(x != 'sslserver' for x in certs) \
-+                or any(x[0] is IPACertType.IPARA for x in extra_certs):
-+            # we renewed a "shared" certificate, therefore we must
-+            # become the renewal master
-+            print("Becoming renewal master.")
-+            cainstance.CAInstance().set_renewal_master()
-+
-+        ipautil.run(['ipactl', 'restart'], raiseonerr=True)
-+
-+
-+def expired_certs(now):
-+    return expired_dogtag_certs(now), expired_ipa_certs(now)
-+
-+
-+def expired_dogtag_certs(now):
-+    """
-+    Determine which Dogtag certs are expired, or close to expiry.
-+
-+    Return a list of (cert_id, cert) pairs.
-+
-+    """
-+    certs = []
-+    db = NSSDatabase(nssdir=paths.PKI_TOMCAT_ALIAS_DIR)
-+
-+    for certid, nickname in [
-+        ('sslserver', 'Server-Cert cert-pki-ca'),
-+        ('subsystem', 'subsystemCert cert-pki-ca'),
-+        ('ca_ocsp_signing', 'ocspSigningCert cert-pki-ca'),
-+        ('ca_audit_signing', 'auditSigningCert cert-pki-ca'),
-+        ('kra_transport', 'transportCert cert-pki-kra'),
-+        ('kra_storage', 'storageCert cert-pki-kra'),
-+        ('kra_audit_signing', 'auditSigningCert cert-pki-kra'),
-+    ]:
-+        try:
-+            cert = db.get_cert(nickname)
-+        except RuntimeError:
-+            pass  # unfortunately certdb doesn't give us a better exception
-+        else:
-+            if cert.not_valid_after <= now:
-+                certs.append((certid, cert))
-+
-+    return certs
-+
-+
-+def expired_ipa_certs(now):
-+    """
-+    Determine which IPA certs are expired, or close to expiry.
-+
-+    Return a list of (IPACertType, cert) pairs.
-+
-+    """
-+    certs = []
-+
-+    # IPA RA
-+    cert = x509.load_certificate_from_file(paths.RA_AGENT_PEM)
-+    if cert.not_valid_after <= now:
-+        certs.append((IPACertType.IPARA, cert))
-+
-+    # Apache HTTPD
-+    db = NSSDatabase(nssdir=paths.HTTPD_ALIAS_DIR)
-+    cert = db.get_cert('Server-Cert')
-+    if cert.not_valid_after <= now:
-+        certs.append((IPACertType.HTTPS, cert))
-+
-+    # LDAPS
-+    ds_dbdir = dsinstance.config_dirname(
-+        installutils.realm_to_serverid(api.env.realm))
-+    db = NSSDatabase(nssdir=ds_dbdir)
-+    cert = db.get_cert('Server-Cert')
-+    if cert.not_valid_after <= now:
-+        certs.append((IPACertType.LDAPS, cert))
-+
-+    # KDC
-+    cert = x509.load_certificate_from_file(paths.KDC_CERT)
-+    if cert.not_valid_after <= now:
-+        certs.append((IPACertType.KDC, cert))
-+
-+    return certs
-+
-+
-+def print_intentions(dogtag_certs, ipa_certs):
-+    print("The following certificates will be renewed: ")
-+    print()
-+
-+    for certid, cert in dogtag_certs:
-+        print_cert_info("Dogtag", certid, cert)
-+
-+    for certtype, cert in ipa_certs:
-+        print_cert_info("IPA", certtype.value, cert)
-+
-+
-+def print_cert_info(context, desc, cert):
-+    print("{} {} certificate:".format(context, desc))
-+    print("  Subject: {}".format(DN(cert.subject)))
-+    print("  Serial:  {}".format(cert.serial_number))
-+    print("  Expires: {}".format(cert.not_valid_after))
-+    print()
-+
-+
-+def run_cert_fix(certs, extra_certs):
-+    ldapi_path = (
-+        paths.SLAPD_INSTANCE_SOCKET_TEMPLATE
-+        % '-'.join(api.env.realm.split('.'))
-+    )
-+    cmd = [
-+        'pki-server',
-+        'cert-fix',
-+        '--ldapi-socket', ldapi_path,
-+        '--agent-uid', 'ipara',
-+    ]
-+    for certid, _cert in certs:
-+        cmd.extend(['--cert', certid])
-+    for _certtype, cert in extra_certs:
-+        cmd.extend(['--extra-cert', str(cert.serial_number)])
-+    ipautil.run(cmd, raiseonerr=True)
-+
-+
-+def replicate_dogtag_certs(subject_base, ca_subject_dn, certs):
-+    for certid, _oldcert in certs:
-+        cert_path = "/etc/pki/pki-tomcat/certs/{}.crt".format(certid)
-+        cert = x509.load_certificate_from_file(cert_path)
-+        print_cert_info("Renewed Dogtag", certid, cert)
-+        replicate_cert(subject_base, ca_subject_dn, cert)
-+
-+
-+def install_ipa_certs(subject_base, ca_subject_dn, certs):
-+    """Print details and install renewed IPA certificates."""
-+    for certtype, oldcert in certs:
-+        cert_path = "/etc/pki/pki-tomcat/certs/{}-renewed.crt" \
-+                .format(oldcert.serial_number)
-+        cert = x509.load_certificate_from_file(cert_path)
-+        print_cert_info("Renewed IPA", certtype.value, cert)
-+
-+        if certtype is IPACertType.IPARA:
-+            shutil.copyfile(cert_path, paths.RA_AGENT_PEM)
-+            cainstance.update_people_entry(cert)
-+            replicate_cert(subject_base, ca_subject_dn, cert)
-+        elif certtype is IPACertType.HTTPS:
-+            db = NSSDatabase(nssdir=paths.HTTPD_ALIAS_DIR)
-+            db.delete_cert('Server-Cert')
-+            db.import_pem_cert('Server-Cert', EMPTY_TRUST_FLAGS, cert_path)
-+        elif certtype is IPACertType.LDAPS:
-+            ds_dbdir = dsinstance.config_dirname(
-+                installutils.realm_to_serverid(api.env.realm))
-+            db = NSSDatabase(nssdir=ds_dbdir)
-+            db.delete_cert('Server-Cert')
-+            db.import_pem_cert('Server-Cert', EMPTY_TRUST_FLAGS, cert_path)
-+        elif certtype is IPACertType.KDC:
-+            shutil.copyfile(cert_path, paths.KDC_CERT)
-+
-+
-+def replicate_cert(subject_base, ca_subject_dn, cert):
-+    nickname = cainstance.get_ca_renewal_nickname(
-+        subject_base, ca_subject_dn, DN(cert.subject))
-+    if nickname:
-+        cainstance.update_ca_renewal_entry(api.Backend.ldap2, nickname, cert)
--- 
-2.20.1
-
diff --git a/SOURCES/0035-ipa-cert-fix-add-man-page.patch b/SOURCES/0035-ipa-cert-fix-add-man-page.patch
deleted file mode 100644
index c9cdcaf..0000000
--- a/SOURCES/0035-ipa-cert-fix-add-man-page.patch
+++ /dev/null
@@ -1,114 +0,0 @@
-From 03e3540e74e7b6da68987574d65668c07d484396 Mon Sep 17 00:00:00 2001
-From: Fraser Tweedale <ftweedal@redhat.com>
-Date: Mon, 25 Mar 2019 16:13:38 +1100
-Subject: [PATCH] ipa-cert-fix: add man page
-
-Part of: https://pagure.io/freeipa/issue/7885
-
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
----
- freeipa.spec.in                  |  1 +
- install/tools/man/Makefile.am    |  1 +
- install/tools/man/ipa-cert-fix.1 | 66 ++++++++++++++++++++++++++++++++
- 3 files changed, 68 insertions(+)
- create mode 100644 install/tools/man/ipa-cert-fix.1
-
-diff --git a/freeipa.spec.in b/freeipa.spec.in
-index 775394619ab0eb682935c0d28fe434bcf8248a01..a18a5b4aab335ad104f1263fa3ae8b26659c3095 100644
---- a/freeipa.spec.in
-+++ b/freeipa.spec.in
-@@ -1450,6 +1450,7 @@ fi
- %{_mandir}/man1/ipa-winsync-migrate.1*
- %{_mandir}/man1/ipa-pkinit-manage.1*
- %{_mandir}/man1/ipa-crlgen-manage.1*
-+%{_mandir}/man1/ipa-cert-fix.1*
- 
- 
- %files -n python2-ipaserver
-diff --git a/install/tools/man/Makefile.am b/install/tools/man/Makefile.am
-index 947e5c65f7d97734a320ee0a1979d7e890de6ed2..28fb57e87648d2a1a8904cc9d96921aa7e0f206e 100644
---- a/install/tools/man/Makefile.am
-+++ b/install/tools/man/Makefile.am
-@@ -29,6 +29,7 @@ dist_man1_MANS = 			\
- 	ipa-winsync-migrate.1		\
- 	ipa-pkinit-manage.1		\
- 	ipa-crlgen-manage.1		\
-+	ipa-cert-fix.1			\
-         $(NULL)
- 
- dist_man8_MANS =			\
-diff --git a/install/tools/man/ipa-cert-fix.1 b/install/tools/man/ipa-cert-fix.1
-new file mode 100644
-index 0000000000000000000000000000000000000000..3edef3118947d203d8972994d0d880850302a348
---- /dev/null
-+++ b/install/tools/man/ipa-cert-fix.1
-@@ -0,0 +1,66 @@
-+.\"
-+.\" Copyright (C) 2019  FreeIPA Contributors see COPYING for license
-+.\"
-+.TH "ipa-cert-fix" "1" "Mar 25 2019" "FreeIPA" "FreeIPA Manual Pages"
-+.SH "NAME"
-+ipa\-cert\-fix \- Renew expired certificates
-+.SH "SYNOPSIS"
-+ipa\-cert\-fix [options]
-+.SH "DESCRIPTION"
-+
-+\fIipa-cert-fix\fR is a tool for recovery when expired certificates
-+prevent the normal operation of FreeIPA.  It should ONLY be used in
-+such scenarios, and backup of the system, especially certificates
-+and keys, is \fBSTRONGLY RECOMMENDED\fR.
-+
-+Do not use this program unless expired certificates are inhibiting
-+normal operation and renewal procedures.
-+
-+To renew the IPA CA certificate, use \fIipa-cacert-manage(1)\fR.
-+
-+This tool cannot renew certificates signed by external CAs.  To
-+install new, externally-signed HTTP, LDAP or KDC certificates, use
-+\fIipa-server-certinstall(1)\fR.
-+
-+\fIipa-cert-fix\fR will examine FreeIPA and Certificate System
-+certificates and renew certificates that are expired, or close to
-+expiry (less than two weeks).  If any "shared" certificates are
-+renewed, \fIipa-cert-fix\fR will set the current server to be the CA
-+renewal master, and add the new shared certificate(s) to LDAP for
-+replication to other CA servers.  Shared certificates include all
-+Dogtag system certificates except the HTTPS certificate, and the IPA
-+RA certificate.
-+
-+To repair certificates across multiple CA servers, first ensure that
-+LDAP replication is working across the topology.  Then run
-+\fIipa-cert-fix\fR on one CA server.  Before running
-+\fIipa-cert-fix\fR on another CA server, trigger Certmonger renewals
-+for shared certificates via \fIgetcert-resubmit(1)\fR (on the other
-+CA server).  This is to avoid unnecessary renewal of shared
-+certificates.
-+
-+.SH "OPTIONS"
-+.TP
-+\fB\-\-version\fR
-+Show the program's version and exit.
-+.TP
-+\fB\-h\fR, \fB\-\-help\fR
-+Show the help for this program.
-+.TP
-+\fB\-v\fR, \fB\-\-verbose\fR
-+Print debugging information.
-+.TP
-+\fB\-q\fR, \fB\-\-quiet\fR
-+Output only errors (output from child processes may still be shown).
-+.TP
-+\fB\-\-log\-file\fR=\fIFILE\fR
-+Log to the given file.
-+.SH "EXIT STATUS"
-+0 if the command was successful
-+
-+1 if an error occurred
-+
-+.SH "SEE ALSO"
-+.BR ipa-cacert-manage(1)
-+.BR ipa-server-certinstall(1)
-+.BR getcert-resubmit(1)
--- 
-2.20.1
-
diff --git a/SOURCES/0036-ipa-cert-fix-use-customary-exit-statuses.patch b/SOURCES/0036-ipa-cert-fix-use-customary-exit-statuses.patch
deleted file mode 100644
index c09450c..0000000
--- a/SOURCES/0036-ipa-cert-fix-use-customary-exit-statuses.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 8bbec6c72b759767bc19681aab9c3d3d9f091b6a Mon Sep 17 00:00:00 2001
-From: Fraser Tweedale <ftweedal@redhat.com>
-Date: Fri, 29 Mar 2019 16:04:20 +1100
-Subject: [PATCH] ipa-cert-fix: use customary exit statuses
-
-It is customary to return 2 when IPA is not configured, and 1 when
-other required bits are not installed or configured.  Update
-ipa-cert-fix exit statuses accordingly.
-
-Part of: https://pagure.io/freeipa/issue/7885
-
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
----
- ipaserver/install/ipa_cert_fix.py | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/ipaserver/install/ipa_cert_fix.py b/ipaserver/install/ipa_cert_fix.py
-index 3d9070eac1e7dc03840215dffeb4d73f4d3d0a47..c8ee51faea9092350c8a182ba55387ddd7b196d8 100644
---- a/ipaserver/install/ipa_cert_fix.py
-+++ b/ipaserver/install/ipa_cert_fix.py
-@@ -71,11 +71,11 @@ class IPACertFix(AdminTool):
-     def run(self):
-         if not is_ipa_configured():
-             print("IPA is not configured.")
--            return 0  # not really an error
-+            return 2
- 
-         if not cainstance.is_ca_installed_locally():
-             print("CA is not installed on this server.")
--            return 0  # not really an error
-+            return 1
- 
-         try:
-             ipautil.run(['pki-server', 'cert-fix', '--help'], raiseonerr=True)
--- 
-2.20.1
-
diff --git a/SOURCES/0037-Show-a-notification-that-sssd-needs-restarting-after.patch b/SOURCES/0037-Show-a-notification-that-sssd-needs-restarting-after.patch
deleted file mode 100644
index aaa3115..0000000
--- a/SOURCES/0037-Show-a-notification-that-sssd-needs-restarting-after.patch
+++ /dev/null
@@ -1,117 +0,0 @@
-From 3c2237e481fdb2241494bd285931803335ed44dd Mon Sep 17 00:00:00 2001
-From: Oleg Kozlov <xxblx@posteo.org>
-Date: Fri, 29 Mar 2019 14:35:02 +0100
-Subject: [PATCH] Show a notification that sssd needs restarting after
- idrange-mod
-
-If the `ipa idrange-mod` command has been used show a notification that sssd.service needs restarting. It's needed for applying changes. E.g. after setup AD trust with a domain with more than 200000 objects (the highest RID > idm's default value, 200000) users with RIDs > 200000 are not able to login, the size needs to be increased via idrange-mod, but it makes an effect only after sssd restarting.
-
-Implementation:
-Notification was implemented via passing `ipalib.messages.ServiceRestartRequired` to `add_message` method in `ipaserver.plugins.idrange.idrange_mod.post_callback`.
-
-Tests:
-Added `messages` with sssd restart required (`ipalib.messages.ServiceRestartRequired`) to cases with idrange_mod where output is expected in `ipatests.test_xmlrpc.test_range_plugin.test_range'.
-
-Fixes: https://pagure.io/freeipa/issue/7708
-Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- ipaplatform/base/services.py              |  3 ++-
- ipaserver/plugins/idrange.py              | 11 ++++++++++-
- ipatests/test_xmlrpc/test_range_plugin.py | 17 ++++++++++++++++-
- 3 files changed, 28 insertions(+), 3 deletions(-)
-
-diff --git a/ipaplatform/base/services.py b/ipaplatform/base/services.py
-index 9fd2a8532837c631945fa837be03c80fa42128bf..b037718f22fc36c4a01b3b0962b3f9e7a69f4b7e 100644
---- a/ipaplatform/base/services.py
-+++ b/ipaplatform/base/services.py
-@@ -53,7 +53,8 @@ wellknownservices = ['certmonger', 'dirsrv', 'httpd', 'ipa', 'krb5kdc',
-                      'messagebus', 'nslcd', 'nscd', 'ntpd', 'portmap',
-                      'rpcbind', 'kadmin', 'sshd', 'autofs', 'rpcgssd',
-                      'rpcidmapd', 'pki_tomcatd', 'chronyd', 'domainname',
--                     'named', 'ods_enforcerd', 'ods_signerd', 'gssproxy']
-+                     'named', 'ods_enforcerd', 'ods_signerd', 'gssproxy',
-+                     'sssd']
- 
- # The common ports for these services. This is used to wait for the
- # service to become available.
-diff --git a/ipaserver/plugins/idrange.py b/ipaserver/plugins/idrange.py
-index ea3d1ff5662800957cde99934e9d2577e6b13ea6..364f128de4a04f484bde0def3c782e1a48be1daa 100644
---- a/ipaserver/plugins/idrange.py
-+++ b/ipaserver/plugins/idrange.py
-@@ -17,13 +17,16 @@
- # You should have received a copy of the GNU General Public License
- # along with this program.  If not, see <http://www.gnu.org/licenses/>.
- 
-+from __future__ import absolute_import
-+
- import six
- 
- from ipalib.plugable import Registry
- from .baseldap import (LDAPObject, LDAPCreate, LDAPDelete,
-                                      LDAPRetrieve, LDAPSearch, LDAPUpdate)
--from ipalib import api, Int, Str, StrEnum, _, ngettext
-+from ipalib import api, Int, Str, StrEnum, _, ngettext, messages
- from ipalib import errors
-+from ipaplatform import services
- from ipapython.dn import DN
- 
- if six.PY3:
-@@ -768,4 +771,10 @@ class idrange_mod(LDAPUpdate):
-         assert isinstance(dn, DN)
-         self.obj.handle_ipabaserid(entry_attrs, options)
-         self.obj.handle_iparangetype(entry_attrs, options)
-+        self.add_message(
-+            messages.ServiceRestartRequired(
-+                service=services.knownservices['sssd'].systemd_name,
-+                server=keys[0]
-+            )
-+        )
-         return dn
-diff --git a/ipatests/test_xmlrpc/test_range_plugin.py b/ipatests/test_xmlrpc/test_range_plugin.py
-index 0a8f66b62dac9ea2e4692f0f64b1c8fbc9272fd2..2adc57ed5f5d23fe5f457ab3a5e23462f24a62fe 100644
---- a/ipatests/test_xmlrpc/test_range_plugin.py
-+++ b/ipatests/test_xmlrpc/test_range_plugin.py
-@@ -21,9 +21,12 @@
- Test the `ipaserver/plugins/idrange.py` module, and XML-RPC in general.
- """
- 
-+from __future__ import absolute_import
-+
- import six
- 
--from ipalib import api, errors
-+from ipalib import api, errors, messages
-+from ipaplatform import services
- from ipatests.test_xmlrpc.xmlrpc_test import Declarative, fuzzy_uuid
- from ipatests.test_xmlrpc import objectclasses
- from ipatests.util import MockLDAP
-@@ -786,6 +789,12 @@ class test_range(Declarative):
-             command=('idrange_mod', [domain3range2],
-                      dict(ipabaseid=domain3range1_base_id)),
-             expected=dict(
-+                messages=(
-+                    messages.ServiceRestartRequired(
-+                        service=services.knownservices['sssd'].systemd_name,
-+                        server=domain3range2
-+                    ).to_dict(),
-+                ),
-                 result=dict(
-                     cn=[domain3range2],
-                     ipabaseid=[unicode(domain3range1_base_id)],
-@@ -851,6 +860,12 @@ class test_range(Declarative):
-             command=('idrange_mod', [domain2range1],
-                      dict(ipabaserid=domain5range1_base_rid)),
-             expected=dict(
-+                messages=(
-+                    messages.ServiceRestartRequired(
-+                        service=services.knownservices['sssd'].systemd_name,
-+                        server=domain2range1
-+                    ).to_dict(),
-+                ),
-                 result=dict(
-                     cn=[domain2range1],
-                     ipabaseid=[unicode(domain2range1_base_id)],
--- 
-2.20.1
-
diff --git a/SOURCES/0038-ipa-server-upgrade-fix-add_systemd_user_hbac.patch b/SOURCES/0038-ipa-server-upgrade-fix-add_systemd_user_hbac.patch
deleted file mode 100644
index cd57fe6..0000000
--- a/SOURCES/0038-ipa-server-upgrade-fix-add_systemd_user_hbac.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-From e3c8a9b78f01e268a907bc97ad2914bf0d1236fc Mon Sep 17 00:00:00 2001
-From: Florence Blanc-Renaud <flo@redhat.com>
-Date: Mon, 1 Apr 2019 11:10:26 +0200
-Subject: [PATCH] ipa-server-upgrade: fix add_systemd_user_hbac
-
-During upgrade, the method add_systemd_user_hbac is creating
-a hbacsvc and a hbacrule, but fails in python2 because of
-unicode conversion errors.
-The arguments should be defined as u'value'.
-
-Fixes: https://pagure.io/freeipa/issue/7896
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- ipaserver/install/server/upgrade.py | 12 ++++++------
- 1 file changed, 6 insertions(+), 6 deletions(-)
-
-diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
-index f4389d37909fc0b5aed960638de67243906b634d..ba0dfa423a3fc9560ef3c81c1d98cad39c320575 100644
---- a/ipaserver/install/server/upgrade.py
-+++ b/ipaserver/install/server/upgrade.py
-@@ -1689,12 +1689,12 @@ def update_replica_config(db_suffix):
- 
- def add_systemd_user_hbac():
-     logger.info('[Create systemd-user hbac service and rule]')
--    rule = 'allow_systemd-user'
--    service = 'systemd-user'
-+    rule = u'allow_systemd-user'
-+    service = u'systemd-user'
-     try:
-         api.Command.hbacsvc_add(
-             service,
--            description='pam_systemd and systemd user@.service'
-+            description=u'pam_systemd and systemd user@.service'
-         )
-     except ipalib.errors.DuplicateEntry:
-         logger.info('hbac service %s already exists', service)
-@@ -1707,10 +1707,10 @@ def add_systemd_user_hbac():
-     try:
-         api.Command.hbacrule_add(
-             rule,
--            description=('Allow pam_systemd to run user@.service to create '
-+            description=(u'Allow pam_systemd to run user@.service to create '
-                          'a system user session'),
--            usercategory='all',
--            hostcategory='all',
-+            usercategory=u'all',
-+            hostcategory=u'all',
-         )
-     except ipalib.errors.DuplicateEntry:
-         logger.info('hbac rule %s already exists', rule)
--- 
-2.20.1
-
diff --git a/SOURCES/0039-ipa-setup-kra-fix-python2-parameter.patch b/SOURCES/0039-ipa-setup-kra-fix-python2-parameter.patch
deleted file mode 100644
index 4f31e3a..0000000
--- a/SOURCES/0039-ipa-setup-kra-fix-python2-parameter.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 031b79d7111d6deaab05a8682014504b328614d7 Mon Sep 17 00:00:00 2001
-From: Florence Blanc-Renaud <flo@redhat.com>
-Date: Mon, 1 Apr 2019 11:35:48 +0200
-Subject: [PATCH] ipa-setup-kra: fix python2 parameter
-
-ipa-setup-kra is failing in python2 with
-invalid 'role_servrole': must be Unicode text
-because of a unicode conversion error.
-
-The method api.Command.server_role_find is called with the parameter
-role_servrole='IPA master' but it should rather be
-role_servrole=u'IPA master'
-
-Fixes: https://pagure.io/freeipa/issue/7897
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- ipaserver/install/service.py | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
-index 8948f64c2ec2db4cd013699e07dd94d5dba6c043..a60cb7f63dc0673deae0839de8c2bb8dc3a905c8 100644
---- a/ipaserver/install/service.py
-+++ b/ipaserver/install/service.py
-@@ -213,7 +213,7 @@ def sync_services_state(fqdn):
-     """
-     result = api.Command.server_role_find(
-         server_server=fqdn,
--        role_servrole='IPA master',
-+        role_servrole=u'IPA master',
-         status=HIDDEN
-     )
-     if result['count']:
--- 
-2.20.1
-
diff --git a/SOURCES/0040-oddjob-allow-to-pass-options-to-trust-fetch-domains.patch b/SOURCES/0040-oddjob-allow-to-pass-options-to-trust-fetch-domains.patch
deleted file mode 100644
index 461a3af..0000000
--- a/SOURCES/0040-oddjob-allow-to-pass-options-to-trust-fetch-domains.patch
+++ /dev/null
@@ -1,286 +0,0 @@
-From 12a079a0b599cf192c4bee8bcc37f1824f82539e Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Sun, 31 Mar 2019 10:39:05 +0300
-Subject: [PATCH] oddjob: allow to pass options to trust-fetch-domains
-
-Refactor com.redhat.idm.trust-fetch.domains oddjob helper to allow
-passing administrative credentials and a domain controller to talk to.
-
-This approach allows to avoid rediscovering a domain controller in case
-a user actually specified the domain controller when establishing trust.
-
-It also allows to pass through admin credentials if user decides to do
-so. The latter will be used later to allow updating trust topology in a
-similar oddjob helper.
-
-Resolves: https://pagure.io/freeipa/issue/7895
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
-(cherry picked from commit de4a9875d410c68ae4f9602b70c753a11034b31b)
----
- API.txt                                       |  4 +-
- VERSION.m4                                    |  4 +-
- .../oddjob/com.redhat.idm.trust-fetch-domains | 91 +++++++++++--------
- .../etc/oddjobd.conf.d/oddjobd-ipa-trust.conf |  2 +-
- ipaserver/plugins/trust.py                    | 31 ++++++-
- 5 files changed, 83 insertions(+), 49 deletions(-)
-
-diff --git a/API.txt b/API.txt
-index 222e30915ccc1fb4a6f3ce228669453f346fdde4..325df7a6ef48afbc438bcc1f7b8ca64efb229886 100644
---- a/API.txt
-+++ b/API.txt
-@@ -5765,10 +5765,12 @@ output: Output('result', type=[<type 'dict'>])
- output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
- output: ListOfPrimaryKeys('value')
- command: trust_fetch_domains/1
--args: 1,5,4
-+args: 1,7,4
- arg: Str('cn', cli_name='realm')
- option: Flag('all', autofill=True, cli_name='all', default=False)
- option: Flag('raw', autofill=True, cli_name='raw', default=False)
-+option: Str('realm_admin?', cli_name='admin')
-+option: Password('realm_passwd?', cli_name='password', confirm=False)
- option: Str('realm_server?', cli_name='server')
- option: Flag('rights', autofill=True, default=False)
- option: Str('version?')
-diff --git a/VERSION.m4 b/VERSION.m4
-index b1425626ca00ffbcc902c66685cb27cbb2136539..da391d8bd4dad6ae8e7418e6af54a9d481133cc8 100644
---- a/VERSION.m4
-+++ b/VERSION.m4
-@@ -82,8 +82,8 @@ define(IPA_DATA_VERSION, 20100614120000)
- #                                                      #
- ########################################################
- define(IPA_API_VERSION_MAJOR, 2)
--define(IPA_API_VERSION_MINOR, 230)
--# Last change: Added `automember-find-orphans' command
-+define(IPA_API_VERSION_MINOR, 231)
-+# Last change: Added admin creds to trust-fetch-domains
- 
- 
- ########################################################
-diff --git a/install/oddjob/com.redhat.idm.trust-fetch-domains b/install/oddjob/com.redhat.idm.trust-fetch-domains
-index 30150793d98011d153081477c0856618e1454ba5..1e90759e0e6e7be36745ec12f4478bfec0f0358e 100755
---- a/install/oddjob/com.redhat.idm.trust-fetch-domains
-+++ b/install/oddjob/com.redhat.idm.trust-fetch-domains
-@@ -14,11 +14,31 @@ import pwd
- import six
- import gssapi
- 
--from ipalib.install.kinit import kinit_keytab
-+from ipalib.install.kinit import kinit_keytab, kinit_password
- 
- if six.PY3:
-     unicode = str
- 
-+
-+def parse_options():
-+    usage = "%prog <trusted domain name>\n"
-+    parser = config.IPAOptionParser(usage=usage,
-+                                    formatter=config.IPAFormatter())
-+
-+    parser.add_option("-d", "--debug", action="store_true", dest="debug",
-+                      help="Display debugging information")
-+    parser.add_option("-s", "--server", action="store", dest="server",
-+                      help="Domain controller for the Active Directory domain (optional)")
-+    parser.add_option("-a", "--admin", action="store", dest="admin",
-+                      help="Active Directory administrator (optional)")
-+    parser.add_option("-p", "--password", action="store", dest="password",
-+                      help="Display debugging information")
-+
-+    options, args = parser.parse_args()
-+    safe_options = parser.get_safe_opts(options)
-+
-+    return safe_options, options, args
-+
- def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal):
-     getkeytab_args = ["/usr/sbin/ipa-getkeytab",
-                       "-s", api.env.host,
-@@ -40,7 +60,7 @@ def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal):
-         pass
- 
- 
--def get_forest_root_domain(api_instance, trusted_domain):
-+def get_forest_root_domain(api_instance, trusted_domain, server=None):
-     """
-     retrieve trusted forest root domain for given domain name
- 
-@@ -53,25 +73,11 @@ def get_forest_root_domain(api_instance, trusted_domain):
-     flatname = trustconfig_show()['result']['ipantflatname'][0]
- 
-     remote_domain = dcerpc.retrieve_remote_domain(
--        api_instance.env.host, flatname, trusted_domain)
-+        api_instance.env.host, flatname, trusted_domain,
-+        realm_server=server)
- 
-     return remote_domain.info['dns_forest']
- 
--
--def parse_options():
--    usage = "%prog <trusted domain name>\n"
--    parser = config.IPAOptionParser(usage=usage,
--                                    formatter=config.IPAFormatter())
--
--    parser.add_option("-d", "--debug", action="store_true", dest="debug",
--                      help="Display debugging information")
--
--    options, args = parser.parse_args()
--    safe_options = parser.get_safe_opts(options)
--
--    return safe_options, options, args
--
--
- if not is_ipa_configured():
-     # LSB status code 6: program is not configured
-     raise ScriptError("IPA is not configured " +
-@@ -153,32 +159,37 @@ trusted_domain = trusted_domain_entry.single_value.get('cn').lower()
- # At this point if we didn't find trusted forest name, an exception will be raised
- # and script will quit. This is actually intended.
- 
--oneway_keytab_name = '/var/lib/sss/keytabs/' + trusted_domain + '.keytab'
--oneway_principal = str('%s$@%s' % (own_trust_flatname, trusted_domain.upper()))
-+if not (options.admin and options.password):
-+    oneway_keytab_name = '/var/lib/sss/keytabs/' + trusted_domain + '.keytab'
-+    oneway_principal = str('%s$@%s' % (own_trust_flatname, trusted_domain.upper()))
- 
--# If keytab does not exist, retrieve it
--if not os.path.isfile(oneway_keytab_name):
--    retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal)
-+    # If keytab does not exist, retrieve it
-+    if not os.path.isfile(oneway_keytab_name):
-+        retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal)
- 
--try:
--    have_ccache = False
-     try:
--        # The keytab may have stale key material (from older trust-add run)
--        cred = kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
--        if cred.lifetime > 0:
--            have_ccache = True
--    except gssapi.exceptions.ExpiredCredentialsError:
--        pass
--    if not have_ccache:
-+        have_ccache = False
-+        try:
-+            # The keytab may have stale key material (from older trust-add run)
-+            cred = kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
-+            if cred.lifetime > 0:
-+                have_ccache = True
-+        except gssapi.exceptions.ExpiredCredentialsError:
-+            pass
-+        if not have_ccache:
-+            if os.path.exists(oneway_ccache_name):
-+                os.unlink(oneway_ccache_name)
-+            kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
-+    except gssapi.exceptions.GSSError:
-+        # If there was failure on using keytab, assume it is stale and retrieve again
-+        retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal)
-         if os.path.exists(oneway_ccache_name):
-             os.unlink(oneway_ccache_name)
-         kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
--except gssapi.exceptions.GSSError:
--    # If there was failure on using keytab, assume it is stale and retrieve again
--    retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal)
--    if os.path.exists(oneway_ccache_name):
--        os.unlink(oneway_ccache_name)
--    kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
-+else:
-+    cred = kinit_password(options.admin, options.password,
-+                          oneway_ccache_name,
-+                          canonicalize=True, enterprise=True)
- 
- # We are done: we have ccache with TDO credentials and can fetch domains
- ipa_domain = api.env.domain
-@@ -186,9 +197,9 @@ os.environ['KRB5CCNAME'] = oneway_ccache_name
- 
- # retrieve the forest root domain name and contact it to retrieve trust
- # topology info
--forest_root = get_forest_root_domain(api, trusted_domain)
-+forest_root = get_forest_root_domain(api, trusted_domain, server=options.server)
- 
--domains = dcerpc.fetch_domains(api, ipa_domain, forest_root, creds=True)
-+domains = dcerpc.fetch_domains(api, ipa_domain, forest_root, creds=True, server=options.server)
- trust_domain_object = api.Command.trust_show(trusted_domain, raw=True)['result']
- trust.add_new_domains_from_trust(api, None, trust_domain_object, domains)
- 
-diff --git a/install/oddjob/etc/oddjobd.conf.d/oddjobd-ipa-trust.conf b/install/oddjob/etc/oddjobd.conf.d/oddjobd-ipa-trust.conf
-index 630a4e6cd4c0d3ed9ce48bf9b882b7d630f6bbf3..9f3f168a51abfdd1cb7cb8b76221bb4ec806859c 100644
---- a/install/oddjob/etc/oddjobd.conf.d/oddjobd-ipa-trust.conf
-+++ b/install/oddjob/etc/oddjobd.conf.d/oddjobd-ipa-trust.conf
-@@ -11,7 +11,7 @@
-       <interface name="com.redhat.idm.trust">
-         <method name="fetch_domains">
-           <helper exec="/usr/libexec/ipa/oddjob/com.redhat.idm.trust-fetch-domains"
--		  arguments="1"
-+		  arguments="30"
-                   argument_passing_method="cmdline"
- 		  prepend_user_name="no"/>
-         </method>
-diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py
-index 91cd1387ce058f34c2319676767d9e50f9b46ed1..bb9e0fe3303989c49cf339df6e5aeeb4ce1435cf 100644
---- a/ipaserver/plugins/trust.py
-+++ b/ipaserver/plugins/trust.py
-@@ -418,9 +418,19 @@ def add_range(myapi, trustinstance, range_name, dom_sid, *keys, **options):
-     return range_type, range_size, base_id
- 
- 
--def fetch_trusted_domains_over_dbus(myapi, forest_name):
-+def fetch_trusted_domains_over_dbus(myapi, *keys, **options):
-     if not _bindings_installed:
-         return
-+
-+    forest_name = keys[0]
-+    method_options = []
-+    if 'realm_server' in options:
-+        method_options.extend(['--server', options['realm_server']])
-+    if 'realm_admin' in options:
-+        method_options.extend(['--admin', options['realm_admin']])
-+    if 'realm_passwd' in options:
-+        method_options.extend(['--password', options['realm_passwd']])
-+
-     # Calling oddjobd-activated service via DBus has some quirks:
-     # - Oddjobd registers multiple canonical names on the same address
-     # - python-dbus only follows name owner changes when mainloop is in use
-@@ -436,7 +446,8 @@ def fetch_trusted_domains_over_dbus(myapi, forest_name):
-         fetch_domains_method = intf.get_dbus_method(
-                 'fetch_domains',
-                 dbus_interface=DBUS_IFACE_TRUST)
--        (_ret, _stdout, _stderr) = fetch_domains_method(forest_name)
-+        (_ret, _stdout, _stderr) = fetch_domains_method(
-+            [forest_name] + method_options)
-     except dbus.DBusException as e:
-         logger.error('Failed to call %s.fetch_domains helper.'
-                      'DBus exception is %s.', DBUS_IFACE_TRUST, str(e))
-@@ -1760,10 +1771,20 @@ class trust_fetch_domains(LDAPRetrieve):
- 
-     has_output = output.standard_list_of_entries
-     takes_options = LDAPRetrieve.takes_options + (
-+        Str('realm_admin?',
-+            cli_name='admin',
-+            label=_("Active Directory domain administrator"),
-+            ),
-+        Password('realm_passwd?',
-+                 cli_name='password',
-+                 label=_("Active Directory domain administrator's password"),
-+                 confirm=False,
-+                 ),
-         Str('realm_server?',
-             cli_name='server',
--            label=_('Domain controller for the Active Directory domain (optional)'),
--        ),
-+            label=_('Domain controller for the Active Directory domain '
-+                    '(optional)'),
-+            ),
-     )
- 
-     def execute(self, *keys, **options):
-@@ -1784,7 +1805,7 @@ class trust_fetch_domains(LDAPRetrieve):
-         # With privilege separation we also cannot authenticate as
-         # HTTP/ principal because we have no access to its key material.
-         # Thus, we'll use DBus call out to oddjobd helper in all cases
--        fetch_trusted_domains_over_dbus(self.api, keys[0])
-+        fetch_trusted_domains_over_dbus(self.api, *keys, **options)
-         result['summary'] = unicode(_('List of trust domains successfully '
-                                       'refreshed. Use trustdomain-find '
-                                       'command to list them.'))
--- 
-2.20.1
-
diff --git a/SOURCES/0041-adtrust-define-Guests-mapping-after-creating-cifs-pr.patch b/SOURCES/0041-adtrust-define-Guests-mapping-after-creating-cifs-pr.patch
deleted file mode 100644
index f3dc8fe..0000000
--- a/SOURCES/0041-adtrust-define-Guests-mapping-after-creating-cifs-pr.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-From bb5026c5a265b78f9c889bd818ccfac9959b7d77 Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Tue, 9 Oct 2018 17:21:37 +0300
-Subject: [PATCH] adtrust: define Guests mapping after creating cifs/ principal
-
-All Samba utilities load passdb modules from the configuration file. As
-result, 'net groupmap' call would try to initialize ipasam passdb module
-and that one would try to connect to LDAP using Kerberos authentication.
-
-We should be running it after cifs/ principal is actually created in
-ipa-adtrust-install or otherwise setting up group mapping will fail.
-
-This only affects new installations. For older ones 'net groupmap' would
-work just fine because adtrust is already configured and all principals
-exist already.
-
-A re-run of 'ipa-server-upgrade' is a workaround too but better to fix
-the initial setup.
-
-Related: https://pagure.io/freeipa/issue/7705
-Reviewed-By: Rob Crittenden <rcritten@redhat.com>
-(cherry picked from commit 1ef0fe8bb824282c2f48417efda3a60e7c1bf580)
----
- ipaserver/install/adtrustinstance.py | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
-index d6b8f5cfa66c0cfbc6d47906703fc09c3e961a53..4141d8991cf75b60dea4ec123f0e3931bb3e6976 100644
---- a/ipaserver/install/adtrustinstance.py
-+++ b/ipaserver/install/adtrustinstance.py
-@@ -845,8 +845,6 @@ class ADTRUSTInstance(service.Service):
-                   self.__create_samba_domain_object)
-         self.step("creating samba config registry", self.__write_smb_registry)
-         self.step("writing samba config file", self.__write_smb_conf)
--        self.step("map BUILTIN\\Guests to nobody group",
--                  self.__map_Guests_to_nobody)
-         self.step("adding cifs Kerberos principal",
-                   self.request_service_keytab)
-         self.step("adding cifs and host Kerberos principals to the adtrust agents group", \
-@@ -858,6 +856,8 @@ class ADTRUSTInstance(service.Service):
-         self.step("updating Kerberos config", self.__update_krb5_conf)
-         self.step("activating CLDAP plugin", self.__add_cldap_module)
-         self.step("activating sidgen task", self.__add_sidgen_task)
-+        self.step("map BUILTIN\\Guests to nobody group",
-+                  self.__map_Guests_to_nobody)
-         self.step("configuring smbd to start on boot", self.__enable)
-         self.step("adding special DNS service records", \
-                   self.__add_dns_service_records)
--- 
-2.20.1
-
diff --git a/SOURCES/0042-net-groupmap-force-using-empty-config-when-mapping-G.patch b/SOURCES/0042-net-groupmap-force-using-empty-config-when-mapping-G.patch
deleted file mode 100644
index 2b2b7ae..0000000
--- a/SOURCES/0042-net-groupmap-force-using-empty-config-when-mapping-G.patch
+++ /dev/null
@@ -1,56 +0,0 @@
-From dae784292fb49559de4aaee2a999c444a72ce272 Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Tue, 16 Oct 2018 17:54:09 +0300
-Subject: [PATCH] net groupmap: force using empty config when mapping Guests
-
-When we define a group mapping for BUILTIN\Guests to 'nobody' group in
-we run 'net groupmap add ...' with a default /etc/samba/smb.conf which
-is now configured to use ipasam passdb module. We authenticate to LDAP
-with GSSAPI in ipasam passdb module initialization.
-
-If GSSAPI authentication failed (KDC is offline, for example, during
-server upgrade), 'net groupmap add' crashes after ~10 attempts to
-re-authenticate. This is intended behavior in smbd/winbindd as they
-cannot work anymore. However, for the command line tools there are
-plenty of operations where passdb module is not needed.
-
-Additionally, GSSAPI authentication uses the default ccache in the
-environment and a key from /etc/samba/samba.keytab keytab. This means
-that if you'd run 'net *' as root, it will replace whatever Kerberos
-tickets you have with a TGT for cifs/`hostname` and a service ticket to
-ldap/`hostname` of IPA master.
-
-Apply a simple solution to avoid using /etc/samba/smb.conf when we
-set up the group mapping by specifying '-s /dev/null' in 'net groupmap'
-call.
-
-For upgrade code this is enough as in
-a678336b8b36cdbea2512e79c09e475fdc249569 we enforce use of empty
-credentials cache during upgrade to prevent tripping on individual
-ccaches from KEYRING: or KCM: cache collections.
-
-Related: https://pagure.io/freeipa/issue/7705
-Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
-(cherry picked from commit 3b79deae537f73ffd18e85f52e00e611543e5e45)
----
- ipaserver/install/adtrustinstance.py | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
-index 4141d8991cf75b60dea4ec123f0e3931bb3e6976..a21be5fba375a48fb82ea4224d00fb71c3688eb8 100644
---- a/ipaserver/install/adtrustinstance.py
-+++ b/ipaserver/install/adtrustinstance.py
-@@ -123,8 +123,8 @@ def make_netbios_name(s):
- 
- def map_Guests_to_nobody():
-     env = {'LC_ALL': 'C'}
--    args = [paths.NET, 'groupmap', 'add', 'sid=S-1-5-32-546',
--            'unixgroup=nobody', 'type=builtin']
-+    args = [paths.NET, '-s', '/dev/null', 'groupmap', 'add',
-+            'sid=S-1-5-32-546', 'unixgroup=nobody', 'type=builtin']
- 
-     logger.debug("Map BUILTIN\\Guests to a group 'nobody'")
-     ipautil.run(args, env=env, raiseonerr=False, capture_error=True)
--- 
-2.20.1
-
diff --git a/SOURCES/0043-Bypass-D-BUS-interface-definition-deficiences-for-tr.patch b/SOURCES/0043-Bypass-D-BUS-interface-definition-deficiences-for-tr.patch
deleted file mode 100644
index a9fd36f..0000000
--- a/SOURCES/0043-Bypass-D-BUS-interface-definition-deficiences-for-tr.patch
+++ /dev/null
@@ -1,102 +0,0 @@
-From 931c7fc1ada309a2d0fe832c95e5a5bf4a89edac Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Mon, 8 Apr 2019 11:43:59 +0300
-Subject: [PATCH] Bypass D-BUS interface definition deficiences for
- trust-fetch-domains
-
-In oddjobd it is possible to pass arguments as command line or on the
-stdin. We use command line to pass them but the way oddjobd registers
-the D-BUS method signatures is by specifying all arguments as mandatory.
-
-Internally, oddjobd simply ignores if you passed less arguments than
-specified in the D-BUS defition. Unfortunately, it is not possible to
-specify less than maximum due to D-BUS seeing all arguments in the
-list (30 is defined for the trust-fetch-domains).
-
-To pass options, have to pad a list of arguments to maximum with empty
-strings and then filter out unneeded ones in the script. Option parser
-already removes all options from the list of arguments so all we need to
-do is to take our actual arguments. In case of trust-fetch-domains, it
-is the name of the domain so we can only care about args[0].
-
-Fixes: https://pagure.io/freeipa/issue/7903
-Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
-(cherry picked from commit add6180ae5c5771b0b0f1c743df069ece4256512)
-
-Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
----
- .../oddjob/com.redhat.idm.trust-fetch-domains | 21 ++++++++++++-------
- ipaserver/plugins/trust.py                    | 11 ++++++++--
- 2 files changed, 22 insertions(+), 10 deletions(-)
-
-diff --git a/install/oddjob/com.redhat.idm.trust-fetch-domains b/install/oddjob/com.redhat.idm.trust-fetch-domains
-index 1e90759e0e6e7be36745ec12f4478bfec0f0358e..029de781b2a1f94b1fd281b79aa69a1e9422dede 100755
---- a/install/oddjob/com.redhat.idm.trust-fetch-domains
-+++ b/install/oddjob/com.redhat.idm.trust-fetch-domains
-@@ -5,6 +5,7 @@ from ipaserver.install.installutils import is_ipa_configured, ScriptError
- from ipapython import config, ipautil
- from ipalib import api
- from ipapython.dn import DN
-+from ipapython.dnsutil import DNSName
- from ipaplatform.constants import constants
- from ipaplatform.paths import paths
- import sys
-@@ -37,7 +38,17 @@ def parse_options():
-     options, args = parser.parse_args()
-     safe_options = parser.get_safe_opts(options)
- 
--    return safe_options, options, args
-+    # We only use first argument of the passed args but as D-BUS interface
-+    # in oddjobd cannot expose optional, we fill in empty slots from IPA side
-+    # and filter them here.
-+    trusted_domain = ipautil.fsdecode(args[0]).lower()
-+
-+    # Accept domain names that at least have two labels. We do not support
-+    # single label Active Directory domains. This also catches empty args.
-+    if len(DNSName(trusted_domain).labels) < 2:
-+        # LSB status code 2: invalid or excess argument(s)
-+        raise ScriptError("You must specify a valid trusted domain name", 2)
-+    return safe_options, options, trusted_domain
- 
- def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal):
-     getkeytab_args = ["/usr/sbin/ipa-getkeytab",
-@@ -87,13 +98,7 @@ if not os.getegid() == 0:
-     # LSB status code 4: user had insufficient privilege
-     raise ScriptError("You must be root to run ipactl.", 4)
- 
--safe_options, options, args = parse_options()
--
--if len(args) != 1:
--    # LSB status code 2: invalid or excess argument(s)
--    raise ScriptError("You must specify trusted domain name", 2)
--
--trusted_domain = ipautil.fsdecode(args[0]).lower()
-+safe_options, options, trusted_domain = parse_options()
- 
- api.bootstrap(in_server=True, log=None,
-               context='server', confdir=paths.ETC_IPA)
-diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py
-index bb9e0fe3303989c49cf339df6e5aeeb4ce1435cf..5de363bda6fdee081d3e4c98e731cecfa9585d21 100644
---- a/ipaserver/plugins/trust.py
-+++ b/ipaserver/plugins/trust.py
-@@ -446,8 +446,15 @@ def fetch_trusted_domains_over_dbus(myapi, *keys, **options):
-         fetch_domains_method = intf.get_dbus_method(
-                 'fetch_domains',
-                 dbus_interface=DBUS_IFACE_TRUST)
--        (_ret, _stdout, _stderr) = fetch_domains_method(
--            [forest_name] + method_options)
-+        # Oddjobd D-BUS method definition only accepts fixed number
-+        # of arguments on the command line. Thus, we need to pass
-+        # remaining ones as ''. There are 30 slots to allow for extension
-+        # and the number comes from the 'arguments' definition in
-+        # install/oddjob/etc/oddjobd.conf.d/oddjobd-ipa-trust.conf
-+        method_arguments = [forest_name]
-+        method_arguments.extend(method_options)
-+        method_arguments.extend([''] * (30 - len(method_arguments)))
-+        (_ret, _stdout, _stderr) = fetch_domains_method(*method_arguments)
-     except dbus.DBusException as e:
-         logger.error('Failed to call %s.fetch_domains helper.'
-                      'DBus exception is %s.', DBUS_IFACE_TRUST, str(e))
--- 
-2.20.1
-
diff --git a/SOURCES/0044-ipactl-restart-fix-wrong-logic-when-checking-service.patch b/SOURCES/0044-ipactl-restart-fix-wrong-logic-when-checking-service.patch
deleted file mode 100644
index 5abeaaa..0000000
--- a/SOURCES/0044-ipactl-restart-fix-wrong-logic-when-checking-service.patch
+++ /dev/null
@@ -1,97 +0,0 @@
-From fc9648e33668afa1c61d62ad9e3b033011dd12d4 Mon Sep 17 00:00:00 2001
-From: Florence Blanc-Renaud <flo@redhat.com>
-Date: Fri, 26 Apr 2019 18:40:05 +0200
-Subject: [PATCH] ipactl restart: fix wrong logic when checking service list
-
-ipactl is building a list of currently running services from
-the content of /var/run/ipa/services.list, and a list of expected services
-from the services configured in LDAP.
-
-Because CA and KRA both correspond to the same pki-tomcatd service, the
-lists may contain duplicates. The code handling these duplicates is called
-at the wrong place, and may result in a wrong list of services to
-stop / restart / start.
-The fix removes the duplicates before returning the lists, hence making sure
-that there is no error when building the list of services to stop / restart
-/ start.
-
-Fixes: https://pagure.io/freeipa/issue/7927
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- install/tools/ipactl | 10 ++--------
- 1 file changed, 2 insertions(+), 8 deletions(-)
-
-diff --git a/install/tools/ipactl b/install/tools/ipactl
-index f40ea5a6df74f04ec7e6e8959d731553651a81d3..5d858b8f9dd2a213a29c50cd2c9778b57fee9e46 100755
---- a/install/tools/ipactl
-+++ b/install/tools/ipactl
-@@ -237,7 +237,7 @@ def get_config(dirsrv):
-     for order, svc in sorted(svc_list):
-         if svc in service.SERVICE_LIST:
-             ordered_list.append(service.SERVICE_LIST[svc].systemd_name)
--    return ordered_list
-+    return deduplicate(ordered_list)
- 
- def get_config_from_file():
- 
-@@ -263,7 +263,7 @@ def get_config_from_file():
-         if svc in svc_list:
-             ordered_list.append(svc)
- 
--    return ordered_list
-+    return deduplicate(ordered_list)
- 
- 
- def stop_services(svc_list):
-@@ -325,7 +325,6 @@ def ipa_start(options):
-         # no service to start
-         return
- 
--    svc_list = deduplicate(svc_list)
-     for svc in svc_list:
-         svchandle = services.service(svc, api=api)
-         try:
-@@ -365,7 +364,6 @@ def ipa_stop(options):
-             finally:
-                 raise IpactlError()
- 
--    svc_list = deduplicate(svc_list)
-     for svc in reversed(svc_list):
-         svchandle = services.service(svc, api=api)
-         try:
-@@ -452,7 +450,6 @@ def ipa_restart(options):
- 
-     if len(old_svc_list) != 0:
-         # we need to definitely stop some services
--        old_svc_list = deduplicate(old_svc_list)
-         for svc in reversed(old_svc_list):
-             svchandle = services.service(svc, api=api)
-             try:
-@@ -477,7 +474,6 @@ def ipa_restart(options):
- 
-     if len(svc_list) != 0:
-         # there are services to restart
--        svc_list = deduplicate(svc_list)
-         for svc in svc_list:
-             svchandle = services.service(svc, api=api)
-             try:
-@@ -500,7 +496,6 @@ def ipa_restart(options):
- 
-     if len(new_svc_list) != 0:
-         # we still need to start some services
--        new_svc_list = deduplicate(new_svc_list)
-         for svc in new_svc_list:
-             svchandle = services.service(svc, api=api)
-             try:
-@@ -552,7 +547,6 @@ def ipa_status(options):
-     if len(svc_list) == 0:
-         return
- 
--    svc_list = deduplicate(svc_list)
-     for svc in svc_list:
-         svchandle = services.service(svc, api=api)
-         try:
--- 
-2.20.1
-
diff --git a/SOURCES/0045-replica-install-acknowledge-ca_host-override.patch b/SOURCES/0045-replica-install-acknowledge-ca_host-override.patch
deleted file mode 100644
index e443c0e..0000000
--- a/SOURCES/0045-replica-install-acknowledge-ca_host-override.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From 14dc08477429ff22acf36052367394a4b59089d0 Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Wed, 27 Mar 2019 11:53:33 +0100
-Subject: [PATCH] replica install: acknowledge ca_host override
-
-Fixup for commit c0fd5e39c726ef4dc12e87a2f9c08ebb32ed27fe. Only set
-ca_host to source master hostname if ca_host points to the local host.
-This permits users to override ca_host in /etc/ipa/default.conf when
-installing a replica.
-
-Related: https://pagure.io/freeipa/issue/7744
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-By: Tibor Dudlak <tdudlak@redhat.com>
-Reviewed-By: Tibor Dudlak <tdudlak@redhat.com>
----
- ipaserver/install/server/replicainstall.py | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
-index 7178238bfb996f987b5e3beaebe05fa104ada089..e13b7f18c4d4df7efde50ac9cb7d2f71bfa765cc 100644
---- a/ipaserver/install/server/replicainstall.py
-+++ b/ipaserver/install/server/replicainstall.py
-@@ -1048,7 +1048,12 @@ def promote_check(installer):
-     config.host_name = api.env.host
-     config.domain_name = api.env.domain
-     config.master_host_name = api.env.server
--    config.ca_host_name = api.env.ca_host
-+    if not api.env.ca_host or api.env.ca_host == api.env.host:
-+        # ca_host has not been configured explicitly, prefer source master
-+        config.ca_host_name = api.env.server
-+    else:
-+        # default to ca_host from IPA config
-+        config.ca_host_name = api.env.ca_host
-     config.kra_host_name = config.ca_host_name
-     config.ca_ds_port = 389
-     config.setup_ca = options.setup_ca
--- 
-2.20.1
-
diff --git a/SOURCES/0046-ipa-console-catch-proper-exception-when-history-file.patch b/SOURCES/0046-ipa-console-catch-proper-exception-when-history-file.patch
deleted file mode 100644
index 9599ec4..0000000
--- a/SOURCES/0046-ipa-console-catch-proper-exception-when-history-file.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From 9fd415c73d0b70c1afadd5694269bf429fbd1aa2 Mon Sep 17 00:00:00 2001
-From: Sergey Orlov <sorlov@redhat.com>
-Date: Thu, 25 Apr 2019 18:30:24 +0200
-Subject: [PATCH] ipa console: catch proper exception when history file can not
- be open
-
-When history file could not be open we were catching OSError. This worked
-for python3, as it raises FileNotFoundError, which is a subclass of
-OSError. But in python2 IOError is raised when file does not exist and
-as this exception was not catched, "ipa conosle" command was crashing.
-As far as in pyton3 IOError and OSError have been merged
-(OSError is IOError) we can safely catch only IOError.
-
-Fixes: https://pagure.io/freeipa/issue/7922
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- ipalib/cli.py | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/ipalib/cli.py b/ipalib/cli.py
-index 7b2af485d94e9f98df44b24489795c45d690956c..2c74a2aaa47a2471a232d81aa6acfafd7f9f930f 100644
---- a/ipalib/cli.py
-+++ b/ipalib/cli.py
-@@ -969,7 +969,7 @@ class console(frontend.Command):
-         history = os.path.join(api.env.dot_ipa, "console.history")
-         try:
-             readline.read_history_file(history)
--        except OSError:
-+        except IOError:
-             pass
- 
-         def save_history():
-@@ -979,7 +979,7 @@ class console(frontend.Command):
-             readline.set_history_length(50)
-             try:
-                 readline.write_history_file(history)
--            except OSError:
-+            except IOError:
-                 logger.exception("Unable to store history %s", history)
- 
-         atexit.register(save_history)
--- 
-2.20.1
-
diff --git a/SOURCES/0047-upgrade-adtrust-catch-empty-result-when-retrieving-l.patch b/SOURCES/0047-upgrade-adtrust-catch-empty-result-when-retrieving-l.patch
deleted file mode 100644
index 26dec09..0000000
--- a/SOURCES/0047-upgrade-adtrust-catch-empty-result-when-retrieving-l.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From dfb08e295420a9ea92776fa99cd1b7fe6a6badaa Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Sat, 11 May 2019 11:54:40 +0300
-Subject: [PATCH] upgrade: adtrust - catch empty result when retrieving list of
- trusts
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Upgrade failure when ipa-server-upgrade is being run on a system with no
-trust established but trust configured
-
-Fixes: https://pagure.io/freeipa/issue/7939
-Reviewed-By: François Cami <fcami@redhat.com>
----
- ipaserver/install/plugins/adtrust.py | 16 +++++++++++-----
- 1 file changed, 11 insertions(+), 5 deletions(-)
-
-diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
-index 1461e000dc855a21665eb5ea0cfe4a47df419344..55df5cd01fd0f585d5955e700ccf20c7fc9a747f 100644
---- a/ipaserver/install/plugins/adtrust.py
-+++ b/ipaserver/install/plugins/adtrust.py
-@@ -610,11 +610,17 @@ class update_tdo_to_new_layout(Updater):
- 
-         trusts_dn = self.api.env.container_adtrusts + self.api.env.basedn
- 
--        trusts = ldap.get_entries(
--            base_dn=trusts_dn,
--            scope=ldap.SCOPE_ONELEVEL,
--            filter=self.trust_filter,
--            attrs_list=self.trust_attrs)
-+        # We might be in a situation when no trusts exist yet
-+        # In such case there is nothing to upgrade but we have to catch
-+        # an exception or it will abort the whole upgrade process
-+        try:
-+            trusts = ldap.get_entries(
-+                base_dn=trusts_dn,
-+                scope=ldap.SCOPE_ONELEVEL,
-+                filter=self.trust_filter,
-+                attrs_list=self.trust_attrs)
-+        except errors.EmptyResult:
-+            trusts = []
- 
-         # For every trust, retrieve its principals and convert
-         for t_entry in trusts:
--- 
-2.20.1
-
diff --git a/SOURCES/0048-Consider-configured-servers-as-valid.patch b/SOURCES/0048-Consider-configured-servers-as-valid.patch
deleted file mode 100644
index 012a807..0000000
--- a/SOURCES/0048-Consider-configured-servers-as-valid.patch
+++ /dev/null
@@ -1,147 +0,0 @@
-From 750a60a989d7c1fe0872af292191889e7e23382d Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Mon, 29 Apr 2019 11:12:30 +0200
-Subject: [PATCH] Consider configured servers as valid
-
-Under some conditions, ipa config-show and several other commands were
-failing with error message:
-
-  ERROR: invalid 'PKINIT enabled server': all masters must have IPA master role enabled
-
-Amongst others the issue can be caused by a broken installation, when
-some services are left in state 'configuredServices'. The problem even
-block uninstallation or removal of replicas. Now configured servers are
-also consider valid providers for associated roles.
-
-A new test verifies that config-show works with hidden and configured HTTP
-service.
-
-Remark: The original intent of the sanity check is no longer clear to me. I
-think it was used to very that all services can be started by ipactl.
-Since ipactl starts hidden, configured, and enabled services, the new
-logic reflect the fact, too.
-
-Fixes: https://pagure.io/freeipa/issue/7929
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
----
- ipaserver/servroles.py                     |  9 ++-
- ipatests/test_integration/test_commands.py | 72 ++++++++++++----------
- 2 files changed, 45 insertions(+), 36 deletions(-)
-
-diff --git a/ipaserver/servroles.py b/ipaserver/servroles.py
-index 0988cbdd7eac599ef26c89a015523b2d92e9502f..984d4bc269fffb4c667e9b8a432b1caf8d3b4f18 100644
---- a/ipaserver/servroles.py
-+++ b/ipaserver/servroles.py
-@@ -346,11 +346,14 @@ class ServerAttribute(LDAPBasedProperty):
-     def _get_assoc_role_providers(self, api_instance):
-         """get list of all servers on which the associated role is enabled
- 
--        Consider a hidden server as a valid provider for a role.
-+        Consider a hidden and configured server as a valid provider for a
-+        role, as all services are started.
-         """
-         return [
--            r[u'server_server'] for r in self.associated_role.status(
--                api_instance) if r[u'status'] in {ENABLED, HIDDEN}]
-+            r[u'server_server']
-+            for r in self.associated_role.status(api_instance)
-+            if r[u'status'] in {ENABLED, HIDDEN, CONFIGURED}
-+        ]
- 
-     def _remove(self, api_instance, masters):
-         """
-diff --git a/ipatests/test_integration/test_commands.py b/ipatests/test_integration/test_commands.py
-index b172a6dd036b5cba4d117f9160ee1ada8712c949..c20213d4b6f0b9d004a8b44afa161a60c538916f 100644
---- a/ipatests/test_integration/test_commands.py
-+++ b/ipatests/test_integration/test_commands.py
-@@ -24,10 +24,15 @@ from ipalib.constants import IPAAPI_USER
- 
- from ipaplatform.paths import paths
- 
-+from ipapython.dn import DN
-+
-+from ipaserver.masters import (
-+    CONFIGURED_SERVICE, ENABLED_SERVICE, HIDDEN_SERVICE
-+)
-+
- from ipatests.test_integration.base import IntegrationTest
- from ipatests.pytest_ipa.integration import tasks
- from ipatests.pytest_ipa.integration.create_external_ca import ExternalCA
--from ipatests.test_ipalib.test_x509 import good_pkcs7, badcert
- 
- logger = logging.getLogger(__name__)
- 
-@@ -499,36 +504,37 @@ class TestIPACommand(IntegrationTest):
-         assert result.returncode != 0
-         assert 'HBAC rule not found' in result.stderr_text
- 
--    def test_ipa_cacert_manage_install(self):
--        # Re-install the IPA CA
--        self.master.run_command([
--            paths.IPA_CACERT_MANAGE,
--            'install',
--            paths.IPA_CA_CRT])
--
--        # Test a non-existent file
--        result = self.master.run_command([
--            paths.IPA_CACERT_MANAGE,
--            'install',
--            '/var/run/cert_not_found'], raiseonerr=False)
--        assert result.returncode == 1
-+    def test_config_show_configured_services(self):
-+        # https://pagure.io/freeipa/issue/7929
-+        states = {CONFIGURED_SERVICE, ENABLED_SERVICE, HIDDEN_SERVICE}
-+        dn = DN(
-+            ('cn', 'HTTP'), ('cn', self.master.hostname), ('cn', 'masters'),
-+            ('cn', 'ipa'), ('cn', 'etc'),
-+            self.master.domain.basedn  # pylint: disable=no-member
-+        )
- 
--        cmd = self.master.run_command(['mktemp'])
--        filename = cmd.stdout_text.strip()
--
--        for contents in (good_pkcs7,):
--            self.master.put_file_contents(filename, contents)
--            result = self.master.run_command([
--                paths.IPA_CACERT_MANAGE,
--                'install',
--                filename])
--
--        for contents in (badcert,):
--            self.master.put_file_contents(filename, contents)
--            result = self.master.run_command([
--                paths.IPA_CACERT_MANAGE,
--                'install',
--                filename], raiseonerr=False)
--            assert result.returncode == 1
--
--        self.master.run_command(['rm', '-f', filename])
-+        conn = self.master.ldap_connect()
-+        entry = conn.get_entry(dn)  # pylint: disable=no-member
-+
-+        # original setting and all settings without state
-+        orig_cfg = list(entry['ipaConfigString'])
-+        other_cfg = [item for item in orig_cfg if item not in states]
-+
-+        try:
-+            # test with hidden
-+            cfg = [HIDDEN_SERVICE]
-+            cfg.extend(other_cfg)
-+            entry['ipaConfigString'] = cfg
-+            conn.update_entry(entry)  # pylint: disable=no-member
-+            self.master.run_command(['ipa', 'config-show'])
-+
-+            # test with configured
-+            cfg = [CONFIGURED_SERVICE]
-+            cfg.extend(other_cfg)
-+            entry['ipaConfigString'] = cfg
-+            conn.update_entry(entry)  # pylint: disable=no-member
-+            self.master.run_command(['ipa', 'config-show'])
-+        finally:
-+            # reset
-+            entry['ipaConfigString'] = orig_cfg
-+            conn.update_entry(entry)  # pylint: disable=no-member
--- 
-2.20.1
-
diff --git a/SOURCES/0049-ipa-cert-fix-handle-pki-server-cert-fix-failure.patch b/SOURCES/0049-ipa-cert-fix-handle-pki-server-cert-fix-failure.patch
deleted file mode 100644
index 8b508d5..0000000
--- a/SOURCES/0049-ipa-cert-fix-handle-pki-server-cert-fix-failure.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From 3c1ac4d5c9c36c2b99ac2b1d9d86e46b563b4361 Mon Sep 17 00:00:00 2001
-From: Fraser Tweedale <ftweedal@redhat.com>
-Date: Mon, 27 May 2019 10:00:28 +1000
-Subject: [PATCH] ipa-cert-fix: handle 'pki-server cert-fix' failure
-
-When DS cert is expired, 'pki-server cert-fix' will fail at the
-final step (restart).  When this case arises, ignore the
-CalledProcessError and continue.
-
-We can't know for sure if the error was due to failure of final
-restart, or something going wrong earlier.  But if it was a more
-serious failure, the next step (installing the renewed IPA-specific
-certificates) will fail.
-
-Part of: https://pagure.io/freeipa/issue/7885
-
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
----
- ipaserver/install/ipa_cert_fix.py | 12 +++++++++++-
- 1 file changed, 11 insertions(+), 1 deletion(-)
-
-diff --git a/ipaserver/install/ipa_cert_fix.py b/ipaserver/install/ipa_cert_fix.py
-index c8ee51faea9092350c8a182ba55387ddd7b196d8..5d5668b1d89115adcda167222ffc38a0caa690a2 100644
---- a/ipaserver/install/ipa_cert_fix.py
-+++ b/ipaserver/install/ipa_cert_fix.py
-@@ -113,7 +113,17 @@ class IPACertFix(AdminTool):
-             return 0
-         print("Proceeding.")
- 
--        run_cert_fix(certs, extra_certs)
-+        try:
-+            run_cert_fix(certs, extra_certs)
-+        except ipautil.CalledProcessError:
-+            if any(x[0] is IPACertType.LDAPS for x in extra_certs):
-+                # The DS cert was expired.  This will cause
-+                # 'pki-server cert-fix' to fail at the final
-+                # restart.  Therefore ignore the CalledProcessError
-+                # and proceed to installing the IPA-specific certs.
-+                pass
-+            else:
-+                raise  # otherwise re-raise
- 
-         replicate_dogtag_certs(subject_base, ca_subject_dn, certs)
-         install_ipa_certs(subject_base, ca_subject_dn, extra_certs)
--- 
-2.20.1
-
diff --git a/SOURCES/0050-ipa-cert-fix-fix-spurious-renewal-master-change.patch b/SOURCES/0050-ipa-cert-fix-fix-spurious-renewal-master-change.patch
deleted file mode 100644
index 3d80f7a..0000000
--- a/SOURCES/0050-ipa-cert-fix-fix-spurious-renewal-master-change.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 1952fb1c90b444f7ecb0057451d5deb599df3d5f Mon Sep 17 00:00:00 2001
-From: Fraser Tweedale <ftweedal@redhat.com>
-Date: Mon, 27 May 2019 10:00:32 +1000
-Subject: [PATCH] ipa-cert-fix: fix spurious renewal master change
-
-We only want to become the renewal master if we actually renewed a
-shared certificate.  But there is a bug in the logic; even if the
-only Dogtag certificate to be renewed is the 'sslserver' (a
-non-shared certificate), the renewal master will be reset.  Fix the
-bug.
-
-A static type system would have excluded this bug.
-
-Part of: https://pagure.io/freeipa/issue/7885
-
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
----
- ipaserver/install/ipa_cert_fix.py | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/ipaserver/install/ipa_cert_fix.py b/ipaserver/install/ipa_cert_fix.py
-index 5d5668b1d89115adcda167222ffc38a0caa690a2..fff054c230c414fdf10eef1cf1b00697a63e386a 100644
---- a/ipaserver/install/ipa_cert_fix.py
-+++ b/ipaserver/install/ipa_cert_fix.py
-@@ -128,7 +128,7 @@ class IPACertFix(AdminTool):
-         replicate_dogtag_certs(subject_base, ca_subject_dn, certs)
-         install_ipa_certs(subject_base, ca_subject_dn, extra_certs)
- 
--        if any(x != 'sslserver' for x in certs) \
-+        if any(x[0] != 'sslserver' for x in certs) \
-                 or any(x[0] is IPACertType.IPARA for x in extra_certs):
-             # we renewed a "shared" certificate, therefore we must
-             # become the renewal master
--- 
-2.20.1
-
diff --git a/SOURCES/0051-adtrust-upgrade-fix-wrong-primary-principal-name.patch b/SOURCES/0051-adtrust-upgrade-fix-wrong-primary-principal-name.patch
deleted file mode 100644
index b4a6a8b..0000000
--- a/SOURCES/0051-adtrust-upgrade-fix-wrong-primary-principal-name.patch
+++ /dev/null
@@ -1,97 +0,0 @@
-From 5b9d7daf27cb10101432e8a25c364dcbe92b37a4 Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Tue, 25 Jun 2019 15:22:57 +0300
-Subject: [PATCH] adtrust upgrade: fix wrong primary principal name
-
-Upgrade code had Kerberos principal names mixed up: instead of creating
-krbtgt/LOCAL-FLAT@REMOTE and marking LOCAL-FLAT$@REMOTE as an alias to
-it, it created LOCAL-FLAT$@REMOTE Kerberos principal and marked
-krbtgt/LOCAL-FLAT@REMOTE as an alias.
-
-This differs from what Active Directory expects and what is created by
-ipasam plugin when trust is established. When upgrading such deployment,
-an upgrade code then unexpectedly failed.
-
-Resolves: https://pagure.io/freeipa/issue/7992
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- daemons/ipa-sam/ipa_sam.c                        | 12 +++++++-----
- .../adtrust/oneway-trust-with-shared-secret.md   | 16 +++++++++-------
- ipaserver/install/plugins/adtrust.py             |  4 ++--
- 3 files changed, 18 insertions(+), 14 deletions(-)
-
-diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c
-index 3cf878c3f99774f7715f776c31d70e2950f9451c..2251f3ddcd9d5549d12b3e411245b00395c6b0d9 100644
---- a/daemons/ipa-sam/ipa_sam.c
-+++ b/daemons/ipa-sam/ipa_sam.c
-@@ -2011,11 +2011,13 @@ static bool handle_cross_realm_princs(struct ipasam_private *ipasam_state,
- 							 pwd_outgoing, trusted_dn,
- 							 KRB_PRINC_CREATE_DEFAULT);
- 
--				/* Second: <OUR FLATNAME$>@<REMOTE REALM> is only used
--				 * for SSSD to be able to talk to AD DCs but it has to
--				 * have canonical name set to <OUR FLATNAME>$ because
--				 * this is the salt used by AD DCs when using this
--				 * principal, otherwise authentication will fail.
-+				/* Second: krbtgt/<OUR FLATNAME>@<REMOTE REALM>
-+				 * is only used for SSSD to be able to talk to
-+				 * AD DCs but it has to have canonical name set
-+				 * to krbtgt/<OUR FLATNAME> and alias it to
-+				 * <OUR FLATNAME$> because it is the salt used
-+				 * by AD DCs when using this principal,
-+				 * otherwise authentication will fail.
- 				 *
- 				 * *disable* use of this principal on our side as it is
- 				 * only used to retrieve trusted domain credentials by
-diff --git a/doc/designs/adtrust/oneway-trust-with-shared-secret.md b/doc/designs/adtrust/oneway-trust-with-shared-secret.md
-index dc58a08941acea447f9234107ebcba775351089e..09a940e34bb43a6e46beb85392c94423d2bfccd3 100644
---- a/doc/designs/adtrust/oneway-trust-with-shared-secret.md
-+++ b/doc/designs/adtrust/oneway-trust-with-shared-secret.md
-@@ -131,16 +131,18 @@ and `LOCAL-FLAT` is the NetBIOS name of the FreeIPA primary domain (e.g.
-   REMOTE-FLAT$@LOCAL | Trusted domain object account for the Active Directory forest root domain
-   krbtgt/REMOTE-FLAT@LOCAL | Alias to REMOTE-FLAT$ TDO
-   krbtgt/LOCAL@REMOTE | Cross-realm principal representing IPA domain in Active Directory forest to allow crross-realm TGT issuance from IPA KDC side
--  LOCAL-FLAT$@REMOTE | Trusted domain object account for IPA domain in Active Directory forest
--  krbtgt/LOCAL-FLAT@REMOTE | Alias to LOCAL-FLAT$
-+  krbtgt/LOCAL-FLAT@REMOTE | Trusted domain object account for IPA domain in Active Directory forest
-+  LOCAL-FLAT$@REMOTE | Alias to krbtgt/LOCAL-FLAT@REMOTE
- 
- For inbound trust `ipasam` module creates following principals:
-   * `krbtgt/LOCAL@REMOTE`, enabled by default
--  * `LOCAL-FLAT$@REMOTE`, used by SSSD to talk to Active Directory domain
--    controllers, with canonical name set to `LOCAL-FLAT$` because Kerberos KDC
--    must use this salt when issuing tickets for this principal. The use of this
--    principal is disabled on IPA side (IPA KDC does not issue tickets in this name)
--    --- we only retrieve a keytab for the principal in SSSD.
-+  * `krbtgt/LOCAL-FLAT@REMOTE`, used by SSSD to talk to Active Directory domain
-+    controllers, with canonical name set to `krbtgt/LOCAL-FLAT@REMOTE` because
-+    Kerberos KDC must use this salt when issuing tickets for this principal. The
-+    use of this principal is disabled on IPA side (IPA KDC does not issue tickets
-+    in this name) --- we only retrieve a keytab for the principal in SSSD. SSSD
-+    retrieves a keytab for this principal using `LOCAL-FLAT$@REMOTE` Principal
-+    name.
- 
- For outbound trust `ipasam` module creates following principals:
-   * `krbtgt/REMOTE@LOCAL`, enabled by default.
-diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
-index 55df5cd01fd0f585d5955e700ccf20c7fc9a747f..f810522b236d8c04f4a417aac8fd3717563c358e 100644
---- a/ipaserver/install/plugins/adtrust.py
-+++ b/ipaserver/install/plugins/adtrust.py
-@@ -680,12 +680,12 @@ class update_tdo_to_new_layout(Updater):
-                     trust_principal, t_realm)
-                 continue
- 
--            # 4. Create <OUR FLATNAME$>@<REMOTE REALM>, disabled
-+            # 4. Create krbtgt/<OUR FLATNAME>@<REMOTE REALM>, disabled
-             nbt_principal = self.nbt_principal_template.format(
-                 nbt=our_nbt_name, realm=t_realm)
-             tgt_principal = self.tgt_principal_template.format(
-                 remote=our_nbt_name, local=t_realm)
--            self.set_krb_principal([nbt_principal, tgt_principal],
-+            self.set_krb_principal([tgt_principal, nbt_principal],
-                                    passwd_incoming,
-                                    t_dn,
-                                    flags=self.KRB_PRINC_CREATE_DEFAULT |
--- 
-2.20.1
-
diff --git a/SOURCES/0052-adtrust-upgrade-fix-wrong-primary-principal-name-par.patch b/SOURCES/0052-adtrust-upgrade-fix-wrong-primary-principal-name-par.patch
deleted file mode 100644
index 62e2acc..0000000
--- a/SOURCES/0052-adtrust-upgrade-fix-wrong-primary-principal-name-par.patch
+++ /dev/null
@@ -1,95 +0,0 @@
-From ca4e0582489a432a1f61fc75a27ef831e911f0fe Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Thu, 27 Jun 2019 11:56:08 +0300
-Subject: [PATCH] adtrust upgrade: fix wrong primary principal name, part 2
-
-Second part of the trust principals upgrade
-
-For existing LOCAL-FLAT$@REMOTE object, convert it to
-krbtgt/LOCAL-FLAT@REMOTE and add LOCAL-FLAT$@REMOTE as an alias. To do
-so we need to modify an entry content a bit so it is better to remove
-the old entry and create a new one instead of renaming.
-
-Resolves: https://pagure.io/freeipa/issue/7992
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
----
- ipaserver/install/plugins/adtrust.py | 36 +++++++++++++++++++++++-----
- 1 file changed, 30 insertions(+), 6 deletions(-)
-
-diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
-index f810522b236d8c04f4a417aac8fd3717563c358e..12596d5bfe71c16a2cb87acb755a88051676e3e5 100644
---- a/ipaserver/install/plugins/adtrust.py
-+++ b/ipaserver/install/plugins/adtrust.py
-@@ -513,16 +513,19 @@ class update_tdo_to_new_layout(Updater):
- 
-         if isinstance(principals, (list, tuple)):
-             trust_principal = principals[0]
--            aliases = principals[1:]
-+            alias = principals[1]
-         else:
-             trust_principal = principals
--            aliases = []
-+            alias = None
- 
-+        entry = None
-+        en = None
-         try:
-             entry = ldap.get_entry(
-                 DN(('krbprincipalname', trust_principal), trustdn))
-             dn = entry.dn
-             action = ldap.update_entry
-+            ticket_flags = int(entry.single_value.get('krbticketflags', 0))
-             logger.debug("Updating Kerberos principal entry for %s",
-                          trust_principal)
-         except errors.NotFound:
-@@ -531,6 +534,19 @@ class update_tdo_to_new_layout(Updater):
-             if flags & self.KRB_PRINC_MUST_EXIST:
-                 raise
- 
-+            ticket_flags = 0
-+            if alias:
-+                try:
-+                    en = ldap.get_entry(
-+                        DN(('krbprincipalname', alias), trustdn))
-+                    ldap.delete_entry(en.dn)
-+                    ticket_flags = int(en.single_value.get(
-+                        'krbticketflags', 0))
-+                except errors.NotFound:
-+                    logger.debug("Entry for alias TDO does not exist for "
-+                                 "trusted domain object %s, skip it",
-+                                 alias)
-+
-             dn = DN(('krbprincipalname', trust_principal), trustdn)
-             entry = ldap.make_entry(dn)
-             logger.debug("Adding Kerberos principal entry for %s",
-@@ -545,15 +561,23 @@ class update_tdo_to_new_layout(Updater):
-             'krbprincipalname': [trust_principal],
-         }
- 
--        entry_data['krbprincipalname'].extend(aliases)
--
-         if flags & self.KRB_PRINC_CREATE_DISABLED:
--            flg = int(entry.single_value.get('krbticketflags', 0))
--            entry_data['krbticketflags'] = flg | self.KRB_DISALLOW_ALL_TIX
-+            entry_data['krbticketflags'] = (ticket_flags |
-+                                            self.KRB_DISALLOW_ALL_TIX)
- 
-         if flags & self.KRB_PRINC_CREATE_AGENT_PERMISSION:
-             entry_data['objectclass'].extend(['ipaAllowedOperations'])
- 
-+        if alias:
-+            entry_data['krbprincipalname'].extend([alias])
-+            if en:
-+                entry_data['krbprincipalkey'] = en.single_value.get(
-+                    'krbprincipalkey')
-+                entry_data['krbextradata'] = en.single_value.get(
-+                    'krbextradata')
-+                entry_data['ipaAllowedToPerform;read_keys'] = en.get(
-+                    'ipaAllowedToPerform;read_keys', [])
-+
-         entry.update(entry_data)
-         try:
-             action(entry)
--- 
-2.20.1
-
diff --git a/SOURCES/0053-trust-fetch-domains-make-sure-we-use-right-KDC-when-.patch b/SOURCES/0053-trust-fetch-domains-make-sure-we-use-right-KDC-when-.patch
deleted file mode 100644
index 781d9b6..0000000
--- a/SOURCES/0053-trust-fetch-domains-make-sure-we-use-right-KDC-when-.patch
+++ /dev/null
@@ -1,441 +0,0 @@
-From a9ff7e93de94de1c7ecaedce582d598d6a4ad30e Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Thu, 27 Jun 2019 15:17:07 +0300
-Subject: [PATCH] trust-fetch-domains: make sure we use right KDC when --server
- is specified
-
-Since we are authenticating against AD DC before talking to it (by using
-trusted domain object's credentials), we need to override krb5.conf
-configuration in case --server option is specified.
-
-The context is a helper which is launched out of process with the help
-of oddjobd. The helper takes existing trusted domain object, uses its
-credentials to authenticate and then runs LSA RPC calls against that
-trusted domain's domain controller. Previous code directed Samba
-bindings to use the correct domain controller. However, if a DC visible
-to MIT Kerberos is not reachable, we would not be able to obtain TGT and
-the whole process will fail.
-
-trust_add.execute() was calling out to the D-Bus helper without passing
-the options (e.g. --server) so there was no chance to get that option
-visible by the oddjob helper.
-
-Also we need to make errors in the oddjob helper more visible to
-error_log. Thus, move error reporting for a normal communication up from
-the exception catching.
-
-Resolves: https://pagure.io/freeipa/issue/7895
-Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
----
- .../oddjob/com.redhat.idm.trust-fetch-domains | 233 +++++++++++++-----
- ipaserver/plugins/trust.py                    |  28 ++-
- 2 files changed, 194 insertions(+), 67 deletions(-)
-
-diff --git a/install/oddjob/com.redhat.idm.trust-fetch-domains b/install/oddjob/com.redhat.idm.trust-fetch-domains
-index 029de781b2a1f94b1fd281b79aa69a1e9422dede..b406201ec2baf8ee9398fc3634060b6d9a5392b0 100755
---- a/install/oddjob/com.redhat.idm.trust-fetch-domains
-+++ b/install/oddjob/com.redhat.idm.trust-fetch-domains
-@@ -8,9 +8,12 @@ from ipapython.dn import DN
- from ipapython.dnsutil import DNSName
- from ipaplatform.constants import constants
- from ipaplatform.paths import paths
-+import io
- import sys
- import os
- import pwd
-+import tempfile
-+import textwrap
- 
- import six
- import gssapi
-@@ -23,17 +26,38 @@ if six.PY3:
- 
- def parse_options():
-     usage = "%prog <trusted domain name>\n"
--    parser = config.IPAOptionParser(usage=usage,
--                                    formatter=config.IPAFormatter())
--
--    parser.add_option("-d", "--debug", action="store_true", dest="debug",
--                      help="Display debugging information")
--    parser.add_option("-s", "--server", action="store", dest="server",
--                      help="Domain controller for the Active Directory domain (optional)")
--    parser.add_option("-a", "--admin", action="store", dest="admin",
--                      help="Active Directory administrator (optional)")
--    parser.add_option("-p", "--password", action="store", dest="password",
--                      help="Display debugging information")
-+    parser = config.IPAOptionParser(
-+        usage=usage, formatter=config.IPAFormatter()
-+    )
-+
-+    parser.add_option(
-+        "-d",
-+        "--debug",
-+        action="store_true",
-+        dest="debug",
-+        help="Display debugging information",
-+    )
-+    parser.add_option(
-+        "-s",
-+        "--server",
-+        action="store",
-+        dest="server",
-+        help="Domain controller for the Active Directory domain (optional)",
-+    )
-+    parser.add_option(
-+        "-a",
-+        "--admin",
-+        action="store",
-+        dest="admin",
-+        help="Active Directory administrator (optional)",
-+    )
-+    parser.add_option(
-+        "-p",
-+        "--password",
-+        action="store",
-+        dest="password",
-+        help="Display debugging information",
-+    )
- 
-     options, args = parser.parse_args()
-     safe_options = parser.get_safe_opts(options)
-@@ -50,17 +74,26 @@ def parse_options():
-         raise ScriptError("You must specify a valid trusted domain name", 2)
-     return safe_options, options, trusted_domain
- 
-+
- def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal):
--    getkeytab_args = ["/usr/sbin/ipa-getkeytab",
--                      "-s", api.env.host,
--                      "-p", oneway_principal,
--                      "-k", oneway_keytab_name,
--                      "-r"]
-+    getkeytab_args = [
-+        "/usr/sbin/ipa-getkeytab",
-+        "-s",
-+        api.env.host,
-+        "-p",
-+        oneway_principal,
-+        "-k",
-+        oneway_keytab_name,
-+        "-r",
-+    ]
-     if os.path.isfile(oneway_keytab_name):
-         os.unlink(oneway_keytab_name)
- 
--    ipautil.run(getkeytab_args, env={'KRB5CCNAME': ccache_name, 'LANG': 'C'},
--                raiseonerr=False)
-+    ipautil.run(
-+        getkeytab_args,
-+        env={"KRB5CCNAME": ccache_name, "LANG": "C"},
-+        raiseonerr=False,
-+    )
-     # Make sure SSSD is able to read the keytab
-     try:
-         sssd = pwd.getpwnam(constants.SSSD_USER)
-@@ -72,8 +105,7 @@ def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal):
- 
- 
- def get_forest_root_domain(api_instance, trusted_domain, server=None):
--    """
--    retrieve trusted forest root domain for given domain name
-+    """Retrieve trusted forest root domain for given domain name
- 
-     :param api_instance: IPA API instance
-     :param trusted_domain: trusted domain name
-@@ -81,18 +113,51 @@ def get_forest_root_domain(api_instance, trusted_domain, server=None):
-     :returns: forest root domain DNS name
-     """
-     trustconfig_show = api_instance.Command.trustconfig_show
--    flatname = trustconfig_show()['result']['ipantflatname'][0]
-+    flatname = trustconfig_show()["result"]["ipantflatname"][0]
- 
-     remote_domain = dcerpc.retrieve_remote_domain(
--        api_instance.env.host, flatname, trusted_domain,
--        realm_server=server)
-+        api_instance.env.host, flatname, trusted_domain, realm_server=server
-+    )
-+
-+    return remote_domain.info["dns_forest"]
-+
-+
-+def generate_krb5_config(realm, server):
-+    """Generate override krb5 config file for trusted domain DC access
-+
-+    :param realm: realm of the trusted AD domain
-+    :param server: server to override KDC to
-+
-+    :returns: tuple (temporary config file name, KRB5_CONFIG string)
-+    """
-+    cfg = paths.KRB5_CONF
-+    tcfg = None
-+    if server:
-+        content = textwrap.dedent(u"""
-+            [realms]
-+               %s = {
-+                   kdc = %s
-+               }
-+            """) % (
-+            realm.upper(),
-+            server,
-+        )
-+
-+        (fd, tcfg) = tempfile.mkstemp(dir="/var/run/ipa",
-+                prefix="krb5conf", text=True)
-+        with io.open(fd, mode='w', encoding='utf-8') as o:
-+            o.write(content)
-+        cfg = ":".join([tcfg, cfg])
-+    return (tcfg, cfg)
- 
--    return remote_domain.info['dns_forest']
- 
- if not is_ipa_configured():
-     # LSB status code 6: program is not configured
--    raise ScriptError("IPA is not configured " +
--                      "(see man pages of ipa-server-install for help)", 6)
-+    raise ScriptError(
-+        "IPA is not configured "
-+        + "(see man pages of ipa-server-install for help)",
-+        6,
-+    )
- 
- if not os.getegid() == 0:
-     # LSB status code 4: user had insufficient privilege
-@@ -100,8 +165,9 @@ if not os.getegid() == 0:
- 
- safe_options, options, trusted_domain = parse_options()
- 
--api.bootstrap(in_server=True, log=None,
--              context='server', confdir=paths.ETC_IPA)
-+api.bootstrap(
-+    in_server=True, log=None, context="server", confdir=paths.ETC_IPA
-+)
- api.finalize()
- 
- # Only import trust plugin after api is initialized or internal imports
-@@ -121,12 +187,12 @@ from ipaserver.plugins import trust
- # and retrieve our own NetBIOS domain name and use cifs/ipa.master@IPA.REALM to
- # retrieve the keys to oneway_keytab_name.
- 
--keytab_name = '/etc/samba/samba.keytab'
-+keytab_name = "/etc/samba/samba.keytab"
- 
--principal = str('cifs/' + api.env.host)
-+principal = str("cifs/" + api.env.host)
- 
--oneway_ccache_name = '/var/run/ipa/krb5cc_oddjob_trusts_fetch'
--ccache_name = '/var/run/ipa/krb5cc_oddjob_trusts'
-+oneway_ccache_name = "/var/run/ipa/krb5cc_oddjob_trusts_fetch"
-+ccache_name = "/var/run/ipa/krb5cc_oddjob_trusts"
- 
- # Standard sequence:
- # - check if ccache exists
-@@ -140,33 +206,45 @@ try:
-     cred = kinit_keytab(principal, keytab_name, ccache_name)
-     if cred.lifetime > 0:
-         have_ccache = True
--except gssapi.exceptions.ExpiredCredentialsError:
-+except (gssapi.exceptions.ExpiredCredentialsError, gssapi.raw.misc.GSSError):
-     pass
- if not have_ccache:
-     # delete stale ccache and try again
--    if os.path.exists(oneway_ccache_name):
-+    if os.path.exists(ccache_name):
-         os.unlink(ccache_name)
-     cred = kinit_keytab(principal, keytab_name, ccache_name)
- 
--old_ccache = os.environ.get('KRB5CCNAME')
-+old_ccache = os.environ.get("KRB5CCNAME")
-+old_config = os.environ.get("KRB5_CONFIG")
- api.Backend.ldap2.connect(ccache_name)
- 
- # Retrieve own NetBIOS name and trusted forest's name.
- # We use script's input to retrieve the trusted forest's name to sanitize input
- # for file-level access as we might need to wipe out keytab in /var/lib/sss/keytabs
--own_trust_dn = DN(('cn', api.env.domain),('cn','ad'), ('cn', 'etc'), api.env.basedn)
--own_trust_entry = api.Backend.ldap2.get_entry(own_trust_dn, ['ipantflatname'])
--own_trust_flatname = own_trust_entry.single_value.get('ipantflatname').upper()
--trusted_domain_dn = DN(('cn', trusted_domain.lower()), api.env.container_adtrusts, api.env.basedn)
--trusted_domain_entry = api.Backend.ldap2.get_entry(trusted_domain_dn, ['cn'])
--trusted_domain = trusted_domain_entry.single_value.get('cn').lower()
-+own_trust_dn = DN(
-+    ("cn", api.env.domain), ("cn", "ad"), ("cn", "etc"), api.env.basedn
-+)
-+own_trust_entry = api.Backend.ldap2.get_entry(own_trust_dn, ["ipantflatname"])
-+own_trust_flatname = own_trust_entry.single_value.get("ipantflatname").upper()
-+trusted_domain_dn = DN(
-+    ("cn", trusted_domain.lower()), api.env.container_adtrusts, api.env.basedn
-+)
-+trusted_domain_entry = api.Backend.ldap2.get_entry(trusted_domain_dn, ["cn"])
-+trusted_domain = trusted_domain_entry.single_value.get("cn").lower()
- 
- # At this point if we didn't find trusted forest name, an exception will be raised
- # and script will quit. This is actually intended.
- 
-+# Generate MIT Kerberos configuration file that potentially overlays
-+# the KDC to connect to for a trusted domain to allow --server option
-+# to take precedence.
-+cfg_file, cfg = generate_krb5_config(trusted_domain, options.server)
-+
- if not (options.admin and options.password):
--    oneway_keytab_name = '/var/lib/sss/keytabs/' + trusted_domain + '.keytab'
--    oneway_principal = str('%s$@%s' % (own_trust_flatname, trusted_domain.upper()))
-+    oneway_keytab_name = "/var/lib/sss/keytabs/" + trusted_domain + ".keytab"
-+    oneway_principal = str(
-+        "%s$@%s" % (own_trust_flatname, trusted_domain.upper())
-+    )
- 
-     # If keytab does not exist, retrieve it
-     if not os.path.isfile(oneway_keytab_name):
-@@ -176,39 +254,78 @@ if not (options.admin and options.password):
-         have_ccache = False
-         try:
-             # The keytab may have stale key material (from older trust-add run)
--            cred = kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
-+            cred = kinit_keytab(
-+                oneway_principal,
-+                oneway_keytab_name,
-+                oneway_ccache_name,
-+                config=cfg,
-+            )
-             if cred.lifetime > 0:
-                 have_ccache = True
--        except gssapi.exceptions.ExpiredCredentialsError:
-+        except (gssapi.exceptions.ExpiredCredentialsError, gssapi.raw.misc.GSSError):
-             pass
-         if not have_ccache:
-             if os.path.exists(oneway_ccache_name):
-                 os.unlink(oneway_ccache_name)
--            kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
--    except gssapi.exceptions.GSSError:
-+            kinit_keytab(
-+                oneway_principal,
-+                oneway_keytab_name,
-+                oneway_ccache_name,
-+                config=cfg,
-+            )
-+    except (gssapi.exceptions.GSSError, gssapi.raw.misc.GSSError):
-         # If there was failure on using keytab, assume it is stale and retrieve again
-         retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal)
-         if os.path.exists(oneway_ccache_name):
-             os.unlink(oneway_ccache_name)
--        kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name)
-+        cred = kinit_keytab(
-+            oneway_principal,
-+            oneway_keytab_name,
-+            oneway_ccache_name,
-+            config=cfg,
-+        )
- else:
--    cred = kinit_password(options.admin, options.password,
--                          oneway_ccache_name,
--                          canonicalize=True, enterprise=True)
-+    cred = kinit_password(
-+        options.admin,
-+        options.password,
-+        oneway_ccache_name,
-+        canonicalize=True,
-+        enterprise=True,
-+        config=cfg,
-+    )
-+
-+if cred and cred.lifetime > 0:
-+    have_ccache = True
-+
-+if not have_ccache:
-+    sys.exit(1)
- 
- # We are done: we have ccache with TDO credentials and can fetch domains
- ipa_domain = api.env.domain
--os.environ['KRB5CCNAME'] = oneway_ccache_name
-+os.environ["KRB5CCNAME"] = oneway_ccache_name
-+os.environ["KRB5_CONFIG"] = cfg
- 
- # retrieve the forest root domain name and contact it to retrieve trust
- # topology info
--forest_root = get_forest_root_domain(api, trusted_domain, server=options.server)
--
--domains = dcerpc.fetch_domains(api, ipa_domain, forest_root, creds=True, server=options.server)
--trust_domain_object = api.Command.trust_show(trusted_domain, raw=True)['result']
--trust.add_new_domains_from_trust(api, None, trust_domain_object, domains)
-+forest_root = get_forest_root_domain(
-+    api, trusted_domain, server=options.server
-+)
-+domains = dcerpc.fetch_domains(
-+    api, ipa_domain, forest_root, creds=True, server=options.server
-+)
- 
- if old_ccache:
--   os.environ['KRB5CCNAME'] = old_ccache
-+    os.environ["KRB5CCNAME"] = old_ccache
-+
-+if old_config:
-+    os.environ["KRB5_CONFIG"] = old_config
-+
-+if cfg_file:
-+    os.remove(cfg_file)
-+
-+trust_domain_object = api.Command.trust_show(trusted_domain, raw=True)[
-+    "result"
-+]
-+trust.add_new_domains_from_trust(api, None, trust_domain_object, domains)
- 
- sys.exit(0)
-diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py
-index 5de363bda6fdee081d3e4c98e731cecfa9585d21..676b5f645a99c40a0c944096d7c6252a4c56f983 100644
---- a/ipaserver/plugins/trust.py
-+++ b/ipaserver/plugins/trust.py
-@@ -424,11 +424,11 @@ def fetch_trusted_domains_over_dbus(myapi, *keys, **options):
- 
-     forest_name = keys[0]
-     method_options = []
--    if 'realm_server' in options:
-+    if options.get('realm_server', None):
-         method_options.extend(['--server', options['realm_server']])
--    if 'realm_admin' in options:
-+    if options.get('realm_admin', None):
-         method_options.extend(['--admin', options['realm_admin']])
--    if 'realm_passwd' in options:
-+    if options.get('realm_passwd', None):
-         method_options.extend(['--password', options['realm_passwd']])
- 
-     # Calling oddjobd-activated service via DBus has some quirks:
-@@ -458,11 +458,15 @@ def fetch_trusted_domains_over_dbus(myapi, *keys, **options):
-     except dbus.DBusException as e:
-         logger.error('Failed to call %s.fetch_domains helper.'
-                      'DBus exception is %s.', DBUS_IFACE_TRUST, str(e))
--        if _ret != 0:
--            logger.error('Helper was called for forest %s, return code is %d',
--                         forest_name, _ret)
--            logger.error('Standard output from the helper:\n%s---\n', _stdout)
--            logger.error('Error output from the helper:\n%s--\n', _stderr)
-+        _ret = 2
-+        _stdout = '<not available>'
-+        _stderr = '<not available>'
-+
-+    if _ret != 0:
-+        logger.error('Helper fetch_domains was called for forest %s, '
-+                     'return code is %d', forest_name, _ret)
-+        logger.error('Standard output from the helper:\n%s---\n', _stdout)
-+        logger.error('Error output from the helper:\n%s--\n', _stderr)
-         raise errors.ServerCommandError(
-             server=myapi.env.host,
-             error=_('Fetching domains from trusted forest failed. '
-@@ -801,7 +805,13 @@ ipa idrange-del before retrying the command with the desired range type.
-                 # object credentials to authenticate to AD with Kerberos,
-                 # run DCE RPC calls to do discovery and will call
-                 # add_new_domains_from_trust() on its own.
--                fetch_trusted_domains_over_dbus(self.api, result['value'])
-+                # We only pass through the realm_server option because we need
-+                # to reach the specified Active Directory domain controller
-+                # No need to pass through admin credentials as we have TDO
-+                # credentials at this point already
-+                fetch_trusted_domains_over_dbus(self.api, result['value'],
-+                                                realm_server=options.get(
-+                                                    'realm_server', None))
- 
-         # Format the output into human-readable values unless `--raw` is given
-         self._format_trust_attrs(result, **options)
--- 
-2.20.1
-
diff --git a/SOURCES/0054-add-default-access-control-when-migrating-trust-obje.patch b/SOURCES/0054-add-default-access-control-when-migrating-trust-obje.patch
deleted file mode 100644
index d4428ee..0000000
--- a/SOURCES/0054-add-default-access-control-when-migrating-trust-obje.patch
+++ /dev/null
@@ -1,55 +0,0 @@
-From b1cefe64e4e91966e59d81c778abc8057af4cd6f Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Tue, 10 Sep 2019 13:39:39 +0300
-Subject: [PATCH] add default access control when migrating trust objects
-
-It looks like for some cases we do not have proper set up keytab
-retrieval configuration in the old trusted domain object. This mostly
-affects two-way trust cases. In such cases, create default configuration
-as ipasam would have created when trust was established.
-
-Resolves: https://pagure.io/freeipa/issue/8067
-
-Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
-Reviewed-By: Rob Crittenden <rcritten@redhat.com>
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
----
- ipaserver/install/plugins/adtrust.py | 14 ++++++++++++--
- 1 file changed, 12 insertions(+), 2 deletions(-)
-
-diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
-index 12596d5bfe71c16a2cb87acb755a88051676e3e5..0dd2c840899abe3b51b9308d38a9d0f4d1fb2f9b 100644
---- a/ipaserver/install/plugins/adtrust.py
-+++ b/ipaserver/install/plugins/adtrust.py
-@@ -28,6 +28,9 @@ logger = logging.getLogger(__name__)
- register = Registry()
- 
- DEFAULT_ID_RANGE_SIZE = 200000
-+trust_read_keys_template = \
-+    ["cn=adtrust agents,cn=sysaccounts,cn=etc,{basedn}",
-+     "cn=trust admins,cn=groups,cn=accounts,{basedn}"]
- 
- 
- @register()
-@@ -575,8 +578,15 @@ class update_tdo_to_new_layout(Updater):
-                     'krbprincipalkey')
-                 entry_data['krbextradata'] = en.single_value.get(
-                     'krbextradata')
--                entry_data['ipaAllowedToPerform;read_keys'] = en.get(
--                    'ipaAllowedToPerform;read_keys', [])
-+                read_keys = en.get('ipaAllowedToPerform;read_keys', [])
-+                if not read_keys:
-+                    # Old style, no ipaAllowedToPerform;read_keys in the entry,
-+                    # use defaults that ipasam should have set when creating a
-+                    # trust
-+                    read_keys = list(map(
-+                        lambda x: x.format(basedn=self.api.env.basedn),
-+                        trust_read_keys_template))
-+                entry_data['ipaAllowedToPerform;read_keys'] = read_keys
- 
-         entry.update(entry_data)
-         try:
--- 
-2.20.1
-
diff --git a/SOURCES/0055-adtrust-add-default-read_keys-permission-for-TDO-obj.patch b/SOURCES/0055-adtrust-add-default-read_keys-permission-for-TDO-obj.patch
deleted file mode 100644
index baf9ee0..0000000
--- a/SOURCES/0055-adtrust-add-default-read_keys-permission-for-TDO-obj.patch
+++ /dev/null
@@ -1,105 +0,0 @@
-From d45545807106958d924d0b92b3e275ac75c3a6fd Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Thu, 12 Sep 2019 11:21:51 +0300
-Subject: [PATCH] adtrust: add default read_keys permission for TDO objects
-
-If trusted domain object (TDO) is lacking ipaAllowedToPerform;read_keys
-attribute values, it cannot be used by SSSD to retrieve TDO keys and the
-whole communication with Active Directory domain controllers will not be
-possible.
-
-This seems to affect trusts which were created before
-ipaAllowedToPerform;read_keys permission granting was introduced
-(FreeIPA 4.2). Add back the default setting for the permissions which
-grants access to trust agents and trust admins.
-
-Resolves: https://pagure.io/freeipa/issue/8067
-
-Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
-Reviewed-By: Rob Crittenden <rcritten@redhat.com>
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
----
- .../updates/90-post_upgrade_plugins.update    |  1 +
- ipaserver/install/plugins/adtrust.py          | 56 +++++++++++++++++++
- 2 files changed, 57 insertions(+)
-
-diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update
-index a9f5f6a924d330b924d9adb8b7eee728258f27c6..77b910fc26858611e44a5ba3f4f4c18f4895c95e 100644
---- a/install/updates/90-post_upgrade_plugins.update
-+++ b/install/updates/90-post_upgrade_plugins.update
-@@ -12,6 +12,7 @@ plugin: update_default_range
- plugin: update_default_trust_view
- plugin: update_tdo_gidnumber
- plugin: update_tdo_to_new_layout
-+plugin: update_tdo_default_read_keys_permissions
- plugin: update_ca_renewal_master
- plugin: update_idrange_type
- plugin: update_pacs
-diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
-index 0dd2c840899abe3b51b9308d38a9d0f4d1fb2f9b..fca83aa6df2cc3fafca91f2ed55339dba016a1fa 100644
---- a/ipaserver/install/plugins/adtrust.py
-+++ b/ipaserver/install/plugins/adtrust.py
-@@ -727,3 +727,59 @@ class update_tdo_to_new_layout(Updater):
-                                    self.KRB_PRINC_CREATE_DISABLED)
- 
-         return False, []
-+
-+
-+@register()
-+class update_tdo_default_read_keys_permissions(Updater):
-+    trust_filter = \
-+        "(&(objectClass=krbPrincipal)(krbPrincipalName=krbtgt/{nbt}@*))"
-+
-+    def execute(self, **options):
-+        ldap = self.api.Backend.ldap2
-+
-+        # First, see if trusts are enabled on the server
-+        if not self.api.Command.adtrust_is_enabled()['result']:
-+            logger.debug('AD Trusts are not enabled on this server')
-+            return False, []
-+
-+        result = self.api.Command.trustconfig_show()['result']
-+        our_nbt_name = result.get('ipantflatname', [None])[0]
-+        if not our_nbt_name:
-+            return False, []
-+
-+        trusts_dn = self.api.env.container_adtrusts + self.api.env.basedn
-+        trust_filter = self.trust_filter.format(nbt=our_nbt_name)
-+
-+        # We might be in a situation when no trusts exist yet
-+        # In such case there is nothing to upgrade but we have to catch
-+        # an exception or it will abort the whole upgrade process
-+        try:
-+            tdos = ldap.get_entries(
-+                base_dn=trusts_dn,
-+                scope=ldap.SCOPE_SUBTREE,
-+                filter=trust_filter,
-+                attrs_list=['*'])
-+        except errors.EmptyResult:
-+            tdos = []
-+
-+        for tdo in tdos:
-+            updates = dict()
-+            oc = tdo.get('objectClass', [])
-+            if 'ipaAllowedOperations' not in oc:
-+                updates['objectClass'] = oc + ['ipaAllowedOperations']
-+
-+            read_keys = tdo.get('ipaAllowedToPerform;read_keys', [])
-+            if not read_keys:
-+                read_keys_values = list(map(
-+                    lambda x: x.format(basedn=self.api.env.basedn),
-+                    trust_read_keys_template))
-+                updates['ipaAllowedToPerform;read_keys'] = read_keys_values
-+
-+            tdo.update(updates)
-+            try:
-+                ldap.update_entry(tdo)
-+            except errors.EmptyModlist:
-+                logger.debug("No update was required for TDO %s",
-+                             tdo.single_value.get('krbCanonicalName'))
-+
-+        return False, []
--- 
-2.20.1
-
diff --git a/SOURCES/0056-Disable-deprecated-lambda-check-in-adtrust-upgrade-c.patch b/SOURCES/0056-Disable-deprecated-lambda-check-in-adtrust-upgrade-c.patch
deleted file mode 100644
index 5fc808c..0000000
--- a/SOURCES/0056-Disable-deprecated-lambda-check-in-adtrust-upgrade-c.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From a2056fe04b9667c4c86925051b9b71c741eb9cd1 Mon Sep 17 00:00:00 2001
-From: Rob Crittenden <rcritten@redhat.com>
-Date: Mon, 16 Sep 2019 09:38:19 -0400
-Subject: [PATCH] Disable deprecated-lambda check in adtrust upgrade code
-
-It is interesting that we don't have this problem with newer
-Python and pylint versions. Ignoring to try to keep the code
-more in line with newer releases.
-
-Reviewed-By: Rob Crittenden <rcritten@redhat.com>
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
----
- ipaserver/install/plugins/adtrust.py | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
-index fca83aa6df2cc3fafca91f2ed55339dba016a1fa..950b7b9c82f1b0e115675ff8093d1bd02e913ae2 100644
---- a/ipaserver/install/plugins/adtrust.py
-+++ b/ipaserver/install/plugins/adtrust.py
-@@ -583,6 +583,7 @@ class update_tdo_to_new_layout(Updater):
-                     # Old style, no ipaAllowedToPerform;read_keys in the entry,
-                     # use defaults that ipasam should have set when creating a
-                     # trust
-+                    # pylint: disable=deprecated-lambda
-                     read_keys = list(map(
-                         lambda x: x.format(basedn=self.api.env.basedn),
-                         trust_read_keys_template))
-@@ -770,6 +771,7 @@ class update_tdo_default_read_keys_permissions(Updater):
- 
-             read_keys = tdo.get('ipaAllowedToPerform;read_keys', [])
-             if not read_keys:
-+                # pylint: disable=deprecated-lambda
-                 read_keys_values = list(map(
-                     lambda x: x.format(basedn=self.api.env.basedn),
-                     trust_read_keys_template))
--- 
-2.20.1
-
diff --git a/SOURCES/0057-Handle-missing-LWCA-certificate-or-chain.patch b/SOURCES/0057-Handle-missing-LWCA-certificate-or-chain.patch
deleted file mode 100644
index dccf25c..0000000
--- a/SOURCES/0057-Handle-missing-LWCA-certificate-or-chain.patch
+++ /dev/null
@@ -1,196 +0,0 @@
-From dc90e83e77f63384f072ca31d79705e26dc5d656 Mon Sep 17 00:00:00 2001
-From: Fraser Tweedale <ftweedal@redhat.com>
-Date: Thu, 30 May 2019 20:57:10 +1000
-Subject: [PATCH] Handle missing LWCA certificate or chain
-
-If lightweight CA key replication has not completed, requests for
-the certificate or chain will return 404**.  This can occur in
-normal operation, and should be a temporary condition.  Detect this
-case and handle it by simply omitting the 'certificate' and/or
-'certificate_out' fields in the response, and add a warning message
-to the response.
-
-Also update the client-side plugin that handles the
---certificate-out option.  Because the CLI will automatically print
-the warning message, if the expected field is missing from the
-response, just ignore it and continue processing.
-
-** after the Dogtag NullPointerException gets fixed!
-
-Part of: https://pagure.io/freeipa/issue/7964
-
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Fraser Tweedale <ftweedal@redhat.com>
-Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-By: Rob Crittenden <rcritten@redhat.com>
----
- ipaclient/plugins/ca.py | 19 +++++++++++---
- ipalib/messages.py      |  9 +++++++
- ipaserver/plugins/ca.py | 57 +++++++++++++++++++++++++++++++----------
- 3 files changed, 68 insertions(+), 17 deletions(-)
-
-diff --git a/ipaclient/plugins/ca.py b/ipaclient/plugins/ca.py
-index f0e7d5ced0d3d9318e34aba84cbc37cf42b9410d..ab47ae85df398e1dc40191691a26639eb3772493 100644
---- a/ipaclient/plugins/ca.py
-+++ b/ipaclient/plugins/ca.py
-@@ -33,13 +33,24 @@ class WithCertOutArgs(MethodOverride):
-                                              error=str(e))
- 
-         result = super(WithCertOutArgs, self).forward(*keys, **options)
-+
-         if filename:
-+            # if result certificate / certificate_chain not present in result,
-+            # it means Dogtag did not provide it (probably due to LWCA key
-+            # replication lag or failure.  The server transmits a warning
-+            # message in this case, which the client automatically prints.
-+            # So in this section we just ignore it and move on.
-+            certs = None
-             if options.get('chain', False):
--                certs = result['result']['certificate_chain']
-+                if 'certificate_chain' in result['result']:
-+                    certs = result['result']['certificate_chain']
-             else:
--                certs = [base64.b64decode(result['result']['certificate'])]
--            certs = (x509.load_der_x509_certificate(cert) for cert in certs)
--            x509.write_certificate_list(certs, filename)
-+                if 'certificate' in result['result']:
-+                    certs = [base64.b64decode(result['result']['certificate'])]
-+            if certs:
-+                x509.write_certificate_list(
-+                    (x509.load_der_x509_certificate(cert) for cert in certs),
-+                    filename)
- 
-         return result
- 
-diff --git a/ipalib/messages.py b/ipalib/messages.py
-index 9e2c990d6db8ee41daf3fba6085eed8355dccbe7..646662795648b5a44a5ce25b7610982d5500cfac 100644
---- a/ipalib/messages.py
-+++ b/ipalib/messages.py
-@@ -487,6 +487,15 @@ class FailedToAddHostDNSRecords(PublicMessage):
-                "%(reason)s")
- 
- 
-+class LightweightCACertificateNotAvailable(PublicMessage):
-+    """
-+    **13031** Certificate is not available
-+    """
-+    errno = 13031
-+    type = "error"
-+    format = _("The certificate for %(ca)s is not available on this server.")
-+
-+
- def iter_messages(variables, base):
-     """Return a tuple with all subclasses
-     """
-diff --git a/ipaserver/plugins/ca.py b/ipaserver/plugins/ca.py
-index 88e7ec2a9f50a3c4f90947c8e3d38e327627a878..c8f1630c65d55ee9e820ea50ef34e08f92c66f4a 100644
---- a/ipaserver/plugins/ca.py
-+++ b/ipaserver/plugins/ca.py
-@@ -6,7 +6,7 @@ import base64
- 
- import six
- 
--from ipalib import api, errors, output, Bytes, DNParam, Flag, Str
-+from ipalib import api, errors, messages, output, Bytes, DNParam, Flag, Str
- from ipalib.constants import IPA_CA_CN
- from ipalib.plugable import Registry
- from ipapython.dn import ATTR_NAME_BY_OID
-@@ -163,28 +163,53 @@ class ca(LDAPObject):
- 
- 
- def set_certificate_attrs(entry, options, want_cert=True):
-+    """
-+    Set certificate attributes into the entry.  Depending on
-+    options, this may contact Dogtag to retrieve certificate or
-+    chain.  If the retrieval fails with 404 (which can occur under
-+    normal operation due to lightweight CA key replication delay),
-+    return a message object that should be set in the response.
-+
-+    """
-     try:
-         ca_id = entry['ipacaid'][0]
-     except KeyError:
--        return
-+        return None
-     full = options.get('all', False)
-     want_chain = options.get('chain', False)
- 
-     want_data = want_cert or want_chain or full
-     if not want_data:
--        return
-+        return None
-+
-+    msg = None
- 
-     with api.Backend.ra_lightweight_ca as ca_api:
-         if want_cert or full:
--            der = ca_api.read_ca_cert(ca_id)
--            entry['certificate'] = base64.b64encode(der).decode('ascii')
-+            try:
-+                der = ca_api.read_ca_cert(ca_id)
-+                entry['certificate'] = base64.b64encode(der).decode('ascii')
-+            except errors.HTTPRequestError as e:
-+                if e.status == 404:  # pylint: disable=no-member
-+                    msg = messages.LightweightCACertificateNotAvailable(
-+                        ca=entry['cn'][0])
-+                else:
-+                    raise e
- 
-         if want_chain or full:
--            pkcs7_der = ca_api.read_ca_chain(ca_id)
--            certs = x509.pkcs7_to_certs(pkcs7_der, x509.DER)
--            ders = [cert.public_bytes(x509.Encoding.DER) for cert in certs]
--            entry['certificate_chain'] = ders
--
-+            try:
-+                pkcs7_der = ca_api.read_ca_chain(ca_id)
-+                certs = x509.pkcs7_to_certs(pkcs7_der, x509.DER)
-+                ders = [cert.public_bytes(x509.Encoding.DER) for cert in certs]
-+                entry['certificate_chain'] = ders
-+            except errors.HTTPRequestError as e:
-+                if e.status == 404:  # pylint: disable=no-member
-+                    msg = messages.LightweightCACertificateNotAvailable(
-+                        ca=entry['cn'][0])
-+                else:
-+                    raise e
-+
-+    return msg
- 
- @register()
- class ca_find(LDAPSearch):
-@@ -198,7 +223,9 @@ class ca_find(LDAPSearch):
-         result = super(ca_find, self).execute(*keys, **options)
-         if not options.get('pkey_only', False):
-             for entry in result['result']:
--                set_certificate_attrs(entry, options, want_cert=False)
-+                msg = set_certificate_attrs(entry, options, want_cert=False)
-+                if msg:
-+                    self.add_message(msg)
-         return result
- 
- 
-@@ -220,7 +247,9 @@ class ca_show(LDAPRetrieve):
-     def execute(self, *keys, **options):
-         ca_enabled_check(self.api)
-         result = super(ca_show, self).execute(*keys, **options)
--        set_certificate_attrs(result['result'], options)
-+        msg = set_certificate_attrs(result['result'], options)
-+        if msg:
-+            self.add_message(msg)
-         return result
- 
- 
-@@ -284,7 +313,9 @@ class ca_add(LDAPCreate):
-         return dn
- 
-     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
--        set_certificate_attrs(entry_attrs, options)
-+        msg = set_certificate_attrs(entry_attrs, options)
-+        if msg:
-+            self.add_message(msg)
-         return dn
- 
- 
--- 
-2.20.1
-
diff --git a/SOURCES/0058-Fix-CustodiaClient-ccache-handling.patch b/SOURCES/0058-Fix-CustodiaClient-ccache-handling.patch
deleted file mode 100644
index 1d60244..0000000
--- a/SOURCES/0058-Fix-CustodiaClient-ccache-handling.patch
+++ /dev/null
@@ -1,275 +0,0 @@
-From 240617674f83305b2a27899aa83f6af0caa69c9c Mon Sep 17 00:00:00 2001
-From: Christian Heimes <cheimes@redhat.com>
-Date: Wed, 12 Jun 2019 22:02:52 +0200
-Subject: [PATCH] Fix CustodiaClient ccache handling
-
-A CustodiaClient object has to the process environment a bit, e.g. set
-up GSSAPI credentials. To reuse the credentials in libldap connections,
-it is also necessary to set up a custom ccache store and to set the
-environment variable KRBCCNAME temporarily.
-
-Fixes: https://pagure.io/freeipa/issue/7964
-Co-Authored-By: Fraser Tweedale <ftweedal@redhat.com>
-Signed-off-by: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
-Reviewed-By: Fraser Tweedale <ftweedal@redhat.com>
-Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-By: Rob Crittenden <rcritten@redhat.com>
----
- install/tools/ipa-pki-retrieve-key |  33 ++++---
- ipaserver/secrets/client.py        | 143 ++++++++++++++++-------------
- 2 files changed, 100 insertions(+), 76 deletions(-)
-
-diff --git a/install/tools/ipa-pki-retrieve-key b/install/tools/ipa-pki-retrieve-key
-index 5056682c3cdaa734be2dadcffd7de0b2d80afaf9..192022b9b40f076e88fd95d5cc8cf8305901dcf5 100755
---- a/install/tools/ipa-pki-retrieve-key
-+++ b/install/tools/ipa-pki-retrieve-key
-@@ -2,9 +2,8 @@
- 
- from __future__ import print_function
- 
-+import argparse
- import os
--import sys
--import traceback
- 
- from ipalib import constants
- from ipalib.config import Env
-@@ -16,27 +15,37 @@ def main():
-     env = Env()
-     env._finalize()
- 
--    keyname = "ca_wrapped/" + sys.argv[1]
--    servername = sys.argv[2]
-+    parser = argparse.ArgumentParser("ipa-pki-retrieve-key")
-+    parser.add_argument("keyname", type=str)
-+    parser.add_argument("servername", type=str)
-+
-+    args = parser.parse_args()
-+    keyname = "ca_wrapped/{}".format(args.keyname)
- 
-     service = constants.PKI_GSSAPI_SERVICE_NAME
-     client_keyfile = os.path.join(paths.PKI_TOMCAT, service + '.keys')
-     client_keytab = os.path.join(paths.PKI_TOMCAT, service + '.keytab')
- 
-+    for filename in [client_keyfile, client_keytab]:
-+        if not os.access(filename, os.R_OK):
-+            parser.error(
-+                "File '{}' missing or not readable.\n".format(filename)
-+            )
-+
-     # pylint: disable=no-member
-     client = CustodiaClient(
--        client_service='%s@%s' % (service, env.host), server=servername,
--        realm=env.realm, ldap_uri="ldaps://" + env.host,
--        keyfile=client_keyfile, keytab=client_keytab,
--        )
-+        client_service="{}@{}".format(service, env.host),
-+        server=args.servername,
-+        realm=env.realm,
-+        ldap_uri="ldaps://" + env.host,
-+        keyfile=client_keyfile,
-+        keytab=client_keytab,
-+    )
- 
-     # Print the response JSON to stdout; it is already in the format
-     # that Dogtag's ExternalProcessKeyRetriever expects
-     print(client.fetch_key(keyname, store=False))
- 
- 
--try:
-+if __name__ == '__main__':
-     main()
--except BaseException:
--    traceback.print_exc()
--    sys.exit(1)
-diff --git a/ipaserver/secrets/client.py b/ipaserver/secrets/client.py
-index 16e7856185aa9786007d3b7f8be0652f70fb4518..40df6c4e69cd673dd8e3c36fbf33f2cda8544a67 100644
---- a/ipaserver/secrets/client.py
-+++ b/ipaserver/secrets/client.py
-@@ -1,93 +1,106 @@
- # Copyright (C) 2015  IPA Project Contributors, see COPYING for license
- 
- from __future__ import print_function, absolute_import
-+
-+import contextlib
-+import os
-+from base64 import b64encode
-+
-+
- # pylint: disable=relative-import
- from custodia.message.kem import KEMClient, KEY_USAGE_SIG, KEY_USAGE_ENC
- # pylint: enable=relative-import
- from jwcrypto.common import json_decode
- from jwcrypto.jwk import JWK
-+from ipalib.krb_utils import krb5_format_service_principal_name
- from ipaserver.secrets.kem import IPAKEMKeys
--from ipaserver.secrets.store import iSecStore
-+from ipaserver.secrets.store import IPASecStore
- from ipaplatform.paths import paths
--from base64 import b64encode
--import ldapurl
- import gssapi
--import os
--import urllib3
- import requests
- 
- 
--class CustodiaClient(object):
--
--    def _client_keys(self):
--        return self.ikk.server_keys
--
--    def _server_keys(self, server, realm):
--        principal = 'host/%s@%s' % (server, realm)
--        sk = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_SIG)))
--        ek = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_ENC)))
--        return (sk, ek)
--
--    def _ldap_uri(self, realm):
--        dashrealm = '-'.join(realm.split('.'))
--        socketpath = paths.SLAPD_INSTANCE_SOCKET_TEMPLATE % (dashrealm,)
--        return 'ldapi://' + ldapurl.ldapUrlEscape(socketpath)
--
--    def _keystore(self, realm, ldap_uri, auth_type):
--        config = dict()
--        if ldap_uri is None:
--            config['ldap_uri'] = self._ldap_uri(realm)
--        else:
--            config['ldap_uri'] = ldap_uri
--        if auth_type is not None:
--            config['auth_type'] = auth_type
-+@contextlib.contextmanager
-+def ccache_env(ccache):
-+    """Temporarily set KRB5CCNAME environment variable
-+    """
-+    orig_ccache = os.environ.get('KRB5CCNAME')
-+    os.environ['KRB5CCNAME'] = ccache
-+    try:
-+        yield
-+    finally:
-+        os.environ.pop('KRB5CCNAME', None)
-+        if orig_ccache is not None:
-+            os.environ['KRB5CCNAME'] = orig_ccache
- 
--        return iSecStore(config)
- 
--    def __init__(
--            self, client_service, keyfile, keytab, server, realm,
--            ldap_uri=None, auth_type=None):
-+class CustodiaClient(object):
-+    def __init__(self, client_service, keyfile, keytab, server, realm,
-+                 ldap_uri=None, auth_type=None):
-+        if client_service.endswith(realm) or "@" not in client_service:
-+            raise ValueError(
-+                "Client service name must be a GSS name (service@host), "
-+                "not '{}'.".format(client_service)
-+            )
-         self.client_service = client_service
-         self.keytab = keytab
--
--        # Init creds immediately to make sure they are valid.  Creds
--        # can also be re-inited by _auth_header to avoid expiry.
--        #
--        self.creds = self.init_creds()
--
--        self.service_name = gssapi.Name('HTTP@%s' % (server,),
--                                        gssapi.NameType.hostbased_service)
-         self.server = server
-+        self.realm = realm
-+        self.ldap_uri = ldap_uri
-+        self.auth_type = auth_type
-+        self.service_name = gssapi.Name(
-+            'HTTP@{}'.format(server), gssapi.NameType.hostbased_service
-+        )
-+        self.keystore = IPASecStore()
-+        # use in-process MEMORY ccache. Handler process don't need a TGT.
-+        token = b64encode(os.urandom(8)).decode('ascii')
-+        self.ccache = 'MEMORY:Custodia_{}'.format(token)
-+
-+        with ccache_env(self.ccache):
-+            # Init creds immediately to make sure they are valid.  Creds
-+            # can also be re-inited by _auth_header to avoid expiry.
-+            self.creds = self._init_creds()
-+
-+            self.ikk = IPAKEMKeys(
-+                {'server_keys': keyfile, 'ldap_uri': ldap_uri}
-+            )
-+            self.kemcli = KEMClient(
-+                self._server_keys(), self._client_keys()
-+            )
- 
--        self.ikk = IPAKEMKeys({'server_keys': keyfile, 'ldap_uri': ldap_uri})
--
--        self.kemcli = KEMClient(self._server_keys(server, realm),
--                                self._client_keys())
--
--        self.keystore = self._keystore(realm, ldap_uri, auth_type)
--
--        # FIXME: Remove warnings about missing subjAltName for the
--        #        requests module
--        urllib3.disable_warnings()
-+    def _client_keys(self):
-+        return self.ikk.server_keys
- 
--    def init_creds(self):
--        name = gssapi.Name(self.client_service,
--                           gssapi.NameType.hostbased_service)
--        store = {'client_keytab': self.keytab,
--                 'ccache': 'MEMORY:Custodia_%s' % b64encode(
--                     os.urandom(8)).decode('ascii')}
-+    def _server_keys(self):
-+        principal = krb5_format_service_principal_name(
-+            'host', self.server, self.realm
-+        )
-+        sk = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_SIG)))
-+        ek = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_ENC)))
-+        return sk, ek
-+
-+    def _init_creds(self):
-+        name = gssapi.Name(
-+            self.client_service, gssapi.NameType.hostbased_service
-+        )
-+        store = {
-+            'client_keytab': self.keytab,
-+            'ccache': self.ccache
-+        }
-         return gssapi.Credentials(name=name, store=store, usage='initiate')
- 
-     def _auth_header(self):
--        if not self.creds or self.creds.lifetime < 300:
--            self.creds = self.init_creds()
--        ctx = gssapi.SecurityContext(name=self.service_name, creds=self.creds)
-+        if self.creds.lifetime < 300:
-+            self.creds = self._init_creds()
-+        ctx = gssapi.SecurityContext(
-+            name=self.service_name,
-+            creds=self.creds
-+        )
-         authtok = ctx.step()
-         return {'Authorization': 'Negotiate %s' % b64encode(
-             authtok).decode('ascii')}
- 
-     def fetch_key(self, keyname, store=True):
--
-         # Prepare URL
-         url = 'https://%s/ipa/keys/%s' % (self.server, keyname)
- 
-@@ -99,9 +112,11 @@ class CustodiaClient(object):
-         headers = self._auth_header()
- 
-         # Perform request
--        r = requests.get(url, headers=headers,
--                         verify=paths.IPA_CA_CRT,
--                         params={'type': 'kem', 'value': request})
-+        r = requests.get(
-+            url, headers=headers,
-+            verify=paths.IPA_CA_CRT,
-+            params={'type': 'kem', 'value': request}
-+        )
-         r.raise_for_status()
-         reply = r.json()
- 
--- 
-2.20.1
-
diff --git a/SOURCES/0059-CustodiaClient-use-ldapi-when-ldap_uri-not-specified.patch b/SOURCES/0059-CustodiaClient-use-ldapi-when-ldap_uri-not-specified.patch
deleted file mode 100644
index cceae12..0000000
--- a/SOURCES/0059-CustodiaClient-use-ldapi-when-ldap_uri-not-specified.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From 8b315055de462005b6b3a5893f7131eb8ddd2640 Mon Sep 17 00:00:00 2001
-From: Fraser Tweedale <ftweedal@redhat.com>
-Date: Wed, 19 Jun 2019 19:11:39 +1000
-Subject: [PATCH] CustodiaClient: use ldapi when ldap_uri not specified
-
-Reinstate ldap_uri selection behaviour that was lost during the
-refactor in the previous commit.  This is required because, on the
-ipa-4-7 branch at least, the IPASecStore needs to use LDAPI to set
-the Directory Manager passphrase digest.  Use LDAPI when the
-ldap_uri has not been explicity specified.
-
-Part of: https://pagure.io/freeipa/issue/7964
-
-Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-By: Rob Crittenden <rcritten@redhat.com>
----
- ipaserver/secrets/client.py | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/ipaserver/secrets/client.py b/ipaserver/secrets/client.py
-index 40df6c4e69cd673dd8e3c36fbf33f2cda8544a67..4c03ef8e4140dd507156d88941600a234b71184e 100644
---- a/ipaserver/secrets/client.py
-+++ b/ipaserver/secrets/client.py
-@@ -13,6 +13,7 @@ from custodia.message.kem import KEMClient, KEY_USAGE_SIG, KEY_USAGE_ENC
- from jwcrypto.common import json_decode
- from jwcrypto.jwk import JWK
- from ipalib.krb_utils import krb5_format_service_principal_name
-+from ipaserver.install.installutils import realm_to_ldapi_uri
- from ipaserver.secrets.kem import IPAKEMKeys
- from ipaserver.secrets.store import IPASecStore
- from ipaplatform.paths import paths
-@@ -46,7 +47,7 @@ class CustodiaClient(object):
-         self.keytab = keytab
-         self.server = server
-         self.realm = realm
--        self.ldap_uri = ldap_uri
-+        self.ldap_uri = ldap_uri or realm_to_ldapi_uri(realm)
-         self.auth_type = auth_type
-         self.service_name = gssapi.Name(
-             'HTTP@{}'.format(server), gssapi.NameType.hostbased_service
--- 
-2.20.1
-
diff --git a/SOURCES/0060-CustodiaClient-fix-IPASecStore-config-on-ipa-4-7.patch b/SOURCES/0060-CustodiaClient-fix-IPASecStore-config-on-ipa-4-7.patch
deleted file mode 100644
index 4096617..0000000
--- a/SOURCES/0060-CustodiaClient-fix-IPASecStore-config-on-ipa-4-7.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From a42c4c1be12f64228f196b42f30fb57019e3943e Mon Sep 17 00:00:00 2001
-From: Fraser Tweedale <ftweedal@redhat.com>
-Date: Tue, 30 Jul 2019 16:21:35 +1000
-Subject: [PATCH] CustodiaClient: fix IPASecStore config on ipa-4-7
-
-The backport of a Custodia client fix for f30 and related refactors
-and improvements, to the ipa-4-7 branch, had no conflicts.  But
-there is a change on newer branches that broke the backport.  The
-running of Custodia handlers in separate processes simplified the
-configuration of the ISecStore.  For ipa-4-7 we need to continue to
-explicitly configure it, so restore the old configuration behaviour.
-
-Part of: https://pagure.io/freeipa/issue/7964
-
-Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
-Reviewed-By: Rob Crittenden <rcritten@redhat.com>
----
- ipaserver/secrets/client.py | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/ipaserver/secrets/client.py b/ipaserver/secrets/client.py
-index 4c03ef8e4140dd507156d88941600a234b71184e..2363b081dbbf3671e8147497bb52811825bdf1a4 100644
---- a/ipaserver/secrets/client.py
-+++ b/ipaserver/secrets/client.py
-@@ -52,7 +52,12 @@ class CustodiaClient(object):
-         self.service_name = gssapi.Name(
-             'HTTP@{}'.format(server), gssapi.NameType.hostbased_service
-         )
--        self.keystore = IPASecStore()
-+
-+        config = {'ldap_uri': self.ldap_uri}
-+        if auth_type is not None:
-+            config['auth_type'] = auth_type
-+        self.keystore = IPASecStore(config)
-+
-         # use in-process MEMORY ccache. Handler process don't need a TGT.
-         token = b64encode(os.urandom(8)).decode('ascii')
-         self.ccache = 'MEMORY:Custodia_{}'.format(token)
--- 
-2.20.1
-
diff --git a/SOURCES/0061-Bump-krb5-min-version.patch b/SOURCES/0061-Bump-krb5-min-version.patch
deleted file mode 100644
index fca1a71..0000000
--- a/SOURCES/0061-Bump-krb5-min-version.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From b62a0a59b3a1b07d5b5868ca0061b4af9b97e203 Mon Sep 17 00:00:00 2001
-From: Fraser Tweedale <ftweedal@redhat.com>
-Date: Wed, 25 Sep 2019 16:43:25 +1000
-Subject: [PATCH] Bump krb5 min version
-
-krb5-1.15.1-36 introduced a ccache behavioural change that broke
-lightweight CA key replication.  The preceding commits (backported
-from the ipa-4-7 branch) fix this issue but this commit ensure that
-the correct version of krb5 is used with the updated FreeIPA code.
-
-Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1755223
-Reviewed-By: Rob Crittenden <rcritten@redhat.com>
----
- freeipa.spec.in | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/freeipa.spec.in b/freeipa.spec.in
-index a18a5b4aab335ad104f1263fa3ae8b26659c3095..72b328a723dd86c3f84a7c86ec68f224e8880af8 100644
---- a/freeipa.spec.in
-+++ b/freeipa.spec.in
-@@ -49,8 +49,8 @@
- 
- %global alt_name ipa
- %if 0%{?rhel}
--# 1.15.1-7: certauth (http://krbdev.mit.edu/rt/Ticket/Display.html?id=8561)
--%global krb5_version 1.15.1-4
-+# 1.15.1-36: https://bugzilla.redhat.com/show_bug.cgi?id=1755223
-+%global krb5_version 1.15.1-36
- # 0.7.16: https://github.com/drkjam/netaddr/issues/71
- %global python_netaddr_version 0.7.5-8
- # Require 4.7.0 which brings Python 3 bindings
--- 
-2.20.1
-
diff --git a/SOURCES/0062-DL0-replica-install-fix-nsDS5ReplicaBindDN-config.patch b/SOURCES/0062-DL0-replica-install-fix-nsDS5ReplicaBindDN-config.patch
deleted file mode 100644
index c54c0a9..0000000
--- a/SOURCES/0062-DL0-replica-install-fix-nsDS5ReplicaBindDN-config.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-From 542297d937d538e3353e06dd052a2e77d594dae8 Mon Sep 17 00:00:00 2001
-From: Florence Blanc-Renaud <flo@redhat.com>
-Date: Thu, 13 Jun 2019 21:54:58 +0200
-Subject: [PATCH] DL0 replica install: fix nsDS5ReplicaBindDN config
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-When setting up a 4.x replica in DL0 from a 3.x replica, the first 4.x
-replica installation succeeds but if a second 4.x replica is configured,
-the replication is not properly set.
-
-This happens because the replica setup needs to add nsDS5ReplicaBindDN:
-krbprincipalname=ldap/replica@DOMAIN to the entry
-cn=replica,cn=...,cn=mapping tree,cn=config in order to allow replication
-(on the 3.x master, the replication manager group is not supported yet).
-
-The issue is that this attribute is added only when the entry
-cn=replication managers,cn=sysaccounts,cn=etc,$BASEDN
-does not exist. This condition is true for the first replica install but
-false for the second replica install.
-
-The fix consists in checking if the remote server has ds version < 1.3.3
-(in this case it is a 3.x server). If it's the case, the installer
-will use nsDS5ReplicaBindDN attribute with the replica krbprincipalname.
-Otherwise the nsDS5ReplicaBindDN attribute will use the replication manager
-group.
-
-Fixes: https://pagure.io/freeipa/issue/7976
-Reviewed-By: François Cami <fcami@redhat.com>
----
- ipaserver/install/replication.py | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py
-index 8644b9ff618d28614a319d6da6a2041fea3c1c1f..c188bd6f5e4d13af7b12f5e0528ee135772af7ab 100644
---- a/ipaserver/install/replication.py
-+++ b/ipaserver/install/replication.py
-@@ -1730,9 +1730,14 @@ class ReplicationManager(object):
-         try:
-             conn.get_entry(self.repl_man_group_dn)
-         except errors.NotFound:
--            self._add_replica_bind_dn(conn, my_dn)
-             self._add_replication_managers(conn)
- 
-+        # On IPA 3.x masters (ds version < 1.3.3),
-+        # add replica bind DN directly into the replica entry
-+        vendor_version = get_ds_version(conn)
-+        if vendor_version < (1, 3, 3):
-+            self._add_replica_bind_dn(conn, my_dn)
-+
-         self._add_dn_to_replication_managers(conn, my_dn)
-         self._add_dn_to_replication_managers(conn, remote_dn)
- 
--- 
-2.23.0
-
diff --git a/SOURCES/0063-extdom-unify-error-code-handling-especially-LDAP_NO_.patch b/SOURCES/0063-extdom-unify-error-code-handling-especially-LDAP_NO_.patch
deleted file mode 100644
index 5f74de1..0000000
--- a/SOURCES/0063-extdom-unify-error-code-handling-especially-LDAP_NO_.patch
+++ /dev/null
@@ -1,287 +0,0 @@
-From 85d71239bb974c8d8988c753f63ec12d1b735da3 Mon Sep 17 00:00:00 2001
-From: Sumit Bose <sbose@redhat.com>
-Date: Fri, 14 Jun 2019 11:13:54 +0200
-Subject: [PATCH] extdom: unify error code handling especially
- LDAP_NO_SUCH_OBJECT
-
-A return code LDAP_NO_SUCH_OBJECT will tell SSSD on the IPA client to
-remove the searched object from the cache. As a consequence
-LDAP_NO_SUCH_OBJECT should only be returned if the object really does
-not exists otherwise the data of existing objects might be removed form
-the cache of the clients causing unexpected behaviour like
-authentication errors.
-
-Currently some code-paths use LDAP_NO_SUCH_OBJECT as default error code.
-With this patch LDAP_NO_SUCH_OBJECT is only returned if the related
-lookup functions return ENOENT. Timeout related error code will lead to
-LDAP_TIMELIMIT_EXCEEDED and LDAP_OPERATIONS_ERROR is used as default
-error code.
-
-Fixes: https://pagure.io/freeipa/issue/8044
-Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
----
- .../ipa-extdom-extop/back_extdom_sss_idmap.c  |  4 +-
- .../ipa-extdom-extop/ipa_extdom_common.c      | 77 ++++++++++++++-----
- .../ipa-extdom-extop/ipa_extdom_extop.c       |  2 +
- 3 files changed, 61 insertions(+), 22 deletions(-)
-
-diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c
-index 89c58ca2de333b26954d916836b57aed5d7e18fb..64b90e3ae8abc40edaaed91601cdded30db35294 100644
---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c
-+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c
-@@ -47,10 +47,10 @@ static enum nss_status __convert_sss_nss2nss_status(int errcode) {
-         return NSS_STATUS_SUCCESS;
-     case ENOENT:
-         return NSS_STATUS_NOTFOUND;
--    case ETIME:
--        /* fall-through */
-     case ERANGE:
-         return NSS_STATUS_TRYAGAIN;
-+    case ETIME:
-+        /* fall-through */
-     case ETIMEDOUT:
-         /* fall-through */
-     default:
-diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c
-index 1b93dce18671756fe9019378ce61e556697ad902..134b623773df418dc47edaf67045e5f4cfff9782 100644
---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c
-+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c
-@@ -523,7 +523,7 @@ int pack_ber_user(struct ipa_extdom_ctx *ctx,
-         if (strcasecmp(locat+1, domain_name) == 0  ) {
-             locat[0] = '\0';
-         } else {
--            ret = LDAP_NO_SUCH_OBJECT;
-+            ret = LDAP_INVALID_SYNTAX;
-             goto done;
-         }
-     }
-@@ -568,10 +568,12 @@ int pack_ber_user(struct ipa_extdom_ctx *ctx,
-             ret = getgrgid_r_wrapper(ctx,
-                                      groups[c], &grp, &buf, &buf_len);
-             if (ret != 0) {
--                if (ret == ENOMEM || ret == ERANGE) {
--                    ret = LDAP_OPERATIONS_ERROR;
--                } else {
-+                if (ret == ENOENT) {
-                     ret = LDAP_NO_SUCH_OBJECT;
-+                } else if (ret == ETIMEDOUT) {
-+                    ret = LDAP_TIMELIMIT_EXCEEDED;
-+                } else {
-+                    ret = LDAP_OPERATIONS_ERROR;
-                 }
-                 goto done;
-             }
-@@ -634,7 +636,7 @@ int pack_ber_group(enum response_types response_type,
-         if (strcasecmp(locat+1, domain_name) == 0  ) {
-             locat[0] = '\0';
-         } else {
--            ret = LDAP_NO_SUCH_OBJECT;
-+            ret = LDAP_INVALID_SYNTAX;
-             goto done;
-         }
-     }
-@@ -836,6 +838,8 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx,
-                             || id_type == SSS_ID_TYPE_BOTH)) {
-             if (ret == ENOENT) {
-                 ret = LDAP_NO_SUCH_OBJECT;
-+            } else if (ret == ETIMEDOUT || ret == ETIME) {
-+                ret = LDAP_TIMELIMIT_EXCEEDED;
-             } else {
-                 set_err_msg(req, "Failed to lookup SID by UID");
-                 ret = LDAP_OPERATIONS_ERROR;
-@@ -847,10 +851,12 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx,
-     } else {
-         ret = getpwuid_r_wrapper(ctx, uid, &pwd, &buf, &buf_len);
-         if (ret != 0) {
--            if (ret == ENOMEM || ret == ERANGE) {
--                ret = LDAP_OPERATIONS_ERROR;
--            } else {
-+            if (ret == ENOENT) {
-                 ret = LDAP_NO_SUCH_OBJECT;
-+            } else if (ret == ETIMEDOUT) {
-+                ret = LDAP_TIMELIMIT_EXCEEDED;
-+            } else {
-+                ret = LDAP_OPERATIONS_ERROR;
-             }
-             goto done;
-         }
-@@ -862,6 +868,8 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx,
-                 set_err_msg(req, "Failed to read original data");
-                 if (ret == ENOENT) {
-                     ret = LDAP_NO_SUCH_OBJECT;
-+                } else if (ret == ETIMEDOUT || ret == ETIME) {
-+                    ret = LDAP_TIMELIMIT_EXCEEDED;
-                 } else {
-                     ret = LDAP_OPERATIONS_ERROR;
-                 }
-@@ -907,6 +915,8 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx,
-         if (ret != 0 || id_type != SSS_ID_TYPE_GID) {
-             if (ret == ENOENT) {
-                 ret = LDAP_NO_SUCH_OBJECT;
-+            } else if (ret == ETIMEDOUT || ret == ETIME) {
-+                ret = LDAP_TIMELIMIT_EXCEEDED;
-             } else {
-                 set_err_msg(req, "Failed to lookup SID by GID");
-                 ret = LDAP_OPERATIONS_ERROR;
-@@ -918,10 +928,12 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx,
-     } else {
-         ret = getgrgid_r_wrapper(ctx, gid, &grp, &buf, &buf_len);
-         if (ret != 0) {
--            if (ret == ENOMEM || ret == ERANGE) {
--                ret = LDAP_OPERATIONS_ERROR;
--            } else {
-+            if (ret == ENOENT) {
-                 ret = LDAP_NO_SUCH_OBJECT;
-+            } else if (ret == ETIMEDOUT) {
-+                ret = LDAP_TIMELIMIT_EXCEEDED;
-+            } else {
-+                ret = LDAP_OPERATIONS_ERROR;
-             }
-             goto done;
-         }
-@@ -933,6 +945,8 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx,
-                 set_err_msg(req, "Failed to read original data");
-                 if (ret == ENOENT) {
-                     ret = LDAP_NO_SUCH_OBJECT;
-+                } else if (ret == ETIMEDOUT || ret == ETIME) {
-+                    ret = LDAP_TIMELIMIT_EXCEEDED;
-                 } else {
-                     ret = LDAP_OPERATIONS_ERROR;
-                 }
-@@ -976,6 +990,8 @@ static int handle_cert_request(struct ipa_extdom_ctx *ctx,
-     if (ret != 0) {
-         if (ret == ENOENT) {
-             ret = LDAP_NO_SUCH_OBJECT;
-+        } else if (ret == ETIMEDOUT || ret == ETIME) {
-+            ret = LDAP_TIMELIMIT_EXCEEDED;
-         } else {
-             set_err_msg(req, "Failed to lookup name by certificate");
-             ret = LDAP_OPERATIONS_ERROR;
-@@ -1020,6 +1036,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
-     if (ret != 0) {
-         if (ret == ENOENT) {
-             ret = LDAP_NO_SUCH_OBJECT;
-+        } else if (ret == ETIMEDOUT || ret == ETIME) {
-+            ret = LDAP_TIMELIMIT_EXCEEDED;
-         } else {
-             set_err_msg(req, "Failed to lookup name by SID");
-             ret = LDAP_OPERATIONS_ERROR;
-@@ -1057,10 +1075,12 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
-     case SSS_ID_TYPE_BOTH:
-         ret = getpwnam_r_wrapper(ctx, fq_name, &pwd, &buf, &buf_len);
-         if (ret != 0) {
--            if (ret == ENOMEM || ret == ERANGE) {
--                ret = LDAP_OPERATIONS_ERROR;
--            } else {
-+            if (ret == ENOENT) {
-                 ret = LDAP_NO_SUCH_OBJECT;
-+            } else if (ret == ETIMEDOUT) {
-+                ret = LDAP_TIMELIMIT_EXCEEDED;
-+            } else {
-+                ret = LDAP_OPERATIONS_ERROR;
-             }
-             goto done;
-         }
-@@ -1072,6 +1092,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
-                 set_err_msg(req, "Failed to read original data");
-                 if (ret == ENOENT) {
-                     ret = LDAP_NO_SUCH_OBJECT;
-+                } else if (ret == ETIMEDOUT || ret == ETIME) {
-+                    ret = LDAP_TIMELIMIT_EXCEEDED;
-                 } else {
-                     ret = LDAP_OPERATIONS_ERROR;
-                 }
-@@ -1089,10 +1111,12 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
-     case SSS_ID_TYPE_GID:
-         ret = getgrnam_r_wrapper(ctx, fq_name, &grp, &buf, &buf_len);
-         if (ret != 0) {
--            if (ret == ENOMEM || ret == ERANGE) {
--                ret = LDAP_OPERATIONS_ERROR;
--            } else {
-+            if (ret == ENOENT) {
-                 ret = LDAP_NO_SUCH_OBJECT;
-+            } else if (ret == ETIMEDOUT) {
-+                ret = LDAP_TIMELIMIT_EXCEEDED;
-+            } else {
-+                ret = LDAP_OPERATIONS_ERROR;
-             }
-             goto done;
-         }
-@@ -1104,6 +1128,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
-                 set_err_msg(req, "Failed to read original data");
-                 if (ret == ENOENT) {
-                     ret = LDAP_NO_SUCH_OBJECT;
-+                } else if (ret == ETIMEDOUT || ret == ETIME) {
-+                    ret = LDAP_TIMELIMIT_EXCEEDED;
-                 } else {
-                     ret = LDAP_OPERATIONS_ERROR;
-                 }
-@@ -1167,6 +1193,8 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx,
-         if (ret != 0) {
-             if (ret == ENOENT) {
-                 ret = LDAP_NO_SUCH_OBJECT;
-+            } else if (ret == ETIMEDOUT || ret == ETIME) {
-+                ret = LDAP_TIMELIMIT_EXCEEDED;
-             } else {
-                 set_err_msg(req, "Failed to lookup SID by name");
-                 ret = LDAP_OPERATIONS_ERROR;
-@@ -1190,6 +1218,8 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx,
-                     set_err_msg(req, "Failed to read original data");
-                     if (ret == ENOENT) {
-                         ret = LDAP_NO_SUCH_OBJECT;
-+                    } else if (ret == ETIMEDOUT || ret == ETIME) {
-+                        ret = LDAP_TIMELIMIT_EXCEEDED;
-                     } else {
-                         ret = LDAP_OPERATIONS_ERROR;
-                     }
-@@ -1205,6 +1235,9 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx,
-         } else if (ret == ENOMEM || ret == ERANGE) {
-             ret = LDAP_OPERATIONS_ERROR;
-             goto done;
-+        } else if (ret == ETIMEDOUT) {
-+            ret = LDAP_TIMELIMIT_EXCEEDED;
-+            goto done;
-         } else { /* no user entry found */
-             /* according to the getpwnam() man page there are a couple of
-              * error codes which can indicate that the user was not found. To
-@@ -1212,10 +1245,12 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx,
-              * errors. */
-             ret = getgrnam_r_wrapper(ctx, fq_name, &grp, &buf, &buf_len);
-             if (ret != 0) {
--                if (ret == ENOMEM || ret == ERANGE) {
--                    ret = LDAP_OPERATIONS_ERROR;
--                } else {
-+                if (ret == ENOENT) {
-                     ret = LDAP_NO_SUCH_OBJECT;
-+                } else if (ret == ETIMEDOUT) {
-+                    ret = LDAP_TIMELIMIT_EXCEEDED;
-+                } else {
-+                    ret = LDAP_OPERATIONS_ERROR;
-                 }
-                 goto done;
-             }
-@@ -1226,6 +1261,8 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx,
-                                     || id_type == SSS_ID_TYPE_BOTH)) {
-                     if (ret == ENOENT) {
-                         ret = LDAP_NO_SUCH_OBJECT;
-+                    } else if (ret == ETIMEDOUT || ret == ETIME) {
-+                        ret = LDAP_TIMELIMIT_EXCEEDED;
-                     } else {
-                         set_err_msg(req, "Failed to read original data");
-                         ret = LDAP_OPERATIONS_ERROR;
-diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
-index 10d3f86ebad920fb9c051aa428cbd675b682f14a..48fcecc1eeb8f2ad6a3bc8791fe94f4ed54fe74d 100644
---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
-+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
-@@ -242,6 +242,8 @@ static int ipa_extdom_extop(Slapi_PBlock *pb)
-     if (ret != LDAP_SUCCESS) {
-         if (ret == LDAP_NO_SUCH_OBJECT) {
-             rc = LDAP_NO_SUCH_OBJECT;
-+        } else if (ret == LDAP_TIMELIMIT_EXCEEDED) {
-+            rc = LDAP_TIMELIMIT_EXCEEDED;
-         } else {
-             rc = LDAP_OPERATIONS_ERROR;
-             err_msg = "Failed to handle the request.\n";
--- 
-2.23.0
-
diff --git a/SOURCES/0064-ipa-extdom-extop-test-timed-out-getgrgid_r.patch b/SOURCES/0064-ipa-extdom-extop-test-timed-out-getgrgid_r.patch
deleted file mode 100644
index 265e9da..0000000
--- a/SOURCES/0064-ipa-extdom-extop-test-timed-out-getgrgid_r.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From 52d90782c1a7ebe5bd984b7560d71a06fe3fb76b Mon Sep 17 00:00:00 2001
-From: Alexander Bokovoy <abokovoy@redhat.com>
-Date: Mon, 19 Aug 2019 10:15:50 +0300
-Subject: [PATCH] ipa-extdom-extop: test timed out getgrgid_r
-
-Simulate getgrgid_r() timeout when packing list of groups user is a
-member of in pack_ber_user().
-
-Related: https://pagure.io/freeipa/issue/8044
-Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
----
- .../ipa_extdom_cmocka_tests.c                 | 29 +++++++++++++++++++
- 1 file changed, 29 insertions(+)
-
-diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c
-index 29699cfa390f5469d7c009388b90e68616cbf984..1fa4c6af823d290412496b5823b90873375f2769 100644
---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c
-+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c
-@@ -493,6 +493,34 @@ void test_set_err_msg(void **state)
- #define TEST_SID "S-1-2-3-4"
- #define TEST_DOMAIN_NAME "DOMAIN"
- 
-+/* Always time out for test */
-+static
-+enum nss_status getgrgid_r_timeout(gid_t gid, struct group *result,
-+                                   char *buffer, size_t buflen, int *errnop) {
-+    return NSS_STATUS_UNAVAIL;
-+}
-+
-+void test_pack_ber_user_timeout(void **state)
-+{
-+    int ret;
-+    struct berval *resp_val = NULL;
-+    struct test_data *test_data;
-+    enum nss_status (*oldgetgrgid_r)(gid_t gid, struct group *result,
-+                                     char *buffer, size_t buflen, int *errnop);
-+
-+    test_data = (struct test_data *) *state;
-+
-+    oldgetgrgid_r = test_data->ctx->nss_ctx->getgrgid_r;
-+    test_data->ctx->nss_ctx->getgrgid_r = getgrgid_r_timeout;
-+
-+    ret = pack_ber_user(test_data->ctx, RESP_USER_GROUPLIST,
-+                        TEST_DOMAIN_NAME, "member001", 12345, 54321,
-+                        "gecos", "homedir", "shell", NULL, &resp_val);
-+    test_data->ctx->nss_ctx->getgrgid_r = oldgetgrgid_r;
-+    assert_int_equal(ret, LDAP_TIMELIMIT_EXCEEDED);
-+    ber_bvfree(resp_val);
-+}
-+
- char res_sid[] = {0x30, 0x0e, 0x0a, 0x01, 0x01, 0x04, 0x09, 0x53, 0x2d, 0x31, \
-                   0x2d, 0x32, 0x2d, 0x33, 0x2d, 0x34};
- char res_nam[] = {0x30, 0x13, 0x0a, 0x01, 0x02, 0x30, 0x0e, 0x04, 0x06, 0x44, \
-@@ -614,6 +642,7 @@ void test_decode(void **state)
- int main(int argc, const char *argv[])
- {
-     const struct CMUnitTest tests[] = {
-+        cmocka_unit_test(test_pack_ber_user_timeout),
-         cmocka_unit_test(test_getpwnam_r_wrapper),
-         cmocka_unit_test(test_getpwuid_r_wrapper),
-         cmocka_unit_test(test_getgrnam_r_wrapper),
--- 
-2.23.0
-
diff --git a/SOURCES/0065-Make-sure-to-have-storage-space-for-tag.patch b/SOURCES/0065-Make-sure-to-have-storage-space-for-tag.patch
deleted file mode 100644
index 7ebf209..0000000
--- a/SOURCES/0065-Make-sure-to-have-storage-space-for-tag.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From 61db30080726bfc4832b8516b335734a5246ac0b Mon Sep 17 00:00:00 2001
-From: Simo Sorce <simo@redhat.com>
-Date: Mon, 16 Sep 2019 11:12:25 -0400
-Subject: [PATCH] Make sure to have storage space for tag
-
-ber_scanf expects a pointer to a ber_tag_t to return the tag pointed at
-by "t", if that is not provided the pointer will be store in whatever
-memory location is pointed by the stack at that time causeing a crash.
-
-Note that this is effectively unused code because in ipa-kdb the only
-party that can write a key_data structure to be stored is te kdb_driver
-itself and we never encode these s2kparam data.
-
-But we need to handle this for future proofing.
-
-Fixes #8071
-
-Signed-off-by: Simo Sorce <simo@redhat.com>
-Reviewed-By: Christian Heimes <cheimes@redhat.com>
----
- util/ipa_krb5.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/util/ipa_krb5.c b/util/ipa_krb5.c
-index a27cd4a4e538c738c6ab2157a4daabf8fea7661c..c09c3daa505655f2e5292a79c03683faa75ad244 100644
---- a/util/ipa_krb5.c
-+++ b/util/ipa_krb5.c
-@@ -554,7 +554,7 @@ int ber_decode_krb5_key_data(struct berval *encoded, int *m_kvno,
-         retag = ber_peek_tag(be, &setlen);
-         if (retag == (LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 2)) {
-             /* not supported yet, skip */
--            retag = ber_scanf(be, "t[x]}");
-+            retag = ber_scanf(be, "t[x]}", &tag);
-         } else {
-             retag = ber_scanf(be, "}");
-         }
--- 
-2.23.0
-
diff --git a/SOURCES/0066-CVE-2019-10195-Don-t-log-passwords-embedded-in-comma.patch b/SOURCES/0066-CVE-2019-10195-Don-t-log-passwords-embedded-in-comma.patch
deleted file mode 100644
index d376429..0000000
--- a/SOURCES/0066-CVE-2019-10195-Don-t-log-passwords-embedded-in-comma.patch
+++ /dev/null
@@ -1,147 +0,0 @@
-From 84317f86f9c96805cf365784794142e65cfbb310 Mon Sep 17 00:00:00 2001
-From: Rob Crittenden <rcritten@redhat.com>
-Date: Tue, 2 Jul 2019 13:44:48 -0400
-Subject: [PATCH] CVE-2019-10195: Don't log passwords embedded in commands in
- calls using batch
-
-A raw batch request was fully logged which could expose parameters
-we don't want logged, like passwords.
-
-Override _repr_iter to use the individual commands to log the
-values so that values are properly obscured.
-
-In case of errors log the full value on when the server is in
-debug mode.
-
-Reported by Jamison Bennett from Cloudera
-
-Signed-off-by: Rob Crittenden <rcritten@redhat.com>
-Reviewed-by:  Florence Blanc-Renaud <frenaud@redhat.com>
----
- ipaserver/plugins/batch.py | 96 ++++++++++++++++++++++++++++----------
- 1 file changed, 72 insertions(+), 24 deletions(-)
-
-diff --git a/ipaserver/plugins/batch.py b/ipaserver/plugins/batch.py
-index 2794db895a014a6129654889289815d4286cf7f4..9df367d16234d1840a2e5297cdd5c3c59fa4828f 100644
---- a/ipaserver/plugins/batch.py
-+++ b/ipaserver/plugins/batch.py
-@@ -92,35 +92,82 @@ class batch(Command):
-         Output('results', (list, tuple), doc='')
-     )
- 
-+    def _validate_request(self, request):
-+        """
-+        Check that an individual request in a batch is parseable and the
-+        commands exists.
-+        """
-+        if 'method' not in request:
-+            raise errors.RequirementError(name='method')
-+        if 'params' not in request:
-+            raise errors.RequirementError(name='params')
-+        name = request['method']
-+        if (name not in self.api.Command or
-+                isinstance(self.api.Command[name], Local)):
-+            raise errors.CommandError(name=name)
-+
-+        # If params are not formated as a tuple(list, dict)
-+        # the following lines will raise an exception
-+        # that triggers an internal server error
-+        # Raise a ConversionError instead to report the issue
-+        # to the client
-+        try:
-+            a, kw = request['params']
-+            newkw = dict((str(k), v) for k, v in kw.items())
-+            api.Command[name].args_options_2_params(*a, **newkw)
-+        except (AttributeError, ValueError, TypeError):
-+            raise errors.ConversionError(
-+                name='params',
-+                error=_(u'must contain a tuple (list, dict)'))
-+        except Exception as e:
-+            raise errors.ConversionError(
-+                name='params',
-+                error=str(e))
-+
-+    def _repr_iter(self, **params):
-+        """
-+        Iterate through the request and use the Command _repr_intr so
-+        that sensitive information (passwords) is not exposed.
-+
-+        In case of a malformatted request redact the entire thing.
-+        """
-+        exceptions = False
-+        for arg in (params.get('methods', [])):
-+            try:
-+                self._validate_request(arg)
-+            except Exception:
-+                # redact the whole request since we don't know what's in it
-+                exceptions = True
-+                yield u'********'
-+                continue
-+
-+            name = arg['method']
-+            a, kw = arg['params']
-+            newkw = dict((str(k), v) for k, v in kw.items())
-+            param = api.Command[name].args_options_2_params(
-+                *a, **newkw)
-+
-+            yield '{}({})'.format(
-+                api.Command[name].name,
-+                ', '.join(api.Command[name]._repr_iter(**param))
-+            )
-+
-+        if exceptions:
-+            logger.debug('batch: %s',
-+                         ', '.join(super(batch, self)._repr_iter(**params)))
-+
-     def execute(self, methods=None, **options):
-         results = []
-         for arg in (methods or []):
-             params = dict()
-             name = None
-             try:
--                if 'method' not in arg:
--                    raise errors.RequirementError(name='method')
--                if 'params' not in arg:
--                    raise errors.RequirementError(name='params')
-+                self._validate_request(arg)
-                 name = arg['method']
--                if (name not in self.api.Command or
--                        isinstance(self.api.Command[name], Local)):
--                    raise errors.CommandError(name=name)
--
--                # If params are not formated as a tuple(list, dict)
--                # the following lines will raise an exception
--                # that triggers an internal server error
--                # Raise a ConversionError instead to report the issue
--                # to the client
--                try:
--                    a, kw = arg['params']
--                    newkw = dict((str(k), v) for k, v in kw.items())
--                    params = api.Command[name].args_options_2_params(
--                        *a, **newkw)
--                except (AttributeError, ValueError, TypeError):
--                    raise errors.ConversionError(
--                        name='params',
--                        error=_(u'must contain a tuple (list, dict)'))
-+                a, kw = arg['params']
-+                newkw = dict((str(k), v) for k, v in kw.items())
-+                params = api.Command[name].args_options_2_params(
-+                    *a, **newkw)
-                 newkw.setdefault('version', options['version'])
- 
-                 result = api.Command[name](*a, **newkw)
-@@ -132,8 +179,9 @@ class batch(Command):
-                 )
-                 result['error']=None
-             except Exception as e:
--                if isinstance(e, errors.RequirementError) or \
--                    isinstance(e, errors.CommandError):
-+                if (isinstance(e, errors.RequirementError) or
-+                        isinstance(e, errors.CommandError) or
-+                        isinstance(e, errors.ConversionError)):
-                     logger.info(
-                         '%s: batch: %s',
-                         context.principal,  # pylint: disable=no-member
--- 
-2.23.0
-
diff --git a/SOURCES/0067-trust-upgrade-ensure-that-host-is-member-of-adtrust-.patch b/SOURCES/0067-trust-upgrade-ensure-that-host-is-member-of-adtrust-.patch
deleted file mode 100644
index 1775c62..0000000
--- a/SOURCES/0067-trust-upgrade-ensure-that-host-is-member-of-adtrust-.patch
+++ /dev/null
@@ -1,110 +0,0 @@
-From de19fe67c341d99171afda61f6419a80c757b0f7 Mon Sep 17 00:00:00 2001
-From: Florence Blanc-Renaud <flo@redhat.com>
-Date: Tue, 3 Dec 2019 12:56:22 +0100
-Subject: [PATCH] trust upgrade: ensure that host is member of adtrust agents
-
-After an upgrade, the group cn=adtrust agents may be missing some members.
-Each ad trust controller must appear twice as member:
-- krbprincipalname=cifs/hostname@realm,cn=services,cn=accounts,basedn
-- fqdn=hostname,cn=computers,cn=accounts,basedn
-
-Add an upgrade plugin that builds a list of hostnames from the cifs
-principals and adds if needed fqdn=hostname...
-
-Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1778777
-Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
-Reviewed-By: Alexander Bokovoy <abbra@users.noreply.github.com>
-Reviewed-By: Alexander Bokovoy <abbra@users.noreply.github.com>
----
- .../updates/90-post_upgrade_plugins.update    |  1 +
- ipaserver/install/plugins/adtrust.py          | 55 +++++++++++++++++++
- 2 files changed, 56 insertions(+)
-
-diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update
-index 77b910fc26858611e44a5ba3f4f4c18f4895c95e..1d9e8bba8486df197fc9a3e9f83df360f55ca251 100644
---- a/install/updates/90-post_upgrade_plugins.update
-+++ b/install/updates/90-post_upgrade_plugins.update
-@@ -13,6 +13,7 @@ plugin: update_default_trust_view
- plugin: update_tdo_gidnumber
- plugin: update_tdo_to_new_layout
- plugin: update_tdo_default_read_keys_permissions
-+plugin: update_adtrust_agents_members
- plugin: update_ca_renewal_master
- plugin: update_idrange_type
- plugin: update_pacs
-diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
-index 950b7b9c82f1b0e115675ff8093d1bd02e913ae2..3da8c9e2021c1ee9cb59a90e9fe269d86e9c337a 100644
---- a/ipaserver/install/plugins/adtrust.py
-+++ b/ipaserver/install/plugins/adtrust.py
-@@ -8,9 +8,11 @@ from ipalib import Updater
- from ipapython.dn import DN
- from ipapython import ipautil
- from ipaplatform.paths import paths
-+from ipaserver.install import service
- from ipaserver.install import sysupgrade
- from ipaserver.install.adtrustinstance import (
-     ADTRUSTInstance, map_Guests_to_nobody)
-+
- from ipaserver.dcerpc_common import TRUST_BIDIRECTIONAL
- 
- try:
-@@ -785,3 +787,56 @@ class update_tdo_default_read_keys_permissions(Updater):
-                              tdo.single_value.get('krbCanonicalName'))
- 
-         return False, []
-+
-+
-+@register()
-+class update_adtrust_agents_members(Updater):
-+    """ Ensure that each adtrust agent is a member of the adtrust agents group
-+
-+    cn=adtrust agents,cn=sysaccounts,cn=etc,$BASEDN must contain:
-+    - member: krbprincipalname=cifs/master@realm,cn=services,cn=accounts,base
-+    - member: fqdn=master,cn=computers,cn=accounts,base
-+    """
-+    def execute(self, **options):
-+        ldap = self.api.Backend.ldap2
-+
-+        # First, see if trusts are enabled on the server
-+        if not self.api.Command.adtrust_is_enabled()['result']:
-+            logger.debug('AD Trusts are not enabled on this server')
-+            return False, []
-+
-+        agents_dn = DN(
-+            ('cn', 'adtrust agents'), ('cn', 'sysaccounts'),
-+            ('cn', 'etc'), self.api.env.basedn)
-+
-+        try:
-+            agents_entry = ldap.get_entry(agents_dn, ['member'])
-+        except errors.NotFound:
-+            logger.error("No adtrust agents group found")
-+            return False, []
-+
-+        # Build a list of agents from the cifs/.. members
-+        agents_list = []
-+        members = agents_entry.get('member', [])
-+        suffix = '@{}'.format(self.api.env.realm).lower()
-+
-+        for amember in members:
-+            if amember[0].attr.lower() == 'krbprincipalname':
-+                # Extract krbprincipalname=cifs/hostname@realm from the DN
-+                value = amember[0].value
-+                if (value.lower().startswith('cifs/') and
-+                        value.lower().endswith(suffix)):
-+                    # 5 = length of 'cifs/'
-+                    hostname = value[5:-len(suffix)]
-+                    agents_list.append(DN(('fqdn', hostname),
-+                                       self.api.env.container_host,
-+                                       self.api.env.basedn))
-+
-+        # Add the fqdn=hostname... to the group
-+        service.add_principals_to_group(
-+            ldap,
-+            agents_dn,
-+            "member",
-+            agents_list)
-+
-+        return False, []
--- 
-2.23.0
-
diff --git a/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch b/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch
index 24b7c73..9cae834 100644
--- a/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch
+++ b/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch
@@ -1,4 +1,4 @@
-From 1a992ce1275797ef376e6c137d10f412b92db9db Mon Sep 17 00:00:00 2001
+From 631d69c25e8211721bd4127dd84a5b41beccb995 Mon Sep 17 00:00:00 2001
 From: Jan Cholasta <jcholast@redhat.com>
 Date: Tue, 14 Mar 2017 15:48:07 +0000
 Subject: [PATCH] Change branding to IPA and Identity Management
@@ -90,7 +90,7 @@ index d95790a366aac4635e32bbc6bc81773bb9a52e68..431b395a907b6978d9e0dba9870ed0bd
  ipa\-certupdate \- Update local IPA certificate databases with certificates from the server
  .SH "SYNOPSIS"
 diff --git a/client/man/ipa-client-automount.1 b/client/man/ipa-client-automount.1
-index 8b9989dec7a2e31f9ccbc0b79d336449bea9e70d..72562ab9582e987cde387583ba033464526899e2 100644
+index e6a32fba432d75dfce0cfc0a9bc7264c4beca2ae..5c3fdb118522c12f93e82bb39572ba1e2a1908a2 100644
 --- a/client/man/ipa-client-automount.1
 +++ b/client/man/ipa-client-automount.1
 @@ -16,7 +16,7 @@
@@ -570,7 +570,7 @@ index 6451f3545e8a133efbcfcfeb21ffdda2a1849367..ed441e3bea9aa9b60fd589bd63897a37
  ipa\-replica\-conncheck \- Check a replica\-master network connection before installation
  .SH "SYNOPSIS"
 diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1
-index a1284135ac67de2b67b322aec3f6bbfb05f1a8ec..4301128afc65780ab73654d8c213a4f8ce4763a2 100644
+index 12764b8994a04bf56e80492bdcc66578a1f991e0..df403a3ff0c56c8cb7026569c71c94187d2226b7 100644
 --- a/install/tools/man/ipa-replica-install.1
 +++ b/install/tools/man/ipa-replica-install.1
 @@ -1,7 +1,7 @@
@@ -1036,7 +1036,7 @@ index 006bc92bec581e1983f11bfd75498b5484f2567a..6302c4cf0798aab420198975c01874a8
      '''
  
 diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
-index c1e593e467cdb856a4ab3251ee103f3da3386a82..78169b501809fcd4db43e433ca4a1693d0c2b92f 100644
+index 5ea4f2e1cc80c995997888aaf44f500524beb796..8bea61fd7ddeff0790b9d875afd24680532dbed9 100644
 --- a/ipaserver/install/server/install.py
 +++ b/ipaserver/install/server/install.py
 @@ -387,7 +387,7 @@ def install_check(installer):
@@ -1049,7 +1049,7 @@ index c1e593e467cdb856a4ab3251ee103f3da3386a82..78169b501809fcd4db43e433ca4a1693
      print("This includes:")
      if setup_ca:
 diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
-index e13b7f18c4d4df7efde50ac9cb7d2f71bfa765cc..7f23414516e718d95ce510d20885240c6dc976b5 100644
+index 14e8b2c3a76525c6ec2a16ca26fa032aab694a59..bff4a0b501ac519c373ea045a721efaeb2d74e13 100644
 --- a/ipaserver/install/server/replicainstall.py
 +++ b/ipaserver/install/server/replicainstall.py
 @@ -628,7 +628,7 @@ def check_domain_level_is_supported(current):
@@ -1075,7 +1075,7 @@ index 5e8dbca0469bb0234449cce09e20212886fc3f9e..ffc5fcb4c491dbf33606eae80f9092d3
  - When importing a profile the "profileId" field, if present, must
    match the ID given on the command line.
 diff --git a/ipaserver/plugins/sudorule.py b/ipaserver/plugins/sudorule.py
-index 6037938330f13a30d0ccfbedcaac59c567bda0d6..b8a0c82d394edb8744de34394895b86fae2c321f 100644
+index 643215985e932cae6e8d954596194032655b25d4..68baa0174ed88ede3f42092fb68150b55962574e 100644
 --- a/ipaserver/plugins/sudorule.py
 +++ b/ipaserver/plugins/sudorule.py
 @@ -47,7 +47,7 @@ give certain users (or groups of users) the ability to run some (or all)
diff --git a/SOURCES/1002-Package-copy-schema-to-ca.py.patch b/SOURCES/1002-Package-copy-schema-to-ca.py.patch
index 22b39aa..c96f4a6 100644
--- a/SOURCES/1002-Package-copy-schema-to-ca.py.patch
+++ b/SOURCES/1002-Package-copy-schema-to-ca.py.patch
@@ -1,4 +1,4 @@
-From b2dadbd58f3203c5d798286e9a3d8da339a5d9ed Mon Sep 17 00:00:00 2001
+From a483fba7c235e8d4eba90c289594e76e85f4d8e4 Mon Sep 17 00:00:00 2001
 From: Jan Cholasta <jcholast@redhat.com>
 Date: Tue, 14 Mar 2017 16:07:15 +0000
 Subject: [PATCH] Package copy-schema-to-ca.py
@@ -10,7 +10,7 @@ This reverts commit f4c7f1dd8a9ce530a8291219a904686ee47e59c7.
  2 files changed, 5 insertions(+), 2 deletions(-)
 
 diff --git a/freeipa.spec.in b/freeipa.spec.in
-index 72b328a723dd86c3f84a7c86ec68f224e8880af8..488cf9c02be3e96ffde7ab2f2c3d80b9c82d428a 100644
+index 0f96778f758cb21c01e31ff35e70c79f020aa2d3..c71b257cd9a28c083c8bc95d13a4c1351916a385 100644
 --- a/freeipa.spec.in
 +++ b/freeipa.spec.in
 @@ -1489,6 +1489,7 @@ fi
diff --git a/SOURCES/1003-Revert-Increased-mod_wsgi-socket-timeout.patch b/SOURCES/1003-Revert-Increased-mod_wsgi-socket-timeout.patch
index 91deb73..b3104cc 100644
--- a/SOURCES/1003-Revert-Increased-mod_wsgi-socket-timeout.patch
+++ b/SOURCES/1003-Revert-Increased-mod_wsgi-socket-timeout.patch
@@ -1,4 +1,4 @@
-From c0e54fa7d42af945fd42261be4ebac90c9641316 Mon Sep 17 00:00:00 2001
+From 0898c40288721ab83f099c34b8d21cab29f931e2 Mon Sep 17 00:00:00 2001
 From: Jan Cholasta <jcholast@redhat.com>
 Date: Wed, 22 Jun 2016 13:53:46 +0200
 Subject: [PATCH] Revert "Increased mod_wsgi socket-timeout"
diff --git a/SOURCES/1004-Remove-csrgen.patch b/SOURCES/1004-Remove-csrgen.patch
index 23d1a61..b4f58d3 100644
--- a/SOURCES/1004-Remove-csrgen.patch
+++ b/SOURCES/1004-Remove-csrgen.patch
@@ -1,4 +1,4 @@
-From 376335dad5438a082e411daf34edb39e738861a5 Mon Sep 17 00:00:00 2001
+From 5132d5d27355c6817dfc5c7807b95c457bcaef39 Mon Sep 17 00:00:00 2001
 From: Jan Cholasta <jcholast@redhat.com>
 Date: Thu, 16 Mar 2017 09:44:21 +0000
 Subject: [PATCH] Remove csrgen
@@ -39,7 +39,7 @@ https://bugzilla.redhat.com/show_bug.cgi?id=1432630
  delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/templates/identity_base.tmpl
 
 diff --git a/freeipa.spec.in b/freeipa.spec.in
-index 488cf9c02be3e96ffde7ab2f2c3d80b9c82d428a..6636b9474564ab48d2f804c3854d33a1b071f2c8 100644
+index c71b257cd9a28c083c8bc95d13a4c1351916a385..8182b67e56fa16d636046a45b8fbc873a908cf45 100644
 --- a/freeipa.spec.in
 +++ b/freeipa.spec.in
 @@ -248,7 +248,6 @@ BuildRequires:  python2-sssdconfig
diff --git a/SOURCES/1005-Removing-filesystem-encoding-check.patch b/SOURCES/1005-Removing-filesystem-encoding-check.patch
index 0791d59..8a2e552 100644
--- a/SOURCES/1005-Removing-filesystem-encoding-check.patch
+++ b/SOURCES/1005-Removing-filesystem-encoding-check.patch
@@ -1,4 +1,4 @@
-From 53dea5370de10eef64a11fede6e2033f13fd2b25 Mon Sep 17 00:00:00 2001
+From 9911f805582d68a98728b76b273f691f2beb45da Mon Sep 17 00:00:00 2001
 From: =?UTF-8?q?Tibor=20Dudl=C3=A1k?= <tdudlak@redhat.com>
 Date: Fri, 10 Aug 2018 13:16:38 +0200
 Subject: [PATCH] Removing filesystem encoding check
diff --git a/SOURCES/ipa-centos-branding.patch b/SOURCES/ipa-centos-branding.patch
deleted file mode 100644
index 673cd2f..0000000
--- a/SOURCES/ipa-centos-branding.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 99efecaf87dc1fc9517efaff441a6a7ce46444eb Mon Sep 17 00:00:00 2001
-From: Jim Perrin <jperrin@centos.org>
-Date: Wed, 11 Mar 2015 10:37:03 -0500
-Subject: [PATCH] update for new ntp server method
-
----
- ipaplatform/base/paths.py        | 1 +
- ipaserver/install/ntpinstance.py | 2 ++
- 2 files changed, 3 insertions(+)
-
-diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
-index af50262..5090062 100644
---- a/ipaplatform/base/paths.py
-+++ b/ipaplatform/base/paths.py
-@@ -99,6 +99,7 @@ class BasePathNamespace(object):
-     PKI_TOMCAT_ALIAS_DIR = "/etc/pki/pki-tomcat/alias/"
-     PKI_TOMCAT_PASSWORD_CONF = "/etc/pki/pki-tomcat/password.conf"
-     ETC_REDHAT_RELEASE = "/etc/redhat-release"
-+    ETC_CENTOS_RELEASE = "/etc/centos-release"
-     RESOLV_CONF = "/etc/resolv.conf"
-     SAMBA_KEYTAB = "/etc/samba/samba.keytab"
-     SMB_CONF = "/etc/samba/smb.conf"
-diff --git a/ipaserver/install/ntpinstance.py b/ipaserver/install/ntpinstance.py
-index c653525..4b0578b 100644
---- a/ipaserver/install/ntpinstance.py
-+++ b/ipaserver/install/ntpinstance.py
-@@ -44,6 +44,8 @@ class NTPInstance(service.Service):
-         os = ""
-         if ipautil.file_exists(paths.ETC_FEDORA_RELEASE):
-             os = "fedora"
-+        elif ipautil.file_exists(paths.ETC_CENTOS_RELEASE):
-+            os = "centos"
-         elif ipautil.file_exists(paths.ETC_REDHAT_RELEASE):
-             os = "rhel"
- 
--- 
-1.8.3.1
-
diff --git a/SPECS/ipa.spec b/SPECS/ipa.spec
index f795a72..2ff1336 100644
--- a/SPECS/ipa.spec
+++ b/SPECS/ipa.spec
@@ -44,8 +44,8 @@
 %if 0%{?rhel}
 # 1.15.1-36: https://bugzilla.redhat.com/show_bug.cgi?id=1755223
 %global krb5_version 1.15.1-36
-# Require 4.6.0-4 which brings RC4 for FIPS + trust fixes to priv. separation
-%global samba_version 4.7.0
+# Require 4.10 for change in ABI for DEBUGLEVEL_CLASS (rename)
+%global samba_version 4.10.0
 # 0.7.16: https://github.com/drkjam/netaddr/issues/71
 %global python_netaddr_version 0.7.5-9
 %global selinux_policy_version 3.13.1-224
@@ -93,7 +93,7 @@
 
 # Work-around fact that RPM SPEC parser does not accept
 # "Version: @VERSION@" in freeipa.spec.in used for Autoconf string replacement
-%define IPA_VERSION 4.6.5
+%define IPA_VERSION 4.6.6
 %define AT_SIGN @
 # redefine IPA_VERSION only if its value matches the Autoconf placeholder
 %if "%{IPA_VERSION}" == "%{AT_SIGN}VERSION%{AT_SIGN}"
@@ -102,7 +102,7 @@
 
 Name:           ipa
 Version:        %{IPA_VERSION}
-Release:        11%{?dist}.4
+Release:        11%{?dist}
 Summary:        The Identity, Policy and Audit system
 
 Group:          System Environment/Base
@@ -110,80 +110,42 @@ License:        GPLv3+
 URL:            http://www.freeipa.org/
 Source0:        https://releases.pagure.org/freeipa/freeipa-%{version}.tar.gz
 # RHEL spec file only: START: Change branding to IPA and Identity Management
-#Source1:        header-logo.png
-#Source2:        login-screen-background.jpg
-#Source4:        product-name.png
+Source1:        header-logo.png
+Source2:        login-screen-background.jpg
+Source4:        product-name.png
 # RHEL spec file only: END: Change branding to IPA and Identity Management
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
 # RHEL spec file only: START
-Patch0001:	0001-Coverity-fix-issue-in-ipa_extdom_extop.c.patch
-Patch0002:	0002-Web-UI-topology-graph-Show-FQDN-for-nodes-if-they-ha.patch
-Patch0003:	0003-ipa-replica-manage-fix-force-sync.patch
-Patch0004:	0004-Unify-and-simplify-LDAP-service-discovery.patch
-Patch0005:	0005-Use-api.env.container_masters.patch
-Patch0006:	0006-Consolidate-container_masters-queries.patch
-Patch0007:	0007-Replace-hard-coded-paths-with-path-constants.patch
-Patch0008:	0008-Support-Samba-4.9.patch
-Patch0009:	0009-Add-design-page-for-one-way-trust-to-AD-with-shared-.patch
-Patch0010:	0010-trust-allow-trust-agents-to-read-POSIX-identities-of.patch
-Patch0011:	0011-trusts-add-support-for-one-way-shared-secret-trust.patch
-Patch0012:	0012-upgrade-upgrade-existing-trust-agreements-to-new-lay.patch
-Patch0013:	0013-upgrade-add-trust-upgrade-to-actual-upgrade-code.patch
-Patch0014:	0014-RFE-ipa-client-should-setup-openldap-for-GSSAPI.patch
-Patch0015:	0015-Add-uniqueness-constraint-on-CA-ACL-name.patch
-Patch0016:	0016-Add-sysadm_r-to-default-SELinux-user-map-order.patch
-Patch0017:	0017-Extend-CALessBase-installer_server-to-accept-extra_a.patch
-Patch0018:	0018-Skip-zone-overlap-check-with-auto-reverse.patch
-Patch0019:	0019-Add-hidden-replica-feature.patch
-Patch0020:	0020-ipatests-Exercise-hidden-replica-feature.patch
-Patch0021:	0021-Simplify-and-improve-tests.patch
-Patch0022:	0022-Implement-server-state-state-enabled-hidden.patch
-Patch0023:	0023-Consider-hidden-servers-as-role-provider.patch
-Patch0024:	0024-Improve-config-show-to-show-hidden-servers.patch
-Patch0025:	0025-More-test-fixes.patch
-Patch0026:	0026-Don-t-allow-to-hide-last-server-for-a-role.patch
-Patch0027:	0027-Synchronize-hidden-state-from-IPA-master-role.patch
-Patch0028:	0028-Test-replica-installation-from-hidden-replica.patch
-Patch0029:	0029-Add-design-draft.patch
-Patch0030:	0030-Don-t-fail-if-config-show-does-not-return-servers.patch
-Patch0031:	0031-Extract-ca_renewal-cert-update-subroutine.patch
-Patch0032:	0032-cainstance-add-function-to-determine-ca_renewal-nick.patch
-Patch0033:	0033-constants-add-ca_renewal-container.patch
-Patch0034:	0034-Add-ipa-cert-fix-tool.patch
-Patch0035:	0035-ipa-cert-fix-add-man-page.patch
-Patch0036:	0036-ipa-cert-fix-use-customary-exit-statuses.patch
-Patch0037:	0037-Show-a-notification-that-sssd-needs-restarting-after.patch
-Patch0038:	0038-ipa-server-upgrade-fix-add_systemd_user_hbac.patch
-Patch0039:	0039-ipa-setup-kra-fix-python2-parameter.patch
-Patch0040:	0040-oddjob-allow-to-pass-options-to-trust-fetch-domains.patch
-Patch0041:	0041-adtrust-define-Guests-mapping-after-creating-cifs-pr.patch
-Patch0042:	0042-net-groupmap-force-using-empty-config-when-mapping-G.patch
-Patch0043:	0043-Bypass-D-BUS-interface-definition-deficiences-for-tr.patch
-Patch0044:	0044-ipactl-restart-fix-wrong-logic-when-checking-service.patch
-Patch0045:	0045-replica-install-acknowledge-ca_host-override.patch
-Patch0046:	0046-ipa-console-catch-proper-exception-when-history-file.patch
-Patch0047:	0047-upgrade-adtrust-catch-empty-result-when-retrieving-l.patch
-Patch0048:	0048-Consider-configured-servers-as-valid.patch
-Patch0049:	0049-ipa-cert-fix-handle-pki-server-cert-fix-failure.patch
-Patch0050:	0050-ipa-cert-fix-fix-spurious-renewal-master-change.patch
-Patch0051:	0051-adtrust-upgrade-fix-wrong-primary-principal-name.patch
-Patch0052:	0052-adtrust-upgrade-fix-wrong-primary-principal-name-par.patch
-Patch0053:	0053-trust-fetch-domains-make-sure-we-use-right-KDC-when-.patch
-Patch0054:      0054-add-default-access-control-when-migrating-trust-obje.patch
-Patch0055:      0055-adtrust-add-default-read_keys-permission-for-TDO-obj.patch
-Patch0056:      0056-Disable-deprecated-lambda-check-in-adtrust-upgrade-c.patch
-Patch0057:      0057-Handle-missing-LWCA-certificate-or-chain.patch
-Patch0058:      0058-Fix-CustodiaClient-ccache-handling.patch
-Patch0059:      0059-CustodiaClient-use-ldapi-when-ldap_uri-not-specified.patch
-Patch0060:      0060-CustodiaClient-fix-IPASecStore-config-on-ipa-4-7.patch
-Patch0061:      0061-Bump-krb5-min-version.patch
-Patch0062:      0062-DL0-replica-install-fix-nsDS5ReplicaBindDN-config.patch
-Patch0063:      0063-extdom-unify-error-code-handling-especially-LDAP_NO_.patch
-Patch0064:      0064-ipa-extdom-extop-test-timed-out-getgrgid_r.patch
-Patch0065:      0065-Make-sure-to-have-storage-space-for-tag.patch
-Patch0066:      0066-CVE-2019-10195-Don-t-log-passwords-embedded-in-comma.patch
-Patch0067:      0067-trust-upgrade-ensure-that-host-is-member-of-adtrust-.patch
+Patch0001:      0001-extdom-unify-error-code-handling.patch
+Patch0002:      0002-Use-unicode-strings-for-Python-2-version.patch
+Patch0003:      0003-ipa_sam-remove-dependency-to-talloc_strackframe.h.patch
+Patch0004:      0004-Remove-ZERO_STRUCT-call.patch
+Patch0005:      0005-ipasam-use-SID-formatting-calls-to-libsss_idmap.patch
+Patch0006:      0006-user-stage-transfer-all-attributes-from-preserved-to.patch
+Patch0007:      0007-xmlrpc-test-add-test-for-preserved-stage-user.patch
+Patch0008:      0008-Don-t-return-SSH-keys-with-ipa-host-find-pkey-only.patch
+Patch0009:      0009-check-for-single-label-domains-only-during-server-in.patch
+Patch0010:      0010-Don-t-configure-KEYRING-ccache-in-containers.patch
+Patch0011:      0011-Add-container-environment-check-to-replicainstall.patch
+Patch0012:      0012-add-default-access-control-when-migrating-trust-obje.patch
+Patch0013:      0013-adtrust-add-default-read_keys-permission-for-TDO-obj.patch
+Patch0014:      0014-Disable-deprecated-lambda-check-in-adtrust-upgrade-c.patch
+Patch0015:      0015-Fix-segfault-in-ipadb_parse_ldap_entry.patch
+Patch0016:      0016-ipa-restore-Restore-ownership-and-perms-on-389-ds-lo.patch
+Patch0017:      0017-replica-install-enforce-server-arg.patch
+Patch0018:      0018-Log-INFO-message-when-LDAP-connection-fails-on-start.patch
+Patch0019:      0019-Fix-NULL-pointer-dereference-in-maybe_require_preaut.patch
+Patch0020:      0020-Handle-missing-LWCA-certificate-or-chain.patch
+Patch0021:      0021-Fix-CustodiaClient-ccache-handling.patch
+Patch0022:      0022-CustodiaClient-use-ldapi-when-ldap_uri-not-specified.patch
+Patch0023:      0023-CustodiaClient-fix-IPASecStore-config-on-ipa-4-7.patch
+Patch0024:      0024-Bump-krb5-min-version.patch
+Patch0025:      0025-ipa-backup-fix-python2-issue-with-os.mkdir.patch
+Patch0026:      0026-Do-not-run-trust-upgrade-code-if-master-lacks-Samba-.patch
+Patch0027:      0027-Make-sure-to-have-storage-space-for-tag.patch
+Patch0028:      0028-CVE-2019-10195-Don-t-log-passwords-embedded-in-comma.patch
+Patch0029:      0029-trust-upgrade-ensure-that-host-is-member-of-adtrust-.patch
 Patch1001:      1001-Change-branding-to-IPA-and-Identity-Management.patch
 Patch1002:      1002-Package-copy-schema-to-ca.py.patch
 Patch1003:      1003-Revert-Increased-mod_wsgi-socket-timeout.patch
@@ -234,9 +196,9 @@ BuildRequires: java-1.7.0-openjdk-devel
 BuildRequires:  389-ds-base-devel >= %{ds_version}
 BuildRequires:  svrcore-devel
 %if 0%{?rhel}
-BuildRequires:  samba-devel >= 4.7.0
+BuildRequires:  samba-devel >= 4.10.0
 %else
-BuildRequires:  samba-devel >= 2:4.7.0
+BuildRequires:  samba-devel >= 2:4.10.0
 %endif
 BuildRequires:  libtalloc-devel
 BuildRequires:  libtevent-devel
@@ -443,10 +405,7 @@ Requires: oddjob
 Requires: gssproxy >= 0.7.0-2
 # 1.15.2: FindByNameAndCertificate (https://pagure.io/SSSD/sssd/issue/3050)
 Requires: sssd-dbus >= 1.15.2
-
-%if 0%{?centos} == 0
 Requires: system-logos >= 70.7.0
-%endif
 
 Provides: %{alt_name}-server = %{version}
 Conflicts: %{alt_name}-server
@@ -1003,9 +962,9 @@ cp -r %{_builddir}/freeipa-%{version} %{_builddir}/freeipa-%{version}-python3
 # with_python3
 
 # RHEL spec file only: START: Change branding to IPA and Identity Management
-#cp %SOURCE1 install/ui/images/header-logo.png
-#cp %SOURCE2 install/ui/images/login-screen-background.jpg
-#cp %SOURCE4 install/ui/images/product-name.png
+cp %SOURCE1 install/ui/images/header-logo.png
+cp %SOURCE2 install/ui/images/login-screen-background.jpg
+cp %SOURCE4 install/ui/images/product-name.png
 # RHEL spec file only: END: Change branding to IPA and Identity Management
 
 
@@ -1029,8 +988,7 @@ find \
 %configure --with-vendor-suffix=-%{release} \
            %{enable_server_option} \
            %{with_ipatests_option} \
-           %{linter_options} \
-           --with-ipaplatform=rhel
+           %{linter_options}
 
 %make_build
 
@@ -1051,8 +1009,7 @@ find \
 %configure --with-vendor-suffix=-%{release} \
            %{enable_server_option} \
            %{with_ipatests_option} \
-           %{linter_options} \
-           --with-ipaplatform=rhel
+           %{linter_options}
 popd
 %endif
 # with_python3
@@ -1139,11 +1096,9 @@ ln -s %{_bindir}/ipa-test-task-%{python2_version} %{buildroot}%{_bindir}/ipa-tes
 # remove files which are useful only for make uninstall
 find %{buildroot} -wholename '*/site-packages/*/install_files.txt' -exec rm {} \;
 
-%if 0%{?centos} == 0
 # RHEL spec file only: START: Replace login-screen-logo.png with a symlink
 ln -sf %{_datadir}/pixmaps/fedora-gdm-logo.png %{buildroot}%{_usr}/share/ipa/ui/images/login-screen-logo.png
 # RHEL spec file only: END: Replace login-screen-logo.png with a symlink
-%endif
 
 %find_lang %{gettext_domain}
 
@@ -1555,19 +1510,19 @@ fi
 %dir %{_sysconfdir}/ipa/html
 %config(noreplace) %{_sysconfdir}/ipa/html/ssbrowser.html
 %config(noreplace) %{_sysconfdir}/ipa/html/unauthorized.html
-%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-rewrite.conf
-%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa.conf
-%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-kdc-proxy.conf
-%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-pki-proxy.conf
-%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/kdcproxy/ipa-kdc-proxy.conf
+%ghost %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-rewrite.conf
+%ghost %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa.conf
+%ghost %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-kdc-proxy.conf
+%ghost %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-pki-proxy.conf
+%ghost %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ipa/kdcproxy/ipa-kdc-proxy.conf
 %dir %attr(0755,root,root) %{_sysconfdir}/ipa/dnssec
 %{_usr}/share/ipa/ipa.conf
 %{_usr}/share/ipa/ipa-rewrite.conf
 %{_usr}/share/ipa/ipa-pki-proxy.conf
-%ghost %attr(0644,root,apache) %config(noreplace) %{_usr}/share/ipa/html/ca.crt
-%ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krb.con
-%ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krb5.ini
-%ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krbrealm.con
+%ghost %attr(0644,root,root) %config(noreplace) %{_usr}/share/ipa/html/ca.crt
+%ghost %attr(0644,root,root) %{_usr}/share/ipa/html/krb.con
+%ghost %attr(0644,root,root) %{_usr}/share/ipa/html/krb5.ini
+%ghost %attr(0644,root,root) %{_usr}/share/ipa/html/krbrealm.con
 %dir %{_usr}/share/ipa/updates/
 %{_usr}/share/ipa/updates/*
 %dir %{_localstatedir}/lib/ipa
@@ -1576,8 +1531,8 @@ fi
 %attr(711,root,root) %dir %{_localstatedir}/lib/ipa/sysrestore
 %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysupgrade
 %attr(755,root,root) %dir %{_localstatedir}/lib/ipa/pki-ca
-%ghost %{_localstatedir}/lib/ipa/pki-ca/publish
-%ghost %{_localstatedir}/named/dyndb-ldap/ipa
+%ghost %attr(775,root,pkiuser) %{_localstatedir}/lib/ipa/pki-ca/publish
+%ghost %attr(770,named,named) %{_localstatedir}/named/dyndb-ldap/ipa
 %dir %attr(0700,root,root) %{_sysconfdir}/ipa/custodia
 %dir %{_usr}/share/ipa/schema.d
 %attr(0644,root,root) %{_usr}/share/ipa/schema.d/README
@@ -1681,19 +1636,20 @@ fi
 %doc README.md Contributors.txt
 %license COPYING
 %dir %attr(0755,root,root) %{_sysconfdir}/ipa/
-%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/default.conf
-%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/ca.crt
+%ghost %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ipa/default.conf
+%ghost %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ipa/ca.crt
 %dir %attr(0755,root,root) %{_sysconfdir}/ipa/nssdb
 # old dbm format
-%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/cert8.db
-%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/key3.db
-%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/secmod.db
+%ghost %attr(644,root,root) %config(noreplace) %{_sysconfdir}/ipa/nssdb/cert8.db
+%ghost %attr(644,root,root) %config(noreplace) %{_sysconfdir}/ipa/nssdb/key3.db
+%ghost %attr(644,root,root) %config(noreplace) %{_sysconfdir}/ipa/nssdb/secmod.db
+%ghost %attr(600,root,root) %config(noreplace) %{_sysconfdir}/ipa/nssdb/pwdfile.txt
 # new sql format
-%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/cert9.db
-%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/key4.db
-%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/pkcs11.txt
-%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/pwdfile.txt
-%ghost %config(noreplace) %{_sysconfdir}/pki/ca-trust/source/ipa.p11-kit
+%ghost %attr(644,root,root) %config(noreplace) %{_sysconfdir}/ipa/nssdb/cert9.db
+%ghost %attr(644,root,root) %config(noreplace) %{_sysconfdir}/ipa/nssdb/key4.db
+%ghost %attr(644,root,root) %config(noreplace) %{_sysconfdir}/ipa/nssdb/pkcs11.txt
+%ghost %attr(600,root,root) %config(noreplace) %{_sysconfdir}/ipa/nssdb/pwdfile.txt
+%ghost %attr(644,root,root) %config(noreplace) %{_sysconfdir}/pki/ca-trust/source/ipa.p11-kit
 %dir %{_localstatedir}/lib/ipa-client
 %dir %{_localstatedir}/lib/ipa-client/pki
 %dir %{_localstatedir}/lib/ipa-client/sysrestore
@@ -1795,36 +1751,88 @@ fi
 
 
 %changelog
-* Tue Feb 04 2020 CentOS Sources <bugs@centos.org> - 4.6.5-11.el7.centos.4
-- Roll in CentOS Branding
-
-* Mon Dec 16 2019 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.5-11.el7_7.4
-- Resolves: #1781153 - After upgrade AD Trust Agents were removed from LDAP
+* Wed Dec 4 2019 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.6-11.el7
+- Resolves: #1778777 - After upgrade AD Trust Agents were removed from LDAP
   - trust upgrade: ensure that host is member of adtrust agents
-- Resolves: #1777303 - CVE-2019-10195 ipa: batch API logging user passwords to /var/log/httpd/error_log
+
+* Tue Nov 26 2019 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.6-10.el7
+- Resolves: #1728123 - EMBARGOED CVE-2019-10195 ipa: FreeIPA: batch API logging user passwords to /var/log/httpd/error_log [rhel-7]
   - CVE-2019-10195: Don't log passwords embedded in commands in calls using batch
-- Resolves: #1773953 - User incorrectly added to negative cache when backend is reconnecting to IPA service / timed out: error code 32 'No such object'
-  - extdom: unify error code handling especially LDAP_NO_SUCH_OBJECT
-  - ipa-extdom-extop: test timed out getgrgid_r
-- Resolves: #1770728 - Issue with adding multiple RHEL 7 IPA replica to RHEL 6 IPA master
-  - DL0 replica install: fix nsDS5ReplicaBindDN config 
-- Resolves: #1767300 - CVE-2019-14867 ipa: Denial of service in IPA server due to wrong use of ber_scanf()
-  - Make sure to have storage space for tag 
-
-* Mon Sep 30 2019 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.5-11.el7_7.3
-- Resolves: #1756914 - Sub-CA key replication failure
+- Resolves: #1773550 - IPA upgrade fails for latest ipa package when adtrust is installed
+  - Do not run trust upgrade code if master lacks Samba bindings
+- Resolves: #1767302 - EMBARGOED CVE-2019-14867 ipa: Denial of service in IPA server due to wrong use of ber_scanf() [rhel-7.8]
+  - Make sure to have storage space for tag
+
+* Wed Oct 30 2019 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.6-9.el7
+- Resolves: #1762317 - ipa-backup command is failing on rhel-7.8
+  -  ipa-backup: fix python2 issue with os.mkdir
+
+* Mon Sep 30 2019 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.6-8.el7
+- Resolves: #1755223 - Sub-CA key replication failure
   - Handle missing LWCA certificate or chain
   - Fix CustodiaClient ccache handling
   - CustodiaClient: use ldapi when ldap_uri not specified
   - CustodiaClient: fix IPASecStore config on ipa-4-7
   - Bump krb5 min version
 
-* Tue Sep 17 2019 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.5-11.el7_7.2
-- Resolves: #1752740 - when migrating trusted domain object structure, add default access control definitions, if they were missing in old trust objects
+* Tue Sep 24 2019 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.6-7.el7
+- Resolves: #1754494 - ipa-replica-install does not enforce --server option
+  - replica install: enforce --server arg
+- Resolves: #1729638 - ipa_kdb: assertion failure from NULL lcontext pointer to ldap_get_values_len()
+  - Fix segfault in ipadb_parse_ldap_entry()
+  - Log INFO message when LDAP connection fails on startup
+  - Fix NULL pointer dereference in maybe_require_preauth()
+- Resolves: #1636765 - ipa-restore set wrong file permissions and ownership for /var/log/dirsrv/slapd- directory
+  - ipa-restore: Restore ownership and perms on 389-ds log directory
+
+* Tue Sep 17 2019 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.6-6.el7
+- Resolves: #1752005 - Keyrings should not be used in containerized environment
+  - Don't configure KEYRING ccache in containers
+- Resolves: #1751951 - When master's IP address does not resolve to its name, ipa-replica-install fails
+  - Add container environment check to replicainstall
+- Resolves: #1750700 - when migrating trusted domain object structure, add default access control definitions, if they were missing in old trust objects
   - add default access control when migrating trust objects
   - adtrust: add default read_keys permission for TDO objects
   - Disable deprecated-lambda check in adtrust upgrade code
 
+* Mon Sep 09 2019 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.6-5.el7
+- Resolves: #1749788 - ipa host-find --pkey-only includes SSH keys in output
+  - Don't return SSH keys with ipa host-find --pkey-only
+- Resolves: #1745108 - Bug 1497334 invalidating single-label domains introduces regression of usage for customers
+  - check for single-label domains only during server install
+- Resolves: #1583950 - IPA: IDM drops all custom attributes when moving account from preserved to stage
+  - user-stage: transfer all attributes from preserved to stage user
+  - xmlrpc test: add test for preserved > stage user
+
+* Fri Aug 23 2019 Alexander Bokovoy <abokovoy@redhat.com> - 4.6.6-4.el7
+- Resolves: 1744926 - rebuild against Samba 4.10 to solve undefined symbol: DEBUGLEVEL_CLASS
+- Backport patches to compile against Samba 4.10
+- Fix Python 2 compatibility in adtrustinstance
+
+* Mon Aug 19 2019 Alexander Bokovoy <abokovoy@redhat.com> - 4.6.6-3.el7
+- Resolves: 1717008 - User incorrectly added to negative cache when backend is reconnecting to IPA service / timed out: error code 32 'No such object'
+
+* Wed Aug 14 2019 Rob Crittenden <rcritten@redhat.com> - 4.6.6-2.el7
+- Rebuild
+
+* Mon Jul 29 2019 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.6-1.el7
+- Resolves: 1733075 - Rebase IPA to latest 4.6.x version
+- Resolves: 1512952 - cert renewal is failing when ipa ca cert is renewed from self-signed > external ca > self-sign
+- Resolves: 1544470 - cn=cacert could show expired certificate
+- Resolves: 1581583 - Error message should be more useful while ipa-backup fails for insufficient space
+- Resolves: 1632351 - remove "last init status" from ipa-replica-manage list <node> if it's None.
+- Resolves: 1691939 - False error is shown when options are added to an existing sudo rule using 'sudooption'
+- Resolves: 1695685 - IPA Web UI is slow to display user details page
+- Resolves: 1702426 - ipa-server-common expected file permissions in package don't match runtime permissions
+- Resolves: 1711172 - Removing TLSv1.0, TLSv1.1 from nss.conf
+- Resolves: 1714076 - Issue with adding multiple RHEL 7 IPA replica to RHEL 6 IPA master
+- Resolves: 1714921 - x509.Name -> ipapython.dn.DN does not handle multi-valued RDNs
+- Resolves: 1720952 - Cannot modify TTL with ipa dnsrecord-mod --ttl alone on command line
+- Resolves: 1721550 - Staged user is not being recognized if the user entry doesn't have an objectClass "posixaccount"
+- Resolves: 1727304 - Restrict cipher lists used by openssl connections
+- Resolves: 1733209 - ipa-client-automount needs option to specify domain
+- Resolves: 1733265 - IPA webgui incorrectly display number of entries in ID views
+
 * Fri Jun 28 2019 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.5-11.el7
 - Resolves: 1723473 - ipa upgrade fails with trust entry already exists
   - adtrust upgrade: fix wrong primary principal name, part 2