diff --git a/.gitignore b/.gitignore
index 3912c13..a08d1d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/freeipa-4.9.10.tar.gz
+SOURCES/freeipa-4.9.11.tar.gz
diff --git a/.ipa.metadata b/.ipa.metadata
index 81f398b..f1dac03 100644
--- a/.ipa.metadata
+++ b/.ipa.metadata
@@ -1 +1 @@
-8f2b6a7f52348421fa7c67048dd5ae454f2642fb SOURCES/freeipa-4.9.10.tar.gz
+4ef188d43f5f2a09e214dd2bae68595a5977bb61 SOURCES/freeipa-4.9.11.tar.gz
diff --git a/README.debrand b/README.debrand
deleted file mode 100644
index 01c46d2..0000000
--- a/README.debrand
+++ /dev/null
@@ -1,2 +0,0 @@
-Warning: This package was configured for automatic debranding, but the changes
-failed to apply.
diff --git a/SOURCES/0001-ipa-otpd-Fix-build-on-older-versions-of-gcc.patch b/SOURCES/0001-ipa-otpd-Fix-build-on-older-versions-of-gcc.patch
deleted file mode 100644
index 4852df8..0000000
--- a/SOURCES/0001-ipa-otpd-Fix-build-on-older-versions-of-gcc.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From ff54fe2fdfbab11e08a138cdfd0da900ee865e3d Mon Sep 17 00:00:00 2001
-From: Rafael Guterres Jeffman <rjeffman@redhat.com>
-Date: Fri, 17 Jun 2022 11:22:32 -0300
-Subject: [PATCH] ipa-otpd: Fix build on older versions of gcc.
-
-Older versions of gcc do not support unnamed parameters.
-
-This patch fixes the build on older gcc by applying the same idiom for
-unsued parameters as used by other functions in the same module.
-
-Signed-off-by: Rafael Guterres Jeffman <rjeffman@redhat.com>
----
- daemons/ipa-otpd/oauth2.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/daemons/ipa-otpd/oauth2.c b/daemons/ipa-otpd/oauth2.c
-index df1ffd50d..11d5c135f 100644
---- a/daemons/ipa-otpd/oauth2.c
-+++ b/daemons/ipa-otpd/oauth2.c
-@@ -319,8 +319,9 @@ static int check_access_token_reply(struct child_ctx *child_ctx,
-     return ret;
- }
- 
--static void oauth2_on_child_readable(verto_ctx *, verto_ev *ev)
-+static void oauth2_on_child_readable(verto_ctx *vctx, verto_ev *ev)
- {
-+    (void)vctx; /* Unused */
-     static char buf[10240];
-     ssize_t io = 0;
-     struct child_ctx *child_ctx = NULL;
--- 
-2.36.1
-
diff --git a/SOURCES/0001-updates-fix-memberManager-ACI-to-allow-managers-from-a-specified-group_rhbz#2056009.patch b/SOURCES/0001-updates-fix-memberManager-ACI-to-allow-managers-from-a-specified-group_rhbz#2056009.patch
new file mode 100644
index 0000000..ecbb24f
--- /dev/null
+++ b/SOURCES/0001-updates-fix-memberManager-ACI-to-allow-managers-from-a-specified-group_rhbz#2056009.patch
@@ -0,0 +1,41 @@
+From 651e28c1fb6b86ad1fbd4ea98644e00b7042499c Mon Sep 17 00:00:00 2001
+From: Alexander Bokovoy <abokovoy@redhat.com>
+Date: Dec 02 2022 12:21:22 +0000
+Subject: updates: fix memberManager ACI to allow managers from a specified group
+
+
+The original implementation of the member manager added support for both
+user and group managers but left out upgrade scenario. This means when
+upgrading existing installation a manager whose rights defined by the
+group membership would not be able to add group members until the ACI is
+fixed.
+
+Remove old ACI and add a full one during upgrade step.
+
+Fixes: https://pagure.io/freeipa/issue/9286
+Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
+Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
+
+---
+
+diff --git a/install/updates/20-aci.update b/install/updates/20-aci.update
+index a168bb9..4a7ba13 100644
+--- a/install/updates/20-aci.update
++++ b/install/updates/20-aci.update
+@@ -141,11 +141,13 @@ add:aci:(targetattr = "usercertificate")(version 3.0;acl "selfservice:Users can 
+ 
+ # Allow member managers to modify members of user groups
+ dn: cn=groups,cn=accounts,$SUFFIX
+-add:aci: (targetattr = "member")(targetfilter = "(objectclass=ipaUserGroup)")(version 3.0; acl "Allow member managers to modify members of user groups"; allow (write) userattr = "memberManager#USERDN";)
++remove:aci: (targetattr = "member")(targetfilter = "(objectclass=ipaUserGroup)")(version 3.0; acl "Allow member managers to modify members of user groups"; allow (write) userattr = "memberManager#USERDN";)
++add:aci: (targetattr = "member")(targetfilter = "(objectclass=ipaUserGroup)")(version 3.0; acl "Allow member managers to modify members of user groups"; allow (write) userattr = "memberManager#USERDN" or userattr = "memberManager#GROUPDN";)
+ 
+ # Allow member managers to modify members of host groups
+ dn: cn=hostgroups,cn=accounts,$SUFFIX
+-add:aci: (targetattr = "member")(targetfilter = "(objectclass=ipaHostGroup)")(version 3.0; acl "Allow member managers to modify members of host groups"; allow (write) userattr = "memberManager#USERDN";)
++remove:aci: (targetattr = "member")(targetfilter = "(objectclass=ipaHostGroup)")(version 3.0; acl "Allow member managers to modify members of host groups"; allow (write) userattr = "memberManager#USERDN";)
++add:aci: (targetattr = "member")(targetfilter = "(objectclass=ipaHostGroup)")(version 3.0; acl "Allow member managers to modify members of host groups"; allow (write) userattr = "memberManager#USERDN" or userattr = "memberManager#GROUPDN";)
+ 
+ # Hosts can add and delete their own services
+ dn: cn=services,cn=accounts,$SUFFIX
+
diff --git a/SOURCES/0002-trust-add-handle-missing-msSFU30MaxGidNumber_rhbz#2162355.patch b/SOURCES/0002-trust-add-handle-missing-msSFU30MaxGidNumber_rhbz#2162355.patch
new file mode 100644
index 0000000..965e3bd
--- /dev/null
+++ b/SOURCES/0002-trust-add-handle-missing-msSFU30MaxGidNumber_rhbz#2162355.patch
@@ -0,0 +1,46 @@
+From 703ab8c4dfb7f8fd1540c3849ad469d39695a26f Mon Sep 17 00:00:00 2001
+From: Florence Blanc-Renaud <flo@redhat.com>
+Date: Jan 25 2023 16:57:02 +0000
+Subject: trust-add: handle missing msSFU30MaxGidNumber
+
+
+When ipa trust-add is executed with --range-type ad-trust-posix,
+the server tries to find the max uidnumber and max gidnumber
+from AD domain controller.
+The values are extracted from the entry
+CN=<domain>,CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System,<AD suffix>
+in the msSFU30MaxUidNumber and msSFU30MaxGidNumber attributes.
+
+msSFU30MaxUidNumber is required but not msSFU30MaxGidNumber.
+In case msSFU30MaxGidNumber is missing, the code is currently assigning
+a "None" value and later on evaluates the max between this value and
+msSFU30MaxUidNumber. The max function cannot compare None and a list
+of string and triggers an exception.
+
+To avoid the exception, assign [b'0'] to max gid if msSFU30MaxGidNumber
+is missing. This way, the comparison succeeds and max returns the
+value from msSFU30MaxUidNumber.
+
+Fixes: https://pagure.io/freeipa/issue/9310
+Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+
+---
+
+diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py
+index c074f6d..79264b8 100644
+--- a/ipaserver/plugins/trust.py
++++ b/ipaserver/plugins/trust.py
+@@ -379,7 +379,10 @@ def add_range(myapi, trustinstance, range_name, dom_sid, *keys, **options):
+                 range_type = u'ipa-ad-trust-posix'
+ 
+                 max_uid = info.get('msSFU30MaxUidNumber')
+-                max_gid = info.get('msSFU30MaxGidNumber', None)
++                # if max_gid is missing, assume 0 and the max will
++                # be obtained from max_uid. We just checked that
++                # msSFU30MaxUidNumber is defined
++                max_gid = info.get('msSFU30MaxGidNumber', [b'0'])
+                 max_id = int(max(max_uid, max_gid)[0])
+ 
+                 base_id = int(info.get('msSFU30OrderNumber')[0])
+
diff --git a/SOURCES/0002-webui-IdP-Remove-arrow-notation-due-to-uglify-js-lim.patch b/SOURCES/0002-webui-IdP-Remove-arrow-notation-due-to-uglify-js-lim.patch
deleted file mode 100644
index 7928884..0000000
--- a/SOURCES/0002-webui-IdP-Remove-arrow-notation-due-to-uglify-js-lim.patch
+++ /dev/null
@@ -1,60 +0,0 @@
-From 7807bcc55b4927fc327830d2237200772d2e1106 Mon Sep 17 00:00:00 2001
-From: Rafael Guterres Jeffman <rjeffman@redhat.com>
-Date: Fri, 17 Jun 2022 15:40:04 -0300
-Subject: [PATCH] webui IdP: Remove arrow notation due to uglify-js limitation.
-
-uglify-js 2.x series do not support ECMAScript 6 arrow notation ('=>')
-for callback definition.
-
-This patch changes the arrow definition callbacks for regular anonymous
-function definitions.
----
- install/ui/src/freeipa/idp.js | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/install/ui/src/freeipa/idp.js b/install/ui/src/freeipa/idp.js
-index ada09c075..be3c4f0e6 100644
---- a/install/ui/src/freeipa/idp.js
-+++ b/install/ui/src/freeipa/idp.js
-@@ -227,7 +227,7 @@ IPA.add_idp_policy = function() {
-         // For custom template we show custom fields
-         // and mark all of them required and passed to the RPC
-         // If show_custom is false, the opposite happens
--        custom_fields.forEach(fname => {
-+        custom_fields.forEach(function(fname) {
-             widget_f = that.container.fields.get_field(fname);
-             widget_f.set_required(show_custom);
-             widget_f.set_enabled(show_custom);
-@@ -235,7 +235,7 @@ IPA.add_idp_policy = function() {
-         });
- 
-         // For template fields we show them if custom aren't shown
--        template_fields.forEach(fname => {
-+        template_fields.forEach(function(fname) {
-             widget_f = that.container.fields.get_field(fname);
-             widget_f.set_enabled(!show_custom);
-             widget_f.widget.set_visible(!show_custom);
-@@ -252,7 +252,7 @@ IPA.add_idp_policy = function() {
-         var value = prov_f.get_value()[0];
- 
-         // First, clear template fields from the previous provider choice
--        template_fields.forEach(fname => {
-+        template_fields.forEach(function(fname) {
-             widget_f = that.container.fields.get_field(fname);
-             widget_f.widget.set_visible(false);
-             widget_f.set_required(false);
-@@ -260,9 +260,9 @@ IPA.add_idp_policy = function() {
-         });
- 
-         // Second, enable and get required template-specific fields
--        idp.templates.forEach(idp_v => {
-+        idp.templates.forEach(function(idp_v) {
-             if (idp_v['value'] == value) {
--                idp_v['fields'].forEach(fname => {
-+                idp_v['fields'].forEach(function(fname) {
-                     widget_f = that.container.fields.get_field(fname);
-                     widget_f.set_required(true);
-                     widget_f.set_enabled(true);
--- 
-2.36.1
-
diff --git a/SOURCES/0003-Backport-latest-test-fixes-python3-ipatests_rhbz#2166929.patch b/SOURCES/0003-Backport-latest-test-fixes-python3-ipatests_rhbz#2166929.patch
new file mode 100644
index 0000000..b980ab8
--- /dev/null
+++ b/SOURCES/0003-Backport-latest-test-fixes-python3-ipatests_rhbz#2166929.patch
@@ -0,0 +1,76 @@
+From e8ef2c2f226704ce510525f07675107179124a95 Mon Sep 17 00:00:00 2001
+From: Sumedh Sidhaye <ssidhaye@redhat.com>
+Date: Feb 02 2023 06:53:56 +0000
+Subject: With the commit #99a74d7, 389-ds changed the message returned in ipa-healthcheck.
+
+
+Previously the message was:
+
+"\n\nIn Directory Server, we offer one hash suitable for this "
+"(PBKDF2_SHA256) and one hash\nfor \"legacy\" support (SSHA512)."
+"\n\nYour configuration does not use these for password storage "
+"or the root password storage\nscheme.\n"
+
+but now the message is:
+
+\n\nIn Directory Server, we offer one hash suitable for this "
+"(PBKDF2-SHA512) and one hash\nfor \"legacy\" support (SSHA512)."
+"\n\nYour configuration does not use these for password storage "
+"or the root password storage\nscheme.\n"
+
+PBKDF2_SHA256 has been replaced with PBKDF2-SHA512
+
+Pagure: https://pagure.io/freeipa/issue/9238
+
+Signed-off-by: Sumedh Sidhaye <ssidhaye@redhat.com>
+Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+Reviewed-By: Stanislav Levin <slev@altlinux.org>
+Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+Reviewed-By: Stanislav Levin <slev@altlinux.org>
+
+---
+
+diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py
+index 18a665e..60e8de9 100644
+--- a/ipatests/test_integration/test_ipahealthcheck.py
++++ b/ipatests/test_integration/test_ipahealthcheck.py
+@@ -1312,9 +1312,6 @@ class TestIpaHealthCheck(IntegrationTest):
+         """
+         error_msg = (
+             "\n\nIn Directory Server, we offer one hash suitable for this "
+-            "(PBKDF2_SHA256) and one hash\nfor \"legacy\" support (SSHA512)."
+-            "\n\nYour configuration does not use these for password storage "
+-            "or the root password storage\nscheme.\n"
+         )
+         returncode, data = run_healthcheck(
+             self.master, "ipahealthcheck.ds.config", "ConfigCheck",
+
+From 1bdd8147e7fa1032025dc6f6868e26f285744ee1 Mon Sep 17 00:00:00 2001
+From: Florence Blanc-Renaud <flo@redhat.com>
+Date: Jan 11 2023 11:56:30 +0000
+Subject: ipatests: mark test_smb as xfail
+
+
+Mark the test test_smb.py::TestSMB::test_smb_service_s4u2self as xfail.
+
+Related: https://pagure.io/freeipa/issue/9124
+Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+
+---
+
+diff --git a/ipatests/test_integration/test_smb.py b/ipatests/test_integration/test_smb.py
+index eb3981b..30f8d59 100644
+--- a/ipatests/test_integration/test_smb.py
++++ b/ipatests/test_integration/test_smb.py
+@@ -349,6 +349,7 @@ class TestSMB(IntegrationTest):
+     @pytest.mark.skipif(
+         osinfo.id == 'fedora' and osinfo.version_number <= (31,),
+         reason='Test requires krb 1.18')
++    @pytest.mark.xfail(reason="Pagure ticket 9124", strict=True)
+     def test_smb_service_s4u2self(self):
+         """Test S4U2Self operation by IPA service
+            against both AD and IPA users
+
diff --git a/SOURCES/0003-Preserve-user-fix-the-confusing-summary_rhbz#2022028.patch b/SOURCES/0003-Preserve-user-fix-the-confusing-summary_rhbz#2022028.patch
deleted file mode 100644
index a7b9808..0000000
--- a/SOURCES/0003-Preserve-user-fix-the-confusing-summary_rhbz#2022028.patch
+++ /dev/null
@@ -1,131 +0,0 @@
-From ff4152539b96d309dcceaf854a3e0a49f435acff Mon Sep 17 00:00:00 2001
-From: Florence Blanc-Renaud <flo@redhat.com>
-Date: Mon, 20 Jun 2022 09:09:11 +0200
-Subject: [PATCH] Preserve user: fix the confusing summary
-
-When ipa user-del --preserve is called, the command output
-prints a summary with:
-    Deleted user: user1
-although the user was preserved.
-Replace the summary with
-    Preserved user: user1
-to reflect what was actually done.
-
-Fixes: https://pagure.io/freeipa/issue/9187
-Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
-Reviewed-By: Michal Polovka <mpolovka@redhat.com>
-Reviewed-By: Rob Crittenden <rcritten@redhat.com>
----
- ipaserver/plugins/user.py | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py
-index 25d2bb6aa..fa8a67d3d 100644
---- a/ipaserver/plugins/user.py
-+++ b/ipaserver/plugins/user.py
-@@ -56,6 +56,7 @@ from .idviews import remove_ipaobject_overrides
- from ipalib.plugable import Registry
- from .baseldap import (
-     LDAPObject,
-+    pkey_to_unicode,
-     pkey_to_value,
-     LDAPCreate,
-     LDAPSearch,
-@@ -701,6 +702,7 @@ class user_del(baseuser_del):
-     __doc__ = _('Delete a user.')
- 
-     msg_summary = _('Deleted user "%(value)s"')
-+    msg_summary_preserved = _('Preserved user "%(value)s"')
- 
-     takes_options = baseuser_del.takes_options + (
-         Bool('preserve?',
-@@ -831,6 +833,8 @@ class user_del(baseuser_del):
-                     failed.append(pkey_to_value(pkey, options))
- 
-             val = dict(result=dict(failed=failed), value=preserved)
-+            val['summary'] = self.msg_summary_preserved % dict(
-+                value=pkey_to_unicode(preserved))
-             return val
-         else:
-             return super(user_del, self).execute(*keys, **options)
--- 
-2.36.1
-
-From 4984ff210a169129e4e56b10e54e9c795520855c Mon Sep 17 00:00:00 2001
-From: Florence Blanc-Renaud <flo@redhat.com>
-Date: Mon, 20 Jun 2022 09:12:14 +0200
-Subject: [PATCH] xmlrpc tests: updated expected output for preserved user
-
-Update the expected summary for the command
-ipa user-del --preserve
-
-The command now displays: Preserved user: user1
-instead of                Deleted user: user1
-
-Related: https://pagure.io/freeipa/issue/9187
-
-Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
-Reviewed-By: Michal Polovka <mpolovka@redhat.com>
-Reviewed-By: Rob Crittenden <rcritten@redhat.com>
----
- ipatests/test_xmlrpc/test_stageuser_plugin.py | 5 ++++-
- ipatests/test_xmlrpc/tracker/user_plugin.py   | 7 ++++++-
- 2 files changed, 10 insertions(+), 2 deletions(-)
-
-diff --git a/ipatests/test_xmlrpc/test_stageuser_plugin.py b/ipatests/test_xmlrpc/test_stageuser_plugin.py
-index bc606b093..fd146876c 100644
---- a/ipatests/test_xmlrpc/test_stageuser_plugin.py
-+++ b/ipatests/test_xmlrpc/test_stageuser_plugin.py
-@@ -479,11 +479,12 @@ class TestActive(XMLRPC_test):
- 
-     def test_delete_preserve(self, user):
-         user.ensure_exists()
--        user.track_delete()
-+        user.track_delete(preserve=True)
-         command = user.make_delete_command(no_preserve=False, preserve=True)
-         result = command()
-         user.check_delete(result)
- 
-+        user.track_delete(preserve=False)
-         command = user.make_delete_command()
-         result = command()
-         user.check_delete(result)
-@@ -622,6 +623,7 @@ class TestCustomAttr(XMLRPC_test):
-         assert 'BusinessCat' in result['result'][u'businesscategory']
- 
-         # delete the user with --preserve
-+        user_customattr.track_delete(preserve=True)
-         command = user_customattr.make_delete_command(no_preserve=False,
-                                                       preserve=True)
-         result = command()
-@@ -763,6 +765,7 @@ class TestGroups(XMLRPC_test):
-         result = command()
-         group.check_retrieve(result)
- 
-+        user.track_delete(preserve=True)
-         command = user.make_delete_command(no_preserve=False, preserve=True)
-         result = command()
-         user.check_delete(result)
-diff --git a/ipatests/test_xmlrpc/tracker/user_plugin.py b/ipatests/test_xmlrpc/tracker/user_plugin.py
-index 03c106250..b04be4c19 100644
---- a/ipatests/test_xmlrpc/tracker/user_plugin.py
-+++ b/ipatests/test_xmlrpc/tracker/user_plugin.py
-@@ -273,9 +273,14 @@ class UserTracker(CertmapdataMixin, KerberosAliasMixin, Tracker):
- 
-     def check_delete(self, result):
-         """ Check 'user-del' command result """
-+        if u'preserved' in self.attrs and self.attrs[u'preserved']:
-+            summary = u'Preserved user "%s"' % self.uid
-+        else:
-+            summary = u'Deleted user "%s"' % self.uid
-+
-         assert_deepequal(dict(
-             value=[self.uid],
--            summary=u'Deleted user "%s"' % self.uid,
-+            summary=summary,
-             result=dict(failed=[]),
-             ), result)
- 
--- 
-2.36.1
-
diff --git a/SOURCES/0004-Only-calculate-LDAP-password-grace-when-the-password_rhbz#782917.patch b/SOURCES/0004-Only-calculate-LDAP-password-grace-when-the-password_rhbz#782917.patch
deleted file mode 100644
index 54da08a..0000000
--- a/SOURCES/0004-Only-calculate-LDAP-password-grace-when-the-password_rhbz#782917.patch
+++ /dev/null
@@ -1,56 +0,0 @@
-From 3675bd1d7aca443832bb9bb2f521cc4d3a088aec Mon Sep 17 00:00:00 2001
-From: Rob Crittenden <rcritten@redhat.com>
-Date: Wed, 29 Jun 2022 13:25:55 +0000
-Subject: [PATCH] Only calculate LDAP password grace when the password is
- expired
-
-The user's pwd expiration was retrieved but inadvertently was never
-compared to current time. So any LDAP bind, including from the
-IPA API, counted against the grace period. There is no need to go
-through the graceperiod code for non-expired passwords.
-
-https://pagure.io/freeipa/issue/1539
-
-Signed-off-by: Rob Crittenden <rcritten@redhat.com>
-Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
----
- .../ipa-graceperiod/ipa_graceperiod.c                | 12 +++++++++---
- 1 file changed, 9 insertions(+), 3 deletions(-)
-
-diff --git a/daemons/ipa-slapi-plugins/ipa-graceperiod/ipa_graceperiod.c b/daemons/ipa-slapi-plugins/ipa-graceperiod/ipa_graceperiod.c
-index 0860b5c20..a3f57cb4b 100644
---- a/daemons/ipa-slapi-plugins/ipa-graceperiod/ipa_graceperiod.c
-+++ b/daemons/ipa-slapi-plugins/ipa-graceperiod/ipa_graceperiod.c
-@@ -359,7 +359,8 @@ static int ipagraceperiod_preop(Slapi_PBlock *pb)
-     Slapi_ValueSet *values = NULL;
-     long grace_limit = 0;
-     int grace_user_time;
--    char *pwd_expiration = NULL;
-+    char *tmpstr = NULL;
-+    time_t pwd_expiration;
-     int pwresponse_requested = 0;
-     Slapi_PBlock *pbtm = NULL;
-     Slapi_Mods *smods = NULL;
-@@ -414,12 +415,17 @@ static int ipagraceperiod_preop(Slapi_PBlock *pb)
-     }
-     slapi_value_free(&objectclass);
- 
--    pwd_expiration = slapi_entry_attr_get_charptr(target_entry, "krbPasswordExpiration");
--    if (pwd_expiration == NULL) {
-+    tmpstr = slapi_entry_attr_get_charptr(target_entry, "krbPasswordExpiration");
-+    if (tmpstr == NULL) {
-         /* No expiration means nothing to do */
-         LOG_TRACE("No krbPasswordExpiration for %s, nothing to do\n", dn);
-         goto done;
-     }
-+    pwd_expiration = ipapwd_gentime_to_time_t(tmpstr);
-+    if (pwd_expiration > time(NULL)) {
-+        /* Not expired, nothing to see here */
-+        goto done;
-+    }
- 
-     ldrc = ipagraceperiod_getpolicy(target_entry, &policy_entry,
-                                     &values, &actual_type_name,
--- 
-2.36.1
-
diff --git a/SOURCES/0004-server-install-remove-error-log-about-missing-bkup-file_rhbz#2160389.patch b/SOURCES/0004-server-install-remove-error-log-about-missing-bkup-file_rhbz#2160389.patch
new file mode 100644
index 0000000..63a358c
--- /dev/null
+++ b/SOURCES/0004-server-install-remove-error-log-about-missing-bkup-file_rhbz#2160389.patch
@@ -0,0 +1,52 @@
+From 6f50b00953c0000d6da8db0f5e8974ae33d7b5d5 Mon Sep 17 00:00:00 2001
+From: Florence Blanc-Renaud <flo@redhat.com>
+Date: Jan 16 2023 07:44:50 +0000
+Subject: server install: remove error log about missing bkup file
+
+
+The client installer code can be called in 3 different ways:
+- from ipa-client-install CLI
+- from ipa-replica-install CLI if the client is not already installed
+- from ipa-server-install
+
+In the last case, the client installer is called with
+options.on_master=True
+As a result, it's skipping the part that is creating the krb5
+configuration:
+    if not options.on_master:
+        nolog = tuple()
+        configure_krb5_conf(...)
+
+The configure_krb5_conf method is the place where the krb5.conf file is
+backup'ed with the extention ".ipabkp". For a master installation, this
+code is not called and the ipabkp file does not exist => delete raises
+an error.
+
+When delete fails because the file does not exist, no need to log an
+error message.
+
+Fixes: https://pagure.io/freeipa/issue/9306
+Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
+Reviewed-By: Rob Crittenden <rcritten@redhat.com>
+
+---
+
+diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py
+index e5d3e82..6e7f17d 100644
+--- a/ipaclient/install/client.py
++++ b/ipaclient/install/client.py
+@@ -124,10 +124,9 @@ def cleanup(func):
+             os.rmdir(ccache_dir)
+         except OSError:
+             pass
+-        try:
+-            os.remove(krb_name + ".ipabkp")
+-        except OSError:
+-            logger.error("Could not remove %s.ipabkp", krb_name)
++        # During master installation, the .ipabkp file is not created
++        # Ignore the delete error if it is "file does not exist"
++        remove_file(krb_name + ".ipabkp")
+ 
+     return inner
+ 
+
diff --git a/SOURCES/0005-Add-end-to-end-integration-tests-for-external-IdP.patch b/SOURCES/0005-Add-end-to-end-integration-tests-for-external-IdP.patch
deleted file mode 100644
index 700df13..0000000
--- a/SOURCES/0005-Add-end-to-end-integration-tests-for-external-IdP.patch
+++ /dev/null
@@ -1,346 +0,0 @@
-From 857713c5a9c8e0b62c06dd92e69c09eeb34b2e99 Mon Sep 17 00:00:00 2001
-From: Anuja More <amore@redhat.com>
-Date: Mon, 23 May 2022 12:26:34 +0530
-Subject: [PATCH] Add end to end integration tests for external IdP
-
-Added tests for HBAC and SUDO rule and other
-test scenarios.
-
-Related : https://pagure.io/freeipa/issue/8805
-Related: https://pagure.io/freeipa/issue/8803
-Related: https://pagure.io/freeipa/issue/8804
-
-Signed-off-by: Anuja More <amore@redhat.com>
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
----
- ipatests/test_integration/test_idp.py | 260 ++++++++++++++++++++++----
- 1 file changed, 226 insertions(+), 34 deletions(-)
-
-diff --git a/ipatests/test_integration/test_idp.py b/ipatests/test_integration/test_idp.py
-index 8f9e92e6a..2ffe6a208 100644
---- a/ipatests/test_integration/test_idp.py
-+++ b/ipatests/test_integration/test_idp.py
-@@ -1,6 +1,8 @@
- from __future__ import absolute_import
- 
- import time
-+import pytest
-+import re
- 
- import textwrap
- from ipaplatform.paths import paths
-@@ -22,12 +24,12 @@ driver.get(verification_uri)
- try:
-     element = WebDriverWait(driver, 90).until(
-         EC.presence_of_element_located((By.ID, "username")))
--    driver.find_element_by_id("username").send_keys("testuser1")
--    driver.find_element_by_id("password").send_keys("{passwd}")
--    driver.find_element_by_id("kc-login").click()
-+    driver.find_element(By.ID, "username").send_keys("testuser1")
-+    driver.find_element(By.ID, "password").send_keys("{passwd}")
-+    driver.find_element(By.ID, "kc-login").click()
-     element = WebDriverWait(driver, 90).until(
-         EC.presence_of_element_located((By.ID, "kc-login")))
--    driver.find_element_by_id("kc-login").click()
-+    driver.find_element(By.ID, "kc-login").click()
-     assert "Device Login Successful" in driver.page_source
- finally:
-     now = datetime.now().strftime("%M-%S")
-@@ -39,18 +41,12 @@ finally:
- def add_user_code(host, verification_uri):
-     contents = user_code_script.format(uri=verification_uri,
-                                        passwd=host.config.admin_password)
--    host.put_file_contents("/tmp/add_user_code.py", contents)
--    tasks.run_repeatedly(
--        host, ['python3', '/tmp/add_user_code.py'])
--
--
--def get_verification_uri(host, since, keycloak_server_name):
--    command = textwrap.dedent("""
--    journalctl -u ipa-otpd\\* --since="%s" | grep "user_code:" | awk '{ print substr($7,2,9) }'""" % since)  # noqa: E501
--    user_code = host.run_command(command).stdout_text.rstrip("\r\n")
--    uri = ("https://{0}:8443/auth/realms/master/device?user_code={1}".format(
--        keycloak_server_name, user_code))
--    return uri
-+    try:
-+        host.put_file_contents("/tmp/add_user_code.py", contents)
-+        tasks.run_repeatedly(
-+            host, ['python3', '/tmp/add_user_code.py'])
-+    finally:
-+        host.run_command(["rm", "-f", "/tmp/add_user_code.py"])
- 
- 
- def kinit_idp(host, user, keycloak_server):
-@@ -58,11 +54,14 @@ def kinit_idp(host, user, keycloak_server):
-     tasks.kdestroy_all(host)
-     # create armor for FAST
-     host.run_command(["kinit", "-n", "-c", ARMOR])
--    since = time.strftime('%Y-%m-%d %H:%M:%S')
-     cmd = ["kinit", "-T", ARMOR, user]
-+
-     with host.spawn_expect(cmd, default_timeout=100) as e:
--        e.expect('Authenticate at .+: ')
--        uri = get_verification_uri(host, since, keycloak_server.hostname)
-+        e.expect('Authenticate at (.+) and press ENTER.:')
-+        prompt = e.get_last_output()
-+        uri = re.search(r'Authenticate at (.*?) and press ENTER.:', prompt
-+                        ).group(1)
-+        time.sleep(15)
-         if uri:
-             add_user_code(keycloak_server, uri)
-         e.sendline('\n')
-@@ -74,21 +73,27 @@ def kinit_idp(host, user, keycloak_server):
- 
- class TestIDPKeycloak(IntegrationTest):
- 
--    num_replicas = 1
-+    num_replicas = 2
-     topology = 'line'
- 
-     @classmethod
-     def install(cls, mh):
--        tasks.install_master(cls.master, setup_dns=True)
--        tasks.install_client(cls.master, cls.replicas[0])
--        content = cls.master.get_file_contents(paths.IPA_DEFAULT_CONF,
--                                               encoding='utf-8')
--        new_content = content + "\noidc_child_debug_level = 10"
--        cls.master.put_file_contents(paths.IPA_DEFAULT_CONF, new_content)
-+        cls.client = cls.replicas[0]
-+        cls.replica = cls.replicas[1]
-+        tasks.install_master(cls.master)
-+        tasks.install_client(cls.master, cls.replicas[0],
-+                             extra_args=["--mkhomedir"])
-+        tasks.install_replica(cls.master, cls.replicas[1])
-+        for host in [cls.master, cls.replicas[0], cls.replicas[1]]:
-+            content = host.get_file_contents(paths.IPA_DEFAULT_CONF,
-+                                             encoding='utf-8')
-+            new_content = content + "\noidc_child_debug_level = 10"
-+            host.put_file_contents(paths.IPA_DEFAULT_CONF, new_content)
-         with tasks.remote_sssd_config(cls.master) as sssd_config:
-             sssd_config.edit_domain(
-                 cls.master.domain, 'krb5_auth_timeout', 1100)
-         tasks.clear_sssd_cache(cls.master)
-+        tasks.clear_sssd_cache(cls.replicas[0])
-         tasks.kinit_admin(cls.master)
-         cls.master.run_command(["ipa", "config-mod", "--user-auth-type=idp",
-                                 "--user-auth-type=password"])
-@@ -97,20 +102,207 @@ class TestIDPKeycloak(IntegrationTest):
-         cls.replicas[0].run_command(xvfb)
- 
-     def test_auth_keycloak_idp(self):
--        keycloak_srv = self.replicas[0]
--        create_quarkus.setup_keycloakserver(keycloak_srv)
-+        """
-+        Test case to check that OAuth 2.0 Device
-+        Authorization Grant is working as
-+        expected for user configured with external idp.
-+        """
-+        create_quarkus.setup_keycloakserver(self.client)
-         time.sleep(60)
--        create_quarkus.setup_keycloak_client(keycloak_srv)
-+        create_quarkus.setup_keycloak_client(self.client)
-         tasks.kinit_admin(self.master)
--        cmd = ["ipa", "idp-add", "keycloak", "--provider=keycloak",
-+        cmd = ["ipa", "idp-add", "keycloakidp", "--provider=keycloak",
-                "--client-id=ipa_oidc_client", "--org=master",
--               "--base-url={0}:8443/auth".format(keycloak_srv.hostname)]
-+               "--base-url={0}:8443/auth".format(self.client.hostname)]
-         self.master.run_command(cmd, stdin_text="{0}\n{0}".format(
--            keycloak_srv.config.admin_password))
-+            self.client.config.admin_password))
-         tasks.user_add(self.master, 'keycloakuser',
-                        extra_args=["--user-auth-type=idp",
-                                    "--idp-user-id=testuser1@ipa.test",
--                                   "--idp=keycloak"]
-+                                   "--idp=keycloakidp"]
-                        )
-+        list_user = self.master.run_command(
-+            ["ipa", "user-find", "--idp-user-id=testuser1@ipa.test"]
-+        )
-+        assert "keycloakuser" in list_user.stdout_text
-+        list_by_idp = self.master.run_command(["ipa", "user-find",
-+                                               "--idp=keycloakidp"]
-+                                              )
-+        assert "keycloakuser" in list_by_idp.stdout_text
-+        list_by_user = self.master.run_command(
-+            ["ipa", "user-find", "--idp-user-id=testuser1@ipa.test", "--all"]
-+        )
-+        assert "keycloakidp" in list_by_user.stdout_text
-+        tasks.clear_sssd_cache(self.master)
-+        kinit_idp(self.master, 'keycloakuser', keycloak_server=self.client)
-+
-+    @pytest.fixture
-+    def hbac_setup_teardown(self):
-+        # allow sshd only on given host
-+        tasks.kinit_admin(self.master)
-+        self.master.run_command(["ipa", "hbacrule-disable", "allow_all"])
-+        self.master.run_command(["ipa", "hbacrule-add", "rule1"])
-+        self.master.run_command(["ipa", "hbacrule-add-user", "rule1",
-+                                 "--users=keycloakuser"]
-+                                )
-+        self.master.run_command(["ipa", "hbacrule-add-host", "rule1",
-+                                 "--hosts", self.replica.hostname])
-+        self.master.run_command(["ipa", "hbacrule-add-service", "rule1",
-+                                 "--hbacsvcs=sshd"]
-+                                )
-+        tasks.clear_sssd_cache(self.master)
-+        tasks.clear_sssd_cache(self.replica)
-+        yield
-+
-+        # cleanup
-+        tasks.kinit_admin(self.master)
-+        self.master.run_command(["ipa", "hbacrule-enable", "allow_all"])
-+        self.master.run_command(["ipa", "hbacrule-del", "rule1"])
-+
-+    def test_auth_hbac(self, hbac_setup_teardown):
-+        """
-+        Test case to check that hbacrule is working as
-+        expected for user configured with external idp.
-+        """
-+        kinit_idp(self.master, 'keycloakuser', keycloak_server=self.client)
-+        ssh_cmd = "ssh -q -K -l keycloakuser {0} whoami"
-+        valid_ssh = self.master.run_command(
-+            ssh_cmd.format(self.replica.hostname))
-+        assert "keycloakuser" in valid_ssh.stdout_text
-+        negative_ssh = self.master.run_command(
-+            ssh_cmd.format(self.master.hostname), raiseonerr=False
-+        )
-+        assert negative_ssh.returncode == 255
-+
-+    def test_auth_sudo_idp(self):
-+        """
-+        Test case to check that sudorule is working as
-+        expected for user configured with external idp.
-+        """
-+        tasks.kdestroy_all(self.master)
-+        tasks.kinit_admin(self.master)
-+        #  rule: keycloakuser are allowed to execute yum on
-+        #  the client machine as root.
-+        cmdlist = [
-+            ["ipa", "sudocmd-add", "/usr/bin/yum"],
-+            ["ipa", "sudorule-add", "sudorule"],
-+            ['ipa', 'sudorule-add-user', '--users=keycloakuser',
-+             'sudorule'],
-+            ['ipa', 'sudorule-add-host', '--hosts',
-+             self.client.hostname, 'sudorule'],
-+            ['ipa', 'sudorule-add-runasuser',
-+             '--users=root', 'sudorule'],
-+            ['ipa', 'sudorule-add-allow-command',
-+             '--sudocmds=/usr/bin/yum', 'sudorule'],
-+            ['ipa', 'sudorule-show', 'sudorule', '--all'],
-+            ['ipa', 'sudorule-add-option',
-+             'sudorule', '--sudooption', "!authenticate"]
-+        ]
-+        for cmd in cmdlist:
-+            self.master.run_command(cmd)
-+        tasks.clear_sssd_cache(self.master)
-+        tasks.clear_sssd_cache(self.client)
-+        try:
-+            cmd = 'sudo -ll -U keycloakuser'
-+            test = self.client.run_command(cmd).stdout_text
-+            assert "User keycloakuser may run the following commands" in test
-+            assert "/usr/bin/yum" in test
-+            kinit_idp(self.client, 'keycloakuser', self.client)
-+            test_sudo = 'su -c "sudo yum list wget" keycloakuser'
-+            self.client.run_command(test_sudo)
-+            list_fail = self.master.run_command(cmd).stdout_text
-+            assert "User keycloakuser is not allowed to run sudo" in list_fail
-+        finally:
-+            tasks.kinit_admin(self.master)
-+            self.master.run_command(['ipa', 'sudorule-del', 'sudorule'])
-+            self.master.run_command(["ipa", "sudocmd-del", "/usr/bin/yum"])
-+
-+    def test_auth_replica(self):
-+        """
-+        Test case to check that OAuth 2.0 Device
-+        Authorization is working as expected on replica.
-+        """
-+        tasks.clear_sssd_cache(self.master)
-+        tasks.clear_sssd_cache(self.replica)
-+        tasks.kinit_admin(self.replica)
-+        list_user = self.master.run_command(
-+            ["ipa", "user-find", "--idp-user-id=testuser1@ipa.test"]
-+        )
-+        assert "keycloakuser" in list_user.stdout_text
-+        list_by_idp = self.replica.run_command(["ipa", "user-find",
-+                                                "--idp=keycloakidp"]
-+                                               )
-+        assert "keycloakuser" in list_by_idp.stdout_text
-+        list_by_user = self.replica.run_command(
-+            ["ipa", "user-find", "--idp-user-id=testuser1@ipa.test", "--all"]
-+        )
-+        assert "keycloakidp" in list_by_user.stdout_text
-+        kinit_idp(self.replica, 'keycloakuser', keycloak_server=self.client)
-+
-+    def test_idp_with_services(self):
-+        """
-+        Test case to check that services can be configured
-+        auth indicator as idp.
-+        """
-         tasks.clear_sssd_cache(self.master)
--        kinit_idp(self.master, 'keycloakuser', keycloak_srv)
-+        tasks.kinit_admin(self.master)
-+        domain = self.master.domain.name.upper()
-+        services = [
-+            "DNS/{0}@{1}".format(self.master.hostname, domain),
-+            "HTTP/{0}@{1}".format(self.client.hostname, domain),
-+            "dogtag/{0}@{1}".format(self.master.hostname, domain),
-+            "ipa-dnskeysyncd/{0}@{1}".format(self.master.hostname, domain)
-+        ]
-+        try:
-+            for service in services:
-+                test = self.master.run_command(["ipa", "service-mod", service,
-+                                                "--auth-ind=idp"]
-+                                               )
-+                assert "Authentication Indicators: idp" in test.stdout_text
-+        finally:
-+            for service in services:
-+                self.master.run_command(["ipa", "service-mod", service,
-+                                         "--auth-ind="])
-+
-+    def test_idp_backup_restore(self):
-+        """
-+        Test case to check that after restore data is retrieved
-+        with related idp configuration.
-+        """
-+        tasks.kinit_admin(self.master)
-+        user = "backupuser"
-+        cmd = ["ipa", "idp-add", "testidp", "--provider=keycloak",
-+               "--client-id=ipa_oidc_client", "--org=master",
-+               "--base-url={0}:8443/auth".format(self.client.hostname)]
-+        self.master.run_command(cmd, stdin_text="{0}\n{0}".format(
-+            self.client.config.admin_password))
-+
-+        tasks.user_add(self.master, user,
-+                       extra_args=["--user-auth-type=idp",
-+                                   "--idp-user-id=testuser1@ipa.test",
-+                                   "--idp=testidp"]
-+                       )
-+
-+        backup_path = tasks.get_backup_dir(self.master)
-+        # change data after backup
-+        self.master.run_command(['ipa', 'user-del', user])
-+        self.master.run_command(['ipa', 'idp-del', 'testidp'])
-+        dirman_password = self.master.config.dirman_password
-+        self.master.run_command(['ipa-restore', backup_path],
-+                                stdin_text=dirman_password + '\nyes')
-+        try:
-+            list_user = self.master.run_command(
-+                ['ipa', 'user-show', 'backupuser', '--all']
-+            ).stdout_text
-+            assert "External IdP configuration: testidp" in list_user
-+            assert "User authentication types: idp" in list_user
-+            assert ("External IdP user identifier: "
-+                    "testuser1@ipa.test") in list_user
-+            list_idp = self.master.run_command(['ipa', 'idp-find', 'testidp'])
-+            assert "testidp" in list_idp.stdout_text
-+            kinit_idp(self.master, user, self.client)
-+        finally:
-+            tasks.kdestroy_all(self.master)
-+            tasks.kinit_admin(self.master)
-+            self.master.run_command(["rm", "-rf", backup_path])
-+            self.master.run_command(["ipa", "idp-del", "testidp"])
--- 
-2.36.1
-
diff --git a/SOURCES/0005-automember-rebuild-add-a-notice-about-high-CPU-usage_rhbz#2018198.patch b/SOURCES/0005-automember-rebuild-add-a-notice-about-high-CPU-usage_rhbz#2018198.patch
new file mode 100644
index 0000000..4fc3a5d
--- /dev/null
+++ b/SOURCES/0005-automember-rebuild-add-a-notice-about-high-CPU-usage_rhbz#2018198.patch
@@ -0,0 +1,64 @@
+From 2deaaa788cbdde22d5b15566599fdcf7a10f02c6 Mon Sep 17 00:00:00 2001
+From: Florence Blanc-Renaud <flo@redhat.com>
+Date: Feb 02 2023 10:08:26 +0000
+Subject: automember-rebuild: add a notice about high CPU usage
+
+
+The automember-rebuild task may require high CPU usage
+if many users/hosts/groups are processed.
+Add a note in the ipa automember-rebuild CLI output
+and in the WebUI confirmation message.
+
+Fixes: https://pagure.io/freeipa/issue/9320
+Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
+Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
+
+---
+
+diff --git a/install/ui/test/data/i18n_messages.json b/install/ui/test/data/i18n_messages.json
+index 49d2883..5b73548 100644
+--- a/install/ui/test/data/i18n_messages.json
++++ b/install/ui/test/data/i18n_messages.json
+@@ -7,7 +7,7 @@
+             "actions": {
+                 "apply": "Apply", 
+                 "automember_rebuild": "Rebuild auto membership", 
+-                "automember_rebuild_confirm": "Are you sure you want to rebuild auto membership?", 
++                "automember_rebuild_confirm": "Are you sure you want to rebuild auto membership? In case of a high number of users, hosts or groups, the operation may require high CPU usage.",
+                 "automember_rebuild_success": "Automember rebuild membership task completed", 
+                 "confirm": "Are you sure you want to proceed with the action?", 
+                 "delete_confirm": "Are you sure you want to delete ${object}?", 
+diff --git a/ipaclient/plugins/automember.py b/ipaclient/plugins/automember.py
+index df4a2e5..7108dc9 100644
+--- a/ipaclient/plugins/automember.py
++++ b/ipaclient/plugins/automember.py
+@@ -34,3 +34,11 @@ class automember_add_condition(MethodOverride):
+             flags=['suppress_empty'],
+         ),
+     )
++
++
++@register(override=True, no_fail=True)
++class automember_rebuild(MethodOverride):
++    def interactive_prompt_callback(self, kw):
++        msg = _('IMPORTANT: In case of a high number of users, hosts or '
++                'groups, the operation may require high CPU usage.')
++        self.Backend.textui.print_plain(msg)
+diff --git a/ipaserver/plugins/internal.py b/ipaserver/plugins/internal.py
+index 5ffa7a2..e1e920f 100644
+--- a/ipaserver/plugins/internal.py
++++ b/ipaserver/plugins/internal.py
+@@ -160,7 +160,11 @@ class i18n_messages(Command):
+         "actions": {
+             "apply": _("Apply"),
+             "automember_rebuild": _("Rebuild auto membership"),
+-            "automember_rebuild_confirm": _("Are you sure you want to rebuild auto membership?"),
++            "automember_rebuild_confirm": _(
++                "Are you sure you want to rebuild auto membership? In case of "
++                "a high number of users, hosts or groups, the operation "
++                "may require high CPU usage."
++            ),
+             "automember_rebuild_success": _("Automember rebuild membership task completed"),
+             "confirm": _("Are you sure you want to proceed with the action?"),
+             "delete_confirm": _("Are you sure you want to delete ${object}?"),
+
diff --git a/SOURCES/0006-ipa-kdb-PAC-consistency-checker-needs-to-handle-child-domains-as-well_rhbz#2166324.patch b/SOURCES/0006-ipa-kdb-PAC-consistency-checker-needs-to-handle-child-domains-as-well_rhbz#2166324.patch
new file mode 100644
index 0000000..aa29c23
--- /dev/null
+++ b/SOURCES/0006-ipa-kdb-PAC-consistency-checker-needs-to-handle-child-domains-as-well_rhbz#2166324.patch
@@ -0,0 +1,185 @@
+From 2a0868fccbc9f4dfc540a7d3bb5dfa22c0bdce4e Mon Sep 17 00:00:00 2001
+From: Alexander Bokovoy <abokovoy@redhat.com>
+Date: Mon, 30 Jan 2023 14:22:30 +0200
+Subject: [PATCH 1/2] ipa-kdb: PAC consistency checker needs to handle child
+ domains as well
+
+When PAC check is performed, we might get a signing TGT instead of the
+client DB entry. This means it is a principal from a trusted domain but
+we don't know which one exactly because we only have a krbtgt for the
+forest root. This happens in MIT Kerberos 1.20 or later where KDB's
+issue_pac() callback never gets the original client principal directly.
+
+Look into known child domains as well and make pass the check if both
+NetBIOS name and SID correspond to one of the trusted domains under this
+forest root. Move check for the SID before NetBIOS name check because we
+can use SID of the domain in PAC to find out the right child domain in
+our trusted domains' topology list.
+
+Fixes: https://pagure.io/freeipa/issue/9316
+
+Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
+---
+ daemons/ipa-kdb/ipa_kdb_mspac.c | 51 +++++++++++++++++++++------------
+ 1 file changed, 32 insertions(+), 19 deletions(-)
+
+diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
+index a15050e2166..476d1cb558a 100644
+--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
+@@ -1827,11 +1827,43 @@ krb5_error_code filter_logon_info(krb5_context context,
+     bool result;
+     char *domstr = NULL;
+ 
++    ipactx = ipadb_get_context(context);
++    if (!ipactx || !ipactx->mspac) {
++        return KRB5_KDB_DBNOTINITED;
++    }
++
+     domain = get_domain_from_realm_update(context, realm);
+     if (!domain) {
+         return EINVAL;
+     }
+ 
++    /* check exact sid */
++    result = dom_sid_check(&domain->domsid, info->info->info3.base.domain_sid, true);
++    if (!result) {
++        struct ipadb_mspac *mspac_ctx = ipactx->mspac;
++        result = FALSE;
++        /* Didn't match but perhaps the original PAC was issued by a child domain's DC? */
++        for (k = 0; k < mspac_ctx->num_trusts; k++) {
++            result = dom_sid_check(&mspac_ctx->trusts[k].domsid,
++                             info->info->info3.base.domain_sid, true);
++            if (result) {
++                domain = &mspac_ctx->trusts[k];
++                break;
++            }
++        }
++        if (!result) {
++            domstr = dom_sid_string(NULL, info->info->info3.base.domain_sid);
++            krb5_klog_syslog(LOG_ERR, "PAC Info mismatch: domain = %s, "
++                                      "expected domain SID = %s, "
++                                      "found domain SID = %s",
++                                      domain->domain_name, domain->domain_sid,
++                                      domstr ? domstr : "<failed to display>");
++            talloc_free(domstr);
++            return EINVAL;
++        }
++    }
++
++    /* At this point we may have changed the domain we look at, */
+     /* check netbios/flat name */
+     if (strcasecmp(info->info->info3.base.logon_domain.string,
+                    domain->flat_name) != 0) {
+@@ -1843,21 +1875,6 @@ krb5_error_code filter_logon_info(krb5_context context,
+         return EINVAL;
+     }
+ 
+-    /* check exact sid */
+-    result = dom_sid_check(&domain->domsid, info->info->info3.base.domain_sid, true);
+-    if (!result) {
+-        domstr = dom_sid_string(NULL, info->info->info3.base.domain_sid);
+-        if (!domstr) {
+-            return EINVAL;
+-        }
+-        krb5_klog_syslog(LOG_ERR, "PAC Info mismatch: domain = %s, "
+-                                  "expected domain SID = %s, "
+-                                  "found domain SID = %s",
+-                                  domain->domain_name, domain->domain_sid, domstr);
+-        talloc_free(domstr);
+-        return EINVAL;
+-    }
+-
+     /* Check if this domain has been filtered out by the trust itself*/
+     if (domain->parent != NULL) {
+         for(k = 0; k < domain->parent->len_sid_blocklist_incoming; k++) {
+@@ -1944,10 +1961,6 @@ krb5_error_code filter_logon_info(krb5_context context,
+      * should include different possibilities into account
+      * */
+     if (info->info->info3.sidcount != 0) {
+-        ipactx = ipadb_get_context(context);
+-        if (!ipactx || !ipactx->mspac) {
+-            return KRB5_KDB_DBNOTINITED;
+-        }
+         count = info->info->info3.sidcount;
+         i = 0;
+         j = 0;
+
+From 1a4f2597253c750696f6cd34613b375dc30fe456 Mon Sep 17 00:00:00 2001
+From: Anuja More <amore@redhat.com>
+Date: Mon, 30 Jan 2023 19:27:49 +0530
+Subject: [PATCH 2/2] Add test for SSH with GSSAPI auth.
+
+Added test for aduser with GSSAPI authentication.
+
+Related : https://pagure.io/freeipa/issue/9316
+
+Signed-off-by: Anuja More <amore@redhat.com>
+---
+ ipatests/test_integration/test_trust.py | 46 +++++++++++++++++++++++++
+ 1 file changed, 46 insertions(+)
+
+diff --git a/ipatests/test_integration/test_trust.py b/ipatests/test_integration/test_trust.py
+index 21c814ff1a9..a1ed906c6ae 100644
+--- a/ipatests/test_integration/test_trust.py
++++ b/ipatests/test_integration/test_trust.py
+@@ -527,6 +527,35 @@ def test_subordinate_suffix(self):
+                    .format(self.ad_domain, subordinate_suffix))
+             self.ad.run_command(['powershell', '-c', cmd])
+ 
++    def test_ssh_aduser(self):
++        """Test ssh with GSSAPI is working with aduser
++
++        When kerberos ticket is obtained for child domain user
++        and ssh with this ticket should be successful
++        with no password prompt.
++
++        Related : https://pagure.io/freeipa/issue/9316
++        """
++        testuser = 'testuser@{0}'.format(self.ad_domain)
++        testusersub = 'subdomaintestuser@{0}'.format(self.ad_subdomain)
++
++        def sshuser(host, user):
++            tasks.kdestroy_all(host)
++            try:
++                tasks.kinit_as_user(host, user,
++                                    host.config.ad_admin_password
++                                    )
++                ssh_cmd = "ssh -q -K -l {user} {host} hostname"
++                valid_ssh = host.run_command(
++                    ssh_cmd.format(user=user, host=host.hostname)
++                )
++                assert host.hostname in valid_ssh.stdout_text
++            finally:
++                tasks.kdestroy_all(host)
++
++        sshuser(self.master, testuser)
++        sshuser(self.master, testusersub)
++
+     def test_remove_nonposix_trust(self):
+         self.remove_trust(self.ad)
+         tasks.unconfigure_dns_for_trust(self.master, self.ad)
+@@ -784,6 +813,23 @@ def test_user_gid_uid_resolution_in_external_treedomain_trust(self):
+         assert re.search(
+             testuser_regex, result.stdout_text), result.stdout_text
+ 
++    def test_ssh_adtreeuser(self):
++        testuser = 'treetestuser@{0}'.format(self.ad_treedomain)
++        self.master.run_command(["id", testuser])
++        tasks.clear_sssd_cache(self.master)
++        tasks.kdestroy_all(self.master)
++        try:
++            tasks.kinit_as_user(self.master, testuser,
++                                password="Secret123456"
++                                )
++            ssh_cmd = "ssh -q -K -l {user} {host} hostname"
++            valid_ssh = self.master.run_command(
++                ssh_cmd.format(user=testuser, host=self.master.hostname)
++            )
++            assert self.master.hostname in valid_ssh.stdout_text
++        finally:
++            tasks.kdestroy_all(self.master)
++
+     def test_remove_external_treedomain_trust(self):
+         self.remove_trust(self.tree_ad)
+         tasks.unconfigure_dns_for_trust(self.master, self.ad, self.tree_ad)
diff --git a/SOURCES/0006-webui-Do-not-allow-empty-pagination-size_rhbz#2094672.patch b/SOURCES/0006-webui-Do-not-allow-empty-pagination-size_rhbz#2094672.patch
deleted file mode 100644
index 25e9f72..0000000
--- a/SOURCES/0006-webui-Do-not-allow-empty-pagination-size_rhbz#2094672.patch
+++ /dev/null
@@ -1,67 +0,0 @@
-From 991849cf58fa990ad4540a61214b5ab4fcd4baa1 Mon Sep 17 00:00:00 2001
-From: Armando Neto <abiagion@redhat.com>
-Date: Fri, 8 Jul 2022 15:56:31 -0300
-Subject: [PATCH] webui: Do not allow empty pagination size
-
-Pagination size must be required, the current validators are triggered after
-form is submitted, thus the only way for check if data is not empty is by making
-the field required.
-
-Fixes: https://pagure.io/freeipa/issue/9192
-
-Signed-off-by: Armando Neto <abiagion@redhat.com>
-Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
----
- .../ui/src/freeipa/Application_controller.js  |  1 +
- ipatests/test_webui/test_misc_cases.py        | 19 +++++++++++++++++++
- 2 files changed, 20 insertions(+)
-
-diff --git a/install/ui/src/freeipa/Application_controller.js b/install/ui/src/freeipa/Application_controller.js
-index 46aabc9c4..140ee8fe0 100644
---- a/install/ui/src/freeipa/Application_controller.js
-+++ b/install/ui/src/freeipa/Application_controller.js
-@@ -318,6 +318,7 @@ define([
-                         $type: 'text',
-                         name: 'pagination_size',
-                         label: '@i18n:customization.table_pagination',
-+                        required: true,
-                         validators: ['positive_integer']
-                     }
-                 ]
-diff --git a/ipatests/test_webui/test_misc_cases.py b/ipatests/test_webui/test_misc_cases.py
-index 5f7ffb54e..aca9e1a99 100644
---- a/ipatests/test_webui/test_misc_cases.py
-+++ b/ipatests/test_webui/test_misc_cases.py
-@@ -11,6 +11,11 @@ from ipatests.test_webui.ui_driver import screenshot
- import pytest
- import re
- 
-+try:
-+    from selenium.webdriver.common.by import By
-+except ImportError:
-+    pass
-+
- 
- @pytest.mark.tier1
- class TestMiscCases(UI_driver):
-@@ -26,3 +31,17 @@ class TestMiscCases(UI_driver):
-         ver_re = re.compile('version: .*')
-         assert re.search(ver_re, about_text), 'Version not found'
-         self.dialog_button_click('ok')
-+
-+    @screenshot
-+    def test_customization_pagination_input_required(self):
-+        """Test if 'pagination size' is required when submitting the form."""
-+        self.init_app()
-+
-+        self.profile_menu_action('configuration')
-+        self.fill_input('pagination_size', '')
-+        self.dialog_button_click('save')
-+
-+        pagination_size_elem = self.find(
-+            ".widget[name='pagination_size']", By.CSS_SELECTOR)
-+
-+        self.assert_field_validation_required(parent=pagination_size_elem)
--- 
-2.36.1
-
diff --git a/SOURCES/0007-Wipe-the-ipa-ca-DNS-record-when-updating-system-records_rhbz#2158775.patch b/SOURCES/0007-Wipe-the-ipa-ca-DNS-record-when-updating-system-records_rhbz#2158775.patch
new file mode 100644
index 0000000..87b63ed
--- /dev/null
+++ b/SOURCES/0007-Wipe-the-ipa-ca-DNS-record-when-updating-system-records_rhbz#2158775.patch
@@ -0,0 +1,64 @@
+From b35c75d864040b98ed3f9214d5d17d32f06d6ee1 Mon Sep 17 00:00:00 2001
+From: Rob Crittenden <rcritten@redhat.com>
+Date: Mon, 11 Jul 2022 14:20:32 -0400
+Subject: [PATCH] Wipe the ipa-ca DNS record when updating system records
+
+If a server with a CA has been marked as hidden and
+contains the last A or AAAA address then that address
+would remain in the ipa-ca entry.
+
+This is because update-dns-system-records did not delete
+values, it just re-computed them. So if no A or AAAA
+records were found then the existing value was left.
+
+Fixes: https://pagure.io/freeipa/issue/9195
+
+Signed-off-by: Rob Crittenden <rcritten@redhat.com>
+---
+ ipaserver/dns_data_management.py | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/ipaserver/dns_data_management.py b/ipaserver/dns_data_management.py
+index e2bc530ee8a..aaae5446856 100644
+--- a/ipaserver/dns_data_management.py
++++ b/ipaserver/dns_data_management.py
+@@ -19,6 +19,7 @@
+ from time import sleep, time
+ 
+ from ipalib import errors
++from ipalib.constants import IPA_CA_RECORD
+ from ipalib.dns import record_name_format
+ from ipapython.dnsutil import DNSName
+ from ipaserver.install import installutils
+@@ -187,7 +188,7 @@ def __add_uri_records(
+ 
+     def __add_ca_records_from_hostname(self, zone_obj, hostname):
+         assert isinstance(hostname, DNSName) and hostname.is_absolute()
+-        r_name = DNSName('ipa-ca') + self.domain_abs
++        r_name = DNSName(IPA_CA_RECORD) + self.domain_abs
+         rrsets = None
+         end_time = time() + CA_RECORDS_DNS_TIMEOUT
+         while True:
+@@ -210,6 +211,7 @@ def __add_ca_records_from_hostname(self, zone_obj, hostname):
+ 
+         for rrset in rrsets:
+             for rd in rrset:
++                logger.debug("Adding CA IP %s for %s", rd.to_text(), hostname)
+                 rdataset = zone_obj.get_rdataset(
+                     r_name, rd.rdtype, create=True)
+                 rdataset.add(rd, ttl=self.TTL)
+@@ -461,6 +463,14 @@ def update_base_records(self):
+             )
+         )
+ 
++        # Remove the ipa-ca record(s). They will be reconstructed in
++        # get_base_records().
++        r_name = DNSName(IPA_CA_RECORD) + self.domain_abs
++        try:
++            self.api_instance.Command.dnsrecord_del(
++                self.domain_abs, r_name, del_all=True)
++        except errors.NotFound:
++            pass
+         base_zone = self.get_base_records()
+         for record_name, node in base_zone.items():
+             set_cname_template = record_name in names_requiring_cname_templates
diff --git a/SOURCES/0007-webui-Allow-grace-login-limit_rhbz#2109243.patch b/SOURCES/0007-webui-Allow-grace-login-limit_rhbz#2109243.patch
deleted file mode 100644
index 93cfab9..0000000
--- a/SOURCES/0007-webui-Allow-grace-login-limit_rhbz#2109243.patch
+++ /dev/null
@@ -1,56 +0,0 @@
-From ade5093b08f92b279c200f341e96972a74f644d8 Mon Sep 17 00:00:00 2001
-From: Carla Martinez <carlmart@redhat.com>
-Date: Fri, 29 Jul 2022 13:16:16 +0200
-Subject: [PATCH] webui: Allow grace login limit
-
-There was no support for setting the grace login limit on the WebUI. The
-only way to so was only via CLI:
-
-   `ipa pwpolicy-mod --gracelimit=2 global_policy`
-
-Thus, the grace login limit must be updated from the policy section and
-this will reflect also on the user settings (under the 'Password Policy'
-section)
-
-Fixes: https://pagure.io/freeipa/issue/9211
-
-Signed-off-by: Carla Martinez <carlmart@redhat.com>
-Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
----
- install/ui/src/freeipa/policy.js | 3 +++
- install/ui/src/freeipa/user.js   | 5 +++++
- 2 files changed, 8 insertions(+)
-
-diff --git a/install/ui/src/freeipa/policy.js b/install/ui/src/freeipa/policy.js
-index fa2028a52..7ec103636 100644
---- a/install/ui/src/freeipa/policy.js
-+++ b/install/ui/src/freeipa/policy.js
-@@ -72,6 +72,9 @@ return {
-                         {
-                             name: 'cospriority',
-                             required: true
-+                        },
-+                        {
-+                            name: 'passwordgracelimit'
-                         }
-                     ]
-                 }]
-diff --git a/install/ui/src/freeipa/user.js b/install/ui/src/freeipa/user.js
-index a580db035..b47c97f72 100644
---- a/install/ui/src/freeipa/user.js
-+++ b/install/ui/src/freeipa/user.js
-@@ -318,6 +318,11 @@ return {
-                             label: '@mo-param:pwpolicy:krbpwdlockoutduration:label',
-                             read_only: true,
-                             measurement_unit: 'seconds'
-+                        },
-+                        {
-+                            name: 'passwordgracelimit',
-+                            label: '@mo-param:pwpolicy:passwordgracelimit:label',
-+                            read_only: true
-                         }
-                     ]
-                 },
--- 
-2.37.2
-
diff --git a/SOURCES/0008-check_repl_update-in-progress-is-a-boolean_rhbz#2117303.patch b/SOURCES/0008-check_repl_update-in-progress-is-a-boolean_rhbz#2117303.patch
deleted file mode 100644
index 36629da..0000000
--- a/SOURCES/0008-check_repl_update-in-progress-is-a-boolean_rhbz#2117303.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 05a298f56485222583cb7dd4f6a3a4c5c77fc8cf Mon Sep 17 00:00:00 2001
-From: Florence Blanc-Renaud <flo@redhat.com>
-Date: Sun, 7 Aug 2022 12:44:47 +0200
-Subject: [PATCH] check_repl_update: in progress is a boolean
-
-With the fix for https://pagure.io/freeipa/issue/9171,
-nsds5replicaUpdateInProgress is now handled as a boolean.
-One remaining occurrence was still handling it as a string
-and calling lower() on its value.
-
-Replace with direct boolean comparison.
-
-Fixes: https://pagure.io/freeipa/issue/9218
-Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
-Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
----
- ipaserver/install/replication.py | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py
-index 16be3760c..9d9aa1c4b 100644
---- a/ipaserver/install/replication.py
-+++ b/ipaserver/install/replication.py
-@@ -1152,7 +1152,7 @@ class ReplicationManager:
-             except (ValueError, TypeError, KeyError):
-                 end = 0
-             # incremental update is done if inprogress is false and end >= start
--            done = inprogress and inprogress.lower() == 'false' and start <= end
-+            done = inprogress is not None and not inprogress and start <= end
-             logger.info("Replication Update in progress: %s: status: %s: "
-                         "start: %d: end: %d",
-                         inprogress, status, start, end)
--- 
-2.37.2
-
diff --git a/SOURCES/0009-Disabling-gracelimit-does-not-prevent-LDAP-binds_rhbz#2109236.patch b/SOURCES/0009-Disabling-gracelimit-does-not-prevent-LDAP-binds_rhbz#2109236.patch
deleted file mode 100644
index 17088cf..0000000
--- a/SOURCES/0009-Disabling-gracelimit-does-not-prevent-LDAP-binds_rhbz#2109236.patch
+++ /dev/null
@@ -1,125 +0,0 @@
-From 1316cd8b2252c2543cf2ef2186956a8833037b1e Mon Sep 17 00:00:00 2001
-From: Rob Crittenden <rcritten@redhat.com>
-Date: Thu, 21 Jul 2022 09:28:46 -0400
-Subject: [PATCH] Disabling gracelimit does not prevent LDAP binds
-
-Originally the code treated 0 as disabled. This was
-changed during the review process to -1 but one remnant
-was missed effetively allowing gracelimit 0 to also mean
-disabled.
-
-Add explicit tests for testing with gracelimit = 0 and
-gracelimit = -1.
-
-Also remove some extranous "str(self.master.domain.basedn)"
-lines from some of the tests.
-
-Fixes: https://pagure.io/freeipa/issue/9206
-
-Signed-off-by: Rob Crittenden <rcritten@redhat.com>
-Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
----
- .../ipa-graceperiod/ipa_graceperiod.c         |  2 +-
- ipatests/test_integration/test_pwpolicy.py    | 55 ++++++++++++++++++-
- 2 files changed, 53 insertions(+), 4 deletions(-)
-
-diff --git a/daemons/ipa-slapi-plugins/ipa-graceperiod/ipa_graceperiod.c b/daemons/ipa-slapi-plugins/ipa-graceperiod/ipa_graceperiod.c
-index a3f57cb4b..345e1dee7 100644
---- a/daemons/ipa-slapi-plugins/ipa-graceperiod/ipa_graceperiod.c
-+++ b/daemons/ipa-slapi-plugins/ipa-graceperiod/ipa_graceperiod.c
-@@ -479,7 +479,7 @@ static int ipagraceperiod_preop(Slapi_PBlock *pb)
-         if (pwresponse_requested) {
-             slapi_pwpolicy_make_response_control(pb, -1, grace_limit - grace_user_time , -1);
-         }
--    } else if ((grace_limit > 0) && (grace_user_time >= grace_limit)) {
-+    } else if (grace_user_time >= grace_limit) {
-         LOG_TRACE("%s password is expired and out of grace limit\n", dn);
-         errstr = "Password is expired.\n";
-         ret = LDAP_INVALID_CREDENTIALS;
-diff --git a/ipatests/test_integration/test_pwpolicy.py b/ipatests/test_integration/test_pwpolicy.py
-index 6d6698284..41d6e9070 100644
---- a/ipatests/test_integration/test_pwpolicy.py
-+++ b/ipatests/test_integration/test_pwpolicy.py
-@@ -36,7 +36,7 @@ class TestPWPolicy(IntegrationTest):
-         cls.master.run_command(['ipa', 'group-add-member', POLICY,
-                                 '--users', USER])
-         cls.master.run_command(['ipa', 'pwpolicy-add', POLICY,
--                                '--priority', '1'])
-+                                '--priority', '1', '--gracelimit', '-1'])
-         cls.master.run_command(['ipa', 'passwd', USER],
-                                stdin_text='{password}\n{password}\n'.format(
-                                password=PASSWORD
-@@ -265,7 +265,6 @@ class TestPWPolicy(IntegrationTest):
- 
-     def test_graceperiod_expired(self):
-         """Test the LDAP bind grace period"""
--        str(self.master.domain.basedn)
-         dn = "uid={user},cn=users,cn=accounts,{base_dn}".format(
-              user=USER, base_dn=str(self.master.domain.basedn))
- 
-@@ -308,7 +307,6 @@ class TestPWPolicy(IntegrationTest):
- 
-     def test_graceperiod_not_replicated(self):
-         """Test that the grace period is reset on password reset"""
--        str(self.master.domain.basedn)
-         dn = "uid={user},cn=users,cn=accounts,{base_dn}".format(
-              user=USER, base_dn=str(self.master.domain.basedn))
- 
-@@ -341,3 +339,54 @@ class TestPWPolicy(IntegrationTest):
-         )
-         assert 'passwordgraceusertime: 0' in result.stdout_text.lower()
-         self.reset_password(self.master)
-+
-+    def test_graceperiod_zero(self):
-+        """Test the LDAP bind with zero grace period"""
-+        dn = "uid={user},cn=users,cn=accounts,{base_dn}".format(
-+             user=USER, base_dn=str(self.master.domain.basedn))
-+
-+        self.master.run_command(
-+            ["ipa", "pwpolicy-mod", POLICY, "--gracelimit", "0", ],
-+        )
-+
-+        # Resetting the password will mark it as expired
-+        self.reset_password(self.master)
-+
-+        # Now grace is done and binds should fail.
-+        result = self.master.run_command(
-+            ["ldapsearch", "-e", "ppolicy", "-D", dn,
-+             "-w", PASSWORD, "-b", dn], raiseonerr=False
-+        )
-+        assert result.returncode == 49
-+
-+        assert 'Password is expired' in result.stderr_text
-+        assert 'Password expired, 0 grace logins remain' in result.stderr_text
-+
-+    def test_graceperiod_disabled(self):
-+        """Test the LDAP bind with grace period disabled (-1)"""
-+        str(self.master.domain.basedn)
-+        dn = "uid={user},cn=users,cn=accounts,{base_dn}".format(
-+             user=USER, base_dn=str(self.master.domain.basedn))
-+
-+        # This can fail if gracelimit is already -1 so ignore it
-+        self.master.run_command(
-+            ["ipa", "pwpolicy-mod", POLICY, "--gracelimit", "-1",],
-+            raiseonerr=False,
-+        )
-+
-+        # Ensure the password is expired
-+        self.reset_password(self.master)
-+
-+        result = self.kinit_as_user(self.master, PASSWORD, PASSWORD)
-+
-+        for _i in range(0, 10):
-+            result = self.master.run_command(
-+                ["ldapsearch", "-e", "ppolicy", "-D", dn,
-+                 "-w", PASSWORD, "-b", dn]
-+            )
-+
-+        # With graceperiod disabled it should not increment
-+        result = tasks.ldapsearch_dm(
-+            self.master, dn, ['passwordgraceusertime',],
-+        )
-+        assert 'passwordgraceusertime: 0' in result.stdout_text.lower()
--- 
-2.37.2
-
diff --git a/SOURCES/0010-Set-passwordgracelimit-to-match-global-policy-on-group-pw-policies_rhbz#2115475.patch b/SOURCES/0010-Set-passwordgracelimit-to-match-global-policy-on-group-pw-policies_rhbz#2115475.patch
deleted file mode 100644
index 952e49b..0000000
--- a/SOURCES/0010-Set-passwordgracelimit-to-match-global-policy-on-group-pw-policies_rhbz#2115475.patch
+++ /dev/null
@@ -1,230 +0,0 @@
-From 434620ee342ac4767beccec647a318bfa7743dfa Mon Sep 17 00:00:00 2001
-From: Rob Crittenden <rcritten@redhat.com>
-Date: Thu, 18 Aug 2022 08:21:58 -0400
-Subject: [PATCH] doc: Update LDAP grace period design with default values
-
-New group password policies will get -1 (unlimited) on creation
-by default.
-
-Existing group password policies will remain untouched and
-those created prior will be treated as no BIND allowed.
-
-Fixes: https://pagure.io/freeipa/issue/9212
-
-Signed-off-by: Rob Crittenden <rcritten@redhat.com>
-Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
----
- doc/designs/ldap_grace_period.md | 17 ++++++++++++++++-
- 1 file changed, 16 insertions(+), 1 deletion(-)
-
-diff --git a/doc/designs/ldap_grace_period.md b/doc/designs/ldap_grace_period.md
-index 4b9db3424..e26aedda9 100644
---- a/doc/designs/ldap_grace_period.md
-+++ b/doc/designs/ldap_grace_period.md
-@@ -51,7 +51,22 @@ The basic flow is:
- 
- On successful password reset (by anyone) reset the user's passwordGraceUserTime to 0.
- 
--The default value on install/upgrade will be -1 to retail existing behavior.
-+Range values for passwordgracelimit are:
-+
-+-1 : password grace checking is disabled
-+ 0 : no grace BIND are allowed at all post-expiration
-+ 1..MAXINT: the number of BIND allowed post-expiration
-+
-+The default value for the global policy on install/upgrade will be -1 to
-+retain existing behavior.
-+
-+New group password policies will default to -1 to retain previous
-+behavior.
-+
-+Existing group policies with no grace limit set are updated to use
-+the default unlimited value, -1. This is done because lack of value in
-+LDAP is treated as 0 so any existing group policies would not allow
-+post-expiration BIND so this will avoid confusion.
- 
- The per-user attempts will not be replicated.
- 
--- 
-2.37.2
-
-From 497a57e7a6872fa30d1855a1d91a455bfdbf9300 Mon Sep 17 00:00:00 2001
-From: Rob Crittenden <rcritten@redhat.com>
-Date: Thu, 4 Aug 2022 12:04:22 -0400
-Subject: [PATCH] Set default gracelimit on group password policies to -1
-
-This will retain previous behavior of unlimited LDAP BIND
-post-expiration.
-
-Fixes: https://pagure.io/freeipa/issue/9212
-
-Signed-off-by: Rob Crittenden <rcritten@redhat.com>
-Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
----
- API.txt                                      | 2 +-
- ipaserver/plugins/pwpolicy.py                | 2 ++
- ipatests/test_xmlrpc/test_pwpolicy_plugin.py | 2 ++
- 3 files changed, 5 insertions(+), 1 deletion(-)
-
-diff --git a/API.txt b/API.txt
-index 5ba9add13..d7ea74f08 100644
---- a/API.txt
-+++ b/API.txt
-@@ -4075,7 +4075,7 @@ option: Int('krbpwdlockoutduration?', cli_name='lockouttime')
- option: Int('krbpwdmaxfailure?', cli_name='maxfail')
- option: Int('krbpwdmindiffchars?', cli_name='minclasses')
- option: Int('krbpwdminlength?', cli_name='minlength')
--option: Int('passwordgracelimit?', cli_name='gracelimit', default=-1)
-+option: Int('passwordgracelimit?', autofill=True, cli_name='gracelimit', default=-1)
- option: Flag('raw', autofill=True, cli_name='raw', default=False)
- option: Str('setattr*', cli_name='setattr')
- option: Str('version?')
-diff --git a/ipaserver/plugins/pwpolicy.py b/ipaserver/plugins/pwpolicy.py
-index 4428aede2..f4ebffd5c 100644
---- a/ipaserver/plugins/pwpolicy.py
-+++ b/ipaserver/plugins/pwpolicy.py
-@@ -408,6 +408,7 @@ class pwpolicy(LDAPObject):
-             minvalue=-1,
-             maxvalue=Int.MAX_UINT32,
-             default=-1,
-+            autofill=True,
-         ),
-     )
- 
-@@ -539,6 +540,7 @@ class pwpolicy_add(LDAPCreate):
-             keys[-1], krbpwdpolicyreference=dn,
-             cospriority=options.get('cospriority')
-         )
-+
-         return dn
- 
-     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
-diff --git a/ipatests/test_xmlrpc/test_pwpolicy_plugin.py b/ipatests/test_xmlrpc/test_pwpolicy_plugin.py
-index 8eee69c18..fc785223b 100644
---- a/ipatests/test_xmlrpc/test_pwpolicy_plugin.py
-+++ b/ipatests/test_xmlrpc/test_pwpolicy_plugin.py
-@@ -387,6 +387,7 @@ class test_pwpolicy_mod_cospriority(Declarative):
-                     krbpwdhistorylength=[u'10'],
-                     krbpwdmindiffchars=[u'3'],
-                     krbpwdminlength=[u'8'],
-+                    passwordgracelimit=[u'-1'],
-                     objectclass=objectclasses.pwpolicy,
-                 ),
-                 summary=None,
-@@ -417,6 +418,7 @@ class test_pwpolicy_mod_cospriority(Declarative):
-                     krbpwdhistorylength=[u'10'],
-                     krbpwdmindiffchars=[u'3'],
-                     krbpwdminlength=[u'8'],
-+                    passwordgracelimit=[u'-1'],
-                 ),
-                 summary=None,
-                 value=u'ipausers',
--- 
-2.37.2
-
-From a4ddaaf3048c4e8d78a1807af7266ee40ab3a30b Mon Sep 17 00:00:00 2001
-From: Rob Crittenden <rcritten@redhat.com>
-Date: Thu, 4 Aug 2022 12:04:41 -0400
-Subject: [PATCH] Set default on group pwpolicy with no grace limit in upgrade
-
-If an existing group policy lacks a password grace limit
-update it to -1 on upgrade.
-
-Fixes: https://pagure.io/freeipa/issue/9212
-
-Signed-off-by: Rob Crittenden <rcritten@redhat.com>
-Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
----
- .../updates/90-post_upgrade_plugins.update    |  1 +
- ipaserver/install/plugins/update_pwpolicy.py  | 66 +++++++++++++++++++
- 2 files changed, 67 insertions(+)
-
-diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update
-index c7ec71d49..6fe91aa6c 100644
---- a/install/updates/90-post_upgrade_plugins.update
-+++ b/install/updates/90-post_upgrade_plugins.update
-@@ -26,6 +26,7 @@ plugin: update_ra_cert_store
- plugin: update_mapping_Guests_to_nobody
- plugin: fix_kra_people_entry
- plugin: update_pwpolicy
-+plugin: update_pwpolicy_grace
- 
- # last
- # DNS version 1
-diff --git a/ipaserver/install/plugins/update_pwpolicy.py b/ipaserver/install/plugins/update_pwpolicy.py
-index dca44ce43..4185f0343 100644
---- a/ipaserver/install/plugins/update_pwpolicy.py
-+++ b/ipaserver/install/plugins/update_pwpolicy.py
-@@ -78,3 +78,69 @@ class update_pwpolicy(Updater):
-                 return False, []
- 
-         return False, []
-+
-+
-+@register()
-+class update_pwpolicy_grace(Updater):
-+    """
-+    Ensure all group policies have a grace period set.
-+    """
-+
-+    def execute(self, **options):
-+        ldap = self.api.Backend.ldap2
-+
-+        base_dn = DN(('cn', self.api.env.realm), ('cn', 'kerberos'),
-+                     self.api.env.basedn)
-+        search_filter = (
-+            "(&(objectClass=krbpwdpolicy)(!(passwordgracelimit=*)))"
-+        )
-+
-+        while True:
-+            # Run the search in loop to avoid issues when LDAP limits are hit
-+            # during update
-+
-+            try:
-+                (entries, truncated) = ldap.find_entries(
-+                    search_filter, ['objectclass'], base_dn, time_limit=0,
-+                    size_limit=0)
-+
-+            except errors.EmptyResult:
-+                logger.debug("update_pwpolicy: no policies without "
-+                             "passwordgracelimit set")
-+                return False, []
-+
-+            except errors.ExecutionError as e:
-+                logger.error("update_pwpolicy: cannot retrieve list "
-+                             "of policies missing passwordgracelimit: %s", e)
-+                return False, []
-+
-+            logger.debug("update_pwpolicy: found %d "
-+                         "policies to update, truncated: %s",
-+                         len(entries), truncated)
-+
-+            error = False
-+
-+            for entry in entries:
-+                # Set unlimited BIND by default
-+                entry['passwordgracelimit'] = -1
-+                try:
-+                    ldap.update_entry(entry)
-+                except (errors.EmptyModlist, errors.NotFound):
-+                    pass
-+                except errors.ExecutionError as e:
-+                    logger.debug("update_pwpolicy: cannot "
-+                                 "update policy: %s", e)
-+                    error = True
-+
-+            if error:
-+                # Exit loop to avoid infinite cycles
-+                logger.error("update_pwpolicy: error(s) "
-+                             "detected during pwpolicy update")
-+                return False, []
-+
-+            elif not truncated:
-+                # All affected entries updated, exit the loop
-+                logger.debug("update_pwpolicy: all policies updated")
-+                return False, []
-+
-+        return False, []
--- 
-2.37.2
-
diff --git a/SOURCES/1002-Revert-freeipa.spec-depend-on-bind-dnssec-utils.patch b/SOURCES/1002-Revert-freeipa.spec-depend-on-bind-dnssec-utils.patch
index e1a74ff..fe9eba6 100644
--- a/SOURCES/1002-Revert-freeipa.spec-depend-on-bind-dnssec-utils.patch
+++ b/SOURCES/1002-Revert-freeipa.spec-depend-on-bind-dnssec-utils.patch
@@ -15,7 +15,7 @@ diff --git a/freeipa.spec.in b/freeipa.spec.in
 index 8f5c370e5..e20edb7bc 100755
 --- a/freeipa.spec.in
 +++ b/freeipa.spec.in
-@@ -576,11 +576,9 @@ Requires: %{name}-server = %{version}-%{release}
+@@ -585,11 +585,9 @@ Requires: %{name}-server = %{version}-%{release}
  Requires: bind-dyndb-ldap >= 11.2-2
  Requires: bind >= %{bind_version}
  Requires: bind-utils >= %{bind_version}
@@ -32,15 +32,16 @@ diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
 index 7d21367ec..42a47f1df 100644
 --- a/ipaplatform/base/paths.py
 +++ b/ipaplatform/base/paths.py
-@@ -259,7 +259,6 @@ class BasePathNamespace:
+@@ -258,8 +258,7 @@ class BasePathNamespace:
      IPA_PKI_RETRIEVE_KEY = "/usr/libexec/ipa/ipa-pki-retrieve-key"
      IPA_HTTPD_PASSWD_READER = "/usr/libexec/ipa/ipa-httpd-pwdreader"
      IPA_PKI_WAIT_RUNNING = "/usr/libexec/ipa/ipa-pki-wait-running"
 -    DNSSEC_KEYFROMLABEL = "/usr/sbin/dnssec-keyfromlabel"
-+    DNSSEC_KEYFROMLABEL = "/usr/sbin/dnssec-keyfromlabel-pkcs11"
 -    DNSSEC_KEYFROMLABEL_9_17 = "/usr/bin/dnssec-keyfromlabel"
++    DNSSEC_KEYFROMLABEL = "/usr/sbin/dnssec-keyfromlabel-pkcs11"
      GETSEBOOL = "/usr/sbin/getsebool"
      GROUPADD = "/usr/sbin/groupadd"
+     USERMOD = "/usr/sbin/usermod"
 diff --git a/ipaplatform/fedora/paths.py b/ipaplatform/fedora/paths.py
 index 4e993c063..92a948966 100644
 --- a/ipaplatform/fedora/paths.py
diff --git a/SOURCES/1003-webui-IdP-Remove-arrow-notation-due-to-uglify-js-lim.patch b/SOURCES/1003-webui-IdP-Remove-arrow-notation-due-to-uglify-js-lim.patch
new file mode 100644
index 0000000..7928884
--- /dev/null
+++ b/SOURCES/1003-webui-IdP-Remove-arrow-notation-due-to-uglify-js-lim.patch
@@ -0,0 +1,60 @@
+From 7807bcc55b4927fc327830d2237200772d2e1106 Mon Sep 17 00:00:00 2001
+From: Rafael Guterres Jeffman <rjeffman@redhat.com>
+Date: Fri, 17 Jun 2022 15:40:04 -0300
+Subject: [PATCH] webui IdP: Remove arrow notation due to uglify-js limitation.
+
+uglify-js 2.x series do not support ECMAScript 6 arrow notation ('=>')
+for callback definition.
+
+This patch changes the arrow definition callbacks for regular anonymous
+function definitions.
+---
+ install/ui/src/freeipa/idp.js | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/install/ui/src/freeipa/idp.js b/install/ui/src/freeipa/idp.js
+index ada09c075..be3c4f0e6 100644
+--- a/install/ui/src/freeipa/idp.js
++++ b/install/ui/src/freeipa/idp.js
+@@ -227,7 +227,7 @@ IPA.add_idp_policy = function() {
+         // For custom template we show custom fields
+         // and mark all of them required and passed to the RPC
+         // If show_custom is false, the opposite happens
+-        custom_fields.forEach(fname => {
++        custom_fields.forEach(function(fname) {
+             widget_f = that.container.fields.get_field(fname);
+             widget_f.set_required(show_custom);
+             widget_f.set_enabled(show_custom);
+@@ -235,7 +235,7 @@ IPA.add_idp_policy = function() {
+         });
+ 
+         // For template fields we show them if custom aren't shown
+-        template_fields.forEach(fname => {
++        template_fields.forEach(function(fname) {
+             widget_f = that.container.fields.get_field(fname);
+             widget_f.set_enabled(!show_custom);
+             widget_f.widget.set_visible(!show_custom);
+@@ -252,7 +252,7 @@ IPA.add_idp_policy = function() {
+         var value = prov_f.get_value()[0];
+ 
+         // First, clear template fields from the previous provider choice
+-        template_fields.forEach(fname => {
++        template_fields.forEach(function(fname) {
+             widget_f = that.container.fields.get_field(fname);
+             widget_f.widget.set_visible(false);
+             widget_f.set_required(false);
+@@ -260,9 +260,9 @@ IPA.add_idp_policy = function() {
+         });
+ 
+         // Second, enable and get required template-specific fields
+-        idp.templates.forEach(idp_v => {
++        idp.templates.forEach(function(idp_v) {
+             if (idp_v['value'] == value) {
+-                idp_v['fields'].forEach(fname => {
++                idp_v['fields'].forEach(function(fname) {
+                     widget_f = that.container.fields.get_field(fname);
+                     widget_f.set_required(true);
+                     widget_f.set_enabled(true);
+-- 
+2.36.1
+
diff --git a/SOURCES/1004-Revert-DNSResolver-Fix-use-of-nameservers-with-ports.patch b/SOURCES/1004-Revert-DNSResolver-Fix-use-of-nameservers-with-ports.patch
new file mode 100644
index 0000000..d5fe2d3
--- /dev/null
+++ b/SOURCES/1004-Revert-DNSResolver-Fix-use-of-nameservers-with-ports.patch
@@ -0,0 +1,114 @@
+From 9a33838407f244e481523fe643bc0626874e8b1a Mon Sep 17 00:00:00 2001
+From: Rafael Guterres Jeffman <rjeffman@redhat.com>
+Date: Mon, 19 Dec 2022 14:57:03 -0300
+Subject: [PATCH] Revert "DNSResolver: Fix use of nameservers with ports"
+
+This reverts commit 5e2e4664aec641886923c2bec61ce25b96edb62a.
+---
+ ipapython/dnsutil.py                    | 41 -------------------------
+ ipatests/test_ipapython/test_dnsutil.py | 40 ------------------------
+ 2 files changed, 81 deletions(-)
+
+diff --git a/ipapython/dnsutil.py b/ipapython/dnsutil.py
+index 58de365ab..4baeaf8cc 100644
+--- a/ipapython/dnsutil.py
++++ b/ipapython/dnsutil.py
+@@ -144,47 +144,6 @@ class DNSResolver(dns.resolver.Resolver):
+             nameservers.remove(ipv4_loopback)
+         self.nameservers = nameservers
+ 
+-    @dns.resolver.Resolver.nameservers.setter
+-    def nameservers(self, nameservers):
+-        """
+-        *nameservers*, a ``list`` of nameservers with optional ports:
+-            "SERVER_IP port PORT_NUMBER".
+-
+-        Overloads dns.resolver.Resolver.nameservers setter to split off ports
+-        into nameserver_ports after setting nameservers successfully with the
+-        setter in dns.resolver.Resolver.
+-        """
+-        # Get nameserver_ports if it is already set
+-        if hasattr(self, "nameserver_ports"):
+-            nameserver_ports = self.nameserver_ports
+-        else:
+-            nameserver_ports = {}
+-
+-        # Check nameserver items in list and split out converted port number
+-        # into nameserver_ports: { nameserver: port }
+-        if isinstance(nameservers, list):
+-            _nameservers = []
+-            for nameserver in nameservers:
+-                splits = nameserver.split()
+-                if len(splits) == 3 and splits[1] == "port":
+-                    nameserver = splits[0]
+-                    try:
+-                        port = int(splits[2])
+-                        if port < 0 or port > 65535:
+-                            raise ValueError()
+-                    except ValueError:
+-                        raise ValueError(
+-                            "invalid nameserver: %s is not a valid port" %
+-                            splits[2])
+-                    nameserver_ports[nameserver] = port
+-                _nameservers.append(nameserver)
+-            nameservers = _nameservers
+-
+-        # Call dns.resolver.Resolver.nameservers setter
+-        dns.resolver.Resolver.nameservers.__set__(self, nameservers)
+-        # Set nameserver_ports after successfull call to setter
+-        self.nameserver_ports = nameserver_ports
+-
+ 
+ class DNSZoneAlreadyExists(dns.exception.DNSException):
+     supp_kwargs = {'zone', 'ns'}
+diff --git a/ipatests/test_ipapython/test_dnsutil.py b/ipatests/test_ipapython/test_dnsutil.py
+index 09463c69d..5e7a46197 100644
+--- a/ipatests/test_ipapython/test_dnsutil.py
++++ b/ipatests/test_ipapython/test_dnsutil.py
+@@ -101,43 +101,3 @@ class TestSortURI:
+         assert dnsutil.sort_prio_weight([h3, h2, h1]) == [h1, h2, h3]
+         assert dnsutil.sort_prio_weight([h3, h3, h3]) == [h3]
+         assert dnsutil.sort_prio_weight([h2, h2, h1, h1]) == [h1, h2]
+-
+-
+-class TestDNSResolver:
+-    def test_nameservers(self):
+-        res = dnsutil.DNSResolver()
+-        res.nameservers = ["4.4.4.4", "8.8.8.8"]
+-        assert res.nameservers == ["4.4.4.4", "8.8.8.8"]
+-
+-    def test_nameservers_with_ports(self):
+-        res = dnsutil.DNSResolver()
+-        res.nameservers = ["4.4.4.4 port 53", "8.8.8.8 port 8053"]
+-        assert res.nameservers == ["4.4.4.4", "8.8.8.8"]
+-        assert res.nameserver_ports == {"4.4.4.4": 53, "8.8.8.8": 8053}
+-
+-        res.nameservers = ["4.4.4.4 port 53", "8.8.8.8  port  8053"]
+-        assert res.nameservers == ["4.4.4.4", "8.8.8.8"]
+-        assert res.nameserver_ports == {"4.4.4.4": 53, "8.8.8.8": 8053}
+-
+-    def test_nameservers_with_bad_ports(self):
+-        res = dnsutil.DNSResolver()
+-        try:
+-            res.nameservers = ["4.4.4.4 port a"]
+-        except ValueError:
+-            pass
+-        else:
+-            pytest.fail("No fail on bad port a")
+-
+-        try:
+-            res.nameservers = ["4.4.4.4 port -1"]
+-        except ValueError:
+-            pass
+-        else:
+-            pytest.fail("No fail on bad port -1")
+-
+-        try:
+-            res.nameservers = ["4.4.4.4 port 65536"]
+-        except ValueError:
+-            pass
+-        else:
+-            pytest.fail("No fail on bad port 65536")
+-- 
+2.38.1
+
diff --git a/SOURCES/freeipa-4.9.10.tar.gz.asc b/SOURCES/freeipa-4.9.10.tar.gz.asc
deleted file mode 100644
index 2804c24..0000000
--- a/SOURCES/freeipa-4.9.10.tar.gz.asc
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN PGP SIGNATURE-----
-
-iQIzBAABCAAdFiEE11Z2TU1+KXxtrRFyaYdvcqbi008FAmKp71wACgkQaYdvcqbi
-008rbg/9G5w7KXgJcrhwBx5qqd4fqzSnwJdyN5oaBIEKNsAigMD7LIYawqgnO3g/
-/3FmJTbeCrOj9EoakvE1YNRT+75oxAO+rMFcRvFHlJyfMCa3r3lrS4LrlQiiyNwZ
-IHovcXr0Q3fizhp/V3acyZqx2pbnSh24CK4q5a1CNUs8SPkEFcOfpAJIMQCHeH6t
-ScfxuWOp8R1FnaNQc/9x3vy3ySQbHMxIWLSfJy7pk7FhLGAvgVNQBAz70Bg7BfR1
-R1V6syGeaPmqLOQw0jV05YMxyKwkbnSK/h2DlCg/iNQ/S71rXhOpuk01dDf73CI4
-Fu1H9TX50Indq31+4qbOlKZqDshhNzRRpn2m2qVvzeTfObHlZMbYNyVamovP9fEZ
-pfJcppI8aNDURjqpf/sVy4G8mhI5FQS+Q7bKvv9C04iE3XpTutg8q5mLMXGwWekY
-yeklBAmdygOKsY1uWb7BCH9eoWCVWKIwi4m5uYteZNxBt4aqsa/VFsxCE1P2T7/S
-+yc1Jo7hXWW8v3wm+dIGJj+Lz9YlJxC9SAiC72a6kTwIe2gnKlxoYbqe/18hEWm6
-0jESl2LiXfBhXz0YQlv2HjcPWZMMrNuhSCGTMgzP8KfZB258mtxpbBTk5/e9Wgsk
-29GCfaMWFUqZsrteG10HT/P6cotre6EVffQl9lNlPNQpX+DUKy4=
-=azus
------END PGP SIGNATURE-----
diff --git a/SOURCES/freeipa-4.9.11.tar.gz.asc b/SOURCES/freeipa-4.9.11.tar.gz.asc
new file mode 100644
index 0000000..47ddb7d
--- /dev/null
+++ b/SOURCES/freeipa-4.9.11.tar.gz.asc
@@ -0,0 +1,16 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCAAdFiEE11Z2TU1+KXxtrRFyaYdvcqbi008FAmOA8kcACgkQaYdvcqbi
+00887g/9GTvueJCypiuTqxKsbkTbWamOyH3W+AqtHw9Ff+wM/hnkSloGizhQ4EZZ
+4Zs1e6bfM1pGXT7DXU9WbiYtcVtUhY5l9SnT9moCMaG1z4aB7z9UCxsqsSCuy3bG
+KQq6AO2z4DaqHiz6ez3QXi+MUCNnPziWmS3bLdDCrTK0PNxqiMPIotlXMgVFgDL7
+go/TAUvUL27zH4ELvG4parSGEKVEqe//RzXklOwGrInyj/4u42x7lUdO2ugOolCI
+wNod8v+NWQWVgxNyhfTjP5VBZzO9wkGx4xruF2cAjVdjnIUGcG0FR3hI/bpi7Lyv
+EmIozbQMK92MLel63E7Z/d5Jxfmuw/n1t5NrgSth+9hhWnBEpiaKkD2zAmUATqHf
++y4mbrtajmjzewEnfUnQfCvSLDPyTpnQKkRY8hUvk7u/J+/ZFWMQl9RdGNw3M0Zr
+WrsqkKLK/n5IOHYHb/lBRaUidssKjQYFIvyNfHDP/lu6iiyLOpi5MIdk9BakO5wc
+oDMk3w9xY7tPPmoesW40BThnAdOR9U4aad8zVvOxhMfzAYRwu95HGQoHnk7/rNut
+IfzMZVjVTLQ8gyApcBlWzu/buiOoEXTKaMyzs0S9RMptknj5Xf0CGRz3bVrZRfJd
+umyhD6/rNk3eZW/yEIv3IqFev0h1txTBPSTlczYUIz6uc7nx82E=
+=8YVm
+-----END PGP SIGNATURE-----
diff --git a/SPECS/ipa.spec b/SPECS/ipa.spec
index 924263b..4aab5cf 100644
--- a/SPECS/ipa.spec
+++ b/SPECS/ipa.spec
@@ -68,8 +68,7 @@
 %global krb5_kdb_version 8.0
 # 0.7.16: https://github.com/drkjam/netaddr/issues/71
 %global python_netaddr_version 0.7.19
-# Require 4.14.5-13 which brings CVE-2020-25717 fixes
-%global samba_version 4.14.5-13
+%global samba_version 4.17.2-1
 %global selinux_policy_version 3.14.3-52
 %global slapi_nis_version 0.56.4
 %global python_ldap_version 3.1.0-1
@@ -93,8 +92,7 @@
 # 0.7.16: https://github.com/drkjam/netaddr/issues/71
 %global python_netaddr_version 0.7.16
 
-# Require 4.14.6 which brings CVE-2020-25717 fixes
-%global samba_version 2:4.14.6
+%global samba_version 2:4.17.2
 
 # 3.14.5-45 or later includes a number of interfaces fixes for IPA interface
 %global selinux_policy_version 3.14.5-45
@@ -178,7 +176,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.9.10
+%define IPA_VERSION 4.9.11
 # Release candidate version -- uncomment with one percent for RC versions
 #%%global rc_version %%nil
 %define AT_SIGN @
@@ -191,7 +189,7 @@
 
 Name:           %{package_name}
 Version:        %{IPA_VERSION}
-Release:        6%{?rc_version:.%rc_version}%{?dist}
+Release:        5%{?rc_version:.%rc_version}%{?dist}
 Summary:        The Identity, Policy and Audit system
 
 License:        GPLv3+
@@ -211,24 +209,28 @@ Source1:        https://releases.pagure.org/freeipa/freeipa-%{version}%{?rc_vers
 # RHEL spec file only: START
 %if %{NON_DEVELOPER_BUILD}
 %if 0%{?rhel} >= 8
-Patch0001:      0001-ipa-otpd-Fix-build-on-older-versions-of-gcc.patch
-Patch0002:      0002-webui-IdP-Remove-arrow-notation-due-to-uglify-js-lim.patch
-Patch0003:      0003-Preserve-user-fix-the-confusing-summary_rhbz#2022028.patch
-Patch0004:      0004-Only-calculate-LDAP-password-grace-when-the-password_rhbz#782917.patch
-Patch0005:      0005-Add-end-to-end-integration-tests-for-external-IdP.patch
-Patch0006:      0006-webui-Do-not-allow-empty-pagination-size_rhbz#2094672.patch
-Patch0007:      0007-webui-Allow-grace-login-limit_rhbz#2109243.patch
-Patch0008:      0008-check_repl_update-in-progress-is-a-boolean_rhbz#2117303.patch
-Patch0009:      0009-Disabling-gracelimit-does-not-prevent-LDAP-binds_rhbz#2109236.patch
-Patch0010:      0010-Set-passwordgracelimit-to-match-global-policy-on-group-pw-policies_rhbz#2115475.patch
+Patch0001:      0001-updates-fix-memberManager-ACI-to-allow-managers-from-a-specified-group_rhbz#2056009.patch
+Patch0002:      0002-trust-add-handle-missing-msSFU30MaxGidNumber_rhbz#2162355.patch
+Patch0003:      0003-Backport-latest-test-fixes-python3-ipatests_rhbz#2166929.patch
+Patch0004:      0004-server-install-remove-error-log-about-missing-bkup-file_rhbz#2160389.patch
+Patch0005:      0005-automember-rebuild-add-a-notice-about-high-CPU-usage_rhbz#2018198.patch
+Patch0006:      0006-ipa-kdb-PAC-consistency-checker-needs-to-handle-child-domains-as-well_rhbz#2166324.patch
+Patch0007:      0007-Wipe-the-ipa-ca-DNS-record-when-updating-system-records_rhbz#2158775.patch
 Patch1001:      1001-Change-branding-to-IPA-and-Identity-Management.patch
 Patch1002:      1002-Revert-freeipa.spec-depend-on-bind-dnssec-utils.patch
+Patch1003:      1003-webui-IdP-Remove-arrow-notation-due-to-uglify-js-lim.patch
+# Due to behavior changes in python3-dns 2.2.0, IPA overrides the setting of the
+# nameserver property inherited from dns.resolver.Resolver class to allow the
+# setting of nameservers with custom ports. The method used is only needed, and
+# only works, on version 2.2.0, or later, of python3-dns. For RHEL 8, which uses
+# series 1.xx, the method override is not needed to provide the same behavior.
+Patch1004:      1004-Revert-DNSResolver-Fix-use-of-nameservers-with-ports.patch
 %endif
 %endif
 # RHEL spec file only: END
 
-# For the timestamp trick in patch application
-BuildRequires:  diffstat
+## For the timestamp trick in patch application
+#BuildRequires:  diffstat
 
 BuildRequires:  openldap-devel
 # For KDB DAL version, make explicit dependency so that increase of version
@@ -295,6 +297,7 @@ BuildRequires:  cracklib-dicts
 # Build dependencies for makeapi/makeaci
 #
 BuildRequires:  python3-cffi
+# RHEL 8 packages will not work with python3-dns 2.2.0 or newer.
 BuildRequires:  python3-dns
 BuildRequires:  python3-ldap >= %{python_ldap_version}
 BuildRequires:  python3-libsss_nss_idmap
@@ -347,6 +350,7 @@ BuildRequires:  python3-cryptography >= 1.6
 BuildRequires:  python3-custodia >= 0.3.1
 BuildRequires:  python3-dateutil
 BuildRequires:  python3-dbus
+# RHEL 8 packages will not work with python3-dns 2.2.0 or newer.
 BuildRequires:  python3-dns >= 1.15
 BuildRequires:  python3-docker
 BuildRequires:  python3-gssapi >= 1.2.0
@@ -421,7 +425,6 @@ Requires: nss-tools >= %{nss_version}
 Requires(post): krb5-server >= %{krb5_version}
 Requires(post): krb5-server >= %{krb5_base_version}
 Requires: krb5-kdb-version = %{krb5_kdb_version}
-Requires: krb5-pkinit-openssl >= %{krb5_version}
 Requires: cyrus-sasl-gssapi%{?_isa}
 Requires: chrony
 Requires: httpd >= %{httpd_version}
@@ -519,6 +522,7 @@ Requires: python3-augeas
 Requires: augeas-libs >= %{augeas_version}
 Requires: python3-custodia >= 0.3.1
 Requires: python3-dbus
+# RHEL 8 packages will not work with python3-dns 2.2.0 or newer.
 Requires: python3-dns >= 1.15
 Requires: python3-gssapi >= 1.2.0
 Requires: python3-ipaclient = %{version}-%{release}
@@ -649,6 +653,8 @@ Requires: python3-sssdconfig >= %{sssd_version}
 Requires: cyrus-sasl-gssapi%{?_isa}
 Requires: chrony
 Requires: krb5-workstation >= %{krb5_version}
+# Support pkinit with client install
+Requires: krb5-pkinit-openssl >= %{krb5_version}
 # authselect: sssd profile with-subid
 %if 0%{?fedora} >= 36
 Requires: authselect >= 1.4.0
@@ -748,6 +754,7 @@ Requires: %{name}-common = %{version}-%{release}
 Requires: python3-ipalib = %{version}-%{release}
 Requires: python3-augeas
 Requires: augeas-libs >= %{augeas_version}
+# RHEL 8 packages will not work with python3-dns 2.2.0 or newer.
 Requires: python3-dns >= 1.15
 Requires: python3-jinja2
 
@@ -828,6 +835,7 @@ Requires: python3-cffi
 Requires: python3-cryptography >= 1.6
 Requires: python3-dateutil
 Requires: python3-dbus
+# RHEL 8 packages will not work with python3-dns 2.2.0 or newer.
 Requires: python3-dns >= 1.15
 Requires: python3-gssapi >= 1.2.0
 Requires: python3-jwcrypto >= 0.4.2
@@ -944,22 +952,8 @@ Custom SELinux policy module for FreeIPA
 
 
 %prep
-# Update timestamps on the files touched by a patch, to avoid non-equal
-# .pyc/.pyo files across the multilib peers within a build, where "Level"
-# is the patch prefix option (e.g. -p1)
-# Taken from specfile for sssd and python-simplejson
-UpdateTimestamps() {
-  Level=$1
-  PatchFile=$2
-
-  # Locate the affected files:
-  for f in $(diffstat $Level -l $PatchFile); do
-    # Set the files to have the same timestamp as that of the patch:
-    touch -c -r $PatchFile $f
-  done
-}
-
-%setup -n freeipa-%{version}%{?rc_version} -q
+
+%autosetup -n freeipa-%{version}%{?rc_version} -N -p1
 
 # To allow proper application patches to the stripped po files, strip originals
 pushd po
@@ -969,10 +963,8 @@ for i in *.po ; do
 done
 popd
 
-for p in %patches ; do
-    %__patch -p1 -i $p
-    UpdateTimestamps -p1 $p
-done
+%autopatch -p1
+
 
 %build
 # PATH is workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1005235
@@ -1242,7 +1234,7 @@ if [ $1 -gt 1 ] ; then
 
         %{__python3} -c 'from ipaclient.install.client import configure_krb5_snippet; configure_krb5_snippet()' >>/var/log/ipaupgrade.log 2>&1
         %{__python3} -c 'from ipaclient.install.client import update_ipa_nssdb; update_ipa_nssdb()' >>/var/log/ipaupgrade.log 2>&1
-        chmod 0600 /var/log/ipaupgrade.lo
+        chmod 0600 /var/log/ipaupgrade.log
         SSH_CLIENT_SYSTEM_CONF="/etc/ssh/ssh_config"
         if [ -f "$SSH_CLIENT_SYSTEM_CONF" ]; then
             sed -E --in-place=.orig 's/^(HostKeyAlgorithms ssh-rsa,ssh-dss)$/# disabled by ipa-client update\n# \1/' "$SSH_CLIENT_SYSTEM_CONF"
@@ -1718,11 +1710,69 @@ fi
 %if %{with selinux}
 %files selinux
 %{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.*
-%ghost %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename}
+%ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename}
 # with selinux
 %endif
 
 %changelog
+* Fri Feb 10 2023 Rafael Jeffman <rjeffman@redhat.com> - 4.9.11-5
+- Wipe the ipa-ca DNS record when updating system records
+  Resolves: RHBZ#2158775
+
+* Thu Feb 09 2023 Rafael Jeffman <rjeffman@redhat.com> - 4.9.11-4
+- trust-add: handle missinf msSFU30MaxGidNumber
+  Resolves: RHBZ#2162355
+- Backport latest test fixes for python3-ipatests
+  Resolves: RHBZ#2166929
+- server install: remove error log about missing bkup file
+  Resolves: RHBZ#2160389
+- automember-rebuild: add a notice about high CPU usage
+  Resolves: RHBZ#2018198
+- ipa-kdb: PAC consistency checker needs to handle child domains as well
+  Resolves: RHBZ#2166324
+
+* Mon Dec 19 2022 Rafael Jeffman <rjeffman@redhat.com> - 4.9.11-3
+- Revert DNSResolver Fix use of nameservers with ports.
+  Related: RHBZ#2141316
+
+* Fri Dec 16 2022 Rafael Jeffman <rjeffman@redhat.com> - 4.9.11-2
+- webui IdP: Remove arrow notation due to uglify-js limitation
+  Related: RHBZ#2141316
+
+* Wed Dec 14 2022 Rafael Jeffman <rjeffman@redhat.com> - 4.9.11-1
+- Rebase ipa to 4.9.11
+  Resolves: RHBZ#2141316
+- updates: fix memberManager ACI to allow managers from a specified group
+  Resolves: RHBZ#2056009
+- Defer creating the final krb5.conf on clients
+  Resolves: RHBZ#2148259
+- Exclude installed policy module file from RPM verification
+  Resolves: RHBZ#2149567
+- Spec file: ipa-client depends on krb5-pkinit-openssl
+  Resolves: RHBZ#2149889
+
+* Thu Nov 24 2022 Rafael Jeffman <rjeffman@redhat.com> - 4.9.10-8
+- ipa man page format the EXAMPLES section
+  Resolves: RHBZ#2129895
+- Fix canonicalization issue in Web UI
+  Resolves: RHBZ#2127035
+- Remove idnssoaserial argument from dns zone API. 
+  Resolves: RHBZ#2108630
+- Warn for permissions with read/write/search/compare and no attrs
+  Resolves: RHBZ#2098187
+- Add PKINIT support to ipa-client-install
+  Resolves: RHBZ#2075452
+- Generate CNAMEs for TXT+URI location krb records
+  Resolves: RHBZ#2104185
+- Vault: fix interoperability issues with older RHEL systems
+  Resolves: RHBZ#2144737
+- Fix typo on ipaupgrade.log chmod during RPM %post snipppet
+  Resolves: RHBZ#2140994
+
+* Tue Nov 1 2022 Rafael Jeffman <rjeffman@redhat.com> - 4.9.10-7
+- Rebuild to samba 4.17.2.
+  Related: RHBZ#2132051
+
 * Mon Aug 22 2022 Rafael Jeffman <rjeffman@redhat.com> - 4.9.10-6
 - webui: Allow grace login limit
   Resolves: RHBZ#2109243