diff --git a/0014-ipatests-enable-firewall-rule-for-http-service-on-ac.patch b/0014-ipatests-enable-firewall-rule-for-http-service-on-ac.patch new file mode 100644 index 0000000..693cfad --- /dev/null +++ b/0014-ipatests-enable-firewall-rule-for-http-service-on-ac.patch @@ -0,0 +1,42 @@ +From 1e8352486cd5f77ff79e18798f04f406baf0a9a1 Mon Sep 17 00:00:00 2001 +From: Mohammad Rizwan +Date: Wed, 14 Jun 2023 17:32:02 +0530 +Subject: [PATCH] ipatests: enable firewall rule for http service on acme + client + +when system hardning done i.e in case of STIG, sometimes http challanges +can't be validated by CA if port 80 is not open. This fix enable it to facilitate +the communication. + +Signed-off-by: Mohammad Rizwan +Reviewed-By: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud +--- + ipatests/test_integration/test_acme.py | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/ipatests/test_integration/test_acme.py b/ipatests/test_integration/test_acme.py +index 9718c408b7f48dd78dc2abae32fb9ecb85445dfb..cca20983e65f99d5ba0bb7bc6dc2b5684a6f37d9 100644 +--- a/ipatests/test_integration/test_acme.py ++++ b/ipatests/test_integration/test_acme.py +@@ -10,6 +10,7 @@ import pytest + + from ipalib.constants import IPA_CA_RECORD + from ipatests.test_integration.base import IntegrationTest ++from ipatests.pytest_ipa.integration.firewall import Firewall + from ipatests.pytest_ipa.integration import tasks + from ipatests.test_integration.test_caless import CALessBase, ipa_certs_cleanup + from ipatests.test_integration.test_random_serial_numbers import ( +@@ -85,6 +86,9 @@ def prepare_acme_client(master, client): + acme_host = f'{IPA_CA_RECORD}.{master.domain.name}' + acme_server = f'https://{acme_host}/acme/directory' + ++ # enable firewall rule on client ++ Firewall(client).enable_services(["http", "https"]) ++ + # install acme client packages + if not skip_certbot_tests: + tasks.install_packages(client, ['certbot']) +-- +2.41.0 + diff --git a/0015-User-plugin-improve-error-related-to-non-existing-id.patch b/0015-User-plugin-improve-error-related-to-non-existing-id.patch new file mode 100644 index 0000000..c92a18c --- /dev/null +++ b/0015-User-plugin-improve-error-related-to-non-existing-id.patch @@ -0,0 +1,79 @@ +From 387873080f1bc14aeaad89311b06dc46934be1ab Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Wed, 19 Jul 2023 13:24:55 +0200 +Subject: [PATCH] User plugin: improve error related to non existing idp + +The user and stageuser commands return the following error +when the user is created/updated with a non existing idp: +$ ipa user-add testuser --first test --last user --idp dummy +ipa: ERROR: no such entry + +The error is not descriptive enough and has been modified to +display instead: +$ ipa user-add testuser --first test --last user --idp dummy +ipa: ERROR: External IdP configuration dummy not found + +Fixes: https://pagure.io/freeipa/issue/9416 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipaserver/plugins/baseuser.py | 6 +++++- + ipaserver/plugins/stageuser.py | 6 +++++- + ipaserver/plugins/user.py | 6 +++++- + 3 files changed, 15 insertions(+), 3 deletions(-) + +diff --git a/ipaserver/plugins/baseuser.py b/ipaserver/plugins/baseuser.py +index 73b76d328a88639afd40bd261c8a35f324ec865b..ba5f9b7763662b32f238c0fb0ca548ff2f07db0d 100644 +--- a/ipaserver/plugins/baseuser.py ++++ b/ipaserver/plugins/baseuser.py +@@ -708,7 +708,11 @@ class baseuser_mod(LDAPUpdate): + if 'ipaidpuser' not in obj_classes: + entry_attrs['objectclass'].append('ipaidpuser') + +- answer = self.api.Object['idp'].get_dn_if_exists(cl) ++ try: ++ answer = self.api.Object['idp'].get_dn_if_exists(cl) ++ except errors.NotFound: ++ reason = "External IdP configuration {} not found" ++ raise errors.NotFound(reason=_(reason).format(cl)) + entry_attrs['ipaidpconfiglink'] = answer + + # Note: we could have used the method add_missing_object_class +diff --git a/ipaserver/plugins/stageuser.py b/ipaserver/plugins/stageuser.py +index 51438a83a95d15fb320148d2934a52f13a38f390..852e51b0eb0d757940b84721a6f01e43c5f36dd2 100644 +--- a/ipaserver/plugins/stageuser.py ++++ b/ipaserver/plugins/stageuser.py +@@ -404,7 +404,11 @@ class stageuser_add(baseuser_add): + if 'ipaidpuser' not in entry_attrs['objectclass']: + entry_attrs['objectclass'].append('ipaidpuser') + +- answer = self.api.Object['idp'].get_dn_if_exists(cl) ++ try: ++ answer = self.api.Object['idp'].get_dn_if_exists(cl) ++ except errors.NotFound: ++ reason = "External IdP configuration {} not found" ++ raise errors.NotFound(reason=_(reason).format(cl)) + entry_attrs['ipaidpconfiglink'] = answer + + self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys, +diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py +index 643b44f141e3add76f95cbeec6e90fec0ad4c9ad..a337e1fc7b44ef41ad16e18bd965b7af0a767d05 100644 +--- a/ipaserver/plugins/user.py ++++ b/ipaserver/plugins/user.py +@@ -638,7 +638,11 @@ class user_add(baseuser_add): + if 'ipaidpuser' not in entry_attrs['objectclass']: + entry_attrs['objectclass'].append('ipaidpuser') + +- answer = self.api.Object['idp'].get_dn_if_exists(rcl) ++ try: ++ answer = self.api.Object['idp'].get_dn_if_exists(rcl) ++ except errors.NotFound: ++ reason = "External IdP configuration {} not found" ++ raise errors.NotFound(reason=_(reason).format(rcl)) + entry_attrs['ipaidpconfiglink'] = answer + + self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys, +-- +2.41.0 + diff --git a/0016-xmlrpc-tests-add-a-test-for-user-plugin-with-non-exi.patch b/0016-xmlrpc-tests-add-a-test-for-user-plugin-with-non-exi.patch new file mode 100644 index 0000000..e5bae94 --- /dev/null +++ b/0016-xmlrpc-tests-add-a-test-for-user-plugin-with-non-exi.patch @@ -0,0 +1,122 @@ +From caacccc6b92c08f510fba2e31d9c56eb372abddc Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Wed, 19 Jul 2023 13:28:43 +0200 +Subject: [PATCH] xmlrpc tests: add a test for user plugin with non-existing + idp + +Add new tests checking the error returned for +ipa user-add ... --idp nonexistingidp +ipa user-mod ... --idp nonexistingidp +ipa stageuser-add ... --idp nonexistingidp +ipa stageuser-mod ... --idp nonexistingidp + +The expected error message is: +ipa: ERROR: External IdP configuration nonexistingidp not found + +Related: https://pagure.io/freeipa/issue/9416 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +--- + ipatests/test_xmlrpc/test_stageuser_plugin.py | 20 +++++++++++++++ + ipatests/test_xmlrpc/test_user_plugin.py | 25 +++++++++++++++++++ + 2 files changed, 45 insertions(+) + +diff --git a/ipatests/test_xmlrpc/test_stageuser_plugin.py b/ipatests/test_xmlrpc/test_stageuser_plugin.py +index 394015f87f9f4bd275a15bab930e28f16b299274..9ae5561dfa4e0d54fe1231501bfea3c0ba261849 100644 +--- a/ipatests/test_xmlrpc/test_stageuser_plugin.py ++++ b/ipatests/test_xmlrpc/test_stageuser_plugin.py +@@ -39,6 +39,8 @@ gid = u'456' + invalidrealm1 = u'suser1@NOTFOUND.ORG' + invalidrealm2 = u'suser1@BAD@NOTFOUND.ORG' + ++nonexistentidp = 'IdPDoesNotExist' ++ + invaliduser1 = u'+tuser1' + invaliduser2 = u'tuser1234567890123456789012345678901234567890' + +@@ -431,6 +433,15 @@ class TestCreateInvalidAttributes(XMLRPC_test): + invalidrealm2))): + command() + ++ def test_create_invalid_idp(self, stageduser): ++ stageduser.ensure_missing() ++ command = stageduser.make_create_command( ++ options={u'ipaidpconfiglink': nonexistentidp}) ++ with raises_exact(errors.NotFound( ++ reason="External IdP configuration {} not found".format( ++ nonexistentidp))): ++ command() ++ + + @pytest.mark.tier1 + class TestUpdateInvalidAttributes(XMLRPC_test): +@@ -466,6 +477,15 @@ class TestUpdateInvalidAttributes(XMLRPC_test): + message=u'invalid \'gidnumber\': must be at least 1')): + command() + ++ def test_update_invalididp(self, stageduser): ++ stageduser.ensure_exists() ++ command = stageduser.make_update_command( ++ updates={u'ipaidpconfiglink': nonexistentidp}) ++ with raises_exact(errors.NotFound( ++ reason="External IdP configuration {} not found".format( ++ nonexistentidp))): ++ command() ++ + + @pytest.mark.tier1 + class TestActive(XMLRPC_test): +diff --git a/ipatests/test_xmlrpc/test_user_plugin.py b/ipatests/test_xmlrpc/test_user_plugin.py +index 8ac19a4f9ce4f341838282ecd3ed1bb491ac7004..baa28672e7552140a703ecdfa5772b445298cb37 100644 +--- a/ipatests/test_xmlrpc/test_user_plugin.py ++++ b/ipatests/test_xmlrpc/test_user_plugin.py +@@ -86,6 +86,8 @@ expired_expiration_string = "1991-12-07T19:54:13Z" + # Date in ISO format (2013-12-10T12:00:00) + isodate_re = re.compile(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$') + ++nonexistentidp = 'IdPDoesNotExist' ++ + + @pytest.fixture(scope='class') + def user_min(request, xmlrpc_setup): +@@ -542,6 +544,18 @@ class TestUpdate(XMLRPC_test): + command() + user.delete() + ++ def test_update_invalid_idp(self, user): ++ """ Test user-mod --idp with a non-existent idp """ ++ user.ensure_exists() ++ command = user.make_update_command( ++ updates=dict(ipaidpconfiglink=nonexistentidp) ++ ) ++ with raises_exact(errors.NotFound( ++ reason="External IdP configuration {} not found".format( ++ nonexistentidp) ++ )): ++ command() ++ + + @pytest.mark.tier1 + class TestCreate(XMLRPC_test): +@@ -770,6 +784,17 @@ class TestCreate(XMLRPC_test): + user_radius.check_create(result) + user_radius.delete() + ++ def test_create_with_invalididp(self): ++ testuser = UserTracker( ++ name='idpuser', givenname='idp', sn='user', ++ ipaidpconfiglink=nonexistentidp ++ ) ++ with raises_exact(errors.NotFound( ++ reason="External IdP configuration {} not found".format( ++ nonexistentidp) ++ )): ++ testuser.create() ++ + + @pytest.mark.tier1 + class TestUserWithGroup(XMLRPC_test): +-- +2.41.0 + diff --git a/0017-Fix-memory-leak-in-the-OTP-last-token-plugin.patch b/0017-Fix-memory-leak-in-the-OTP-last-token-plugin.patch new file mode 100644 index 0000000..08b2092 --- /dev/null +++ b/0017-Fix-memory-leak-in-the-OTP-last-token-plugin.patch @@ -0,0 +1,117 @@ +From 421e8e9ac886c50b4bb463a62b8ad5de8da94f31 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Mon, 26 Jun 2023 13:06:51 -0400 +Subject: [PATCH] Fix memory leak in the OTP last token plugin + +Three memory leaks are addressed: + +1. String values retrieved from the pblock need to be manually +freed. + +2. The list of objectclasses retreived from the pblock need to be +freed. + +3. Internal search results need to be freed. + +Fixes: https://pagure.io/freeipa/issue/9403 + +Signed-off-by: Rob Crittenden +Reviewed-By: Rafael Guterres Jeffman +Reviewed-By: Alexander Bokovoy +--- + .../ipa-otp-lasttoken/ipa_otp_lasttoken.c | 38 +++++++++++++------ + daemons/ipa-slapi-plugins/libotp/otp_token.c | 1 + + 2 files changed, 27 insertions(+), 12 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c +index b7a2ba7f012fdbf90284ee6605788e196aa4793b..11106b239f9de9074125979cfae7c02e434936e1 100644 +--- a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c ++++ b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c +@@ -54,7 +54,7 @@ void *ipa_otp_lasttoken_plugin_id; + + static bool entry_is_token(Slapi_Entry *entry) + { +- char **ocls; ++ char **ocls = NULL; + + ocls = slapi_entry_attr_get_charray(entry, SLAPI_ATTR_OBJECTCLASS); + for (size_t i = 0; ocls != NULL && ocls[i] != NULL; i++) { +@@ -64,6 +64,7 @@ static bool entry_is_token(Slapi_Entry *entry) + } + } + ++ slapi_ch_array_free(ocls); + return false; + } + +@@ -138,7 +139,8 @@ static bool is_pwd_enabled(const char *user_dn) + static bool is_allowed(Slapi_PBlock *pb, Slapi_Entry *entry) + { + Slapi_DN *target_sdn = NULL; +- const char *bind_dn; ++ char *bind_dn; ++ bool rv = false; + + /* Ignore internal operations. */ + if (slapi_op_internal(pb)) +@@ -147,23 +149,35 @@ static bool is_allowed(Slapi_PBlock *pb, Slapi_Entry *entry) + /* Load parameters. */ + (void) slapi_pblock_get(pb, SLAPI_TARGET_SDN, &target_sdn); + (void) slapi_pblock_get(pb, SLAPI_CONN_DN, &bind_dn); +- if (target_sdn == NULL || bind_dn == NULL) { +- LOG_FATAL("Missing parameters!\n"); +- return false; ++ if (bind_dn == NULL) { ++ LOG_FATAL("bind_dn parameter missing!\n"); ++ goto done; ++ } ++ if (target_sdn == NULL) { ++ LOG_FATAL("target_sdn parameter missing!\n"); ++ goto done; + } + + if (entry != NULL + ? !entry_is_token(entry) +- : !sdn_in_otp_container(target_sdn)) +- return true; ++ : !sdn_in_otp_container(target_sdn)) { ++ rv = true; ++ goto done; ++ } + +- if (!sdn_is_only_enabled_token(target_sdn, bind_dn)) +- return true; ++ if (!sdn_is_only_enabled_token(target_sdn, bind_dn)) { ++ rv = true; ++ goto done; ++ } + +- if (is_pwd_enabled(bind_dn)) +- return true; ++ if (is_pwd_enabled(bind_dn)) { ++ rv = true; ++ goto done; ++ } + +- return false; ++done: ++ slapi_ch_free_string(&bind_dn); ++ return rv; + } + + static inline int send_error(Slapi_PBlock *pb, int rc, const char *errstr) +diff --git a/daemons/ipa-slapi-plugins/libotp/otp_token.c b/daemons/ipa-slapi-plugins/libotp/otp_token.c +index a3cbfb0621c071f8addb29f7ce02f870a807c61d..4be4ede07cbbd0d26bcc9952ef4d84d777076ae7 100644 +--- a/daemons/ipa-slapi-plugins/libotp/otp_token.c ++++ b/daemons/ipa-slapi-plugins/libotp/otp_token.c +@@ -398,6 +398,7 @@ static struct otp_token **find(const struct otp_config *cfg, const char *user_dn + } + + error: ++ slapi_free_search_results_internal(pb); + slapi_pblock_destroy(pb); + return tokens; + } +-- +2.41.0 + diff --git a/0018-Prevent-the-admin-user-from-being-deleted.patch b/0018-Prevent-the-admin-user-from-being-deleted.patch new file mode 100644 index 0000000..ee01e45 --- /dev/null +++ b/0018-Prevent-the-admin-user-from-being-deleted.patch @@ -0,0 +1,136 @@ +From 4b02322fc786ee9caaa0380659507a2cec0d4101 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Thu, 25 May 2023 18:24:29 -0400 +Subject: [PATCH] Prevent the admin user from being deleted + +admin is required for trust operations + +Note that testing for removing the last member is now +irrelevant because admin must always exist so the test +for it was removed, but the code check remains. It is done +after the protected member check. + +Fixes: https://pagure.io/freeipa/issue/8878 + +Signed-off-by: Rob Crittenden +Reviewed-By: Alexander Bokovoy +--- + ipaserver/plugins/user.py | 19 +++++++++-- + ipatests/test_xmlrpc/test_user_plugin.py | 40 ++++++++++++------------ + 2 files changed, 37 insertions(+), 22 deletions(-) + +diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py +index a337e1fc7b44ef41ad16e18bd965b7af0a767d05..6f5e34917e1b838a463dee146a4e9390f20c130a 100644 +--- a/ipaserver/plugins/user.py ++++ b/ipaserver/plugins/user.py +@@ -138,14 +138,23 @@ MEMBEROF_ADMINS = "(memberOf={})".format( + ) + + NOT_MEMBEROF_ADMINS = '(!{})'.format(MEMBEROF_ADMINS) ++PROTECTED_USERS = ('admin',) + + + def check_protected_member(user, protected_group_name=u'admins'): + ''' +- Ensure the last enabled member of a protected group cannot be deleted or +- disabled by raising LastMemberError. ++ Ensure admin and the last enabled member of a protected group cannot ++ be deleted or disabled by raising ProtectedEntryError or ++ LastMemberError as appropriate. + ''' + ++ if user in PROTECTED_USERS: ++ raise errors.ProtectedEntryError( ++ label=_("user"), ++ key=user, ++ reason=_("privileged user"), ++ ) ++ + # Get all users in the protected group + result = api.Command.user_find(in_group=protected_group_name) + +@@ -868,6 +877,12 @@ class user_mod(baseuser_mod): + + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): + dn, oc = self.obj.get_either_dn(*keys, **options) ++ if options.get('rename') and keys[-1] in PROTECTED_USERS: ++ raise errors.ProtectedEntryError( ++ label=_("user"), ++ key=keys[-1], ++ reason=_("privileged user"), ++ ) + if 'objectclass' not in entry_attrs and 'rename' not in options: + entry_attrs.update({'objectclass': oc}) + self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys, +diff --git a/ipatests/test_xmlrpc/test_user_plugin.py b/ipatests/test_xmlrpc/test_user_plugin.py +index baa28672e7552140a703ecdfa5772b445298cb37..df105a23529b29944411a6418e5db55d56e2c72a 100644 +--- a/ipatests/test_xmlrpc/test_user_plugin.py ++++ b/ipatests/test_xmlrpc/test_user_plugin.py +@@ -978,22 +978,32 @@ class TestManagers(XMLRPC_test): + + @pytest.mark.tier1 + class TestAdmins(XMLRPC_test): +- def test_remove_original_admin(self): +- """ Try to remove the only admin """ ++ def test_delete_admin(self): ++ """ Try to delete the protected admin user """ + tracker = Tracker() +- command = tracker.make_command('user_del', [admin1]) ++ command = tracker.make_command('user_del', admin1) + +- with raises_exact(errors.LastMemberError( +- key=admin1, label=u'group', container=admin_group)): ++ with raises_exact(errors.ProtectedEntryError(label=u'user', ++ key=admin1, reason='privileged user')): ++ command() ++ ++ def test_rename_admin(self): ++ """ Try to rename the admin user """ ++ tracker = Tracker() ++ command = tracker.make_command('user_mod', admin1, ++ **dict(rename=u'newadmin')) ++ ++ with raises_exact(errors.ProtectedEntryError(label=u'user', ++ key=admin1, reason='privileged user')): + command() + + def test_disable_original_admin(self): +- """ Try to disable the only admin """ ++ """ Try to disable the original admin """ + tracker = Tracker() + command = tracker.make_command('user_disable', admin1) + +- with raises_exact(errors.LastMemberError( +- key=admin1, label=u'group', container=admin_group)): ++ with raises_exact(errors.ProtectedEntryError(label=u'user', ++ key=admin1, reason='privileged user')): + command() + + def test_create_admin2(self, admin2): +@@ -1011,21 +1021,11 @@ class TestAdmins(XMLRPC_test): + admin2.disable() + tracker = Tracker() + +- with raises_exact(errors.LastMemberError( +- key=admin1, label=u'group', container=admin_group)): ++ with raises_exact(errors.ProtectedEntryError(label=u'user', ++ key=admin1, reason='privileged user')): + tracker.run_command('user_disable', admin1) +- with raises_exact(errors.LastMemberError( +- key=admin1, label=u'group', container=admin_group)): +- tracker.run_command('user_del', admin1) + admin2.delete() + +- with raises_exact(errors.LastMemberError( +- key=admin1, label=u'group', container=admin_group)): +- tracker.run_command('user_disable', admin1) +- with raises_exact(errors.LastMemberError( +- key=admin1, label=u'group', container=admin_group)): +- tracker.run_command('user_del', admin1) +- + + @pytest.mark.tier1 + class TestPreferredLanguages(XMLRPC_test): +-- +2.41.0 + diff --git a/0019-ipa-kdb-fix-error-handling-of-is_master_host.patch b/0019-ipa-kdb-fix-error-handling-of-is_master_host.patch new file mode 100644 index 0000000..957d97f --- /dev/null +++ b/0019-ipa-kdb-fix-error-handling-of-is_master_host.patch @@ -0,0 +1,87 @@ +From fd32e6a3d95f28d2d11d41ee5dabb0d563cb5d51 Mon Sep 17 00:00:00 2001 +From: Julien Rische +Date: Mon, 31 Jul 2023 11:26:43 +0200 +Subject: [PATCH] ipa-kdb: fix error handling of is_master_host() + +Adding proper error handling to the is_master_host() function to allow +it to make the difference between the absence of a master host object +and a connection failure. This will keep the krb5kdc daemon from +continuing to run with a NULL LDAP context. + +Fixes: https://pagure.io/freeipa/issue/9422 + +Signed-off-by: Julien Rische +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-kdb/ipa_kdb_mspac.c | 41 +++++++++++++++++++-------------- + 1 file changed, 24 insertions(+), 17 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index 83b507cb422c735f933edaebfc7b903b8fa908e4..1558e2bead288d9d00014e9b3b059934e80b54e4 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -401,27 +401,29 @@ static krb5_error_code ipadb_add_asserted_identity(struct ipadb_context *ipactx, + return 0; + } + +-static bool is_master_host(struct ipadb_context *ipactx, const char *fqdn) ++static krb5_error_code ++is_master_host(struct ipadb_context *ipactx, const char *fqdn, bool *result) + { +- int ret; ++ int err; + char *master_host_base = NULL; +- LDAPMessage *result = NULL; +- krb5_error_code err; ++ LDAPMessage *ldap_res = NULL; + +- ret = asprintf(&master_host_base, "cn=%s,cn=masters,cn=ipa,cn=etc,%s", ++ err = asprintf(&master_host_base, "cn=%s,cn=masters,cn=ipa,cn=etc,%s", + fqdn, ipactx->base); +- if (ret == -1) { +- return false; +- } ++ if (err == -1) ++ return ENOMEM; ++ + err = ipadb_simple_search(ipactx, master_host_base, LDAP_SCOPE_BASE, +- NULL, NULL, &result); ++ NULL, NULL, &ldap_res); + free(master_host_base); +- ldap_msgfree(result); +- if (err == 0) { +- return true; +- } ++ ldap_msgfree(ldap_res); ++ if (err != KRB5_KDB_NOENTRY && err != 0) ++ return err; ++ ++ if (result) ++ *result = err != KRB5_KDB_NOENTRY; + +- return false; ++ return 0; + } + + static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx, +@@ -692,9 +694,14 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx, + if ((is_host || is_service)) { + /* it is either host or service, so get the hostname first */ + char *sep = strchr(info3->base.account_name.string, '/'); +- bool is_master = is_master_host( +- ipactx, +- sep ? sep + 1 : info3->base.account_name.string); ++ bool is_master; ++ ++ ret = is_master_host(ipactx, ++ sep ? sep + 1 : info3->base.account_name.string, ++ &is_master); ++ if (ret) ++ return ret; ++ + if (is_master) { + /* Well known RID of domain controllers group */ + if (info3->base.rid == 0) { +-- +2.41.0 + diff --git a/0020-ipatests-update-expected-webui-msg-for-admin-deletio.patch b/0020-ipatests-update-expected-webui-msg-for-admin-deletio.patch new file mode 100644 index 0000000..17ad7c5 --- /dev/null +++ b/0020-ipatests-update-expected-webui-msg-for-admin-deletio.patch @@ -0,0 +1,38 @@ +From 13d5e88eb4ebb7a0132cbb050a9d230304ecbcff Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Wed, 2 Aug 2023 15:41:57 +0200 +Subject: [PATCH] ipatests: update expected webui msg for admin deletion + +The deletion of the admin is now forbidden (even if it is +not the last member of the admins group) and the error +message has changed from "admin cannot be deleted or +disabled because it is the last member of group admins" +to " user admin cannot be deleted/modified: privileged user". + +Update the expected message in the webui test. + +Related: https://pagure.io/freeipa/issue/8878 + +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Alexander Bokovoy +--- + ipatests/test_webui/test_user.py | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/ipatests/test_webui/test_user.py b/ipatests/test_webui/test_user.py +index 8d44fbdb9380c94058307b02a96299d0e178cdc7..a8a92d00c7e1f40ef10eb9133cea8752daafe730 100644 +--- a/ipatests/test_webui/test_user.py ++++ b/ipatests/test_webui/test_user.py +@@ -50,8 +50,7 @@ INV_FIRSTNAME = ("invalid 'first': Leading and trailing spaces are " + FIELD_REQ = 'Required field' + ERR_INCLUDE = 'may only include letters, numbers, _, -, . and $' + ERR_MISMATCH = 'Passwords must match' +-ERR_ADMIN_DEL = ('admin cannot be deleted or disabled because it is the last ' +- 'member of group admins') ++ERR_ADMIN_DEL = ('user admin cannot be deleted/modified: privileged user') + USR_EXIST = 'user with name "{}" already exists' + ENTRY_EXIST = 'This entry already exists' + ACTIVE_ERR = 'active user with name "{}" already exists' +-- +2.41.0 + diff --git a/0021-ipatests-remove-fixture-call-and-wait-to-get-things-.patch b/0021-ipatests-remove-fixture-call-and-wait-to-get-things-.patch new file mode 100644 index 0000000..1a01ef2 --- /dev/null +++ b/0021-ipatests-remove-fixture-call-and-wait-to-get-things-.patch @@ -0,0 +1,70 @@ +From ff6cfcacd67a0461a0341e17854732cbe301f1d6 Mon Sep 17 00:00:00 2001 +From: Mohammad Rizwan +Date: Wed, 2 Aug 2023 12:48:40 +0530 +Subject: [PATCH] ipatests: remove fixture call and wait to get things settle + +system date moved in order to expire the certs. Sometime it +is observed that subsequent operation fails with 500 error for CA, +hence restart the services after moving date and wait for sometime +to get things settle. + +Also the tests was calling fixture which is not required for it, hence +removed it as well. + +Fixes: https://pagure.io/freeipa/issue/9348 + +Signed-off-by: Mohammad Rizwan +Reviewed-By: Florence Blanc-Renaud +--- + ipatests/test_integration/test_acme.py | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/ipatests/test_integration/test_acme.py b/ipatests/test_integration/test_acme.py +index cca20983e65f99d5ba0bb7bc6dc2b5684a6f37d9..c7389732cd067d49541cd04ea6687a6b95b4669f 100644 +--- a/ipatests/test_integration/test_acme.py ++++ b/ipatests/test_integration/test_acme.py +@@ -606,6 +606,11 @@ def issue_and_expire_acme_cert(): + tasks.kdestroy_all(host) + tasks.move_date(host, 'stop', '+90days+60minutes') + ++ # restart ipa services as date moved and wait to get things settle ++ time.sleep(10) ++ master.run_command(['ipactl', 'restart']) ++ time.sleep(10) ++ + tasks.get_kdcinfo(master) + # Note raiseonerr=False: + # the assert is located after kdcinfo retrieval. +@@ -627,6 +632,11 @@ def issue_and_expire_acme_cert(): + for host in hosts: + tasks.move_date(host, 'start', '-90days-60minutes') + ++ # restart ipa services as date moved and wait to get things settle ++ time.sleep(10) ++ hosts[0].run_command(['ipactl', 'restart']) ++ time.sleep(10) ++ + + class TestACMERenew(IntegrationTest): + +@@ -960,7 +970,7 @@ class TestACMEPrune(IntegrationTest): + ) + assert f'Number of entries returned {no_of_cert - search_size_limit}' + +- def test_prune_config_show(self, issue_and_expire_acme_cert): ++ def test_prune_config_show(self): + """Test to check config-show command shows set param""" + if (tasks.get_pki_version(self.master) + < tasks.parse_version('11.3.0')): +@@ -1001,7 +1011,7 @@ class TestACMEPrune(IntegrationTest): + assert 'Request Search Time Limit: 0' in result.stdout_text + assert 'cron Schedule: 0 0 1 * *' in result.stdout_text + +- def test_prune_disable(self, issue_and_expire_acme_cert): ++ def test_prune_disable(self): + """Test prune command throw error after disabling the pruning""" + if (tasks.get_pki_version(self.master) + < tasks.parse_version('11.3.0')): +-- +2.41.0 + diff --git a/freeipa.spec b/freeipa.spec index feb4b2f..8b273a7 100644 --- a/freeipa.spec +++ b/freeipa.spec @@ -223,7 +223,7 @@ Name: %{package_name} Version: %{IPA_VERSION} -Release: 2%{?rc_version:.%rc_version}%{?dist} +Release: 3%{?rc_version:.%rc_version}%{?dist} Summary: The Identity, Policy and Audit system License: GPL-3.0-or-later @@ -260,6 +260,14 @@ Patch0010: 0010-Upgrade-fix-replica-agreement.patch Patch0011: 0011-Integration-tests-add-a-test-to-ipa-server-upgrade.patch Patch0012: 0012-tests-fix-backup-restore-scenario-with-replica.patch Patch0013: 0013-OTP-fix-data-type-to-avoid-endianness-issue.patch +Patch0014: 0014-ipatests-enable-firewall-rule-for-http-service-on-ac.patch +Patch0015: 0015-User-plugin-improve-error-related-to-non-existing-id.patch +Patch0016: 0016-xmlrpc-tests-add-a-test-for-user-plugin-with-non-exi.patch +Patch0017: 0017-Fix-memory-leak-in-the-OTP-last-token-plugin.patch +Patch0018: 0018-Prevent-the-admin-user-from-being-deleted.patch +Patch0019: 0019-ipa-kdb-fix-error-handling-of-is_master_host.patch +Patch0020: 0020-ipatests-update-expected-webui-msg-for-admin-deletio.patch +Patch0021: 0021-ipatests-remove-fixture-call-and-wait-to-get-things-.patch Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch %endif %endif @@ -1751,6 +1759,13 @@ fi %endif %changelog +* Thu Aug 10 2023 Florence Blanc-Renaud - 4.10.2-3 +- Resolves: rhbz#2229712 Delete operation protection for admin user +- Resolves: rhbz#2227831 Interrupt request processing in ipadb_fill_info3() if connection to 389ds is lost +- Resolves: rhbz#2227784 libipa_otp_lasttoken plugin memory leak +- Resolves: rhbz#2224570 Improved error messages are needed when attempting to add a non-existing idp to a user +- Resolves: rhbz#2230251 Backport latest test fixes to python3-ipatests + * Thu Jun 29 2023 Florence Blanc-Renaud - 4.10.2-2 - Resolves: rhbz#2192969 Better handling of the command line and web UI cert search and/or list features - Resolves: rhbz#2214933 Uninstalling of the IPA server is encountering a failure during the unconfiguration of the CA (Unconfiguring CA)