Compare commits

..

No commits in common. "c8-stream-DL1" and "changed/a9/ipa-4.10.2-5.el9_3.alma.1" have entirely different histories.

68 changed files with 5719 additions and 11289 deletions

2
.gitignore vendored
View File

@ -1 +1 @@
SOURCES/freeipa-4.9.13.tar.gz SOURCES/freeipa-4.10.2.tar.gz

View File

@ -1 +1 @@
da1bb0220894d8dc06afb98dcf087fea38076a79 SOURCES/freeipa-4.9.13.tar.gz 17d580b7dccb1586898aa46c7ecdd2bd2754ee5f SOURCES/freeipa-4.10.2.tar.gz

View File

@ -1,73 +0,0 @@
From 06b4c61b4484efe2093501caf21b03f1fc14093b Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Thu, 19 Oct 2023 12:47:03 +0200
Subject: [PATCH] group-add-member fails with an external member
The command ipa group-add-member --external aduser@addomain.test
fails with an internal error when used with samba 4.19.
The command internally calls samba.security.dom_sid(sid) which
used to raise a TypeError but now raises a ValueError
(commit 9abdd67 on https://github.com/samba-team/samba).
IPA source code needs to handle properly both exception types.
Fixes: https://pagure.io/freeipa/issue/9466
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
ipaserver/dcerpc.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
index c1db2f9a499..ee0a229d1f0 100644
--- a/ipaserver/dcerpc.py
+++ b/ipaserver/dcerpc.py
@@ -303,7 +303,7 @@ def get_domain_by_sid(self, sid, exact_match=False):
# Parse sid string to see if it is really in a SID format
try:
test_sid = security.dom_sid(sid)
- except TypeError:
+ except (TypeError, ValueError):
raise errors.ValidationError(name='sid',
error=_('SID is not valid'))
From aa3397378acf1a03fc8bbe34b9fae33e84588b34 Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Fri, 20 Oct 2023 10:20:57 +0200
Subject: [PATCH] Handle samba changes in samba.security.dom_sid()
samba.security.dom_sid() in 4.19 now raises ValueError instead of
TypeError. Fix the expected exception.
Related: https://pagure.io/freeipa/issue/9466
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
---
ipaserver/dcerpc.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
index ee0a229d1f0..3e4c71d9976 100644
--- a/ipaserver/dcerpc.py
+++ b/ipaserver/dcerpc.py
@@ -97,7 +97,7 @@
def is_sid_valid(sid):
try:
security.dom_sid(sid)
- except TypeError:
+ except (TypeError, ValueError):
return False
else:
return True
@@ -457,7 +457,7 @@ def get_trusted_domain_object_sid(self, object_name,
try:
test_sid = security.dom_sid(sid)
return unicode(test_sid)
- except TypeError:
+ except (TypeError, ValueError):
raise errors.ValidationError(name=_('trusted domain object'),
error=_('Trusted domain did not '
'return a valid SID for '

View File

@ -0,0 +1,35 @@
From 4f6ebb5fdf6d2514d4683247e5d1bfc6022a500e Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Tue, 6 Jun 2023 09:04:48 +0200
Subject: [PATCH] webuitests: close notification which hides Add button
The webui test test_service.py::test_service::test_arbitrary_certificates
randomly fails.
The test is creating a new service then navigates to the Service page
and clicks on the Add Certificate button.
The notification area may still be present and hide the button, with
the message "Service successfully added".
Close all notifications before navigating to the Service page.
Fixes: https://pagure.io/freeipa/issue/9389
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
---
ipatests/test_webui/test_service.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/ipatests/test_webui/test_service.py b/ipatests/test_webui/test_service.py
index f1d9a9d624bc587634e03a86050627a648feb26d..e2976d73acd1f574f1164828be9d8e871b737d7f 100644
--- a/ipatests/test_webui/test_service.py
+++ b/ipatests/test_webui/test_service.py
@@ -296,6 +296,7 @@ class test_service(sevice_tasks):
cert_widget_sel = "div.certificate-widget"
self.add_record(ENTITY, data)
+ self.close_notifications()
self.navigate_to_record(pkey)
# check whether certificate section is present
--
2.41.0

View File

@ -0,0 +1,48 @@
From 8d34f453fb139c4cef055a4963f307a760316a73 Mon Sep 17 00:00:00 2001
From: Anuja More <amore@redhat.com>
Date: Thu, 11 May 2023 12:50:10 +0530
Subject: [PATCH] ipatests: Check that SSSD_PUBCONF_KRB5_INCLUDE_D_DIR is not
included in krb5.conf
SSSD already provides a config snippet which includes
SSSD_PUBCONF_KRB5_INCLUDE_D_DIR, and having both breaks Java.
Test checks that krb5.conf does not include
SSSD_PUBCONF_KRB5_INCLUDE_D_DIR.
Related: https://pagure.io/freeipa/issue/9267
Signed-off-by: Anuja More <amore@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
---
.../test_integration/test_installation_client.py | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/ipatests/test_integration/test_installation_client.py b/ipatests/test_integration/test_installation_client.py
index 014b0f6ab34dd92c00c0187c2c86b8bfbaa70e81..56e1593bfcfa3eb7f9918fc6f2993d836884ea38 100644
--- a/ipatests/test_integration/test_installation_client.py
+++ b/ipatests/test_integration/test_installation_client.py
@@ -76,6 +76,21 @@ class TestInstallClient(IntegrationTest):
result = self.clients[0].run_command(['cat', '/etc/ssh/ssh_config'])
assert 'HostKeyAlgorithms' not in result.stdout_text
+ def test_client_install_with_krb5(self):
+ """Test that SSSD_PUBCONF_KRB5_INCLUDE_D_DIR is not added in krb5.conf
+
+ SSSD already provides a config snippet which includes
+ SSSD_PUBCONF_KRB5_INCLUDE_D_DIR, and having both breaks Java.
+ Test checks that krb5.conf does not include
+ SSSD_PUBCONF_KRB5_INCLUDE_D_DIR.
+
+ related: https://pagure.io/freeipa/issue/9267
+ """
+ krb5_cfg = self.master.get_file_contents(paths.KRB5_CONF)
+ assert 'includedir {dir}'.format(
+ dir=paths.SSSD_PUBCONF_KRB5_INCLUDE_D_DIR
+ ).encode() not in krb5_cfg
+
class TestClientInstallBind(IntegrationTest):
"""
--
2.41.0

View File

@ -0,0 +1,103 @@
From 276138087158c6b2ea76b43c754084144e543c0b Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Wed, 7 Jun 2023 11:32:21 -0400
Subject: [PATCH] Revert "Use the OpenSSL certificate parser in cert-find"
This reverts commit 191880bc9f77c3e8a3cecc82e6eea33ab5ad03e4.
The problem isn't with python-cryptography, it is with the
IPACertificate class which does way more work on a certificate
than is necessary in cert-find.
Related: https://pagure.io/freeipa/issue/9331
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
---
freeipa.spec.in | 2 --
ipaserver/plugins/cert.py | 26 +++-----------------------
2 files changed, 3 insertions(+), 25 deletions(-)
diff --git a/freeipa.spec.in b/freeipa.spec.in
index 3e23bbfe9d054a3a9febf468de0bcb4a6e81bb32..bec9780a82fe0d9bc5a50a93bdce8aa7e27a9f30 100755
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -412,7 +412,6 @@ BuildRequires: python3-pylint
BuildRequires: python3-pytest-multihost
BuildRequires: python3-pytest-sourceorder
BuildRequires: python3-qrcode-core >= 5.0.0
-BuildRequires: python3-pyOpenSSL
BuildRequires: python3-samba
BuildRequires: python3-six
BuildRequires: python3-sss
@@ -884,7 +883,6 @@ Requires: python3-netifaces >= 0.10.4
Requires: python3-pyasn1 >= 0.3.2-2
Requires: python3-pyasn1-modules >= 0.3.2-2
Requires: python3-pyusb
-Requires: python3-pyOpenSSL
Requires: python3-qrcode-core >= 5.0.0
Requires: python3-requests
Requires: python3-six
diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py
index 400b1b3cec0aba82e699a4a981516e121f3e0c77..2e32f4ecd50ac92c28bcaffcebe9c2c87557858a 100644
--- a/ipaserver/plugins/cert.py
+++ b/ipaserver/plugins/cert.py
@@ -30,7 +30,6 @@ import cryptography.x509
from cryptography.hazmat.primitives import hashes, serialization
from dns import resolver, reversename
import six
-import sys
from ipalib import Command, Str, Int, Flag, StrEnum, SerialNumber
from ipalib import api
@@ -1618,19 +1617,7 @@ class cert_find(Search, CertMethod):
)
def _get_cert_key(self, cert):
- # for cert-find with a certificate value
- if isinstance(cert, x509.IPACertificate):
- return (DN(cert.issuer), cert.serial_number)
-
- issuer = []
- for oid, value in cert.get_issuer().get_components():
- issuer.append(
- '{}={}'.format(oid.decode('utf-8'), value.decode('utf-8'))
- )
- issuer = ','.join(issuer)
- # Use this to flip from OpenSSL reverse to X500 ordering
- issuer = DN(issuer).x500_text()
- return (DN(issuer), cert.get_serial_number())
+ return (DN(cert.issuer), cert.serial_number)
def _cert_search(self, pkey_only, **options):
result = collections.OrderedDict()
@@ -1750,11 +1737,6 @@ class cert_find(Search, CertMethod):
return result, False, complete
def _ldap_search(self, all, pkey_only, no_members, **options):
- # defer import of the OpenSSL module to not affect the requests
- # module which will use pyopenssl if this is available.
- if sys.modules.get('OpenSSL.SSL', False) is None:
- del sys.modules["OpenSSL.SSL"]
- import OpenSSL.crypto
ldap = self.api.Backend.ldap2
filters = []
@@ -1813,14 +1795,12 @@ class cert_find(Search, CertMethod):
ca_enabled = getattr(context, 'ca_enabled')
for entry in entries:
for attr in ('usercertificate', 'usercertificate;binary'):
- for der in entry.raw.get(attr, []):
- cert = OpenSSL.crypto.load_certificate(
- OpenSSL.crypto.FILETYPE_ASN1, der)
+ for cert in entry.get(attr, []):
cert_key = self._get_cert_key(cert)
try:
obj = result[cert_key]
except KeyError:
- obj = {'serial_number': cert.get_serial_number()}
+ obj = {'serial_number': cert.serial_number}
if not pkey_only and (all or not ca_enabled):
# Retrieving certificate details is now deferred
# until after all certificates are collected.
--
2.41.0

View File

@ -0,0 +1,32 @@
From d83a4b0babdc7beb124d3748b5815ce309739eb7 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Tue, 13 Jun 2023 17:01:49 -0400
Subject: [PATCH] Revert "cert_find: fix call with --all"
This reverts commit 1f30cc65276a532e7288217f216b72a2b0628c8f.
The problem isn't with python-cryptography, it is with the
IPACertificate class which does way more work on a certificate
than is necessary in cert-find.
Related: https://pagure.io/freeipa/issue/9331
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
---
ipaserver/plugins/cert.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py
index 2e32f4ecd50ac92c28bcaffcebe9c2c87557858a..36a0e8cb31b4dbdd9bff09165d1d8aa203936d37 100644
--- a/ipaserver/plugins/cert.py
+++ b/ipaserver/plugins/cert.py
@@ -1807,7 +1807,6 @@ class cert_find(Search, CertMethod):
# For the case of CA-less we need to keep
# the certificate because getting it again later
# would require unnecessary LDAP searches.
- cert = cert.to_cryptography()
obj['certificate'] = (
base64.b64encode(
cert.public_bytes(x509.Encoding.DER))
--
2.41.0

View File

@ -1,265 +0,0 @@
From 013be398bced31f567ef01ac2471cb7529789b4a Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Mon, 9 Oct 2023 15:47:03 +0200
Subject: [PATCH] ipa-kdb: Detect and block Bronze-Bit attacks
The C8S/RHEL8 version of FreeIPA is vulnerable to the Bronze-Bit attack
because it does not implement PAC ticket signature to protect the
"forwardable" flag. However, it does implement the PAC extended KDC
signature, which protects against PAC spoofing.
Based on information available in the PAC and the
"ok-to-auth-as-delegate" attribute in the database. It is possible to
detect and reject requests where the "forwardable" flag was flipped by
the attacker in the evidence ticket.
---
daemons/ipa-kdb/ipa_kdb.h | 13 +++
daemons/ipa-kdb/ipa_kdb_kdcpolicy.c | 6 +
daemons/ipa-kdb/ipa_kdb_mspac.c | 173 ++++++++++++++++++++++++++++
ipaserver/install/server/install.py | 8 ++
4 files changed, 200 insertions(+)
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
index 7aa5be494..02b2cb631 100644
--- a/daemons/ipa-kdb/ipa_kdb.h
+++ b/daemons/ipa-kdb/ipa_kdb.h
@@ -367,6 +367,19 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
const char *test_realm, size_t size,
char **trusted_realm);
+/* Try to detect a Bronze-Bit attack based on the content of the request and
+ * data from the KDB.
+ *
+ * context krb5 context
+ * request KDB request
+ * detected Set to "true" if a bronze bit attack is detected and the
+ * pointer is not NULL. Remains unset otherwise.
+ * status If the call fails and the pointer is not NULL, set it with a
+ * message describing the cause of the failure. */
+krb5_error_code
+ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
+ bool *detected, const char **status);
+
/* DELEGATION CHECKS */
krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext,
diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
index f2804c9b2..1032dff0b 100644
--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
+++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
@@ -185,6 +185,12 @@ ipa_kdcpolicy_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata,
const char **status, krb5_deltat *lifetime_out,
krb5_deltat *renew_lifetime_out)
{
+ krb5_error_code kerr;
+
+ kerr = ipadb_check_for_bronze_bit_attack(context, request, NULL, status);
+ if (kerr)
+ return KRB5KDC_ERR_POLICY;
+
*status = NULL;
*lifetime_out = 0;
*renew_lifetime_out = 0;
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
index 83cb9914d..b4e22d431 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
@@ -3298,3 +3298,176 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
return KRB5_KDB_NOENTRY;
}
+
+krb5_error_code
+ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
+ bool *detected, const char **status)
+{
+ krb5_error_code kerr;
+ const char *st = NULL;
+ size_t i, j;
+ krb5_ticket *evidence_tkt;
+ krb5_authdata **authdata, **ifrel = NULL;
+ krb5_pac pac = NULL;
+ TALLOC_CTX *tmpctx = NULL;
+ krb5_data fullsign = { 0, 0, NULL }, linfo_blob = { 0, 0, NULL };
+ DATA_BLOB linfo_data;
+ struct PAC_LOGON_INFO_CTR linfo;
+ enum ndr_err_code ndr_err;
+ struct dom_sid asserted_identity_sid;
+ bool evtkt_is_s4u2self = false;
+ krb5_db_entry *proxy_entry = NULL;
+
+ /* If no additional ticket, this is not a constrained delegateion request.
+ * Skip checks. */
+ if (!(request->kdc_options & KDC_OPT_CNAME_IN_ADDL_TKT)) {
+ kerr = 0;
+ goto end;
+ }
+
+ evidence_tkt = request->second_ticket[0];
+
+ /* No need to check the Forwardable flag. If it was not set, this request
+ * would have failed earlier. */
+
+ /* We only support general constrained delegation (not RBCD), which is not
+ * available for cross-realms. */
+ if (!krb5_realm_compare(context, evidence_tkt->server, request->server)) {
+ st = "S4U2PROXY_NOT_SUPPORTED_FOR_CROSS_REALMS";
+ kerr = ENOTSUP;
+ goto end;
+ }
+
+ authdata = evidence_tkt->enc_part2->authorization_data;
+
+ /* Search for the PAC. */
+ for (i = 0; authdata != NULL && authdata[i] != NULL; i++) {
+ if (authdata[i]->ad_type != KRB5_AUTHDATA_IF_RELEVANT)
+ continue;
+
+ kerr = krb5_decode_authdata_container(context,
+ KRB5_AUTHDATA_IF_RELEVANT,
+ authdata[i], &ifrel);
+ if (kerr) {
+ st = "S4U2PROXY_CANNOT_DECODE_EVIDENCE_TKT_AUTHDATA";
+ goto end;
+ }
+
+ for (j = 0; ifrel[j] != NULL; j++) {
+ if (ifrel[j]->ad_type == KRB5_AUTHDATA_WIN2K_PAC)
+ break;
+ }
+ if (ifrel[j] != NULL)
+ break;
+
+ krb5_free_authdata(context, ifrel);
+ ifrel = NULL;
+ }
+
+ if (ifrel == NULL) {
+ st = "S4U2PROXY_EVIDENCE_TKT_WITHOUT_PAC";
+ kerr = ENOENT;
+ goto end;
+ }
+
+ /* Parse the PAC. */
+ kerr = krb5_pac_parse(context, ifrel[j]->contents, ifrel[j]->length, &pac);
+ if (kerr) {
+ st = "S4U2PROXY_CANNOT_DECODE_EVICENCE_TKT_PAC";
+ goto end;
+ }
+
+ /* Check that the PAC extanded KDC signature is present. If it is, it was
+ * already tested.
+ * If absent, the context of the PAC cannot be trusted. */
+ kerr = krb5_pac_get_buffer(context, pac, KRB5_PAC_FULL_CHECKSUM, &fullsign);
+ if (kerr) {
+ st = "S4U2PROXY_MISSING_EXTENDED_KDC_SIGN_IN_EVIDENCE_TKT_PAC";
+ goto end;
+ }
+
+ /* Get the PAC Logon Info. */
+ kerr = krb5_pac_get_buffer(context, pac, KRB5_PAC_LOGON_INFO, &linfo_blob);
+ if (kerr) {
+ st = "S4U2PROXY_NO_PAC_LOGON_INFO_IN_EVIDENCE_TKT";
+ goto end;
+ }
+
+ /* Parse the PAC Logon Info. */
+ tmpctx = talloc_new(NULL);
+ if (!tmpctx) {
+ st = "OUT_OF_MEMORY";
+ kerr = ENOMEM;
+ goto end;
+ }
+
+ linfo_data.length = linfo_blob.length;
+ linfo_data.data = (uint8_t *)linfo_blob.data;
+ ndr_err = ndr_pull_union_blob(&linfo_data, tmpctx, &linfo,
+ PAC_TYPE_LOGON_INFO,
+ (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ st = "S4U2PROXY_CANNOT_PARSE_ENVIDENCE_TKT_PAC_LOGON_INFO";
+ kerr = EINVAL;
+ goto end;
+ }
+
+ /* Check that the extra SIDs array is not empty. */
+ if (linfo.info->info3.sidcount == 0) {
+ st = "S4U2PROXY_NO_EXTRA_SID";
+ kerr = ENOENT;
+ goto end;
+ }
+
+ /* Search for the S-1-18-2 domain SID, which indicates the ticket was
+ * obtained using S4U2Self */
+ kerr = ipadb_string_to_sid("S-1-18-2", &asserted_identity_sid);
+ if (kerr) {
+ st = "S4U2PROXY_CANNOT_CREATE_ASSERTED_IDENTITY_SID";
+ goto end;
+ }
+
+ for (i = 0; i < linfo.info->info3.sidcount; i++) {
+ if (dom_sid_check(&asserted_identity_sid,
+ linfo.info->info3.sids[0].sid, true)) {
+ evtkt_is_s4u2self = true;
+ break;
+ }
+ }
+
+ /* If the ticket was obtained using S4U2Self, the proxy principal entry must
+ * have the "ok_to_auth_as_delegate" attribute set to true. */
+ if (evtkt_is_s4u2self) {
+ kerr = ipadb_get_principal(context, evidence_tkt->server, 0,
+ &proxy_entry);
+ if (kerr) {
+ st = "S4U2PROXY_CANNOT_FIND_PROXY_PRINCIPAL";
+ goto end;
+ }
+
+ if (!(proxy_entry->attributes & KRB5_KDB_OK_TO_AUTH_AS_DELEGATE)) {
+ /* This evidence ticket cannot be forwardable given the privileges
+ * of the proxy principal.
+ * This is a Bronze Bit attack. */
+ if (detected)
+ *detected = true;
+ st = "S4U2PROXY_BRONZE_BIT_ATTACK_DETECTED";
+ kerr = EBADE;
+ goto end;
+ }
+ }
+
+ kerr = 0;
+
+end:
+ if (st && status)
+ *status = st;
+
+ krb5_free_authdata(context, ifrel);
+ krb5_pac_free(context, pac);
+ krb5_free_data_contents(context, &linfo_blob);
+ krb5_free_data_contents(context, &fullsign);
+ talloc_free(tmpctx);
+ ipadb_free_principal(context, proxy_entry);
+ return kerr;
+}
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
index 4e4076410..bfbb83bcb 100644
--- a/ipaserver/install/server/install.py
+++ b/ipaserver/install/server/install.py
@@ -981,6 +981,14 @@ def install(installer):
# Set the admin user kerberos password
ds.change_admin_password(admin_password)
+ # Force KDC to refresh the cached value of ipaKrbAuthzData by restarting.
+ # ipaKrbAuthzData has to be set with "MS-PAC" to trigger PAC generation,
+ # which is required to handle S4U2Proxy with the Bronze-Bit fix.
+ # Not doing so would cause API malfunction for around a minute, which is
+ # long enough to cause the hereafter client installation to fail.
+ service.print_msg("Restarting the KDC")
+ krb.restart()
+
# Call client install script
service.print_msg("Configuring client side components")
try:
--
2.41.0

View File

@ -1,212 +0,0 @@
From 3add9ba03a0af913d03b1f5ecaa8e48e46a93f91 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Jan 15 2024 13:42:08 +0000
Subject: Server affinity: Retain user-requested remote server
We want to avoid splitting a replica server installation between
two hosts where possible so if a CA or KRA is requested then
we only try to install against a remote server that also provides
those capabilities. This avoids race conditions.
If a CA or KRA is not requested and the user has provided a
server to install against then use that instead of overriding it.
Extend the logic of picking the remote Custodia mode
(KRA, CA, *MASTER*) to include considering whether the
CA and KRA services are requested. If the service(s) are
not requested the the associated hostname may not be
reliable.
Fixes: https://pagure.io/freeipa/issue/9491
Related: https://pagure.io/freeipa/issue/9289
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
---
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index 27fbdef..8096b6a 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -782,6 +782,7 @@ def promotion_check_host_principal_auth_ind(conn, hostdn):
def remote_connection(config):
+ logger.debug("Creating LDAP connection to %s", config.master_host_name)
ldapuri = 'ldaps://%s' % ipautil.format_netloc(config.master_host_name)
xmlrpc_uri = 'https://{}/ipa/xml'.format(
ipautil.format_netloc(config.master_host_name))
@@ -1087,7 +1088,7 @@ def promote_check(installer):
'CA', conn, preferred_cas
)
if ca_host is not None:
- if config.master_host_name != ca_host:
+ if options.setup_ca and config.master_host_name != ca_host:
conn.disconnect()
del remote_api
config.master_host_name = ca_host
@@ -1096,8 +1097,7 @@ def promote_check(installer):
conn = remote_api.Backend.ldap2
conn.connect(ccache=installer._ccache)
config.ca_host_name = ca_host
- config.master_host_name = ca_host
- ca_enabled = True
+ ca_enabled = True # There is a CA somewhere in the topology
if options.dirsrv_cert_files:
logger.error("Certificates could not be provided when "
"CA is present on some master.")
@@ -1135,7 +1135,7 @@ def promote_check(installer):
'KRA', conn, preferred_kras
)
if kra_host is not None:
- if config.master_host_name != kra_host:
+ if options.setup_kra and config.master_host_name != kra_host:
conn.disconnect()
del remote_api
config.master_host_name = kra_host
@@ -1143,10 +1143,9 @@ def promote_check(installer):
installer._remote_api = remote_api
conn = remote_api.Backend.ldap2
conn.connect(ccache=installer._ccache)
- config.kra_host_name = kra_host
- config.ca_host_name = kra_host
- config.master_host_name = kra_host
- kra_enabled = True
+ config.kra_host_name = kra_host
+ config.ca_host_name = kra_host
+ kra_enabled = True # There is a KRA somewhere in the topology
if options.setup_kra and options.server and \
kra_host != options.server:
# Installer was provided with a specific master
@@ -1372,10 +1371,10 @@ def install(installer):
otpd.create_instance('OTPD', config.host_name,
ipautil.realm_to_suffix(config.realm_name))
- if kra_enabled:
+ if options.setup_kra and kra_enabled:
# A KRA peer always provides a CA, too.
mode = custodiainstance.CustodiaModes.KRA_PEER
- elif ca_enabled:
+ elif options.setup_ca and ca_enabled:
mode = custodiainstance.CustodiaModes.CA_PEER
else:
mode = custodiainstance.CustodiaModes.MASTER_PEER
From 701339d4fed539713eb1a13495992879f56a6daa Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Jan 18 2024 14:53:28 +0000
Subject: Server affinity: Don't rely just on [ca|kra]_enabled for installs
ca_enable and kra_enabled are intended to be used to identify that
a CA or KRA is available in the topology. It was also being used
to determine whether a CA or KRA service is desired on a replica
install, rather than options.setup_[ca|kra]
Fixes: https://pagure.io/freeipa/issue/9510
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
---
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index 8096b6a..191913d 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -1143,7 +1143,8 @@ def promote_check(installer):
installer._remote_api = remote_api
conn = remote_api.Backend.ldap2
conn.connect(ccache=installer._ccache)
- config.kra_host_name = kra_host
+ config.kra_host_name = kra_host
+ if options.setup_kra: # only reset ca_host if KRA is requested
config.ca_host_name = kra_host
kra_enabled = True # There is a KRA somewhere in the topology
if options.setup_kra and options.server and \
@@ -1381,7 +1382,7 @@ def install(installer):
custodia = custodiainstance.get_custodia_instance(config, mode)
custodia.create_instance()
- if ca_enabled:
+ if options.setup_ca and ca_enabled:
options.realm_name = config.realm_name
options.domain_name = config.domain_name
options.host_name = config.host_name
@@ -1397,7 +1398,7 @@ def install(installer):
service.print_msg("Finalize replication settings")
ds.finalize_replica_config()
- if kra_enabled:
+ if options.setup_kra and kra_enabled:
kra.install(api, config, options, custodia=custodia)
service.print_msg("Restarting the KDC")
From e6014a5c1996528b255480b67fe2937203bff81b Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Jan 23 2024 15:32:58 +0000
Subject: Server affinity: call ca.install() if there is a CA in the topology
This should not have been gated on options.setup_ca because we need
the RA agent on all servers if there is a CA in the topology otherwise
the non-CA servers won't be able to communicate with the CA.
Fixes: https://pagure.io/freeipa/issue/9510
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
---
diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
index c93ae1f..187f803 100644
--- a/ipaserver/install/ca.py
+++ b/ipaserver/install/ca.py
@@ -387,9 +387,10 @@ def install_step_0(standalone, replica_config, options, custodia):
promote = False
else:
cafile = os.path.join(replica_config.dir, 'cacert.p12')
- custodia.get_ca_keys(
- cafile,
- replica_config.dirman_password)
+ if replica_config.setup_ca:
+ custodia.get_ca_keys(
+ cafile,
+ replica_config.dirman_password)
ca_signing_algorithm = None
ca_type = None
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index f8d4733..4c1c07c 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -1359,11 +1359,13 @@ def install(installer):
custodia = custodiainstance.get_custodia_instance(config, mode)
custodia.create_instance()
- if options.setup_ca and ca_enabled:
+ if ca_enabled:
options.realm_name = config.realm_name
options.domain_name = config.domain_name
options.host_name = config.host_name
options.dm_password = config.dirman_password
+ # Always call ca.install() if there is a CA in the topology
+ # to ensure the RA agent is present.
ca.install(False, config, options, custodia=custodia)
# configure PKINIT now that all required services are in place
@@ -1375,7 +1377,8 @@ def install(installer):
service.print_msg("Finalize replication settings")
ds.finalize_replica_config()
- if options.setup_kra and kra_enabled:
+ if kra_enabled:
+ # The KRA installer checks for itself the status of setup_kra
kra.install(api, config, options, custodia=custodia)
service.print_msg("Restarting the KDC")

View File

@ -0,0 +1,115 @@
From d9aa75459d650e5282a160a3eef09ed175dc5b51 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Wed, 7 Jun 2023 11:44:05 -0400
Subject: [PATCH] Use the python-cryptography parser directly in cert-find
cert-find is a rather complex beast because it not only
looks for certificates in the optional CA but within the
IPA LDAP database as well. It has a process to deduplicate
the certificates since any PKI issued certificates will
also be associated with an IPA record.
In order to obtain the data to deduplicate the certificates
the cert from LDAP must be parser for issuer and serial number.
ipaldap has automation to determine the datatype of an
attribute and will use the ipalib.x509 IPACertificate class to
decode a certificate automatically if you access
entry['usercertificate'].
The downside is that this is comparatively slow. Here is the
parse time in microseconds:
cryptography 0.0081
OpenSSL.crypto 0.2271
ipalib.x509 2.6814
Since only issuer and subject are required there is no need to
make the expensive IPACertificate call.
The IPACertificate parsing time is fine if you're parsing one
certificate but if the LDAP search returns a lot of certificates,
say in the thousands, then those microseconds add up quickly.
In testing it took ~17 seconds to parse 5k certificates (excluding
transmission overhead, etc).
cert-find when there are a lot of certificates has been
historically slow. It isn't related to the CA which returns
large sets (well, 5k anyway) in a second or two. It was the
LDAP comparision adding tens of seconds to the runtime.
When searching with the default sizelimit of 100 the time is
~10s without this patch. With it the time is 1.5s.
CLI times from before and after searching for all certs:
original:
-------------------------------
Number of entries returned 5038
-------------------------------
real 0m15.507s
user 0m0.828s
sys 0m0.241s
using cryptography:
real 0m4.037s
user 0m0.816s
sys 0m0.193s
Fixes: https://pagure.io/freeipa/issue/9331
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
---
ipaserver/plugins/cert.py | 3 ++-
ipatests/test_xmlrpc/test_cert_plugin.py | 12 +++++++++++-
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py
index 36a0e8cb31b4dbdd9bff09165d1d8aa203936d37..4fb85069a835d94969c9d05789714345ecc60e2e 100644
--- a/ipaserver/plugins/cert.py
+++ b/ipaserver/plugins/cert.py
@@ -1795,7 +1795,8 @@ class cert_find(Search, CertMethod):
ca_enabled = getattr(context, 'ca_enabled')
for entry in entries:
for attr in ('usercertificate', 'usercertificate;binary'):
- for cert in entry.get(attr, []):
+ for der in entry.raw.get(attr, []):
+ cert = cryptography.x509.load_der_x509_certificate(der)
cert_key = self._get_cert_key(cert)
try:
obj = result[cert_key]
diff --git a/ipatests/test_xmlrpc/test_cert_plugin.py b/ipatests/test_xmlrpc/test_cert_plugin.py
index 433cebcd79f792e5c97307c6d599e50855ff4151..583c67fd942a61f42e578cc51a0e456cacf9a5e5 100644
--- a/ipatests/test_xmlrpc/test_cert_plugin.py
+++ b/ipatests/test_xmlrpc/test_cert_plugin.py
@@ -254,6 +254,16 @@ class test_cert(BaseCert):
result = _emails_are_valid(email_addrs, [])
assert not result
+ def test_00012_cert_find_all(self):
+ """
+ Test that cert-find --all returns successfully.
+
+ We don't know how many we'll get but there should be at least 10
+ by default.
+ """
+ res = api.Command['cert_find'](all=True)
+ assert 'count' in res and res['count'] >= 10
+
def test_99999_cleanup(self):
"""
Clean up cert test data
@@ -283,7 +293,7 @@ class test_cert_find(XMLRPC_test):
short = api.env.host.split('.', maxsplit=1)[0]
- def test_0001_find_all(self):
+ def test_0001_find_all_certs(self):
"""
Search for all certificates.
--
2.41.0

View File

@ -0,0 +1,38 @@
From f25003a730c0e28c22fae5fce607df734b55525c Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Mon, 19 Jun 2023 19:01:25 +0200
Subject: [PATCH] Upgrade: add PKI drop-in file if missing
During the installation of IPA server, the installer adds a drop-in
file in /etc/systemd/system/pki-tomcatd@pki-tomcat.service.d/ipa.conf
that ensures the CA is reachable before the start command returns.
If the file is missing (for instance because the server was installed
with an old version before this drop-in was created), the upgrade
should add the file.
Fixes: https://pagure.io/freeipa/issue/9381
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
ipaserver/install/server/upgrade.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index f8701c8a0d43c7c1c1090e8576976b1c370b0104..8f3d57353605f28103c69cb0a34bf1c16fc4ae19 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -1742,6 +1742,10 @@ def upgrade_configuration():
os.path.join(paths.USR_SHARE_IPA_DIR,
"ipa-kdc-proxy.conf.template"))
if ca.is_configured():
+ # Ensure that the drop-in file is present
+ if not os.path.isfile(paths.SYSTEMD_PKI_TOMCAT_IPA_CONF):
+ ca.add_ipa_wait()
+
# Handle upgrade of AJP connector configuration
rewrite = ca.secure_ajp_connector()
if ca.ajp_secret:
--
2.41.0

View File

@ -1,97 +0,0 @@
From 3842116185de6ae8714f30b57bd75c7eddde53d8 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Jan 15 2024 13:50:10 +0000
Subject: host: update System: Manage Host Keytab permission
Since commit 5c0e7a5fb420377dcc06a956695afdcb35196444, a new extended
operation to get a keytab is supposed to be used. This keytab
setting/retrieval extended operation checks access rights of the bound
DN to write to a virtual attribute 'ipaProtectedOperation;write_keys'.
If the write isn't allowed, the operation is rejected and ipa-getkeytab
tool falls back to an older code that generates the keytab on the client
and forcibly sets to the LDAP entry. For the latter, a check is done to
make sure the bound DN is allowed to write to 'krbPrincipalKey' attribute.
This fallback should never happen for newer deployments. When enrollemnt
operation is delegated to non-administrative user with the help of 'Host
Enrollment' role, a host can be pre-created or created at enrollment
time, if this non-administrative user has 'Host Administrators' role. In
the latter case a system permission 'System: Manage Host Keytab' grants
write access to 'krbPrincipalKey' attribute but lacks any access to the
virtual attributes expected by the new extended operation.
There is a second virtual attribute, 'ipaProtectedOperation;read_keys',
that allows to retrieve existing keys for a host. However, during
initial enrollment we do not allow to retrieve and reuse existing
Kerberos key: while 'ipa-getkeytab -r' would give ability to retrieve
the existing key, 'ipa-join' has no way to trigger that operation.
Hence, permission 'System: Manage Host Keytab' will not grant the right
to read the Kerberos key via extended operation used by 'ipa-getkeytab
-r'. Such operation can be done later by utilizing 'ipa
service/host-allow-retrieve-keytab' commands.
Fix 'System: Manage Host Keytab' permission and extend a permission test
to see that we do not fallback to the old extended operation.
Fixes: https://pagure.io/freeipa/issue/9496
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
diff --git a/ACI.txt b/ACI.txt
index e6d6e3d..236bb43 100644
--- a/ACI.txt
+++ b/ACI.txt
@@ -147,7 +147,7 @@ aci: (targetattr = "usercertificate")(targetfilter = "(objectclass=ipahost)")(ve
dn: cn=computers,cn=accounts,dc=ipa,dc=example
aci: (targetattr = "userpassword")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Manage Host Enrollment Password";allow (write) groupdn = "ldap:///cn=System: Manage Host Enrollment Password,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=computers,cn=accounts,dc=ipa,dc=example
-aci: (targetattr = "krblastpwdchange || krbprincipalkey")(targetfilter = "(&(!(memberOf=cn=ipaservers,cn=hostgroups,cn=accounts,dc=ipa,dc=example))(objectclass=ipahost))")(version 3.0;acl "permission:System: Manage Host Keytab";allow (write) groupdn = "ldap:///cn=System: Manage Host Keytab,cn=permissions,cn=pbac,dc=ipa,dc=example";)
+aci: (targetattr = "ipaprotectedoperation;write_keys || krblastpwdchange || krbprincipalkey")(targetfilter = "(&(!(memberOf=cn=ipaservers,cn=hostgroups,cn=accounts,dc=ipa,dc=example))(objectclass=ipahost))")(version 3.0;acl "permission:System: Manage Host Keytab";allow (write) groupdn = "ldap:///cn=System: Manage Host Keytab,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=computers,cn=accounts,dc=ipa,dc=example
aci: (targetattr = "createtimestamp || entryusn || ipaallowedtoperform;read_keys || ipaallowedtoperform;write_keys || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Manage Host Keytab Permissions";allow (compare,read,search,write) groupdn = "ldap:///cn=System: Manage Host Keytab Permissions,cn=permissions,cn=pbac,dc=ipa,dc=example";)
dn: cn=computers,cn=accounts,dc=ipa,dc=example
diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py
index 3ef510e..b02c8b5 100644
--- a/ipaserver/plugins/host.py
+++ b/ipaserver/plugins/host.py
@@ -409,7 +409,8 @@ class host(LDAPObject):
api.env.container_hostgroup,
api.env.basedn),
],
- 'ipapermdefaultattr': {'krblastpwdchange', 'krbprincipalkey'},
+ 'ipapermdefaultattr': {'krblastpwdchange', 'krbprincipalkey',
+ 'ipaprotectedoperation;write_keys'},
'replaces': [
'(targetattr = "krbprincipalkey || krblastpwdchange")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Manage host keytab";allow (write) groupdn = "ldap:///cn=Manage host keytab,cn=permissions,cn=pbac,$SUFFIX";)',
],
diff --git a/ipatests/test_integration/test_user_permissions.py b/ipatests/test_integration/test_user_permissions.py
index 3333a4f..cd1096f 100644
--- a/ipatests/test_integration/test_user_permissions.py
+++ b/ipatests/test_integration/test_user_permissions.py
@@ -277,6 +277,9 @@ class TestInstallClientNoAdmin(IntegrationTest):
self.master.run_command(['ipa', 'privilege-add-permission',
'--permissions', 'System: Add Hosts',
'Add Hosts'])
+ self.master.run_command(['ipa', 'privilege-add-permission',
+ '--permissions', 'System: Manage Host Keytab',
+ 'Add Hosts'])
self.master.run_command(['ipa', 'role-add-privilege', 'useradmin',
'--privileges', 'Host Enrollment'])
@@ -301,6 +304,10 @@ class TestInstallClientNoAdmin(IntegrationTest):
encoding='utf-8')
assert msg in install_log
+ # Make sure we do not fallback to an old keytab retrieval method anymore
+ msg = "Retrying with pre-4.0 keytab retrieval method..."
+ assert msg not in install_log
+
# check that user is able to request a host cert, too
result = tasks.run_certutil(client, ['-L'], paths.IPA_NSSDB_DIR)
assert 'Local IPA host' in result.stdout_text

View File

@ -0,0 +1,53 @@
From 392e60e3fa0e39a2e364268a21d869a2f3a85905 Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Mon, 19 Jun 2023 19:04:32 +0200
Subject: [PATCH] Integration test: add a test for upgrade and PKI drop-in file
Add an upgrade test with the following scenario:
- remove PKI drop-in file (to simulate an upgrade from an old
version)
- remove caECServerCertWithSCT profile from LDAP
- launch the ipa-server-upgrade command
- check that the upgrade added the file
Related: https://pagure.io/freeipa/issue/9381
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
ipatests/test_integration/test_upgrade.py | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/ipatests/test_integration/test_upgrade.py b/ipatests/test_integration/test_upgrade.py
index 9203503cdccf4478f9864bd487e458761e9a2a2f..182e3b5da3c758cc10913ad4eed119b0983fcc23 100644
--- a/ipatests/test_integration/test_upgrade.py
+++ b/ipatests/test_integration/test_upgrade.py
@@ -455,3 +455,25 @@ class TestUpgrade(IntegrationTest):
assert 'tXTRecord' in location_krb_rec
assert len(location_krb_rec['tXTRecord']) == 1
assert location_krb_rec['tXTRecord'][0] == f'"{realm}"'
+
+ def test_pki_dropin_file(self):
+ """Test that upgrade adds the drop-in file if missing
+
+ Test for ticket 9381
+ Simulate an update from a version that didn't provide
+ /etc/systemd/system/pki-tomcatd@pki-tomcat.service.d/ipa.conf,
+ remove one of the certificate profiles from LDAP and check that upgrade
+ completes successfully and adds the missing file.
+ When the drop-in file is missing, the upgrade tries to login to
+ PKI in order to migrate the profile and fails because PKI failed to
+ start.
+ """
+ self.master.run_command(["rm", "-f", paths.SYSTEMD_PKI_TOMCAT_IPA_CONF])
+ ldif = textwrap.dedent("""
+ dn: cn=caECServerCertWithSCT,ou=certificateProfiles,ou=ca,o=ipaca
+ changetype: delete
+ """)
+ tasks.ldapmodify_dm(self.master, ldif)
+ self.master.run_command(['ipa-server-upgrade'])
+ assert self.master.transport.file_exists(
+ paths.SYSTEMD_PKI_TOMCAT_IPA_CONF)
--
2.41.0

View File

@ -1,32 +0,0 @@
From 2f17319df6147832dceff7c06154363f8d58b194 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Jan 18 2024 09:07:31 +0000
Subject: adtrustinstance: make sure NetBIOS name defaults are set properly
Some tools may pass None as NetBIOS name if not put explicitly by a
user. This meant to use default NetBIOS name generator based on the
domain (realm) name. However, this wasn't done properly, so None is
passed later to python-ldap and it rejects such LDAP entry.
Fixes: https://pagure.io/freeipa/issue/9514
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
---
diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
index bf0cc3b..bb5b61a 100644
--- a/ipaserver/install/adtrustinstance.py
+++ b/ipaserver/install/adtrustinstance.py
@@ -189,6 +189,8 @@ class ADTRUSTInstance(service.Service):
self.fqdn = self.fqdn or api.env.host
self.host_netbios_name = make_netbios_name(self.fqdn)
self.realm = self.realm or api.env.realm
+ if not self.netbios_name:
+ self.netbios_name = make_netbios_name(self.realm)
self.suffix = ipautil.realm_to_suffix(self.realm)
self.ldapi_socket = "%%2fvar%%2frun%%2fslapd-%s.socket" % \

View File

@ -0,0 +1,129 @@
From f93a6d3ff52247ce5e582816fec689b8901fc984 Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Wed, 14 Jun 2023 15:12:39 +0200
Subject: [PATCH] Uninstaller: uninstall PKI before shutting down services
The uninstaller is stopping all the services before
calling pkidestroy to uninstall the CA.
With PKI 11.4+ this sequence fails as pkidestroy tries
to connect to PKI server in order to unregister from the
security domain. The error interrupts the full completion
of pkidestroy, is logged but doesn't make ipa uninstallation
fail.
The issue is that trying to re-install later on would fail because
pkidestroy did not completely uninstall the CA.
To avoid this, call pkidestroy before shutting down the services.
Also add an uninstall_check method that restarts IPA if it is
not running, and use pkidestroy --force to make sure that PKI
is uninstalled even if restart failed.
Fixes: https://pagure.io/freeipa/issue/9330
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
ipaserver/install/ca.py | 18 ++++++++++++++++++
ipaserver/install/dogtaginstance.py | 2 +-
ipaserver/install/kra.py | 2 ++
ipaserver/install/server/install.py | 8 +++++---
4 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
index be0e732e8ff6966ccc0077d9339f9f0bc66ae6ec..c93ae1fce4c8848d493677eafee7952740e51631 100644
--- a/ipaserver/install/ca.py
+++ b/ipaserver/install/ca.py
@@ -169,6 +169,24 @@ def print_ca_configuration(options):
def uninstall_check(options):
+ """IPA needs to be running so pkidestroy can unregister CA"""
+ ca = cainstance.CAInstance(api.env.realm)
+ if not ca.is_installed():
+ return
+
+ result = ipautil.run([paths.IPACTL, 'status'],
+ raiseonerr=False)
+
+ if result.returncode not in [0, 4]:
+ try:
+ logger.info(
+ "Starting services to unregister CA from security domain")
+ ipautil.run([paths.IPACTL, 'start'])
+ except Exception:
+ logger.info("Re-starting IPA failed, continuing uninstall")
+
+
+def uninstall_crl_check(options):
"""Check if the host is CRL generation master"""
# Skip the checks if the host is not a CA instance
ca = cainstance.CAInstance(api.env.realm)
diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py
index c2c6b3f49243f096448c178fafd09f429f0f46c8..4967aca01807e58dfcc3157af10b92eff5dba206 100644
--- a/ipaserver/install/dogtaginstance.py
+++ b/ipaserver/install/dogtaginstance.py
@@ -305,7 +305,7 @@ class DogtagInstance(service.Service):
self.print_msg("Unconfiguring %s" % self.subsystem)
args = [paths.PKIDESTROY,
- "-i", "pki-tomcat",
+ "-i", "pki-tomcat", "--force",
"-s", self.subsystem]
# specify --log-file <path> on PKI 11.0.0 or later
diff --git a/ipaserver/install/kra.py b/ipaserver/install/kra.py
index 857c5165b808baee3f0815e78828fb899eb78a2d..59cbda812a853997752f7d932e0690e3a950aa1f 100644
--- a/ipaserver/install/kra.py
+++ b/ipaserver/install/kra.py
@@ -132,6 +132,8 @@ def uninstall_check(options):
if result.returncode not in [0, 4]:
try:
+ logger.info(
+ "Starting services to unregister KRA from security domain")
ipautil.run([paths.IPACTL, 'start'])
except Exception:
logger.info("Re-starting IPA failed, continuing uninstall")
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
index 4e4076410f1c1af188a0ab3606ef13be39702b7d..ccb958232935de2166f2d4867b626f59d7ba5333 100644
--- a/ipaserver/install/server/install.py
+++ b/ipaserver/install/server/install.py
@@ -1110,6 +1110,7 @@ def uninstall_check(installer):
raise ScriptError("Aborting uninstall operation.")
kra.uninstall_check(options)
+ ca.uninstall_check(options)
try:
api.Backend.ldap2.connect(autobind=True)
@@ -1132,7 +1133,7 @@ def uninstall_check(installer):
else:
dns.uninstall_check(options)
- ca.uninstall_check(options)
+ ca.uninstall_crl_check(options)
cleanup_dogtag_server_specific_data()
@@ -1181,6 +1182,9 @@ def uninstall(installer):
# Uninstall the KRA prior to shutting the services down so it
# can un-register with the CA.
kra.uninstall()
+ # Uninstall the CA priori to shutting the services down so it
+ # can unregister from the security domain
+ ca.uninstall()
print("Shutting down all IPA services")
try:
@@ -1194,8 +1198,6 @@ def uninstall(installer):
restore_time_sync(sstore, fstore)
- ca.uninstall()
-
dns.uninstall()
httpinstance.HTTPInstance(fstore).uninstall()
--
2.41.0

View File

@ -1,175 +0,0 @@
From 5afda72afc6fd626359411b55f092989fdd7d82d Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Jan 15 2024 13:39:21 +0000
Subject: ipatests: ignore nsslapd-accesslog-logbuffering WARN in healthcheck
Log buffering is disabled in the integration tests so we can have all
the logs at the end. This is causing a warning to show in the 389-ds
checks and causing tests to fail that expect all SUCCESS.
Add an exclude for this specific key so tests will pass again.
We may eventually want a more sophisiticated mechanism to handle
excludes, or updating the config in general, but this is fine for now.
Fixes: https://pagure.io/freeipa/issue/9400
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
---
diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py
index 7fb8e40..14fba26 100644
--- a/ipatests/test_integration/test_ipahealthcheck.py
+++ b/ipatests/test_integration/test_ipahealthcheck.py
@@ -9,6 +9,7 @@ from __future__ import absolute_import
from configparser import RawConfigParser, NoOptionError
from datetime import datetime, timedelta
+import io
import json
import os
import re
@@ -208,6 +209,28 @@ def run_healthcheck(host, source=None, check=None, output_type="json",
return result.returncode, data
+def set_excludes(host, option, value,
+ config_file='/etc/ipahealthcheck/ipahealthcheck.conf'):
+ """Mark checks that should be excluded from the results
+
+ This will set in the [excludes] section on host:
+ option=value
+ """
+ EXCLUDES = "excludes"
+
+ conf = host.get_file_contents(config_file, encoding='utf-8')
+ cfg = RawConfigParser()
+ cfg.read_string(conf)
+ if not cfg.has_section(EXCLUDES):
+ cfg.add_section(EXCLUDES)
+ if not cfg.has_option(EXCLUDES, option):
+ cfg.set(EXCLUDES, option, value)
+ out = io.StringIO()
+ cfg.write(out)
+ out.seek(0)
+ host.put_file_contents(config_file, out.read())
+
+
@pytest.fixture
def restart_service():
"""Shut down and restart a service as a fixture"""
@@ -265,6 +288,7 @@ class TestIpaHealthCheck(IntegrationTest):
setup_dns=True,
extra_args=['--no-dnssec-validation']
)
+ set_excludes(cls.master, "key", "DSCLE0004")
def test_ipa_healthcheck_install_on_master(self):
"""
@@ -552,6 +576,7 @@ class TestIpaHealthCheck(IntegrationTest):
setup_dns=True,
extra_args=['--no-dnssec-validation']
)
+ set_excludes(self.replicas[0], "key", "DSCLE0004")
# Init a user on replica to assign a DNA range
tasks.kinit_admin(self.replicas[0])
@@ -692,6 +717,7 @@ class TestIpaHealthCheck(IntegrationTest):
'output_type=human'
])
)
+ set_excludes(self.master, "key", "DSCLE0004", config_file)
returncode, output = run_healthcheck(
self.master, failures_only=True, config=config_file
)
@@ -707,6 +733,7 @@ class TestIpaHealthCheck(IntegrationTest):
'output_file=%s' % HC_LOG,
])
)
+ set_excludes(self.master, "key", "DSCLE0004")
returncode, _unused = run_healthcheck(
self.master, config=config_file
)
@@ -2396,6 +2423,7 @@ class TestIpaHealthCLI(IntegrationTest):
cls.master, setup_dns=True, extra_args=['--no-dnssec-validation']
)
tasks.install_packages(cls.master, HEALTHCHECK_PKG)
+ set_excludes(cls.master, "key", "DSCLE0004")
def test_indent(self):
"""
diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py
index d477c3a..b71f2d5 100644
--- a/ipatests/test_integration/test_replica_promotion.py
+++ b/ipatests/test_integration/test_replica_promotion.py
@@ -13,7 +13,7 @@ import pytest
from ipatests.test_integration.base import IntegrationTest
from ipatests.test_integration.test_ipahealthcheck import (
- run_healthcheck, HEALTHCHECK_PKG
+ run_healthcheck, set_excludes, HEALTHCHECK_PKG
)
from ipatests.pytest_ipa.integration import tasks
from ipatests.pytest_ipa.integration.tasks import (
@@ -983,6 +983,9 @@ class TestHiddenReplicaPromotion(IntegrationTest):
# manually install KRA to verify that hidden state is synced
tasks.install_kra(cls.replicas[0])
+ set_excludes(cls.master, "key", "DSCLE0004")
+ set_excludes(cls.replicas[0], "key", "DSCLE0004")
+
def _check_dnsrecords(self, hosts_expected, hosts_unexpected=()):
domain = DNSName(self.master.domain.name).make_absolute()
rset = [
From f1cfe7d9ff2489dbb6cad70999b0e1bd433c0537 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Jan 15 2024 13:39:21 +0000
Subject: ipatests: fix expected output for ipahealthcheck.ipa.host
ipa-healthcheck commit e69589d5 changed the output when a service
keytab is missing to not report the GSSAPI error but to report
that the keytab doesn't exist at all. This distinguishes from real
Kerberos issues like kvno.
Fixes: https://pagure.io/freeipa/issue/9482
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
---
diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py
index 14fba26..8aae9fa 100644
--- a/ipatests/test_integration/test_ipahealthcheck.py
+++ b/ipatests/test_integration/test_ipahealthcheck.py
@@ -629,9 +629,15 @@ class TestIpaHealthCheck(IntegrationTest):
ipahealthcheck.ipa.host when GSSAPI credentials cannot be obtained
from host's keytab.
"""
- msg = (
- "Minor (2529639107): No credentials cache found"
- )
+ version = tasks.get_healthcheck_version(self.master)
+ if parse_version(version) >= parse_version("0.15"):
+ msg = (
+ "Service {service} keytab {path} does not exist."
+ )
+ else:
+ msg = (
+ "Minor (2529639107): No credentials cache found"
+ )
with tasks.FileBackup(self.master, paths.KRB5_KEYTAB):
self.master.run_command(["rm", "-f", paths.KRB5_KEYTAB])

View File

@ -0,0 +1,44 @@
From b9a07b1e97ee4e310b50860103872685da540da4 Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Mon, 19 Jun 2023 15:40:39 +0200
Subject: [PATCH] Detection of PKI subsystem
In order to know if ca/kra is installed locally, the code
is calling pki-server subsystem-show _subsystem_
and ensures that "Enabled: True" is in the output.
If a subsystem fails to start, the command returns
"Enabled: False" but it doesn't mean that the subsystem
is not installed, it just means that it is not active
right now.
Same output if the subsystem has been disabled with
pki-server subsystem-disable _subsystem_.
The correct way to check if a subsystem is installed is to
ensure that subsystem-show does not exit on error and
contains "Enabled: ", whatever the value.
Related: https://pagure.io/freeipa/issue/9330
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
ipaserver/install/dogtaginstance.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py
index 4967aca01807e58dfcc3157af10b92eff5dba206..7fdf2e0ed0f3ed99a6672f527d38dda0ce5ef8bb 100644
--- a/ipaserver/install/dogtaginstance.py
+++ b/ipaserver/install/dogtaginstance.py
@@ -184,7 +184,7 @@ class DogtagInstance(service.Service):
['pki-server', 'subsystem-show', self.subsystem.lower()],
capture_output=True)
# parse the command output
- return 'Enabled: True' in result.output
+ return 'Enabled: ' in result.output
except ipautil.CalledProcessError:
return False
--
2.41.0

View File

@ -1,45 +0,0 @@
From dcb9d6edc7ae4278cd552e87f644705faa13d558 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Jan 31 2024 08:31:13 +0000
Subject: kdb: PAC generator: do not fail if canonical principal is missing
krbCanonicalName is mandatory for services but IPA services created
before commit e6ff83e (FreeIPA 4.4.0, ~2016) had no normalization done
to set krbCanonicalName; services created after that version were
upgraded to do have krbCanonicalName.
Accept krbPrincipalName alone since they have no alias either */
Fixes: https://pagure.io/freeipa/issue/9465
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Thierry Bordaz <tbordaz@redhat.com>
---
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
index 9e1431c..8035036 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
@@ -496,8 +496,16 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
"krbCanonicalName", &strres);
if (ret) {
- /* krbCanonicalName is mandatory for services */
- return ret;
+ /* krbCanonicalName is mandatory for services but IPA services
+ * created before commit e6ff83e (FreeIPA 4.4.0, ~2016) had no
+ * normalization to set krbCanonicalName; services created after
+ * that version were upgraded to do have krbCanonicalName.
+ *
+ * Accept krbPrincipalName alone since they have no alias either */
+ ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
+ "krbPrincipalName", &strres);
+ if (ret)
+ return ret;
}
ret = krb5_parse_name(ipactx->kcontext, strres, &princ);

View File

@ -0,0 +1,164 @@
From ad77c4c6512f82019d1970d910647761b60aaedb Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Mon, 19 Jun 2023 10:36:29 +0200
Subject: [PATCH] Upgrade: fix replica agreement
The upgrade checks the replication agreements to ensure that
some attributes are excluded from replication. The agreements
are stored in entries like
cn=serverToreplica,cn=replica,cn=_suffix_,cn=mapping tree,cn=config
but those entries are managed by the replication topology plugin
and should not be updated directly. The consequence is that the update
of the attributes fails and ipa-server-update prints an error message:
Error caught updating nsDS5ReplicatedAttributeList: Server is unwilling
to perform: Entry and attributes are managed by topology plugin.No direct
modifications allowed.
Error caught updating nsDS5ReplicatedAttributeListTotal: Server is
unwilling to perform: Entry and attributes are managed by topology
plugin.No direct modifications allowed.
The upgrade continues but the replication is not excluding
passwordgraceusertime.
Instead of editing the agreements, perform the modifications on
the topology segments.
Fixes: https://pagure.io/freeipa/issue/9385
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
.../install/plugins/fix_replica_agreements.py | 80 +++++++++----------
1 file changed, 38 insertions(+), 42 deletions(-)
diff --git a/ipaserver/install/plugins/fix_replica_agreements.py b/ipaserver/install/plugins/fix_replica_agreements.py
index c0cdd3eb19c486121f727476360ce421b1d82728..d963753d0bf9ee65285a86fa9a249198c28a66e2 100644
--- a/ipaserver/install/plugins/fix_replica_agreements.py
+++ b/ipaserver/install/plugins/fix_replica_agreements.py
@@ -22,6 +22,7 @@ import logging
from ipaserver.install import replication
from ipalib import Registry
from ipalib import Updater
+from ipalib import errors
logger = logging.getLogger(__name__)
@@ -41,35 +42,42 @@ class update_replica_attribute_lists(Updater):
def execute(self, **options):
# We need an LDAPClient connection to the backend
logger.debug("Start replication agreement exclude list update task")
- conn = self.api.Backend.ldap2
- repl = replication.ReplicationManager(self.api.env.realm,
- self.api.env.host,
- None, conn=conn)
-
- # We need to update only IPA replica agreements, not winsync
- ipa_replicas = repl.find_ipa_replication_agreements()
-
- logger.debug("Found %d agreement(s)", len(ipa_replicas))
-
- for replica in ipa_replicas:
- for desc in replica.get('description', []):
- logger.debug('%s', desc)
-
- self._update_attr(repl, replica,
- 'nsDS5ReplicatedAttributeList',
- replication.EXCLUDES, template=EXCLUDE_TEMPLATE)
- self._update_attr(repl, replica,
- 'nsDS5ReplicatedAttributeListTotal',
- replication.TOTAL_EXCLUDES, template=EXCLUDE_TEMPLATE)
- self._update_attr(repl, replica,
- 'nsds5ReplicaStripAttrs', replication.STRIP_ATTRS)
+ # Find suffixes
+ suffixes = self.api.Command.topologysuffix_find()['result']
+ for suffix in suffixes:
+ suffix_name = suffix['cn'][0]
+ # Find segments
+ sgmts = self.api.Command.topologysegment_find(
+ suffix_name, all=True)['result']
+ for segment in sgmts:
+ updates = {}
+ updates = self._update_attr(
+ segment, updates,
+ 'nsds5replicatedattributelist',
+ replication.EXCLUDES, template=EXCLUDE_TEMPLATE)
+ updates = self._update_attr(
+ segment, updates,
+ 'nsds5replicatedattributelisttotal',
+ replication.TOTAL_EXCLUDES, template=EXCLUDE_TEMPLATE)
+ updates = self._update_attr(
+ segment, updates,
+ 'nsds5replicastripattrs', replication.STRIP_ATTRS)
+ if updates:
+ try:
+ self.api.Command.topologysegment_mod(
+ suffix_name, segment['cn'][0],
+ **updates)
+ except errors.EmptyModlist:
+ # No update done
+ logger.debug("No update required for the segment %s",
+ segment['cn'][0])
logger.debug("Done updating agreements")
return False, [] # No restart, no updates
- def _update_attr(self, repl, replica, attribute, values, template='%s'):
+ def _update_attr(self, segment, updates, attribute, values, template='%s'):
"""Add or update an attribute of a replication agreement
If the attribute doesn't already exist, it is added and set to
@@ -77,27 +85,21 @@ class update_replica_attribute_lists(Updater):
If the attribute does exist, `values` missing from it are just
appended to the end, also space-separated.
- :param repl: Replication manager
- :param replica: Replica agreement
+ :param: updates: dict containing the updates
+ :param segment: dict containing segment information
:param attribute: Attribute to add or update
:param values: List of values the attribute should hold
:param template: Template to use when adding attribute
"""
- attrlist = replica.single_value.get(attribute)
+ attrlist = segment.get(attribute)
if attrlist is None:
logger.debug("Adding %s", attribute)
# Need to add it altogether
- replica[attribute] = [template % " ".join(values)]
-
- try:
- repl.conn.update_entry(replica)
- logger.debug("Updated")
- except Exception as e:
- logger.error("Error caught updating replica: %s", str(e))
+ updates[attribute] = template % " ".join(values)
else:
- attrlist_normalized = attrlist.lower().split()
+ attrlist_normalized = attrlist[0].lower().split()
missing = [a for a in values
if a.lower() not in attrlist_normalized]
@@ -105,14 +107,8 @@ class update_replica_attribute_lists(Updater):
logger.debug("%s needs updating (missing: %s)", attribute,
', '.join(missing))
- replica[attribute] = [
- '%s %s' % (attrlist, ' '.join(missing))]
+ updates[attribute] = '%s %s' % (attrlist[0], ' '.join(missing))
- try:
- repl.conn.update_entry(replica)
- logger.debug("Updated %s", attribute)
- except Exception as e:
- logger.error("Error caught updating %s: %s",
- attribute, str(e))
else:
logger.debug("%s: No update necessary", attribute)
+ return updates
--
2.41.0

View File

@ -1,89 +0,0 @@
From bac601b7f35827236a106f7137f378e4888260da Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Jan 30 2024 15:17:44 +0000
Subject: ipa-kdb: Fix memory leak during PAC verification
Commit 0022bd70d93708d325855d5271516d6cd894d6e8 introduced a memory leak
during the copy of some PAC buffers, because of an unfreed memory
allocation context.
Fixes: https://pagure.io/freeipa/issue/9520
Signed-off-by: Julien Rische <jrische@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
---
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
index a18beff..9e1431c 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
@@ -2316,6 +2316,7 @@ krb5_error_code ipadb_common_verify_pac(krb5_context context,
size_t i;
struct dom_sid *requester_sid = NULL;
struct dom_sid req_sid;
+ TALLOC_CTX *tmpctx = NULL;
if (signing_krbtgt != NULL &&
ipadb_is_cross_realm_krbtgt(signing_krbtgt->princ)) {
@@ -2371,6 +2372,12 @@ krb5_error_code ipadb_common_verify_pac(krb5_context context,
goto done;
}
+ tmpctx = talloc_new(NULL);
+ if (tmpctx == NULL) {
+ kerr = ENOMEM;
+ goto done;
+ }
+
for (i = 0; i < num_buffers; i++) {
if (types[i] == KRB5_PAC_SERVER_CHECKSUM ||
types[i] == KRB5_PAC_PRIVSVR_CHECKSUM ||
@@ -2395,32 +2402,21 @@ krb5_error_code ipadb_common_verify_pac(krb5_context context,
DATA_BLOB pac_attrs_data;
krb5_boolean pac_requested;
- TALLOC_CTX *tmpctx = talloc_new(NULL);
- if (tmpctx == NULL) {
- kerr = ENOMEM;
- goto done;
- }
-
kerr = ipadb_client_requested_pac(context, old_pac, tmpctx, &pac_requested);
- if (kerr != 0) {
- talloc_free(tmpctx);
+ if (kerr)
goto done;
- }
kerr = ipadb_get_pac_attrs_blob(tmpctx, &pac_requested, &pac_attrs_data);
- if (kerr) {
- talloc_free(tmpctx);
+ if (kerr)
goto done;
- }
+
data.magic = KV5M_DATA;
data.data = (char *)pac_attrs_data.data;
data.length = pac_attrs_data.length;
kerr = krb5_pac_add_buffer(context, new_pac, PAC_TYPE_ATTRIBUTES_INFO, &data);
- if (kerr) {
- talloc_free(tmpctx);
+ if (kerr)
goto done;
- }
continue;
}
@@ -2467,6 +2463,8 @@ done:
if (kerr != 0 && (new_pac != *pac)) {
krb5_pac_free(context, new_pac);
}
+ if (tmpctx)
+ talloc_free(tmpctx);
krb5_free_data_contents(context, &pac_blob);
free(types);
return kerr;

View File

@ -1,238 +0,0 @@
From 381af470779ea87335f57038dcbe72cd042ae6bb Mon Sep 17 00:00:00 2001
From: Stanislav Levin <slev@altlinux.org>
Date: Jan 30 2024 15:11:05 +0000
Subject: ipapython: Clean up krb5_error
`krb5_error` has different definition in MIT krb.
https://web.mit.edu/kerberos/krb5-latest/doc/appdev/refs/types/krb5_error.html
> Error message structure.
>
> Declaration:
> typedef struct _krb5_error krb5_error
While `krb5_error_code`
https://web.mit.edu/kerberos/www/krb5-latest/doc/appdev/refs/types/krb5_error_code.html#c.krb5_error_code
> krb5_error_code
> Used to convey an operation status.
>
> The value 0 indicates success; any other values are com_err codes. Use krb5_get_error_message() to obtain a string describing the error.
>
> Declaration
> typedef krb5_int32 krb5_error_code
And this is what was actually used.
To prevent confusion of types `krb5_error` was replaced with
`krb5_error_code`.
Fixes: https://pagure.io/freeipa/issue/9519
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
---
diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py
index c43ef7d..371cf15 100644
--- a/ipapython/session_storage.py
+++ b/ipapython/session_storage.py
@@ -111,7 +111,7 @@ class KRB5Error(Exception):
def krb5_errcheck(result, func, arguments):
- """Error checker for krb5_error return value"""
+ """Error checker for krb5_error_code return value"""
if result != 0:
raise KRB5Error(result, func.__name__, arguments)
@@ -119,14 +119,13 @@ def krb5_errcheck(result, func, arguments):
krb5_context = ctypes.POINTER(_krb5_context)
krb5_ccache = ctypes.POINTER(_krb5_ccache)
krb5_data_p = ctypes.POINTER(_krb5_data)
-krb5_error = ctypes.c_int32
krb5_creds = _krb5_creds
krb5_pointer = ctypes.c_void_p
krb5_cc_cursor = krb5_pointer
krb5_init_context = LIBKRB5.krb5_init_context
krb5_init_context.argtypes = (ctypes.POINTER(krb5_context), )
-krb5_init_context.restype = krb5_error
+krb5_init_context.restype = krb5_error_code
krb5_init_context.errcheck = krb5_errcheck
krb5_free_context = LIBKRB5.krb5_free_context
@@ -143,30 +142,30 @@ krb5_free_data_contents.restype = None
krb5_cc_default = LIBKRB5.krb5_cc_default
krb5_cc_default.argtypes = (krb5_context, ctypes.POINTER(krb5_ccache), )
-krb5_cc_default.restype = krb5_error
+krb5_cc_default.restype = krb5_error_code
krb5_cc_default.errcheck = krb5_errcheck
krb5_cc_close = LIBKRB5.krb5_cc_close
krb5_cc_close.argtypes = (krb5_context, krb5_ccache, )
-krb5_cc_close.restype = krb5_error
+krb5_cc_close.restype = krb5_error_code
krb5_cc_close.errcheck = krb5_errcheck
krb5_parse_name = LIBKRB5.krb5_parse_name
krb5_parse_name.argtypes = (krb5_context, ctypes.c_char_p,
ctypes.POINTER(krb5_principal), )
-krb5_parse_name.restype = krb5_error
+krb5_parse_name.restype = krb5_error_code
krb5_parse_name.errcheck = krb5_errcheck
krb5_cc_set_config = LIBKRB5.krb5_cc_set_config
krb5_cc_set_config.argtypes = (krb5_context, krb5_ccache, krb5_principal,
ctypes.c_char_p, krb5_data_p, )
-krb5_cc_set_config.restype = krb5_error
+krb5_cc_set_config.restype = krb5_error_code
krb5_cc_set_config.errcheck = krb5_errcheck
krb5_cc_get_principal = LIBKRB5.krb5_cc_get_principal
krb5_cc_get_principal.argtypes = (krb5_context, krb5_ccache,
ctypes.POINTER(krb5_principal), )
-krb5_cc_get_principal.restype = krb5_error
+krb5_cc_get_principal.restype = krb5_error_code
krb5_cc_get_principal.errcheck = krb5_errcheck
# krb5_build_principal is a variadic function but that can't be expressed
@@ -177,26 +176,26 @@ krb5_build_principal.argtypes = (krb5_context, ctypes.POINTER(krb5_principal),
ctypes.c_uint, ctypes.c_char_p,
ctypes.c_char_p, ctypes.c_char_p,
ctypes.c_char_p, ctypes.c_char_p, )
-krb5_build_principal.restype = krb5_error
+krb5_build_principal.restype = krb5_error_code
krb5_build_principal.errcheck = krb5_errcheck
krb5_cc_start_seq_get = LIBKRB5.krb5_cc_start_seq_get
krb5_cc_start_seq_get.argtypes = (krb5_context, krb5_ccache,
ctypes.POINTER(krb5_cc_cursor), )
-krb5_cc_start_seq_get.restype = krb5_error
+krb5_cc_start_seq_get.restype = krb5_error_code
krb5_cc_start_seq_get.errcheck = krb5_errcheck
krb5_cc_next_cred = LIBKRB5.krb5_cc_next_cred
krb5_cc_next_cred.argtypes = (krb5_context, krb5_ccache,
ctypes.POINTER(krb5_cc_cursor),
ctypes.POINTER(krb5_creds), )
-krb5_cc_next_cred.restype = krb5_error
+krb5_cc_next_cred.restype = krb5_error_code
krb5_cc_next_cred.errcheck = krb5_errcheck
krb5_cc_end_seq_get = LIBKRB5.krb5_cc_end_seq_get
krb5_cc_end_seq_get.argtypes = (krb5_context, krb5_ccache,
ctypes.POINTER(krb5_cc_cursor), )
-krb5_cc_end_seq_get.restype = krb5_error
+krb5_cc_end_seq_get.restype = krb5_error_code
krb5_cc_end_seq_get.errcheck = krb5_errcheck
krb5_free_cred_contents = LIBKRB5.krb5_free_cred_contents
@@ -212,7 +211,7 @@ krb5_principal_compare.restype = krb5_boolean
krb5_unparse_name = LIBKRB5.krb5_unparse_name
krb5_unparse_name.argtypes = (krb5_context, krb5_principal,
ctypes.POINTER(ctypes.c_char_p), )
-krb5_unparse_name.restype = krb5_error
+krb5_unparse_name.restype = krb5_error_code
krb5_unparse_name.errcheck = krb5_errcheck
krb5_free_unparsed_name = LIBKRB5.krb5_free_unparsed_name
From 2a4bad8bb3295c5c0f5a760ecd41871c4c5a0c56 Mon Sep 17 00:00:00 2001
From: Stanislav Levin <slev@altlinux.org>
Date: Jan 30 2024 15:11:05 +0000
Subject: ipapython: Correct return type of krb5_free_cred_contents
According to https://web.mit.edu/kerberos/krb5-latest/doc/appdev/refs/api/krb5_free_cred_contents.html
> krb5_free_cred_contents - Free the contents of a krb5_creds structure.
>
> void krb5_free_cred_contents(krb5_context context, krb5_creds * val)
> param:
> [in] context - Library context
>
> [in] val - Credential structure to free contents of
>
> This function frees the contents of val , but not the structure itself.
https://github.com/krb5/krb5/blob/5b00197227231943bd2305328c8260dd0b0dbcf0/src/lib/krb5/krb/kfree.c#L166
This leads to undefined behavior and `krb5_free_cred_contents` can
raise KRB5Error (because of garbage data) while actually its foreign
function doesn't.
Fixes: https://pagure.io/freeipa/issue/9519
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
---
diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py
index 371cf15..dc36f54 100644
--- a/ipapython/session_storage.py
+++ b/ipapython/session_storage.py
@@ -200,8 +200,7 @@ krb5_cc_end_seq_get.errcheck = krb5_errcheck
krb5_free_cred_contents = LIBKRB5.krb5_free_cred_contents
krb5_free_cred_contents.argtypes = (krb5_context, ctypes.POINTER(krb5_creds))
-krb5_free_cred_contents.restype = krb5_error
-krb5_free_cred_contents.errcheck = krb5_errcheck
+krb5_free_cred_contents.restype = None
krb5_principal_compare = LIBKRB5.krb5_principal_compare
krb5_principal_compare.argtypes = (krb5_context, krb5_principal,
From beb402afdbf32c01eed860e9416356f7b492ad74 Mon Sep 17 00:00:00 2001
From: Stanislav Levin <slev@altlinux.org>
Date: Jan 30 2024 15:11:05 +0000
Subject: ipapython: Propagate KRB5Error exceptions on iterating ccache
`ipapython.session_storage.get_data` iterates over
credentials in a credential cache till `krb5_cc_next_cred` returns
an error. This function doesn't expect any error on calling
other kerberos foreign functions during iteration. But that can
actually happen and KRB5Error exceptions stop an iteration while
they should be propagated.
With this change iteration will exactly stop on `krb5_cc_next_cred`
error as it was supposed to be.
Fixes: https://pagure.io/freeipa/issue/9519
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
---
diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py
index dc36f54..e890dc9 100644
--- a/ipapython/session_storage.py
+++ b/ipapython/session_storage.py
@@ -312,8 +312,12 @@ def get_data(princ_name, key):
checkcreds = krb5_creds()
# the next function will throw an error and break out of the
# while loop when we try to access past the last cred
- krb5_cc_next_cred(context, ccache, ctypes.byref(cursor),
- ctypes.byref(checkcreds))
+ try:
+ krb5_cc_next_cred(context, ccache, ctypes.byref(cursor),
+ ctypes.byref(checkcreds))
+ except KRB5Error:
+ break
+
if (krb5_principal_compare(context, principal,
checkcreds.client) == 1 and
krb5_principal_compare(context, srv_princ,
@@ -328,8 +332,6 @@ def get_data(princ_name, key):
else:
krb5_free_cred_contents(context,
ctypes.byref(checkcreds))
- except KRB5Error:
- pass
finally:
krb5_cc_end_seq_get(context, ccache, ctypes.byref(cursor))

View File

@ -0,0 +1,69 @@
From 3b58487c7b2f8ac133e37e8f90f85ff2fb05bf34 Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Mon, 19 Jun 2023 10:36:59 +0200
Subject: [PATCH] Integration tests: add a test to ipa-server-upgrade
Add an integration test ensuring that the upgrade
properly updates the attributes to be excluded from
replication.
Related: https://pagure.io/freeipa/issue/9385
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
.../test_simple_replication.py | 30 +++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/ipatests/test_integration/test_simple_replication.py b/ipatests/test_integration/test_simple_replication.py
index 17092a49966e61d5a4a9b04c15abcb1de8be9683..d1e65ef7cc3e748670f2cdebe2a5cb7172af27f0 100644
--- a/ipatests/test_integration/test_simple_replication.py
+++ b/ipatests/test_integration/test_simple_replication.py
@@ -23,8 +23,10 @@ import pytest
from ipaplatform.paths import paths
from ipapython.dn import DN
+from ipaserver.install.replication import EXCLUDES
from ipatests.pytest_ipa.integration import tasks
from ipatests.test_integration.base import IntegrationTest
+from ipatests.test_integration.test_topology import find_segment
def check_replication(source_host, dest_host, login):
@@ -104,6 +106,34 @@ class TestSimpleReplication(IntegrationTest):
[paths.IPA_CUSTODIA_CHECK, self.master.hostname]
)
+ def test_fix_agreements(self):
+ """Test that upgrade fixes the list of attributes excluded from repl
+
+ Test for ticket 9385
+ """
+ # Prepare the server by removing some values from
+ # from the nsDS5ReplicatedAttributeList
+ segment = find_segment(self.master, self.replicas[0], "domain")
+ self.master.run_command([
+ "ipa", "topologysegment-mod", "domain", segment,
+ "--replattrs",
+ "(objectclass=*) $ EXCLUDE memberof idnssoaserial entryusn"])
+ # Run the upgrade
+ result = self.master.run_command(["ipa-server-upgrade"])
+ # Ensure that the upgrade updated the attribute without error
+ errmsg = "Error caught updating nsDS5ReplicatedAttributeList"
+ assert errmsg not in result.stdout_text
+ # Check the updated value
+ suffix = DN(self.master.domain.basedn)
+ dn = DN(('cn', str(suffix)), ('cn', 'mapping tree'), ('cn', 'config'))
+ result = tasks.ldapsearch_dm(self.master, str(dn),
+ ["nsDS5ReplicatedAttributeList"])
+ output = result.stdout_text.lower()
+
+ template = 'nsDS5ReplicatedAttributeList: (objectclass=*) $ EXCLUDE %s'
+ expected_value = template % " ".join(EXCLUDES)
+ assert expected_value.lower() in output
+
def test_replica_removal(self):
"""Test replica removal"""
result = self.master.run_command(['ipa-replica-manage', 'list'])
--
2.41.0

View File

@ -1,109 +0,0 @@
From b56a80581ef388e19d5761020454e51463036cd6 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Tue, 23 Jan 2024 14:47:50 +0200
Subject: [PATCH] sidgen: ignore staged users when generating SIDs
Staged users have
uidNumber: -1
gidNumber: -1
ipaUniqueID: autogenerate
We cannot generate ipaSecurityIdentifier based on those UID/GID numbers.
However, '-1' value will trigger an error
find_sid_for_ldap_entry - [file ipa_sidgen_common.c, line 483]: ID value too large.
And that, in turn, will cause stopping SID generation for all users.
Detect 'ipaUniqueID: autogenerate' situation and ignore these entries.
Fixes: https://pagure.io/freeipa/issue/9517
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Thierry Bordaz <tbordaz@redhat.com>
---
daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h | 2 ++
.../ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c | 12 ++++++++++++
2 files changed, 14 insertions(+)
diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
index 0feff7eec..bd46982d0 100644
--- a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
@@ -45,6 +45,8 @@
#define UID_NUMBER "uidnumber"
#define GID_NUMBER "gidnumber"
#define IPA_SID "ipantsecurityidentifier"
+#define IPA_UNIQUEID "ipauniqueid"
+#define IPA_UNIQUEID_AUTOGENERATE "autogenerate"
#define DOM_ATTRS_FILTER OBJECTCLASS"=ipantdomainattrs"
#define DOMAIN_ID_RANGE_FILTER OBJECTCLASS"=ipadomainidrange"
#define POSIX_ACCOUNT "posixaccount"
diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c
index 6f784804c..cb763ebf8 100644
--- a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c
+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c
@@ -454,6 +454,7 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry,
uint32_t id;
char *sid = NULL;
char **objectclasses = NULL;
+ char *uniqueid = NULL;
Slapi_PBlock *mod_pb = NULL;
Slapi_Mods *smods = NULL;
int result;
@@ -479,6 +480,16 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry,
goto done;
}
+ uniqueid = slapi_entry_attr_get_charptr(entry, IPA_UNIQUEID);
+ if (uniqueid != NULL &&
+ strncmp(IPA_UNIQUEID_AUTOGENERATE, uniqueid,
+ sizeof(IPA_UNIQUEID_AUTOGENERATE)) == 0) {
+ LOG("Staged entry [%s] does not have Posix IDs, nothing to do.\n",
+ dn_str);
+ ret = 0;
+ goto done;
+ }
+
if (uid_number >= UINT32_MAX || gid_number >= UINT32_MAX) {
LOG_FATAL("ID value too large.\n");
ret = LDAP_CONSTRAINT_VIOLATION;
@@ -554,6 +565,7 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry,
}
done:
+ slapi_ch_free_string(&uniqueid);
slapi_ch_free_string(&sid);
slapi_pblock_destroy(mod_pb);
slapi_mods_free(&smods);
--
2.43.0
From 07150b71537744f491d022c737ef04775c72a10a Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Tue, 23 Jan 2024 14:53:39 +0200
Subject: [PATCH] sidgen: fix missing prototypes
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Thierry Bordaz <tbordaz@redhat.com>
---
daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
index bd46982d0..aec862796 100644
--- a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
@@ -106,3 +106,6 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry,
const char *base_dn,
const char *dom_sid,
struct range_info **ranges);
+
+int sidgen_task_init(Slapi_PBlock *pb);
+int ipa_sidgen_init(Slapi_PBlock *pb);
--
2.43.0

View File

@ -0,0 +1,55 @@
From 5e291da42898cc646f699c21a44b03b833d346e8 Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Tue, 27 Jun 2023 15:30:08 +0200
Subject: [PATCH] tests: fix backup-restore scenario with replica
The test TestBackupAndRestoreWithReplica is simulating a
master crash in order to check the behavior after ipa-restore.
Since commit 67a33e5, the uninstaller restarts the services in
order to unregister the server from PKI security domain. An
indirect consequence is that master/replica communication is re-
established and operations removing entries (done by the uninstaller)
are replicated to the replica.
This means that the scenario does not really simulate a server crash.
To make sure that no replication happens during this "crash", stop
the replica first, then uninstall the master, and finally restart
the replica before calling the ipa-restore command on the master.
Fixes: https://pagure.io/freeipa/issue/9404
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
ipatests/test_integration/test_backup_and_restore.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/ipatests/test_integration/test_backup_and_restore.py b/ipatests/test_integration/test_backup_and_restore.py
index 390c065f373e9a8a667f228a09eebd9ac033a19f..83b6a6b44d805fb0615e2128d4be984c6f858bf9 100644
--- a/ipatests/test_integration/test_backup_and_restore.py
+++ b/ipatests/test_integration/test_backup_and_restore.py
@@ -602,6 +602,12 @@ class TestBackupAndRestoreWithReplica(IntegrationTest):
tasks.user_add(self.replica1, 'test2_replica')
# simulate master crash
+ # the replica is stopped to make sure master uninstallation
+ # does not delete any entry on the replica. In case of a
+ # real master crash there would not be any communication between
+ # master and replica
+ self.replica1.run_command(['ipactl', 'stop'])
+
self.master.run_command(['ipactl', 'stop'])
tasks.uninstall_master(self.master, clean=False)
@@ -612,6 +618,7 @@ class TestBackupAndRestoreWithReplica(IntegrationTest):
self.master.run_command([
"systemctl", "disable", "oddjobd"
])
+ self.replica1.run_command(['ipactl', 'start'])
self.master.run_command(['ipa-restore', '-U', backup_path])
--
2.41.0

View File

@ -0,0 +1,54 @@
From 631dd72369385b0793e5bc0e019c088b4f1e2bb3 Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Mon, 26 Jun 2023 18:24:46 +0200
Subject: [PATCH] OTP: fix data type to avoid endianness issue
When 389-ds process an OTP authentication, the ipa-pwd-extop
plugin reads a buffer to extract the authentication type.
The type is stored in an int but the data is a ber_tag_t.
On big endian machines the type cast does not cause any issue
but on s390x the buffer that should return 128 is seen as 0.
As a consequence, the plugin considers that the method is not
LDAP_AUTH_SIMPLE and exits early, without processing the OTP.
The fix is simple and consists in using the right type
(ber_tag_t is an unsigned long).
Fixes: https://pagure.io/freeipa/issue/9402
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
index 937594117956d57540d4cf4eabeef6d22860aec8..45626523ffa1030cdff4f3e0ccdfa1618a51ccaf 100644
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
@@ -1433,7 +1433,7 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
Slapi_DN *target_sdn = NULL;
Slapi_DN *sdn = NULL;
const char *dn = NULL;
- int method = 0;
+ ber_tag_t method = 0;
bool syncreq;
bool otpreq;
int ret = 0;
@@ -1454,8 +1454,10 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
}
/* We're only interested in simple authentication. */
- if (method != LDAP_AUTH_SIMPLE || credentials->bv_len == 0)
+ if (method != LDAP_AUTH_SIMPLE || credentials->bv_len == 0) {
+ LOG("Not handled (not simple bind or NULL dn/credentials)\n");
return 0;
+ }
/* Retrieve the user's entry. */
sdn = slapi_sdn_dup(target_sdn);
--
2.41.0

View File

@ -1,310 +0,0 @@
From 67ca47ba4092811029eec02f8af9c34ba7662924 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Mon, 9 Oct 2023 15:47:03 +0200
Subject: [PATCH] ipa-kdb: Ensure Bronze-Bit check can be enabled
MIT krb5 1.19 and older do not implement support for PAC ticket
signature to protect the encrypted part of tickets. This is the cause of
the Bronze-Bit vulnerability (CVE-2020-17043). The Bronze-Bit attack
detection mechanism introduced in a847e248 relies on the content of the
PAC.
However, since CVE-2022-37967, the content of the PAC can no longer be
trusted if the KDC does not support PAC extended KDC signature (aka.
PAC full checksum). This signature is supported in MIT krb5 since
version 1.21.
Support for the PAC extended KDC signature was backported downstream to
krb5 1.18.2 for CentOS 8 Stream (dist-git commit 7d215a54). This makes
the content of the PAC still trustworthy there.
This commit disables the Bronze-Bit attack detection mechanism at build
time in case krb5 does not provide the krb5_pac_full_sign_compat()
function.
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
---
daemons/ipa-kdb/ipa_kdb.h | 4 ++++
daemons/ipa-kdb/ipa_kdb_kdcpolicy.c | 7 +++++++
daemons/ipa-kdb/ipa_kdb_mspac.c | 4 ++++
3 files changed, 15 insertions(+)
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
index 02b2cb631..c6926f7d5 100644
--- a/daemons/ipa-kdb/ipa_kdb.h
+++ b/daemons/ipa-kdb/ipa_kdb.h
@@ -367,6 +367,8 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
const char *test_realm, size_t size,
char **trusted_realm);
+#if KRB5_KDB_DAL_MAJOR_VERSION <= 8
+# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT
/* Try to detect a Bronze-Bit attack based on the content of the request and
* data from the KDB.
*
@@ -379,6 +381,8 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
krb5_error_code
ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
bool *detected, const char **status);
+# endif
+#endif
/* DELEGATION CHECKS */
diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
index 1032dff0b..ee0546c01 100644
--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
+++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
@@ -185,11 +185,18 @@ ipa_kdcpolicy_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata,
const char **status, krb5_deltat *lifetime_out,
krb5_deltat *renew_lifetime_out)
{
+#if KRB5_KDB_DAL_MAJOR_VERSION <= 8
+# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT
krb5_error_code kerr;
kerr = ipadb_check_for_bronze_bit_attack(context, request, NULL, status);
if (kerr)
return KRB5KDC_ERR_POLICY;
+# else
+# warning Support for Kerberos PAC extended KDC signature is missing.\
+ This makes FreeIPA vulnerable to the Bronze-Bit exploit (CVE-2020-17049).
+# endif
+#endif
*status = NULL;
*lifetime_out = 0;
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
index b4e22d431..05d5b407d 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
@@ -3299,6 +3299,8 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
return KRB5_KDB_NOENTRY;
}
+#if KRB5_KDB_DAL_MAJOR_VERSION <= 8
+# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT
krb5_error_code
ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
bool *detected, const char **status)
@@ -3471,3 +3473,5 @@ end:
ipadb_free_principal(context, proxy_entry);
return kerr;
}
+# endif
+#endif
--
2.43.0
From 27b96c17dd51d076e04d97662b7c788658a5094a Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Jan 26 2024 09:35:57 +0000
Subject: ipa-kdb: Disable Bronze-Bit check if PAC not available
The Bronze-Bit check introduced in commit
a847e2483b4c4832ee5129901da169f4eb0d1392 requires the MS-PAC to be
present in the evidence ticket in order for S4U2Proxy requests to be
accepted. This actually requires SIDs to be set.
However, domains that were initialized before commit
e527857d000e558b3288a7a210400abaf2171237 may still not have SIDs
configured. This would results in all S4U2Proxy requests to fail
(including all the HTTP API requests).
This present commit disables the check for the Bronze-Bit exploit
(CVE-2020-17049) in case the domain is not able to generate PACs.
Instead, it prints a warning message in the KDC logs each time a
S4U2Proxy request is processed.
Fixes: https://pagure.io/freeipa/issue/9521
Signed-off-by: Julien Rische <jrische@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
---
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
index c6926f7..621c235 100644
--- a/daemons/ipa-kdb/ipa_kdb.h
+++ b/daemons/ipa-kdb/ipa_kdb.h
@@ -370,17 +370,21 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
#if KRB5_KDB_DAL_MAJOR_VERSION <= 8
# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT
/* Try to detect a Bronze-Bit attack based on the content of the request and
- * data from the KDB.
+ * data from the KDB. This check will work only if the domain supports MS-PAC.
*
* context krb5 context
* request KDB request
- * detected Set to "true" if a bronze bit attack is detected and the
- * pointer is not NULL. Remains unset otherwise.
+ * supported If not NULL, set to "false" in case the Bronze-Bit exploit
+ * detection process silently failed to complete because the
+ * domain does not meet requirements. Set to "true" otherwise.
+ * detected If not NULL, set to "true" if a Bronze-Bit attack is detected.
+ * Set to "false" otherwise.
* status If the call fails and the pointer is not NULL, set it with a
* message describing the cause of the failure. */
krb5_error_code
ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
- bool *detected, const char **status);
+ bool *supported, bool *detected,
+ const char **status);
# endif
#endif
diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
index ee0546c..713e9a0 100644
--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
+++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
@@ -188,10 +188,18 @@ ipa_kdcpolicy_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata,
#if KRB5_KDB_DAL_MAJOR_VERSION <= 8
# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT
krb5_error_code kerr;
+ bool supported;
- kerr = ipadb_check_for_bronze_bit_attack(context, request, NULL, status);
+ kerr = ipadb_check_for_bronze_bit_attack(context, request, supported, NULL,
+ status);
if (kerr)
return KRB5KDC_ERR_POLICY;
+
+ if (!supported)
+ krb5_klog_syslog(LOG_WARNING, "MS-PAC not available. This makes "
+ "FreeIPA vulnerable to the Bronze-Bit exploit "
+ "(CVE-2020-17049). Please generate SIDs to enable "
+ "PAC support.");
# else
# warning Support for Kerberos PAC extended KDC signature is missing.\
This makes FreeIPA vulnerable to the Bronze-Bit exploit (CVE-2020-17049).
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
index 05d5b40..a18beff 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
@@ -3303,11 +3303,14 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT
krb5_error_code
ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
- bool *detected, const char **status)
+ bool *supported, bool *detected,
+ const char **status)
{
krb5_error_code kerr;
const char *st = NULL;
size_t i, j;
+ bool in_supported = true, in_detected = false;
+ struct ipadb_context *ipactx;
krb5_ticket *evidence_tkt;
krb5_authdata **authdata, **ifrel = NULL;
krb5_pac pac = NULL;
@@ -3327,6 +3330,21 @@ ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
goto end;
}
+ ipactx = ipadb_get_context(context);
+ if (!ipactx) {
+ kerr = KRB5_KDB_DBNOTINITED;
+ goto end;
+ }
+
+ /* Handle the case where the domain is not able to generate PACs (probably
+ * because SIDs are not set). In this case, we just skip the Bronze-Bit
+ * check. */
+ if (!ipactx->mspac) {
+ in_supported = false;
+ kerr = 0;
+ goto end;
+ }
+
evidence_tkt = request->second_ticket[0];
/* No need to check the Forwardable flag. If it was not set, this request
@@ -3451,8 +3469,7 @@ ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
/* This evidence ticket cannot be forwardable given the privileges
* of the proxy principal.
* This is a Bronze Bit attack. */
- if (detected)
- *detected = true;
+ in_detected = true;
st = "S4U2PROXY_BRONZE_BIT_ATTACK_DETECTED";
kerr = EBADE;
goto end;
@@ -3464,6 +3481,10 @@ ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
end:
if (st && status)
*status = st;
+ if (supported)
+ *supported = in_supported;
+ if (detected)
+ *detected = in_detected;
krb5_free_authdata(context, ifrel);
krb5_pac_free(context, pac);
From 81aa6ef695838a4b2fb5a53e773ea379a492913d Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Fri, 9 Feb 2024 16:36:03 +0100
Subject: [PATCH] ipd-kdb: Fix some mistakes in
ipadb_check_for_bronze_bit_attack()
Fixes: https://pagure.io/freeipa/issue/9521
Signed-off-by: Julien Rische <jrische@redhat.com>
Reviewed-By: Alexander Bokovoy <abbra@users.noreply.github.com>
---
daemons/ipa-kdb/ipa_kdb.h | 3 ++-
daemons/ipa-kdb/ipa_kdb_kdcpolicy.c | 2 +-
daemons/ipa-kdb/ipa_kdb_mspac.c | 5 +++--
3 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
index 621c23591..5de5ea7a5 100644
--- a/daemons/ipa-kdb/ipa_kdb.h
+++ b/daemons/ipa-kdb/ipa_kdb.h
@@ -382,7 +382,8 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
* status If the call fails and the pointer is not NULL, set it with a
* message describing the cause of the failure. */
krb5_error_code
-ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
+ipadb_check_for_bronze_bit_attack(krb5_context context,
+ const krb5_kdc_req *request,
bool *supported, bool *detected,
const char **status);
# endif
diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
index 713e9a0c8..44959f3de 100644
--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
+++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
@@ -190,7 +190,7 @@ ipa_kdcpolicy_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata,
krb5_error_code kerr;
bool supported;
- kerr = ipadb_check_for_bronze_bit_attack(context, request, supported, NULL,
+ kerr = ipadb_check_for_bronze_bit_attack(context, request, &supported, NULL,
status);
if (kerr)
return KRB5KDC_ERR_POLICY;
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
index 80350364a..886ed7785 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
@@ -3308,13 +3308,14 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
#if KRB5_KDB_DAL_MAJOR_VERSION <= 8
# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT
krb5_error_code
-ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
+ipadb_check_for_bronze_bit_attack(krb5_context context,
+ const krb5_kdc_req *request,
bool *supported, bool *detected,
const char **status)
{
krb5_error_code kerr;
const char *st = NULL;
- size_t i, j;
+ size_t i, j = 0;
bool in_supported = true, in_detected = false;
struct ipadb_context *ipactx;
krb5_ticket *evidence_tkt;
--
2.43.0

View File

@ -0,0 +1,42 @@
From 1e8352486cd5f77ff79e18798f04f406baf0a9a1 Mon Sep 17 00:00:00 2001
From: Mohammad Rizwan <myusuf@redhat.com>
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 <myusuf@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
---
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

View File

@ -1,272 +0,0 @@
From 00f8ddbfd2795228b343e1c39c1944b44d482c18 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Fri, 24 Nov 2023 11:46:19 +0200
Subject: [PATCH 1/4] ipa-kdb: add better detection of allowed user auth type
If default user authentication type is set to a list that does not
include a password or a hardened credential, the resulting configuration
might be incorrect for special service principals, including a krbtgt/..
one.
Add detection of special principals to avoid these situations and always
allow password or hardened for services.
Special handling is needed for the following principals:
- krbtgt/.. -- TGT service principals
- K/M -- master key principal
- kadmin/changepw -- service for changing passwords
- kadmin/kadmin -- kadmin service principal
- kadmin/history -- key used to encrypt history
Additionally, implicitly allow password or hardened credential use for
IPA services and IPA hosts since applications typically use keytabs for
that purpose.
Fixes: https://pagure.io/freeipa/issue/9485
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
---
daemons/ipa-kdb/ipa_kdb.c | 62 ++++++++++++++++++++++++++++++++++-----
1 file changed, 54 insertions(+), 8 deletions(-)
diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c
index 06d511c76..dbb98dba6 100644
--- a/daemons/ipa-kdb/ipa_kdb.c
+++ b/daemons/ipa-kdb/ipa_kdb.c
@@ -26,6 +26,7 @@
#include "ipa_kdb.h"
#include "ipa_krb5.h"
#include "ipa_hostname.h"
+#include <kadm5/admin.h>
#define IPADB_GLOBAL_CONFIG_CACHE_TIME 60
@@ -207,6 +208,19 @@ static const struct {
{ "idp", IPADB_USER_AUTH_IDP },
{ "passkey", IPADB_USER_AUTH_PASSKEY },
{ }
+},
+ objclass_table[] = {
+ { "ipaservice", IPADB_USER_AUTH_PASSWORD },
+ { "ipahost", IPADB_USER_AUTH_PASSWORD },
+ { }
+},
+ princname_table[] = {
+ { KRB5_TGS_NAME, IPADB_USER_AUTH_PASSWORD },
+ { KRB5_KDB_M_NAME, IPADB_USER_AUTH_PASSWORD },
+ { KADM5_ADMIN_SERVICE, IPADB_USER_AUTH_PASSWORD },
+ { KADM5_CHANGEPW_SERVICE, IPADB_USER_AUTH_PASSWORD },
+ { KADM5_HIST_PRINCIPAL, IPADB_USER_AUTH_PASSWORD },
+ { }
};
void ipadb_parse_user_auth(LDAP *lcontext, LDAPMessage *le,
@@ -217,17 +231,49 @@ void ipadb_parse_user_auth(LDAP *lcontext, LDAPMessage *le,
*userauth = IPADB_USER_AUTH_NONE;
vals = ldap_get_values_len(lcontext, le, IPA_USER_AUTH_TYPE);
- if (!vals)
- return;
-
- for (i = 0; vals[i]; i++) {
- for (j = 0; userauth_table[j].name; j++) {
- if (strcasecmp(vals[i]->bv_val, userauth_table[j].name) == 0) {
- *userauth |= userauth_table[j].flag;
- break;
+ if (!vals) {
+ /* if there is no explicit ipaUserAuthType set, use objectclass */
+ vals = ldap_get_values_len(lcontext, le, "objectclass");
+ if (!vals)
+ return;
+
+ for (i = 0; vals[i]; i++) {
+ for (j = 0; objclass_table[j].name; j++) {
+ if (strcasecmp(vals[i]->bv_val, objclass_table[j].name) == 0) {
+ *userauth |= objclass_table[j].flag;
+ break;
+ }
+ }
+ }
+ } else {
+ for (i = 0; vals[i]; i++) {
+ for (j = 0; userauth_table[j].name; j++) {
+ if (strcasecmp(vals[i]->bv_val, userauth_table[j].name) == 0) {
+ *userauth |= userauth_table[j].flag;
+ break;
+ }
}
}
}
+
+ /* If neither ipaUserAuthType nor objectClass were definitive,
+ * check the krbPrincipalName to see if it is krbtgt/ or K/M one */
+ if (*userauth == IPADB_USER_AUTH_NONE) {
+ ldap_value_free_len(vals);
+ vals = ldap_get_values_len(lcontext, le, "krbprincipalname");
+ if (!vals)
+ return;
+ for (i = 0; vals[i]; i++) {
+ for (j = 0; princname_table[j].name; j++) {
+ if (strncmp(vals[i]->bv_val, princname_table[j].name,
+ strlen(princname_table[j].name)) == 0) {
+ *userauth |= princname_table[j].flag;
+ break;
+ }
+ }
+ }
+
+ }
/* If password auth is enabled, enable hardened policy too. */
if (*userauth & IPADB_USER_AUTH_PASSWORD) {
*userauth |= IPADB_USER_AUTH_HARDENED;
--
2.43.0
From 69ae9febfb4462766b3bfe3e07e76550ece97b42 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Fri, 24 Nov 2023 11:54:04 +0200
Subject: [PATCH 2/4] ipa-kdb: when applying ticket policy, do not deny PKINIT
PKINIT differs from other pre-authentication methods by the fact that it
can be matched indepedently of the user authentication types via certmap
plugin in KDC.
Since PKINIT is a strong authentication method, allow its authentication
indicator and only apply the ticket policy.
Fixes: https://pagure.io/freeipa/issue/9485
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
---
daemons/ipa-kdb/ipa_kdb_kdcpolicy.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
index 436ee0e62..2802221c7 100644
--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
+++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
@@ -119,11 +119,8 @@ ipa_kdcpolicy_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata,
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_RADIUS]);
} else if (strcmp(auth_indicator, "pkinit") == 0) {
valid_auth_indicators++;
- if (!(ua & IPADB_USER_AUTH_PKINIT)) {
- *status = "PKINIT pre-authentication not allowed for this user.";
- kerr = KRB5KDC_ERR_POLICY;
- goto done;
- }
+ /* allow PKINIT unconditionally -- it has passed already at this
+ * point so some certificate was useful, only apply the limits */
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_PKINIT]);
} else if (strcmp(auth_indicator, "hardened") == 0) {
valid_auth_indicators++;
--
2.43.0
From 62c44c9e69aa2721990ca3628434713e1af6f59b Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Fri, 24 Nov 2023 12:20:55 +0200
Subject: [PATCH 3/4] ipa-kdb: clarify user auth table mapping use of
_AUTH_PASSWORD
Related: https://pagure.io/freeipa/issue/9485
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
---
daemons/ipa-kdb/ipa_kdb.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c
index dbb98dba6..4e6cacf24 100644
--- a/daemons/ipa-kdb/ipa_kdb.c
+++ b/daemons/ipa-kdb/ipa_kdb.c
@@ -195,6 +195,9 @@ done:
return base;
}
+/* In this table all _AUTH_PASSWORD entries will be
+ * expanded to include _AUTH_HARDENED in ipadb_parse_user_auth()
+ * which means there is no need to explicitly add it here */
static const struct {
const char *name;
enum ipadb_user_auth flag;
--
2.43.0
From c3bc938650b19a51706d8ccd98cdf8deaa26dc28 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Fri, 24 Nov 2023 13:00:48 +0200
Subject: [PATCH 4/4] ipatests: make sure PKINIT enrollment works with a strict
policy
Previously, for a global policy which does not include
'password', krb5kdc restart was failing. Now it should succeed.
We set admin user authentication type to PASSWORD to simplify
configuration in the test.
What matters here is that global policy does not include PKINIT and that
means a code in the ticket policy check will allow PKINIT implicitly
rather than explicitly.
Related: https://pagure.io/freeipa/issue/9485
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
---
.../test_integration/test_pkinit_install.py | 26 +++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/ipatests/test_integration/test_pkinit_install.py b/ipatests/test_integration/test_pkinit_install.py
index caa0e6a34..5c2e7af02 100644
--- a/ipatests/test_integration/test_pkinit_install.py
+++ b/ipatests/test_integration/test_pkinit_install.py
@@ -23,6 +23,24 @@ class TestPkinitClientInstall(IntegrationTest):
def install(cls, mh):
tasks.install_master(cls.master)
+ def enforce_password_and_otp(self):
+ """enforce otp by default and password for admin """
+ self.master.run_command(
+ [
+ "ipa",
+ "config-mod",
+ "--user-auth-type=otp",
+ ]
+ )
+ self.master.run_command(
+ [
+ "ipa",
+ "user-mod",
+ "admin",
+ "--user-auth-type=password",
+ ]
+ )
+
def add_certmaperule(self):
"""add certmap rule to map SAN dNSName to host entry"""
self.master.run_command(
@@ -86,6 +104,14 @@ class TestPkinitClientInstall(IntegrationTest):
cabundle = self.master.get_file_contents(paths.KDC_CA_BUNDLE_PEM)
client.put_file_contents(self.tmpbundle, cabundle)
+ def test_restart_krb5kdc(self):
+ tasks.kinit_admin(self.master)
+ self.enforce_password_and_otp()
+ self.master.run_command(['systemctl', 'stop', 'krb5kdc.service'])
+ self.master.run_command(['systemctl', 'start', 'krb5kdc.service'])
+ self.master.run_command(['systemctl', 'stop', 'kadmin.service'])
+ self.master.run_command(['systemctl', 'start', 'kadmin.service'])
+
def test_client_install_pkinit(self):
tasks.kinit_admin(self.master)
self.add_certmaperule()
--
2.43.0

View File

@ -0,0 +1,79 @@
From 387873080f1bc14aeaad89311b06dc46934be1ab Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
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 <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
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

View File

@ -1,139 +0,0 @@
From 48846e98e5e988d600ddf81c937f353fcecdea1a Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Mon, 27 Nov 2023 16:11:08 -0500
Subject: [PATCH 1/2] hbactest was not collecting or returning messages
hbactest does a number of internal searches, one of which
can exceed the configured sizelimit: hbacrule-find
Collect any messages returned from thsi call and display them
to the user on the cli.
Fixes: https://pagure.io/freeipa/issue/9486
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
---
ipaclient/plugins/hbactest.py | 2 ++
ipaserver/plugins/hbactest.py | 14 +++++++++++---
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/ipaclient/plugins/hbactest.py b/ipaclient/plugins/hbactest.py
index 1b54530b2..e0f93b9c2 100644
--- a/ipaclient/plugins/hbactest.py
+++ b/ipaclient/plugins/hbactest.py
@@ -38,6 +38,8 @@ class hbactest(CommandOverride):
# Note that we don't actually use --detail below to see if details need
# to be printed as our execute() method will return None for corresponding
# entries and None entries will be skipped.
+ self.log_messages(output)
+
for o in self.output:
if o == 'value':
continue
diff --git a/ipaserver/plugins/hbactest.py b/ipaserver/plugins/hbactest.py
index 887a35b7e..568c13174 100644
--- a/ipaserver/plugins/hbactest.py
+++ b/ipaserver/plugins/hbactest.py
@@ -24,6 +24,8 @@ from ipalib import Command, Str, Flag, Int
from ipalib import _
from ipapython.dn import DN
from ipalib.plugable import Registry
+from ipalib.messages import VersionMissing
+
if api.env.in_server:
try:
import ipaserver.dcerpc
@@ -323,6 +325,9 @@ class hbactest(Command):
# 2. Required options are (user, target host, service)
# 3. Options: rules to test (--rules, --enabled, --disabled), request for detail output
rules = []
+ result = {
+ 'warning':None, 'matched':None, 'notmatched':None, 'error':None
+ }
# Use all enabled IPA rules by default
all_enabled = True
@@ -351,8 +356,12 @@ class hbactest(Command):
hbacset = []
if len(testrules) == 0:
- hbacset = self.api.Command.hbacrule_find(
- sizelimit=sizelimit, no_members=False)['result']
+ hbacrules = self.api.Command.hbacrule_find(
+ sizelimit=sizelimit, no_members=False)
+ hbacset = hbacrules['result']
+ for message in hbacrules['messages']:
+ if message['code'] != VersionMissing.errno:
+ result.setdefault('messages', []).append(message)
else:
for rule in testrules:
try:
@@ -469,7 +478,6 @@ class hbactest(Command):
error_rules = []
warning_rules = []
- result = {'warning':None, 'matched':None, 'notmatched':None, 'error':None}
if not options['nodetail']:
# Validate runs rules one-by-one and reports failed ones
for ipa_rule in rules:
--
2.43.0
From d1e09c68af8ac77f656dd639af5d9a7f07c41f9d Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Tue, 28 Nov 2023 13:35:13 -0500
Subject: [PATCH 2/2] ipatests: Verify that hbactest will return messages
Limit the sizelimit of the hbactest request to confirm that
the output includes a SearchResultTruncated message.
Fixes: https://pagure.io/freeipa/issue/9486
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
---
ipatests/test_xmlrpc/test_hbactest_plugin.py | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/ipatests/test_xmlrpc/test_hbactest_plugin.py b/ipatests/test_xmlrpc/test_hbactest_plugin.py
index 73c4ce232..e2e66c759 100644
--- a/ipatests/test_xmlrpc/test_hbactest_plugin.py
+++ b/ipatests/test_xmlrpc/test_hbactest_plugin.py
@@ -134,6 +134,7 @@ class test_hbactest(XMLRPC_test):
assert ret['value']
assert ret['error'] is None
assert ret['matched'] is None
+ assert 'messages' not in ret
assert ret['notmatched'] is None
def test_c_hbactest_check_rules_enabled_detail(self):
@@ -200,7 +201,23 @@ class test_hbactest(XMLRPC_test):
nodetail=True
)
- def test_g_hbactest_clear_testing_data(self):
+ def test_g_hbactest_searchlimit_message(self):
+ """
+ Test running 'ipa hbactest' with limited --sizelimit
+
+ We know there are at least 6 rules, 4 created here + 2 default.
+ """
+ ret = api.Command['hbactest'](
+ user=self.test_user,
+ targethost=self.test_host,
+ service=self.test_service,
+ nodetail=True,
+ sizelimit=2,
+ )
+
+ assert ret['messages'] is not None
+
+ def test_h_hbactest_clear_testing_data(self):
"""
Clear data for HBAC test plugin testing.
"""
--
2.43.0

View File

@ -1,43 +0,0 @@
From 16a739e0260f97705827f972d53c828809dbfdb2 Mon Sep 17 00:00:00 2001
From: Masahiro Matsuya <mmatsuya@redhat.com>
Date: Tue, 9 Jan 2024 23:12:11 +0900
Subject: [PATCH] ipatests: wait for replica update in test_dns_locations
test_ipa_ca_records and test_adtrust_system_records can fail with
NXDOMAIN, because it doesn't wait enough for the update on replica.
It can be resolved by waiting for the update with wait_for_replication.
Fixes: https://pagure.io/freeipa/issue/9504
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
(cherry picked from commit 905a55a4ef926068630ebd2ab375f58c24dedcd1)
---
ipatests/test_integration/test_dns_locations.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/ipatests/test_integration/test_dns_locations.py b/ipatests/test_integration/test_dns_locations.py
index 44900af80..89a310892 100644
--- a/ipatests/test_integration/test_dns_locations.py
+++ b/ipatests/test_integration/test_dns_locations.py
@@ -534,6 +534,9 @@ class TestDNSLocations(IntegrationTest):
expected_servers = (self.master.ip, self.replicas[1].ip)
+ ldap = self.master.ldap_connect()
+ tasks.wait_for_replication(ldap)
+
for ip in (self.master.ip, self.replicas[0].ip, self.replicas[1].ip):
self._test_A_rec_against_server(ip, self.domain, expected_servers)
@@ -557,6 +560,9 @@ class TestDNSLocations(IntegrationTest):
(self.PRIO_HIGH, self.WEIGHT, DNSName(self.master.hostname)),
)
+ ldap = self.master.ldap_connect()
+ tasks.wait_for_replication(ldap)
+
for ip in (self.master.ip, self.replicas[0].ip, self.replicas[1].ip):
self._test_SRV_rec_against_server(
ip, self.domain, expected_servers,
--
2.43.0

View File

@ -0,0 +1,122 @@
From caacccc6b92c08f510fba2e31d9c56eb372abddc Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
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 <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
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

View File

@ -0,0 +1,117 @@
From 421e8e9ac886c50b4bb463a62b8ad5de8da94f31 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
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 <rcritten@redhat.com>
Reviewed-By: Rafael Guterres Jeffman <rjeffman@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
---
.../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

View File

@ -1,707 +0,0 @@
From c3ac69e9cf8dfcc31ed11fc988c37bd99d3ec3cf Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Wed, 14 Feb 2024 17:47:00 +0100
Subject: [PATCH] ipa-kdb: Rework ipadb_reinit_mspac()
Modify ipadb_reinit_mspac() to allocate and initialize ipactx->mspac
only if all its attributes can be set. If not, ipactx->mspac is set to
NULL. This makes easier to determine if the KDC is able to generate PACs
or not.
Also ipadb_reinit_mspac() is now able to return a status message
explaining why initialization of the PAC generator failed. This message
is printed in KDC logs.
Fixes: https://pagure.io/freeipa/issue/9535
Signed-off-by: Julien Rische <jrische@redhat.com>
Reviewed-By: Alexander Bokovoy <abbra@users.noreply.github.com>
(cherry picked from commit 7f072e348d318e928f6270a182ca04dee8716677)
---
daemons/ipa-kdb/ipa_kdb.c | 14 +-
daemons/ipa-kdb/ipa_kdb.h | 4 +-
daemons/ipa-kdb/ipa_kdb_mspac.c | 340 +++++++++++++-----------
daemons/ipa-kdb/ipa_kdb_mspac_private.h | 2 +-
daemons/ipa-kdb/ipa_kdb_mspac_v6.c | 5 +-
daemons/ipa-kdb/ipa_kdb_mspac_v9.c | 16 +-
daemons/ipa-kdb/ipa_kdb_principals.c | 6 +-
7 files changed, 218 insertions(+), 169 deletions(-)
diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c
index 0c6325df9..fcadb8ee7 100644
--- a/daemons/ipa-kdb/ipa_kdb.c
+++ b/daemons/ipa-kdb/ipa_kdb.c
@@ -443,6 +443,7 @@ int ipadb_get_connection(struct ipadb_context *ipactx)
struct timeval tv = { 5, 0 };
LDAPMessage *res = NULL;
LDAPMessage *first;
+ const char *stmsg;
int ret;
int v3;
@@ -522,16 +523,9 @@ int ipadb_get_connection(struct ipadb_context *ipactx)
}
/* get adtrust options using default refresh interval */
- ret = ipadb_reinit_mspac(ipactx, false);
- if (ret && ret != ENOENT) {
- /* TODO: log that there is an issue with adtrust settings */
- if (ipactx->lcontext == NULL) {
- /* for some reason ldap connection was reset in ipadb_reinit_mspac
- * and is no longer established => failure of ipadb_get_connection
- */
- goto done;
- }
- }
+ ret = ipadb_reinit_mspac(ipactx, false, &stmsg);
+ if (ret && stmsg)
+ krb5_klog_syslog(LOG_WARNING, "MS-PAC generator: %s", stmsg);
ret = 0;
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
index 5de5ea7a5..7baf4697f 100644
--- a/daemons/ipa-kdb/ipa_kdb.h
+++ b/daemons/ipa-kdb/ipa_kdb.h
@@ -352,7 +352,9 @@ krb5_error_code ipadb_v9_issue_pac(krb5_context context, unsigned int flags,
krb5_data ***auth_indicators);
#endif
-krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit);
+krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx,
+ bool force_reinit,
+ const char **stmsg);
void ipadb_mspac_struct_free(struct ipadb_mspac **mspac);
krb5_error_code ipadb_check_transited_realms(krb5_context kcontext,
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
index 886ed7785..deed513b9 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
@@ -793,16 +793,16 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
return ret;
}
+ if (!ipactx->mspac) {
+ /* can't give a PAC without server NetBIOS name or primary group RID */
+ return ENOENT;
+ }
+
if (info3->base.primary_gid == 0) {
if (is_host || is_service) {
info3->base.primary_gid = 515; /* Well known RID for domain computers group */
} else {
- if (ipactx->mspac->fallback_rid) {
- info3->base.primary_gid = ipactx->mspac->fallback_rid;
- } else {
- /* can't give a pack without a primary group rid */
- return ENOENT;
- }
+ info3->base.primary_gid = ipactx->mspac->fallback_rid;
}
}
@@ -812,26 +812,16 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
/* always zero out, not used for Krb, only NTLM */
memset(&info3->base.key, '\0', sizeof(info3->base.key));
- if (ipactx->mspac->flat_server_name) {
- info3->base.logon_server.string =
- talloc_strdup(memctx, ipactx->mspac->flat_server_name);
- if (!info3->base.logon_server.string) {
- return ENOMEM;
- }
- } else {
- /* can't give a pack without Server NetBIOS Name :-| */
- return ENOENT;
+ info3->base.logon_server.string =
+ talloc_strdup(memctx, ipactx->mspac->flat_server_name);
+ if (!info3->base.logon_server.string) {
+ return ENOMEM;
}
- if (ipactx->mspac->flat_domain_name) {
- info3->base.logon_domain.string =
- talloc_strdup(memctx, ipactx->mspac->flat_domain_name);
- if (!info3->base.logon_domain.string) {
- return ENOMEM;
- }
- } else {
- /* can't give a pack without Domain NetBIOS Name :-| */
- return ENOENT;
+ info3->base.logon_domain.string =
+ talloc_strdup(memctx, ipactx->mspac->flat_domain_name);
+ if (!info3->base.logon_domain.string) {
+ return ENOMEM;
}
if (is_host || is_service) {
@@ -1044,6 +1034,11 @@ krb5_error_code ipadb_get_pac(krb5_context kcontext,
return KRB5_KDB_DBNOTINITED;
}
+ /* Check if PAC generator is initialized */
+ if (!ipactx->mspac) {
+ return ENOENT;
+ }
+
ied = (struct ipadb_e_data *)client->e_data;
if (ied->magic != IPA_E_DATA_MAGIC) {
return EINVAL;
@@ -1626,14 +1621,14 @@ static struct ipadb_adtrusts *get_domain_from_realm(krb5_context context,
{
struct ipadb_context *ipactx;
struct ipadb_adtrusts *domain;
- int i;
+ size_t i;
ipactx = ipadb_get_context(context);
if (!ipactx) {
return NULL;
}
- if (ipactx->mspac == NULL) {
+ if (!ipactx->mspac) {
return NULL;
}
@@ -1655,6 +1650,7 @@ static struct ipadb_adtrusts *get_domain_from_realm_update(krb5_context context,
{
struct ipadb_context *ipactx;
struct ipadb_adtrusts *domain;
+ const char *stmsg = NULL;
krb5_error_code kerr;
ipactx = ipadb_get_context(context);
@@ -1663,8 +1659,10 @@ static struct ipadb_adtrusts *get_domain_from_realm_update(krb5_context context,
}
/* re-init MS-PAC info using default update interval */
- kerr = ipadb_reinit_mspac(ipactx, false);
+ kerr = ipadb_reinit_mspac(ipactx, false, &stmsg);
if (kerr != 0) {
+ if (stmsg)
+ krb5_klog_syslog(LOG_WARNING, "MS-PAC generator: %s", stmsg);
return NULL;
}
domain = get_domain_from_realm(context, realm);
@@ -1717,6 +1715,7 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
struct ipadb_e_data *ied = NULL;
int flags = 0;
struct dom_sid client_sid;
+ const char *stmsg = NULL;
#ifdef KRB5_KDB_FLAG_ALIAS_OK
flags = KRB5_KDB_FLAG_ALIAS_OK;
#endif
@@ -1730,10 +1729,14 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
* check that our own view on the PAC details is up to date */
if (ipactx->mspac->domsid.num_auths == 0) {
/* Force re-init of KDB's view on our domain */
- kerr = ipadb_reinit_mspac(ipactx, true);
+ kerr = ipadb_reinit_mspac(ipactx, true, &stmsg);
if (kerr != 0) {
- krb5_klog_syslog(LOG_ERR,
- "PAC issue: unable to update realm's view on PAC info");
+ if (stmsg) {
+ krb5_klog_syslog(LOG_ERR, "MS-PAC generator: %s", stmsg);
+ } else {
+ krb5_klog_syslog(LOG_ERR, "PAC issue: unable to update " \
+ "realm's view on PAC info");
+ }
return KRB5KDC_ERR_POLICY;
}
}
@@ -1746,7 +1749,7 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
if (is_s4u && (ipactx->mspac->trusts != NULL)) {
/* Iterate through list of trusts and check if this SID belongs to
* one of the domains we trust */
- for(int i = 0 ; i < ipactx->mspac->num_trusts ; i++) {
+ for(size_t i = 0 ; i < ipactx->mspac->num_trusts ; i++) {
result = dom_sid_check(&ipactx->mspac->trusts[i].domsid,
info->info->info3.base.domain_sid, true);
if (result) {
@@ -1858,11 +1861,11 @@ krb5_error_code filter_logon_info(krb5_context context,
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,
+ for (size_t m = 0; m < mspac_ctx->num_trusts; m++) {
+ result = dom_sid_check(&mspac_ctx->trusts[m].domsid,
info->info->info3.base.domain_sid, true);
if (result) {
- domain = &mspac_ctx->trusts[k];
+ domain = &mspac_ctx->trusts[m];
break;
}
}
@@ -2091,10 +2094,10 @@ static krb5_error_code ipadb_check_logon_info(krb5_context context,
return KRB5_KDB_DBNOTINITED;
}
/* In S4U case we might be dealing with the PAC issued by the trusted domain */
- if ((ipactx->mspac->trusts != NULL)) {
+ if (ipactx->mspac->trusts) {
/* Iterate through list of trusts and check if this SID belongs to
* one of the domains we trust */
- for(int i = 0 ; i < ipactx->mspac->num_trusts ; i++) {
+ for(size_t i = 0 ; i < ipactx->mspac->num_trusts ; i++) {
result = dom_sid_check(&ipactx->mspac->trusts[i].domsid,
&client_sid, false);
if (result) {
@@ -2631,7 +2634,7 @@ static char *get_server_netbios_name(struct ipadb_context *ipactx)
void ipadb_mspac_struct_free(struct ipadb_mspac **mspac)
{
- int i, j;
+ size_t i, j;
if (!*mspac) return;
@@ -2786,7 +2789,8 @@ ipadb_mspac_get_trusted_domains(struct ipadb_context *ipactx)
LDAPDN dn = NULL;
char **sid_blocklist_incoming = NULL;
char **sid_blocklist_outgoing = NULL;
- int ret, n, i;
+ size_t i, n;
+ int ret;
ret = asprintf(&base, "cn=ad,cn=trusts,%s", ipactx->base);
if (ret == -1) {
@@ -2871,7 +2875,7 @@ ipadb_mspac_get_trusted_domains(struct ipadb_context *ipactx)
t[n].upn_suffixes_len = NULL;
if (t[n].upn_suffixes != NULL) {
- int len = 0;
+ size_t len = 0;
for (; t[n].upn_suffixes[len] != NULL; len++);
@@ -2986,108 +2990,114 @@ done:
return ret;
}
-krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit)
+krb5_error_code
+ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit,
+ const char **stmsg)
{
char *dom_attrs[] = { "ipaNTFlatName",
"ipaNTFallbackPrimaryGroup",
"ipaNTSecurityIdentifier",
NULL };
char *grp_attrs[] = { "ipaNTSecurityIdentifier", NULL };
- krb5_error_code kerr;
LDAPMessage *result = NULL;
LDAPMessage *lentry;
- struct dom_sid gsid;
- char *resstr;
- int ret;
+ struct dom_sid gsid, domsid;
+ char *resstr = NULL;
+ char *flat_domain_name = NULL;
+ char *flat_server_name = NULL;
+ char *fallback_group = NULL;
+ uint32_t fallback_rid;
time_t now;
+ const char *in_stmsg = NULL;
+ int err;
+ krb5_error_code trust_kerr = 0;
+
/* Do not update the mspac struct more than once a minute. This would
* avoid heavy load on the directory server if there are lots of requests
* from domains which we do not trust. */
now = time(NULL);
- if (ipactx->mspac != NULL &&
- (force_reinit == false) &&
- (now > ipactx->mspac->last_update) &&
- (now - ipactx->mspac->last_update) < 60) {
- return 0;
- }
-
- if (ipactx->mspac && ipactx->mspac->num_trusts == 0) {
- /* Check if there is any trust configured. If not, just return
- * and do not re-initialize the MS-PAC structure. */
- kerr = ipadb_mspac_check_trusted_domains(ipactx);
- if (kerr == KRB5_KDB_NOENTRY) {
- kerr = 0;
- goto done;
- } else if (kerr != 0) {
- goto done;
+ if (ipactx->mspac) {
+ if (!force_reinit &&
+ (now > ipactx->mspac->last_update) &&
+ (now - ipactx->mspac->last_update) < 60) {
+ /* SKIP */
+ err = 0;
+ goto end;
}
- }
-
- /* clean up in case we had old values around */
- ipadb_mspac_struct_free(&ipactx->mspac);
- ipactx->mspac = calloc(1, sizeof(struct ipadb_mspac));
- if (!ipactx->mspac) {
- kerr = ENOMEM;
- goto done;
+ if (ipactx->mspac->num_trusts == 0) {
+ /* Check if there is any trust configured. If not, just return
+ * and do not re-initialize the MS-PAC structure. */
+ err = ipadb_mspac_check_trusted_domains(ipactx);
+ if (err) {
+ if (err == KRB5_KDB_NOENTRY) {
+ /* SKIP */
+ err = 0;
+ } else {
+ in_stmsg = "Failed to fetch trusted domains information";
+ }
+ goto end;
+ }
+ }
}
- ipactx->mspac->last_update = now;
-
- kerr = ipadb_simple_search(ipactx, ipactx->base, LDAP_SCOPE_SUBTREE,
- "(objectclass=ipaNTDomainAttrs)", dom_attrs,
- &result);
- if (kerr == KRB5_KDB_NOENTRY) {
- return ENOENT;
- } else if (kerr != 0) {
- return EIO;
+ err = ipadb_simple_search(ipactx, ipactx->base, LDAP_SCOPE_SUBTREE,
+ "(objectclass=ipaNTDomainAttrs)", dom_attrs,
+ &result);
+ if (err == KRB5_KDB_NOENTRY) {
+ err = ENOENT;
+ in_stmsg = "Local domain NT attributes not configured";
+ goto end;
+ } else if (err) {
+ err = EIO;
+ in_stmsg = "Failed to fetch local domain NT attributes";
+ goto end;
}
lentry = ldap_first_entry(ipactx->lcontext, result);
if (!lentry) {
- kerr = ENOENT;
- goto done;
+ err = ENOENT;
+ in_stmsg = "Local domain NT attributes not configured";
+ goto end;
}
- ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
- "ipaNTFlatName",
- &ipactx->mspac->flat_domain_name);
- if (ret) {
- kerr = ret;
- goto done;
+ err = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry, "ipaNTFlatName",
+ &flat_domain_name);
+ if (err) {
+ in_stmsg = "Local domain NT flat name not configured";
+ goto end;
}
- ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
- "ipaNTSecurityIdentifier",
- &resstr);
- if (ret) {
- kerr = ret;
- goto done;
+ err = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
+ "ipaNTSecurityIdentifier", &resstr);
+ if (err) {
+ in_stmsg = "Local domain SID not configured";
+ goto end;
}
- ret = ipadb_string_to_sid(resstr, &ipactx->mspac->domsid);
- if (ret) {
- kerr = ret;
- free(resstr);
- goto done;
+ err = ipadb_string_to_sid(resstr, &domsid);
+ if (err) {
+ in_stmsg = "Malformed local domain SID";
+ goto end;
}
+
free(resstr);
- free(ipactx->mspac->flat_server_name);
- ipactx->mspac->flat_server_name = get_server_netbios_name(ipactx);
- if (!ipactx->mspac->flat_server_name) {
- kerr = ENOMEM;
- goto done;
+ flat_server_name = get_server_netbios_name(ipactx);
+ if (!flat_server_name) {
+ err = ENOMEM;
+ goto end;
}
- ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
- "ipaNTFallbackPrimaryGroup",
- &ipactx->mspac->fallback_group);
- if (ret && ret != ENOENT) {
- kerr = ret;
- goto done;
+ err = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
+ "ipaNTFallbackPrimaryGroup", &fallback_group);
+ if (err) {
+ in_stmsg = (err == ENOENT)
+ ? "Local fallback primary group not configured"
+ : "Failed to fetch local fallback primary group";
+ goto end;
}
/* result and lentry not valid any more from here on */
@@ -3095,53 +3105,81 @@ krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_rein
result = NULL;
lentry = NULL;
- if (ret != ENOENT) {
- kerr = ipadb_simple_search(ipactx, ipactx->mspac->fallback_group,
- LDAP_SCOPE_BASE,
- "(objectclass=posixGroup)",
- grp_attrs, &result);
- if (kerr && kerr != KRB5_KDB_NOENTRY) {
- kerr = ret;
- goto done;
- }
+ err = ipadb_simple_search(ipactx, fallback_group, LDAP_SCOPE_BASE,
+ "(objectclass=posixGroup)", grp_attrs, &result);
+ if (err) {
+ in_stmsg = (err == KRB5_KDB_NOENTRY)
+ ? "Local fallback primary group has no POSIX definition"
+ : "Failed to fetch SID of POSIX group mapped as local fallback " \
+ "primary group";
+ goto end;
+ }
- lentry = ldap_first_entry(ipactx->lcontext, result);
- if (!lentry) {
- kerr = ENOENT;
- goto done;
- }
+ lentry = ldap_first_entry(ipactx->lcontext, result);
+ if (!lentry) {
+ err = ENOENT;
+ goto end;
+ }
- if (kerr == 0) {
- ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
- "ipaNTSecurityIdentifier",
- &resstr);
- if (ret && ret != ENOENT) {
- kerr = ret;
- goto done;
- }
- if (ret == 0) {
- ret = ipadb_string_to_sid(resstr, &gsid);
- if (ret) {
- free(resstr);
- kerr = ret;
- goto done;
- }
- ret = sid_split_rid(&gsid, &ipactx->mspac->fallback_rid);
- if (ret) {
- free(resstr);
- kerr = ret;
- goto done;
- }
- free(resstr);
- }
- }
+ err = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
+ "ipaNTSecurityIdentifier", &resstr);
+ if (err) {
+ in_stmsg = (err == ENOENT)
+ ? "The POSIX group set as fallback primary group has no SID " \
+ "configured"
+ : "Failed to fetch SID of POSIX group set as local fallback " \
+ "primary group";
+ goto end;
}
- kerr = ipadb_mspac_get_trusted_domains(ipactx);
+ err = ipadb_string_to_sid(resstr, &gsid);
+ if (err) {
+ in_stmsg = "Malformed SID of POSIX group set as local fallback " \
+ "primary group";
+ goto end;
+ }
-done:
+ err = sid_split_rid(&gsid, &fallback_rid);
+ if (err) {
+ in_stmsg = "Malformed SID of POSIX group mapped as local fallback " \
+ "primary group";
+ goto end;
+ }
+
+ /* clean up in case we had old values around */
+ ipadb_mspac_struct_free(&ipactx->mspac);
+
+ ipactx->mspac = calloc(1, sizeof(struct ipadb_mspac));
+ if (!ipactx->mspac) {
+ err = ENOMEM;
+ goto end;
+ }
+
+ ipactx->mspac->last_update = now;
+ ipactx->mspac->flat_domain_name = flat_domain_name;
+ ipactx->mspac->flat_server_name = flat_server_name;
+ ipactx->mspac->domsid = domsid;
+ ipactx->mspac->fallback_group = fallback_group;
+ ipactx->mspac->fallback_rid = fallback_rid;
+
+ trust_kerr = ipadb_mspac_get_trusted_domains(ipactx);
+ if (trust_kerr)
+ in_stmsg = "Failed to assemble trusted domains information";
+
+end:
+ if (stmsg)
+ *stmsg = in_stmsg;
+
+ if (resstr) free(resstr);
ldap_msgfree(result);
- return kerr;
+
+ if (err) {
+ if (flat_domain_name) free(flat_domain_name);
+ if (flat_server_name) free(flat_server_name);
+ if (fallback_group) free(fallback_group);
+ }
+
+ return err ? (krb5_error_code)err : trust_kerr;
}
krb5_error_code ipadb_check_transited_realms(krb5_context kcontext,
@@ -3151,11 +3189,11 @@ krb5_error_code ipadb_check_transited_realms(krb5_context kcontext,
{
struct ipadb_context *ipactx;
bool has_transited_contents, has_client_realm, has_server_realm;
- int i;
+ size_t i;
krb5_error_code ret;
ipactx = ipadb_get_context(kcontext);
- if (!ipactx || !ipactx->mspac) {
+ if (!ipactx) {
return KRB5_KDB_DBNOTINITED;
}
@@ -3217,7 +3255,7 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
char **trusted_realm)
{
struct ipadb_context *ipactx;
- int i, j, length;
+ size_t i, j, length;
const char *name;
bool result = false;
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac_private.h b/daemons/ipa-kdb/ipa_kdb_mspac_private.h
index 7f0ca7a79..e650cfa73 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac_private.h
+++ b/daemons/ipa-kdb/ipa_kdb_mspac_private.h
@@ -31,7 +31,7 @@ struct ipadb_mspac {
char *fallback_group;
uint32_t fallback_rid;
- int num_trusts;
+ size_t num_trusts;
struct ipadb_adtrusts *trusts;
time_t last_update;
};
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac_v6.c b/daemons/ipa-kdb/ipa_kdb_mspac_v6.c
index faf47ad1b..96cd50e4c 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac_v6.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac_v6.c
@@ -233,6 +233,7 @@ krb5_error_code ipadb_sign_authdata(krb5_context context,
krb5_db_entry *client_entry = NULL;
krb5_boolean is_equal;
bool force_reinit_mspac = false;
+ const char *stmsg = NULL;
is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0);
@@ -309,7 +310,9 @@ krb5_error_code ipadb_sign_authdata(krb5_context context,
force_reinit_mspac = true;
}
- (void)ipadb_reinit_mspac(ipactx, force_reinit_mspac);
+ kerr = ipadb_reinit_mspac(ipactx, force_reinit_mspac, &stmsg);
+ if (kerr && stmsg)
+ krb5_klog_syslog(LOG_WARNING, "MS-PAC generator: %s", stmsg);
kerr = ipadb_get_pac(context, flags, client, server, NULL, authtime, &pac);
if (kerr != 0 && kerr != ENOENT) {
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac_v9.c b/daemons/ipa-kdb/ipa_kdb_mspac_v9.c
index 3badd5b08..60db048e1 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac_v9.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac_v9.c
@@ -46,6 +46,7 @@ ipadb_v9_issue_pac(krb5_context context, unsigned int flags,
bool with_pad;
krb5_error_code kerr = 0;
bool is_as_req = flags & CLIENT_REFERRALS_FLAGS;
+ const char *stmsg = NULL;
if (is_as_req) {
get_authz_data_types(context, client, &with_pac, &with_pad);
@@ -110,12 +111,19 @@ ipadb_v9_issue_pac(krb5_context context, unsigned int flags,
force_reinit_mspac = TRUE;
}
}
- (void)ipadb_reinit_mspac(ipactx, force_reinit_mspac);
- /* MS-PAC needs proper configuration and if it is missing, we simply skip issuing one */
- if (ipactx->mspac->flat_server_name == NULL) {
+ /* MS-PAC generator has to be initalized */
+ kerr = ipadb_reinit_mspac(ipactx, force_reinit_mspac, &stmsg);
+ if (kerr && stmsg)
+ krb5_klog_syslog(LOG_ERR, "MS-PAC generator: %s", stmsg);
+
+ /* Continue even if initilization of PAC generator failed.
+ * It may caused by the trust objects part only. */
+
+ /* At least the core part of the PAC generator is required. */
+ if (!ipactx->mspac)
return KRB5_PLUGIN_OP_NOTSUPP;
- }
+
kerr = ipadb_get_pac(context, flags,
client, server, replaced_reply_key,
authtime, &new_pac);
diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c
index fadb132ed..07cc87746 100644
--- a/daemons/ipa-kdb/ipa_kdb_principals.c
+++ b/daemons/ipa-kdb/ipa_kdb_principals.c
@@ -1495,6 +1495,7 @@ static krb5_error_code dbget_alias(krb5_context kcontext,
krb5_db_entry *kentry = NULL;
krb5_data *realm;
krb5_boolean check = FALSE;
+ const char *stmsg = NULL;
/* TODO: also support hostbased aliases */
@@ -1562,8 +1563,11 @@ static krb5_error_code dbget_alias(krb5_context kcontext,
if (kerr == KRB5_KDB_NOENTRY) {
/* If no trusted realm found, refresh trusted domain data and try again
* because it might be a freshly added trust to AD */
- kerr = ipadb_reinit_mspac(ipactx, false);
+ kerr = ipadb_reinit_mspac(ipactx, false, &stmsg);
if (kerr != 0) {
+ if (stmsg)
+ krb5_klog_syslog(LOG_WARNING, "MS-PAC generator: %s",
+ stmsg);
kerr = KRB5_KDB_NOENTRY;
goto done;
}
--
2.43.0

View File

@ -0,0 +1,136 @@
From 4b02322fc786ee9caaa0380659507a2cec0d4101 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
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 <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
---
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

View File

@ -1,34 +0,0 @@
From 44a762413c83f9637399afeb61b1e4b1ac111260 Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Feb 14 2024 12:24:48 +0000
Subject: ipatests: fix tasks.wait_for_replication method
With the fix for https://pagure.io/freeipa/issue/9171, the
method entry.single_value['nsds5replicaupdateinprogress'] now
returns a Boolean instead of a string "TRUE"/"FALSE".
The method tasks.wait_for_replication needs to be fixed so that
it properly detects when replication is not done.
Fixes: https://pagure.io/freeipa/issue/9530
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py
index 9068ba6..952c9e6 100755
--- a/ipatests/pytest_ipa/integration/tasks.py
+++ b/ipatests/pytest_ipa/integration/tasks.py
@@ -1510,7 +1510,7 @@ def wait_for_replication(ldap, timeout=30,
statuses = [entry.single_value[status_attr] for entry in entries]
wrong_statuses = [s for s in statuses
if not re.match(target_status_re, s)]
- if any(e.single_value[progress_attr] == 'TRUE' for e in entries):
+ if any(e.single_value[progress_attr] for e in entries):
msg = 'Replication not finished'
logger.debug(msg)
elif wrong_statuses:

View File

@ -1,127 +0,0 @@
From 163f06cab678d517ab30ab6da59ae339f39ee7cf Mon Sep 17 00:00:00 2001
From: Francisco Trivino <ftrivino@redhat.com>
Date: Fri, 27 May 2022 17:31:40 +0200
Subject: [PATCH] Vault: add support for RSA-OAEP wrapping algo
None of the FIPS certified modules in RHEL support PKCS#1 v1.5 as FIPS
approved mechanism. This commit adds support for RSA-OAEP padding as a
fallback.
Fixes: https://pagure.io/freeipa/issue/9191
Signed-off-by: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
(cherry picked from commit b1fb31fd20c900c9ff1d5d28dfe136439f6bf605)
---
ipaclient/plugins/vault.py | 57 ++++++++++++++++++++++++++++++--------
1 file changed, 45 insertions(+), 12 deletions(-)
diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py
index d4c84eb6b..ed16c73ae 100644
--- a/ipaclient/plugins/vault.py
+++ b/ipaclient/plugins/vault.py
@@ -119,8 +119,8 @@ def encrypt(data, symmetric_key=None, public_key=None):
return public_key_obj.encrypt(
data,
padding.OAEP(
- mgf=padding.MGF1(algorithm=hashes.SHA1()),
- algorithm=hashes.SHA1(),
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
+ algorithm=hashes.SHA256(),
label=None
)
)
@@ -154,8 +154,8 @@ def decrypt(data, symmetric_key=None, private_key=None):
return private_key_obj.decrypt(
data,
padding.OAEP(
- mgf=padding.MGF1(algorithm=hashes.SHA1()),
- algorithm=hashes.SHA1(),
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
+ algorithm=hashes.SHA256(),
label=None
)
)
@@ -705,14 +705,39 @@ class ModVaultData(Local):
return transport_cert, wrapping_algo
def _do_internal(self, algo, transport_cert, raise_unexpected,
- *args, **options):
+ use_oaep=False, *args, **options):
public_key = transport_cert.public_key()
# wrap session key with transport certificate
- wrapped_session_key = public_key.encrypt(
- algo.key,
- padding.PKCS1v15()
- )
+ # KRA may be configured using either the default PKCS1v15 or RSA-OAEP.
+ # there is no way to query this info using the REST interface.
+ if not use_oaep:
+ # PKCS1v15() causes an OpenSSL exception when FIPS is enabled
+ # if so, we fallback to RSA-OAEP
+ try:
+ wrapped_session_key = public_key.encrypt(
+ algo.key,
+ padding.PKCS1v15()
+ )
+ except ValueError:
+ wrapped_session_key = public_key.encrypt(
+ algo.key,
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
+ algorithm=hashes.SHA256(),
+ label=None
+ )
+ )
+ else:
+ wrapped_session_key = public_key.encrypt(
+ algo.key,
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
+ algorithm=hashes.SHA256(),
+ label=None
+ )
+ )
+
options['session_key'] = wrapped_session_key
name = self.name + '_internal'
@@ -723,7 +748,7 @@ class ModVaultData(Local):
errors.ExecutionError,
errors.GenericError):
_kra_config_cache.remove(self.api.env.domain)
- if raise_unexpected:
+ if raise_unexpected and use_oaep:
raise
return None
@@ -733,15 +758,23 @@ class ModVaultData(Local):
"""
# try call with cached transport certificate
result = self._do_internal(algo, transport_cert, False,
- *args, **options)
+ False, *args, **options)
if result is not None:
return result
# retrieve transport certificate (cached by vaultconfig_show)
transport_cert = self._get_vaultconfig(force_refresh=True)[0]
+
# call with the retrieved transport certificate
+ result = self._do_internal(algo, transport_cert, True,
+ False, *args, **options)
+
+ if result is not None:
+ return result
+
+ # call and use_oaep this time, last attempt
return self._do_internal(algo, transport_cert, True,
- *args, **options)
+ True, *args, **options)
@register(no_fail=True)
--
2.43.0

View File

@ -0,0 +1,87 @@
From fd32e6a3d95f28d2d11d41ee5dabb0d563cb5d51 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
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 <jrische@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
---
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

View File

@ -1,88 +0,0 @@
From 84798137fabf75fe79aebbd97e4b8418de8ab0f2 Mon Sep 17 00:00:00 2001
From: Francisco Trivino <ftrivino@redhat.com>
Date: Fri, 19 Jan 2024 18:15:28 +0100
Subject: [PATCH] Vault: improve vault server archival/retrieval calls
error handling
If a vault operation fails, the error message just says "InternalError". This commit
improves error handling of key archival and retrieval calls by catching the PKIException
error and raising it as an IPA error.
Related: https://pagure.io/freeipa/issue/9191
Signed-off-by: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
(cherry picked from commit dc1ab53f0aa0398d493f7440b5ec4d70d9c7d663)
---
ipaserver/plugins/vault.py | 40 +++++++++++++++++++++++++-------------
1 file changed, 26 insertions(+), 14 deletions(-)
diff --git a/ipaserver/plugins/vault.py b/ipaserver/plugins/vault.py
index 574c83a9a..13c4fac9a 100644
--- a/ipaserver/plugins/vault.py
+++ b/ipaserver/plugins/vault.py
@@ -45,6 +45,7 @@ if api.env.in_server:
import pki.key
from pki.crypto import DES_EDE3_CBC_OID
from pki.crypto import AES_128_CBC_OID
+ from pki import PKIException
if six.PY3:
unicode = str
@@ -1094,16 +1095,21 @@ class vault_archive_internal(PKQuery):
pki.key.KeyClient.KEY_STATUS_INACTIVE)
# forward wrapped data to KRA
- kra_client.keys.archive_encrypted_data(
- client_key_id,
- pki.key.KeyClient.PASS_PHRASE_TYPE,
- wrapped_vault_data,
- wrapped_session_key,
- algorithm_oid=algorithm_oid,
- nonce_iv=nonce,
- )
-
- kra_account.logout()
+ try:
+ kra_client.keys.archive_encrypted_data(
+ client_key_id,
+ pki.key.KeyClient.PASS_PHRASE_TYPE,
+ wrapped_vault_data,
+ wrapped_session_key,
+ algorithm_oid=algorithm_oid,
+ nonce_iv=nonce,
+ )
+ except PKIException as e:
+ kra_account.logout()
+ raise errors.EncodingError(
+ message=_("Unable to archive key: %s") % e)
+ finally:
+ kra_account.logout()
response = {
'value': args[-1],
@@ -1174,11 +1180,17 @@ class vault_retrieve_internal(PKQuery):
kra_client.keys.encrypt_alg_oid = algorithm_oid
# retrieve encrypted data from KRA
- key = kra_client.keys.retrieve_key(
- key_info.get_key_id(),
- wrapped_session_key)
+ try:
- kra_account.logout()
+ key = kra_client.keys.retrieve_key(
+ key_info.get_key_id(),
+ wrapped_session_key)
+ except PKIException as e:
+ kra_account.logout()
+ raise errors.EncodingError(
+ message=_("Unable to retrieve key: %s") % e)
+ finally:
+ kra_account.logout()
response = {
'value': args[-1],
--
2.43.0

View File

@ -0,0 +1,38 @@
From 13d5e88eb4ebb7a0132cbb050a9d230304ecbcff Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
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 <flo@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
---
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

View File

@ -0,0 +1,70 @@
From ff6cfcacd67a0461a0341e17854732cbe301f1d6 Mon Sep 17 00:00:00 2001
From: Mohammad Rizwan <myusuf@redhat.com>
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 <myusuf@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
---
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

View File

@ -1,98 +0,0 @@
From a406fd9aec7d053c044e73f16b05489bebd84bc8 Mon Sep 17 00:00:00 2001
From: Francisco Trivino <ftrivino@redhat.com>
Date: Fri, 19 Jan 2024 17:12:07 +0100
Subject: [PATCH] kra: set RSA-OAEP as default wrapping algo when FIPS is
enabled
Vault uses PKCS1v15 as default padding wrapping algo, which is not an approved
FIPS algorithm. This commit ensures that KRA is installed with RSA-OAEP if FIPS
is enabled. It also handles upgrade path.
Fixes: https://pagure.io/freeipa/issue/9191
Signed-off-by: Francisco Trivino <ftrivino@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
(cherry picked from commit f2eec9eb208e62f923375b9eaf34fcc491046a0d)
---
install/share/ipaca_default.ini | 3 +++
ipaserver/install/dogtaginstance.py | 4 +++-
ipaserver/install/krainstance.py | 12 ++++++++++++
ipaserver/install/server/upgrade.py | 12 ++++++++++++
4 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/install/share/ipaca_default.ini b/install/share/ipaca_default.ini
index 082f507b2..691f1e1b7 100644
--- a/install/share/ipaca_default.ini
+++ b/install/share/ipaca_default.ini
@@ -166,3 +166,6 @@ pki_audit_signing_subject_dn=cn=KRA Audit,%(ipa_subject_base)s
# We will use the dbuser created for the CA.
pki_share_db=True
pki_share_dbuser_dn=uid=pkidbuser,ou=people,o=ipaca
+
+# KRA padding, set RSA-OAEP in FIPS mode
+pki_use_oaep_rsa_keywrap=%(fips_use_oaep_rsa_keywrap)s
\ No newline at end of file
diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py
index c2c6b3f49..c3c726f68 100644
--- a/ipaserver/install/dogtaginstance.py
+++ b/ipaserver/install/dogtaginstance.py
@@ -1020,7 +1020,9 @@ class PKIIniLoader:
# for softhsm2 testing
softhsm2_so=paths.LIBSOFTHSM2_SO,
# Configure a more secure AJP password by default
- ipa_ajp_secret=ipautil.ipa_generate_password(special=None)
+ ipa_ajp_secret=ipautil.ipa_generate_password(special=None),
+ # in FIPS mode use RSA-OAEP wrapping padding algo as default
+ fips_use_oaep_rsa_keywrap=tasks.is_fips_enabled()
)
@classmethod
diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py
index 13cb2dcaa..0e04840a1 100644
--- a/ipaserver/install/krainstance.py
+++ b/ipaserver/install/krainstance.py
@@ -277,6 +277,18 @@ class KRAInstance(DogtagInstance):
# A restart is required
+ def enable_oaep_wrap_algo(self):
+ """
+ Enable KRA OAEP key wrap algorithm
+ """
+ with installutils.stopped_service('pki-tomcatd', 'pki-tomcat'):
+ directivesetter.set_directive(
+ self.config,
+ 'keyWrap.useOAEP',
+ 'true', quotes=False, separator='=')
+
+ # A restart is required
+
def update_cert_config(self, nickname, cert):
"""
When renewing a KRA subsystem certificate the configuration file
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index e4dc7ae73..c84516b56 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -1780,6 +1780,18 @@ def upgrade_configuration():
else:
logger.info('ephemeralRequest is already enabled')
+ if tasks.is_fips_enabled():
+ logger.info('[Ensuring KRA OAEP wrap algo is enabled in FIPS]')
+ value = directivesetter.get_directive(
+ paths.KRA_CS_CFG_PATH,
+ 'keyWrap.useOAEP',
+ separator='=')
+ if value is None or value.lower() != 'true':
+ logger.info('Use the OAEP key wrap algo')
+ kra.enable_oaep_wrap_algo()
+ else:
+ logger.info('OAEP key wrap algo is already enabled')
+
# several upgrade steps require running CA. If CA is configured,
# always run ca.start() because we need to wait until CA is really ready
# by checking status using http
--
2.43.0

View File

@ -1,29 +0,0 @@
From a8e433f7c8d844d9f337a34db09b0197f2dbc5af Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Tue, 20 Feb 2024 15:14:24 +0100
Subject: [PATCH] ipa-kdb: Fix double free in ipadb_reinit_mspac()
Fixes: https://pagure.io/freeipa/issue/9535
Signed-off-by: Julien Rische <jrische@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
(cherry picked from commit dd27d225524aa81c038a970961a4f878cf742e2a)
---
daemons/ipa-kdb/ipa_kdb_mspac.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
index deed513b9..0964d112a 100644
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
@@ -3084,6 +3084,7 @@ ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit,
}
free(resstr);
+ resstr = NULL;
flat_server_name = get_server_netbios_name(ipactx);
if (!flat_server_name) {
--
2.43.0

View File

@ -0,0 +1,60 @@
From 1278e614dd93bf0ac3d6e0c36cb9c277808afb2c Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Fri, 11 Aug 2023 08:01:18 +0200
Subject: [PATCH] ipatests: fix test_topology
The test TestTopologyOptions::test_add_remove_segment is
randomly failing downstream. Test scenario:
- create a line topology master <-> repl1 <-> repl2
- create user on master
- wait for repl success on master
- check that the user is seen on repl2
The test waits for replication to complete on the master but
it should also wait for the replication to complete on repl1
before checking the user presence on repl2.
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Anuja More <amore@redhat.com>
---
ipatests/test_integration/test_topology.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/ipatests/test_integration/test_topology.py b/ipatests/test_integration/test_topology.py
index 8a240fa3c081a05b8f4501fe48694e01086003a1..618c9d5dcce994cd0359a291b044eb2cf0bddc74 100644
--- a/ipatests/test_integration/test_topology.py
+++ b/ipatests/test_integration/test_topology.py
@@ -124,6 +124,9 @@ class TestTopologyOptions(IntegrationTest):
self.replicas[0],
self.replicas[1])
assert err == "", err
+ # At this point we have replicas[1] <-> master <-> replicas[0]
+ # ^--------------------------^
+
# Make sure the new segment is shown by `ipa topologysegment-find`
result1 = self.master.run_command(['ipa', 'topologysegment-find',
DOMAIN_SUFFIX_NAME]).stdout_text
@@ -137,9 +140,12 @@ class TestTopologyOptions(IntegrationTest):
deleteme = find_segment(self.master, self.replicas[1])
returncode, error = tasks.destroy_segment(self.master, deleteme)
assert returncode == 0, error
+ # At this point we have master <-> replicas[0] <-> replicas[1]
+
# Wait till replication ends and make sure replica1 does not have
# segment that was deleted on master
master_ldap = self.master.ldap_connect()
+ repl_ldap = self.replicas[0].ldap_connect()
tasks.wait_for_replication(master_ldap)
result3 = self.replicas[0].run_command(['ipa', 'topologysegment-find',
DOMAIN_SUFFIX_NAME]).stdout_text
@@ -150,6 +156,7 @@ class TestTopologyOptions(IntegrationTest):
'--first', 'test',
'--last', 'user'])
tasks.wait_for_replication(master_ldap)
+ tasks.wait_for_replication(repl_ldap)
result4 = self.replicas[1].run_command(['ipa', 'user-find'])
assert('someuser' in result4.stdout_text), 'User not found: someuser'
# We end up having a line topology: master <-> replica1 <-> replica2
--
2.41.0

View File

@ -0,0 +1,560 @@
From ac6a2172f5dcb46701148c7b096ffa1b44076816 Mon Sep 17 00:00:00 2001
From: Sudhir Menon <sumenon@redhat.com>
Date: Thu, 27 Jul 2023 14:33:08 +0530
Subject: [PATCH] ipatests: idm api related tests.
IDM API related tests are automated in the
above PR
Ref: https://freeipa.readthedocs.io/en/latest/api/basic_usage.html
Signed-off-by: Sudhir Menon <sumenon@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
---
ipatests/test_integration/test_idm_api.py | 534 ++++++++++++++++++++++
1 file changed, 534 insertions(+)
create mode 100644 ipatests/test_integration/test_idm_api.py
diff --git a/ipatests/test_integration/test_idm_api.py b/ipatests/test_integration/test_idm_api.py
new file mode 100644
index 0000000000000000000000000000000000000000..eafef5dd8526bc14725d6bc32819cb5c7387f868
--- /dev/null
+++ b/ipatests/test_integration/test_idm_api.py
@@ -0,0 +1,534 @@
+#
+# Copyright (C) 2018 FreeIPA Contributors see COPYING for license
+#
+from __future__ import absolute_import
+
+from ipatests.test_integration.base import IntegrationTest
+import textwrap
+
+API_INIT = """
+ from ipalib import api, errors
+ api.bootstrap_with_global_options(context="server")
+ api.finalize()
+ api.Backend.ldap2.connect()
+ """
+
+CERT = (
+ b"MIIEkDCCAvigAwIBAgIBCzANBgkqhkiG9w0BAQsFADA5MRcwFQYDVQQKD\n"
+ b"A5URVNUUkVBTE0uVEVTVDEeMBwGA1UEAwwVQ2VydGlmaWNhdGUgQXV0aG\n"
+ b"9yaXR5MB4XDTIzMDcyODE3MTIxOVoXDTI1MDcyODE3MTIxOVowKjEXMBU\n"
+ b"GA1UECgwOVEVTVFJFQUxNLlRFU1QxDzANBgNVBAMMBmpzbWl0aDCCASIw\n"
+ b"DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOF0XFrdVXmKp95AVZW5o\n"
+ b"BWcij6vJPqeU3UpzTLbM+fROhNaKMX9S+yXrJHifOmhCOuNA8TtptKVJx\n"
+ b"CIDZ1/5KwPBk4vrnwOBtVMCftHj87MabBqV/nmQQrCiKTcJu4aQEDI9Qh\n"
+ b"yza09EJKvG8KkpnyuShtkP2LgkUxIqkjBg4DLV7grO+I+aG17QTuQxUTy\n"
+ b"icfYDBnzD4hTKPLf7d9KNyG+sEeyN0gceLFMUYaQ4lyapcSzYJwOSAc2B\n"
+ b"EU73tLaJlQORHL7HmhxrjD1IgZyxFjp/ofLVZFFoJAqjz2FWzOxmQw+bc\n"
+ b"0WTzQjeSTGx+l3htj7MmhIRBMqr3Um6zXkLKMCAwEAAaOCATAwggEsMB8\n"
+ b"GA1UdIwQYMBaAFCIXu6QtsiBVo1yZQZ7MMHTl5Wj6MEAGCCsGAQUFBwEB\n"
+ b"BDQwMjAwBggrBgEFBQcwAYYkaHR0cDovL2lwYS1jYS50ZXN0cmVhbG0ud\n"
+ b"GVzdC9jYS9vY3NwMA4GA1UdDwEB/wQEAwIE8DAdBgNVHSUEFjAUBggrBg\n"
+ b"EFBQcDAQYIKwYBBQUHAwIweQYDVR0fBHIwcDBuoDagNIYyaHR0cDovL2l\n"
+ b"wYS1jYS50ZXN0cmVhbG0udGVzdC9pcGEvY3JsL01hc3RlckNSTC5iaW6i\n"
+ b"NKQyMDAxDjAMBgNVBAoMBWlwYWNhMR4wHAYDVQQDDBVDZXJ0aWZpY2F0Z\n"
+ b"SBBdXRob3JpdHkwHQYDVR0OBBYEFNwQNQAG8MsKQPwMFyGzRiMzRAa5MA\n"
+ b"0GCSqGSIb3DQEBCwUAA4IBgQB2g0mS8XAPI+aRBa5q7Vbp1245CvMP0Eq\n"
+ b"Cz6gvCNwtxW0UDKnB++d/YQ13ft+x9Xj3rB/M2YXxdxTpQnQQv34CUcyh\n"
+ b"PQKJthAsbKBpdusCGrbS54zKFR0MjxwOwIIDHuI6eu2AoSpsmYs5UGzQm\n"
+ b"oCfQhbImK7iGLy0rOHaON1cWAFmC6lzJ2TFELc4N3eLYGVZy2ZtyZTgA3\n"
+ b"l97rBCwbDDFF1JWoOByIq8Ij99ksyMXws++sNUpo/1l8Jt0Gn6RBiidZB\n"
+ b"ef4+kJN+t6RAAwRQ / 3cmEggXcFoV13KZ70PeMXeX6CKMwXIwt3q7A78\n"
+ b"Wc/0OIBREZLhXpkmogCzWCuatdzeBIhMhx0vDEzaxlhf32ZWfN5pFMpgq\n"
+ b"wLZsdwMf6J65kGbE5Pg3Yxk7OiByxZJnR8UlvbU3r6RhMWutD6C0aqqNt\n"
+ b"o3us5gTmfRc8Mf1l/BUgDqkBKOTU8FHREGemG1HoklBym/Pbua0VMUA+s\n"
+ b"0nECR4LLM/o9PCJ2Y3QPBZy8Hg=\n"
+)
+
+
+class TestAPIScenario(IntegrationTest):
+ """
+ Tests for IDM API scenarios
+ """
+
+ topology = "line"
+
+ def create_and_run_script(self, filename, user_code_script):
+ self.master.put_file_contents(filename, user_code_script)
+ self.master.run_command(["python3", filename])
+ self.master.run_command(["rm", filename])
+
+ def test_idm_user_add(self):
+ """
+ This test checks that ipa user using api.Command["user_add"]
+ and then checks that user is displayed using
+ api.Command["user_show"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ api.Command["user_add"]("jsmith", givenname="John", sn="Smith",
+ ipauserauthtype="otp")
+ cmd = api.Command["user_show"]("jsmith", all=True)["result"]
+ assert 'otp' in cmd['ipauserauthtype']
+ assert 'John Smith' in cmd['cn']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/user_add.py", user_code_script
+ )
+
+ def test_idm_user_find(self):
+ """
+ This test checks that user is displayed
+ using api.Command["user_find"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["user_find"]("jsmith")
+ assert '1 user matched' in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/user_find.py", user_code_script
+ )
+
+ def test_idm_user_mod(self):
+ """
+ This test checks that user attribute is modified
+ using api.Command["user_mod"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["user_mod"]("jsmith",
+ mail="jsmith@example.org")["result"]
+ assert 'jsmith@example.org' in cmd['mail']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/user_mod.py", user_code_script
+ )
+
+ def test_disable_user(self):
+ """
+ This test checks that user is disabled
+ using api.Command["user_disable"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["user_disable"]("jsmith")
+ assert 'Disabled user account "jsmith"' in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/disable_user.py", user_code_script
+ )
+
+ def test_enable_user(self):
+ """
+ This test checks that user is enabled
+ using api.Command["user_enable"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["user_enable"]("jsmith")
+ assert 'Enabled user account "jsmith"' in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/enable_user.py", user_code_script
+ )
+
+ def test_create_ipa_group(self):
+ """
+ This test checks that group is created
+ using api.Command["group_add"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["group_add"]("developers", gidnumber=500,
+ description="Developers")
+ assert 'Added group "developers"' in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/create_group.py", user_code_script
+ )
+
+ def test_show_ipa_group(self):
+ """
+ This test checks that group is displayed
+ using api.Command["group_show"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["group_show"]("developers")
+ assert 'developers' in cmd['result']['cn']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/group_show.py", user_code_script
+ )
+
+ def test_ipa_group_mod(self):
+ """
+ This test checks that group description is modified
+ using api.Command["group_mod"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["group_mod"]("developers", description='developer')
+ ["result"]
+ assert 'Modified group "developers"' in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/group_mod.py", user_code_script
+ )
+
+ def test_add_members_to_ipa_group(self):
+ """
+ This test checks that member is added to group
+ using api.Command["group_add_member"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["group_add_member"]("developers",
+ user='jsmith')["result"]
+ assert 'jsmith' in cmd['member_user']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/create_group_members.py", user_code_script
+ )
+
+ def test_ipa_group_find(self):
+ """
+ This test checks that group is displayed
+ using api.Command["group_find"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["group_find"]("developers")
+ assert '1 group matched' in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/group_find.py", user_code_script
+ )
+
+ def test_remove_member_group(self):
+ """
+ This test checks that group member is removed
+ using api.Command["group_remove_member"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["group_remove_member"]("developers",
+ user="jsmith")
+ assert 'member_user' not in cmd
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/remove_member_group.py", user_code_script
+ )
+
+ def test_add_permission(self):
+ """
+ This test checks that permission is added
+ using api.Command["permission_add"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["permission_add"]("Create users",
+ ipapermright='add', type='user')
+ assert 'Added permission "Create users"' in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/add_perm.py", user_code_script
+ )
+
+ def test_create_hbac_rule(self):
+ """
+ This test checks that hbac rule is added
+ using api.Command["hbacrule_add"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["hbacrule_add"]("sshd_rule")
+ assert 'Added HBAC rule "sshd_rule"' in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/add_hbac_rule.py", user_code_script
+ )
+
+ def test_add_hbac_service(self):
+ """
+ This test checks that hbac service is added using
+ api.Command["hbacsvc_add"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["hbacsvc_add"]("chronyd")
+ assert 'Added HBAC service "chronyd"' in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/add_hbac_svc.py", user_code_script
+ )
+
+ def test_enable_hbac_rule(self):
+ """
+ This test checks that hbac rule is enabled using
+ api.Command["hbacrule_enable"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["hbacrule_enable"]("sshd_rule")
+ assert 'Enabled HBAC rule "sshd_rule"' in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/enable_hbacrule.py", user_code_script
+ )
+
+ def test_create_sudo_rule(self):
+ """
+ This test checks that sudo rule is created using
+ api.Command["sudorule_add"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["sudorule_add"]("timechange")
+ assert 'Added Sudo Rule "timechange"' in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/create_sudos.py", user_code_script
+ )
+
+ def test_add_user_certificate(self):
+ """
+ This test checks user certificate is added using
+ api.Command["user_add_cert"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ msg = 'Added certificates to user "jsmith"'
+ cmd = api.Command["user_add_cert"]("jsmith", usercertificate={CERT})
+ assert msg in cmd["summary"]
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/add_cert.py", user_code_script
+ )
+
+ def test_remove_user_certificate(self):
+ """
+ This test checks that user certificate is removed
+ using api.Command["user_remove_cert"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ msg = 'Removed certificates from user "jsmith"'
+ cmd = api.Command["user_remove_cert"]("jsmith", usercertificate={CERT})
+ assert msg in cmd["summary"]
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/remove_cert.py", user_code_script
+ )
+
+ def test_certmaprule_add(self):
+ """
+ This test checks that certmap rule is added using
+ api.Command["certmaprule_add"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ msg = ('Added Certificate Identity Mapping Rule "testrule"')
+ cmd = api.Command["certmaprule_add"]("testrule")
+ assert msg in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/certmap_rule_add.py", user_code_script
+ )
+
+ def test_certmaprule_enable(self):
+ """
+ This test checks that certmap rule is enabled
+ using api.Command["certmaprule_enable"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ msg = ('Enabled Certificate Identity Mapping Rule "testrule"')
+ cmd = api.Command["certmaprule_enable"]("testrule")
+ assert msg in cmd["summary"]
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/certmap_rule_enable.py", user_code_script
+ )
+
+ def test_certmaprule_disable(self):
+ """
+ This test checks that certmap rule is disabled using
+ api.Command["certmaprule_disable"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ msg = ('Disabled Certificate Identity Mapping Rule "testrule"')
+ cmd = api.Command["certmaprule_disable"]("testrule")
+ assert msg in cmd["summary"]
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/certmap_rule_disable.py", user_code_script
+ )
+
+ def test_certmaprule_del(self):
+ """
+ This test checks that certmap rule is deleted using
+ api.Command["certmaprule_del"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ msg = ('Deleted Certificate Identity Mapping Rule "testrule"')
+ cmd = api.Command["certmaprule_del"]("testrule")
+ assert msg in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/certmap_rule_del.py", user_code_script
+ )
+
+ def test_add_role(self):
+ """
+ This test checks that role and privilege is added using
+ api.Command["role_add"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd1 = api.Command["role_add"]("junioradmin",
+ description="Junior admin")
+ assert 'Added role "junioradmin"' in cmd1["summary"]
+ cmd2 = api.Command.role_add_privilege("junioradmin",
+ privilege="Vault Administrators")["result"]
+ assert 'Vault Administrators' in cmd2["memberof_privilege"]
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/add_role.py", user_code_script
+ )
+
+ def test_add_subid(self):
+ """
+ This test checks that subid is added for IPA user
+ using api.Command["subid_add"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["subid_add"](ipaowner="jsmith")
+ assert 'Added subordinate id ' in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/add_subid.py", user_code_script
+ )
+
+ def test_add_otptoken(self):
+ """
+ This test checks that otp token is added for IPA user
+ using api.Command["otptoken_add"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["otptoken_add"](
+ type='HOTP', description='testotp',
+ ipatokenotpalgorithm='sha512', ipatokenowner='jsmith',
+ ipatokenotpdigits='6')
+ assert 'Added OTP token' in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/add_otptoken.py", user_code_script
+ )
+
+ def test_user_del(self):
+ """
+ This test checks that user is deleted
+ using api.Command["user_del"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["user_del"]("jsmith")
+ assert 'Deleted user "jsmith"' in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/user_del.py", user_code_script
+ )
+
+ def test_remove_ipa_group(self):
+ """
+ This test checks that group is removed
+ using api.Command["group_del"]
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ cmd = api.Command["group_del"]("developers")
+ assert 'Deleted group "developers"' in cmd['summary']
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/show_group.py", user_code_script
+ )
+
+ def test_batch_command(self):
+ """
+ This test checks that batch commands
+ can be run using api.
+ """
+ user_code_script = textwrap.dedent(
+ f"""
+ {API_INIT}
+ batch_args = []
+ for i in range(5):
+ user_id = "user%i" % i
+ args = [user_id]
+ kw = {{'givenname' : user_id, 'sn' : user_id}}
+ batch_args.append({{'method' : 'user_add', 'params' : [args, kw]}})
+ api.Command["batch"](*batch_args)
+ """
+ )
+ self.create_and_run_script(
+ "/tmp/batch.py", user_code_script
+ )
--
2.41.0

View File

@ -1,392 +0,0 @@
From b039f3087a13de3f34b230dbe29a7cfb1965700d Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Feb 23 2024 09:49:27 +0000
Subject: rpcserver: validate Kerberos principal name before running kinit
Do minimal validation of the Kerberos principal name when passing it to
kinit command line tool. Also pass it as the final argument to prevent
option injection.
Accepted Kerberos principals are:
- user names, using the following regexp
(username with optional @realm, no spaces or slashes in the name):
"(?!^[0-9]+$)^[a-zA-Z0-9_.][a-zA-Z0-9_.-]*[a-zA-Z0-9_.$-]?@?[a-zA-Z0-9.-]*$"
- service names (with slash in the name but no spaces). Validation of
the hostname is done. There is no validation of the service name.
The regular expression above also covers cases where a principal name
starts with '-'. This prevents option injection as well.
This fixes CVE-2024-1481
Fixes: https://pagure.io/freeipa/issue/9541
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
---
diff --git a/ipalib/install/kinit.py b/ipalib/install/kinit.py
index cc839ec..4ad4eaa 100644
--- a/ipalib/install/kinit.py
+++ b/ipalib/install/kinit.py
@@ -6,12 +6,16 @@ from __future__ import absolute_import
import logging
import os
+import re
import time
import gssapi
from ipaplatform.paths import paths
from ipapython.ipautil import run
+from ipalib.constants import PATTERN_GROUPUSER_NAME
+from ipalib.util import validate_hostname
+from ipalib import api
logger = logging.getLogger(__name__)
@@ -21,6 +25,40 @@ KRB5_KDC_UNREACH = 2529639068
# A service is not available that s required to process the request
KRB5KDC_ERR_SVC_UNAVAILABLE = 2529638941
+PATTERN_REALM = '@?([a-zA-Z0-9.-]*)$'
+PATTERN_PRINCIPAL = '(' + PATTERN_GROUPUSER_NAME[:-1] + ')' + PATTERN_REALM
+PATTERN_SERVICE = '([a-zA-Z0-9.-]+)/([a-zA-Z0-9.-]+)' + PATTERN_REALM
+
+user_pattern = re.compile(PATTERN_PRINCIPAL)
+service_pattern = re.compile(PATTERN_SERVICE)
+
+
+def validate_principal(principal):
+ if not isinstance(principal, str):
+ raise RuntimeError('Invalid principal: not a string')
+ if ('/' in principal) and (' ' in principal):
+ raise RuntimeError('Invalid principal: bad spacing')
+ else:
+ realm = None
+ match = user_pattern.match(principal)
+ if match is None:
+ match = service_pattern.match(principal)
+ if match is None:
+ raise RuntimeError('Invalid principal: cannot parse')
+ else:
+ # service = match[1]
+ hostname = match[2]
+ realm = match[3]
+ try:
+ validate_hostname(hostname)
+ except ValueError as e:
+ raise RuntimeError(str(e))
+ else: # user match, validate realm
+ # username = match[1]
+ realm = match[2]
+ if realm and 'realm' in api.env and realm != api.env.realm:
+ raise RuntimeError('Invalid principal: realm mismatch')
+
def kinit_keytab(principal, keytab, ccache_name, config=None, attempts=1):
"""
@@ -29,6 +67,7 @@ def kinit_keytab(principal, keytab, ccache_name, config=None, attempts=1):
The optional parameter 'attempts' specifies how many times the credential
initialization should be attempted in case of non-responsive KDC.
"""
+ validate_principal(principal)
errors_to_retry = {KRB5KDC_ERR_SVC_UNAVAILABLE,
KRB5_KDC_UNREACH}
logger.debug("Initializing principal %s using keytab %s",
@@ -65,6 +104,7 @@ def kinit_keytab(principal, keytab, ccache_name, config=None, attempts=1):
return None
+
def kinit_password(principal, password, ccache_name, config=None,
armor_ccache_name=None, canonicalize=False,
enterprise=False, lifetime=None):
@@ -73,8 +113,9 @@ def kinit_password(principal, password, ccache_name, config=None,
web-based authentication, use armor_ccache_path to specify http service
ccache.
"""
+ validate_principal(principal)
logger.debug("Initializing principal %s using password", principal)
- args = [paths.KINIT, principal, '-c', ccache_name]
+ args = [paths.KINIT, '-c', ccache_name]
if armor_ccache_name is not None:
logger.debug("Using armor ccache %s for FAST webauth",
armor_ccache_name)
@@ -91,6 +132,7 @@ def kinit_password(principal, password, ccache_name, config=None,
logger.debug("Using enterprise principal")
args.append('-E')
+ args.extend(['--', principal])
env = {'LC_ALL': 'C'}
if config is not None:
env['KRB5_CONFIG'] = config
@@ -154,6 +196,7 @@ def kinit_pkinit(
:raises: CalledProcessError if PKINIT fails
"""
+ validate_principal(principal)
logger.debug(
"Initializing principal %s using PKINIT %s", principal, user_identity
)
@@ -168,7 +211,7 @@ def kinit_pkinit(
assert pkinit_anchor.startswith(("FILE:", "DIR:", "ENV:"))
args.extend(["-X", f"X509_anchors={pkinit_anchor}"])
args.extend(["-X", f"X509_user_identity={user_identity}"])
- args.append(principal)
+ args.extend(['--', principal])
# this workaround enables us to capture stderr and put it
# into the raised exception in case of unsuccessful authentication
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
index 3555014..60bfa61 100644
--- a/ipaserver/rpcserver.py
+++ b/ipaserver/rpcserver.py
@@ -1134,10 +1134,6 @@ class login_password(Backend, KerberosSession):
canonicalize=True,
lifetime=self.api.env.kinit_lifetime)
- if armor_path:
- logger.debug('Cleanup the armor ccache')
- ipautil.run([paths.KDESTROY, '-A', '-c', armor_path],
- env={'KRB5CCNAME': armor_path}, raiseonerr=False)
except RuntimeError as e:
if ('kinit: Cannot read password while '
'getting initial credentials') in str(e):
@@ -1155,6 +1151,11 @@ class login_password(Backend, KerberosSession):
raise KrbPrincipalWrongFAST(principal=principal)
raise InvalidSessionPassword(principal=principal,
message=unicode(e))
+ finally:
+ if armor_path:
+ logger.debug('Cleanup the armor ccache')
+ ipautil.run([paths.KDESTROY, '-A', '-c', armor_path],
+ env={'KRB5CCNAME': armor_path}, raiseonerr=False)
class change_password(Backend, HTTP_Status):
diff --git a/ipatests/prci_definitions/gating.yaml b/ipatests/prci_definitions/gating.yaml
index 91be057..400a248 100644
--- a/ipatests/prci_definitions/gating.yaml
+++ b/ipatests/prci_definitions/gating.yaml
@@ -310,3 +310,15 @@ jobs:
template: *ci-ipa-4-9-latest
timeout: 3600
topology: *master_1repl_1client
+
+ fedora-latest-ipa-4-9/test_ipalib_install:
+ requires: [fedora-latest-ipa-4-9/build]
+ priority: 100
+ job:
+ class: RunPytest
+ args:
+ build_url: '{fedora-latest-ipa-4-9/build_url}'
+ test_suite: test_ipalib_install/test_kinit.py
+ template: *ci-ipa-4-9-latest
+ timeout: 600
+ topology: *master_1repl
diff --git a/ipatests/prci_definitions/nightly_ipa-4-9_latest.yaml b/ipatests/prci_definitions/nightly_ipa-4-9_latest.yaml
index b2ab765..7c03a48 100644
--- a/ipatests/prci_definitions/nightly_ipa-4-9_latest.yaml
+++ b/ipatests/prci_definitions/nightly_ipa-4-9_latest.yaml
@@ -1801,3 +1801,15 @@ jobs:
template: *ci-ipa-4-9-latest
timeout: 5000
topology: *master_2repl_1client
+
+ fedora-latest-ipa-4-9/test_ipalib_install:
+ requires: [fedora-latest-ipa-4-9/build]
+ priority: 50
+ job:
+ class: RunPytest
+ args:
+ build_url: '{fedora-latest-ipa-4-9/build_url}'
+ test_suite: test_ipalib_install/test_kinit.py
+ template: *ci-ipa-4-9-latest
+ timeout: 600
+ topology: *master_1repl
diff --git a/ipatests/prci_definitions/nightly_ipa-4-9_latest_selinux.yaml b/ipatests/prci_definitions/nightly_ipa-4-9_latest_selinux.yaml
index b7b3d3b..802bd2a 100644
--- a/ipatests/prci_definitions/nightly_ipa-4-9_latest_selinux.yaml
+++ b/ipatests/prci_definitions/nightly_ipa-4-9_latest_selinux.yaml
@@ -1944,3 +1944,16 @@ jobs:
template: *ci-ipa-4-9-latest
timeout: 5000
topology: *master_2repl_1client
+
+ fedora-latest-ipa-4-9/test_ipalib_install:
+ requires: [fedora-latest-ipa-4-9/build]
+ priority: 50
+ job:
+ class: RunPytest
+ args:
+ build_url: '{fedora-latest-ipa-4-9/build_url}'
+ selinux_enforcing: True
+ test_suite: test_ipalib_install/test_kinit.py
+ template: *ci-ipa-4-9-latest
+ timeout: 600
+ topology: *master_1repl
diff --git a/ipatests/prci_definitions/nightly_ipa-4-9_previous.yaml b/ipatests/prci_definitions/nightly_ipa-4-9_previous.yaml
index eb3849e..1e1adb8 100644
--- a/ipatests/prci_definitions/nightly_ipa-4-9_previous.yaml
+++ b/ipatests/prci_definitions/nightly_ipa-4-9_previous.yaml
@@ -1801,3 +1801,15 @@ jobs:
template: *ci-ipa-4-9-previous
timeout: 5000
topology: *master_2repl_1client
+
+ fedora-previous-ipa-4-9/test_ipalib_install:
+ requires: [fedora-previous-ipa-4-9/build]
+ priority: 50
+ job:
+ class: RunPytest
+ args:
+ build_url: '{fedora-previous-ipa-4-9/build_url}'
+ test_suite: test_ipalib_install/test_kinit.py
+ template: *ci-ipa-4-9-previous
+ timeout: 600
+ topology: *master_1repl
diff --git a/ipatests/setup.py b/ipatests/setup.py
index 6217a1b..0aec4a7 100644
--- a/ipatests/setup.py
+++ b/ipatests/setup.py
@@ -41,6 +41,7 @@ if __name__ == '__main__':
"ipatests.test_integration",
"ipatests.test_ipaclient",
"ipatests.test_ipalib",
+ "ipatests.test_ipalib_install",
"ipatests.test_ipaplatform",
"ipatests.test_ipapython",
"ipatests.test_ipaserver",
diff --git a/ipatests/test_ipalib_install/__init__.py b/ipatests/test_ipalib_install/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ipatests/test_ipalib_install/__init__.py
diff --git a/ipatests/test_ipalib_install/test_kinit.py b/ipatests/test_ipalib_install/test_kinit.py
new file mode 100644
index 0000000..f89ea17
--- /dev/null
+++ b/ipatests/test_ipalib_install/test_kinit.py
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2024 FreeIPA Contributors see COPYING for license
+#
+"""Tests for ipalib.install.kinit module
+"""
+
+import pytest
+
+from ipalib.install.kinit import validate_principal
+
+
+# None means no exception is expected
+@pytest.mark.parametrize('principal, exception', [
+ ('testuser', None),
+ ('testuser@EXAMPLE.TEST', None),
+ ('test/ipa.example.test', None),
+ ('test/ipa.example.test@EXAMPLE.TEST', None),
+ ('test/ipa@EXAMPLE.TEST', RuntimeError),
+ ('test/-ipa.example.test@EXAMPLE.TEST', RuntimeError),
+ ('test/ipa.1example.test@EXAMPLE.TEST', RuntimeError),
+ ('test /ipa.example,test', RuntimeError),
+ ('testuser@OTHER.TEST', RuntimeError),
+ ('test/ipa.example.test@OTHER.TEST', RuntimeError),
+])
+def test_validate_principal(principal, exception):
+ try:
+ validate_principal(principal)
+ except Exception as e:
+ assert e.__class__ == exception
From 96a478bbedd49c31e0f078f00f2d1cb55bb952fd Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Feb 23 2024 09:49:27 +0000
Subject: validate_principal: Don't try to verify that the realm is known
The actual value is less important than whether it matches the
regular expression. A number of legal but difficult to know in
context realms could be passed in here (trust for example).
This fixes CVE-2024-1481
Fixes: https://pagure.io/freeipa/issue/9541
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
---
diff --git a/ipalib/install/kinit.py b/ipalib/install/kinit.py
index 4ad4eaa..d5fb56b 100644
--- a/ipalib/install/kinit.py
+++ b/ipalib/install/kinit.py
@@ -15,7 +15,6 @@ from ipaplatform.paths import paths
from ipapython.ipautil import run
from ipalib.constants import PATTERN_GROUPUSER_NAME
from ipalib.util import validate_hostname
-from ipalib import api
logger = logging.getLogger(__name__)
@@ -39,7 +38,9 @@ def validate_principal(principal):
if ('/' in principal) and (' ' in principal):
raise RuntimeError('Invalid principal: bad spacing')
else:
- realm = None
+ # For a user match in the regex
+ # username = match[1]
+ # realm = match[2]
match = user_pattern.match(principal)
if match is None:
match = service_pattern.match(principal)
@@ -48,16 +49,11 @@ def validate_principal(principal):
else:
# service = match[1]
hostname = match[2]
- realm = match[3]
+ # realm = match[3]
try:
validate_hostname(hostname)
except ValueError as e:
raise RuntimeError(str(e))
- else: # user match, validate realm
- # username = match[1]
- realm = match[2]
- if realm and 'realm' in api.env and realm != api.env.realm:
- raise RuntimeError('Invalid principal: realm mismatch')
def kinit_keytab(principal, keytab, ccache_name, config=None, attempts=1):
diff --git a/ipatests/test_ipalib_install/test_kinit.py b/ipatests/test_ipalib_install/test_kinit.py
index f89ea17..8289c4b 100644
--- a/ipatests/test_ipalib_install/test_kinit.py
+++ b/ipatests/test_ipalib_install/test_kinit.py
@@ -17,13 +17,16 @@ from ipalib.install.kinit import validate_principal
('test/ipa.example.test@EXAMPLE.TEST', None),
('test/ipa@EXAMPLE.TEST', RuntimeError),
('test/-ipa.example.test@EXAMPLE.TEST', RuntimeError),
- ('test/ipa.1example.test@EXAMPLE.TEST', RuntimeError),
+ ('test/ipa.1example.test@EXAMPLE.TEST', None),
('test /ipa.example,test', RuntimeError),
- ('testuser@OTHER.TEST', RuntimeError),
- ('test/ipa.example.test@OTHER.TEST', RuntimeError),
+ ('testuser@OTHER.TEST', None),
+ ('test/ipa.example.test@OTHER.TEST', None)
])
def test_validate_principal(principal, exception):
try:
validate_principal(principal)
except Exception as e:
assert e.__class__ == exception
+ else:
+ if exception is not None:
+ raise RuntimeError('Test should have failed')

View File

@ -1,43 +0,0 @@
From d7c1ba0672fc8964f7674a526f3019429a551372 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com>
Date: Mar 06 2024 08:34:57 +0000
Subject: Vault: add additional fallback to RSA-OAEP wrapping algo
There is a fallback when creating the wrapping key but one was missing
when trying to use the cached transport_cert.
This allows, along with forcing keyWrap.useOAEP=true, vault creation
on an nCipher HSM.
This can be seen in HSMs where the device doesn't support the
PKCS#1 v1.5 mechanism. It will error out with either "invalid
algorithm" or CKR_FUNCTION_FAILED.
Related: https://pagure.io/freeipa/issue/9191
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
---
diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py
index ed16c73..1523187 100644
--- a/ipaclient/plugins/vault.py
+++ b/ipaclient/plugins/vault.py
@@ -757,8 +757,12 @@ class ModVaultData(Local):
Calls the internal counterpart of the command.
"""
# try call with cached transport certificate
- result = self._do_internal(algo, transport_cert, False,
- False, *args, **options)
+ try:
+ result = self._do_internal(algo, transport_cert, False,
+ False, *args, **options)
+ except errors.EncodingError:
+ result = self._do_internal(algo, transport_cert, False,
+ True, *args, **options)
if result is not None:
return result

View File

@ -0,0 +1,45 @@
From f816b4d9e6ff7a47b0da1a368d2454add78af07c Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Fri, 11 Aug 2023 09:10:30 +0200
Subject: [PATCH] ipatests: fixture can produce IndexError
The fixture issue_and_expire_acme_cert returns a function
that fills the hosts array. If the function is not called in
the test (for instance because a test is skipped, as in
TestACMEPrune::test_prune_cert_search_size_limit), hosts = []
and hosts[0] raises an IndexError.
Fix the fixture to check first that hosts is not empty.
Related: https://pagure.io/freeipa/issue/9348
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Mohammad Rizwan Yusuf <myusuf@redhat.com>
---
ipatests/test_integration/test_acme.py | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/ipatests/test_integration/test_acme.py b/ipatests/test_integration/test_acme.py
index c7389732cd067d49541cd04ea6687a6b95b4669f..bc989a9a2a00b0ac68b9dcffd4ccea269314961b 100644
--- a/ipatests/test_integration/test_acme.py
+++ b/ipatests/test_integration/test_acme.py
@@ -633,9 +633,13 @@ def issue_and_expire_acme_cert():
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)
+ # if the internal fixture was not called (for instance because the test
+ # was skipped), hosts = [] and hosts[0] would produce an IndexError
+ # exception.
+ if hosts:
+ time.sleep(10)
+ hosts[0].run_command(['ipactl', 'restart'])
+ time.sleep(10)
class TestACMERenew(IntegrationTest):
--
2.41.0

View File

@ -0,0 +1,42 @@
From 4a62a21499a4884f0db55d01966a6ff532a4ed1e Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Mon, 14 Aug 2023 10:53:05 +0200
Subject: [PATCH] Installer: activate nss and pam services in sssd.conf
If there is already a sssd.conf file before the installer is
executed, the nss and pam services may not be enabled by the
installer. This happens for instance if the machine is hardened
for STIG and sssd.conf does not define services=... in the
[sssd] section.
The consequence is that trust cannot be established with an AD
domain.
The installer must enable nss and pam services even if there is
a pre-existing sssd.conf file.
Fixes: https://pagure.io/freeipa/issue/9427
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
---
ipaclient/install/client.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py
index ef29a2c8a3f673860cb22e0e6953853fd96a8572..07d62a748f77e990a38e28e3675abb05eef0da8d 100644
--- a/ipaclient/install/client.py
+++ b/ipaclient/install/client.py
@@ -969,6 +969,9 @@ def configure_sssd_conf(
nss_service.set_option('memcache_timeout', 600)
sssdconfig.save_service(nss_service)
+ sssd_enable_service(sssdconfig, 'nss')
+ sssd_enable_service(sssdconfig, 'pam')
+
domain.set_option('ipa_domain', cli_domain)
domain.set_option('ipa_hostname', client_hostname)
if cli_domain.lower() != cli_realm.lower():
--
2.41.0

View File

@ -1,50 +0,0 @@
From 656a11ae961f8d1afad54567cfe8ccb53e084a67 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Mar 20 2024 10:06:07 +0000
Subject: dcerpc: invalidate forest trust info cache when filtering out realm domains
When get_realmdomains() method is called, it will filter out subdomains
of the IPA primary domain. This is required because Active Directory
domain controllers are assuming subdomains already covered by the main
domain namespace.
[MS-LSAD] 3.1.4.7.16.1, 'Forest Trust Collision Generation' defines the
method of validating the forest trust information. They are the same as
rules in [MS-ADTS] section 6.1.6. Specifically,
- A top-level name must not be superior to an enabled top-level name
for another trusted domain object, unless the current trusted domain
object has a corresponding exclusion record.
In practice, we filtered those subdomains already but the code wasn't
invalidating a previously retrieved forest trust information.
Fixes: https://pagure.io/freeipa/issue/9551
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
---
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
index b6139db..7ee553d 100644
--- a/ipaserver/dcerpc.py
+++ b/ipaserver/dcerpc.py
@@ -1103,6 +1103,7 @@ class TrustDomainInstance:
info.count = len(ftinfo_records)
info.entries = ftinfo_records
+ another_domain.ftinfo_data = info
return info
def clear_ftinfo_conflict(self, another_domain, cinfo):
@@ -1778,6 +1779,7 @@ class TrustDomainJoins:
return
self.local_domain.ftinfo_records = []
+ self.local_domain.ftinfo_data = None
realm_domains = self.api.Command.realmdomains_show()['result']
# Use realmdomains' modification timestamp

View File

@ -1,7 +1,7 @@
From ae006b436cfb4ccee5972cf1db0a309fcd80e669 Mon Sep 17 00:00:00 2001 From 363fd5de98e883800ac08b2760e8c3150783e7e2 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com> From: Rob Crittenden <rcritten@redhat.com>
Date: Fri, 6 Oct 2023 20:16:29 +0000 Date: Fri, 6 Oct 2023 20:16:29 +0000
Subject: [PATCH] Check the HTTP Referer header on all requests Subject: [PATCH 1/3] Check the HTTP Referer header on all requests
The referer was only checked in WSGIExecutioner classes: The referer was only checked in WSGIExecutioner classes:
@ -18,12 +18,13 @@ against CSRF attacks.
CVE-2023-5455 CVE-2023-5455
Signed-off-by: Rob Crittenden <rcritten@redhat.com> Signed-off-by: Rob Crittenden <rcritten@redhat.com>
(cherry picked from commit 63f76159b0fe5ab779206a28e07a49500fc1fdbe)
--- ---
ipaserver/rpcserver.py | 34 +++++++++++++++++++++++++++++++--- ipaserver/rpcserver.py | 34 +++++++++++++++++++++++++++++++---
1 file changed, 31 insertions(+), 3 deletions(-) 1 file changed, 31 insertions(+), 3 deletions(-)
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
index 4e8a08b66..3555014ca 100644 index b7116469d..198fc9e7d 100644
--- a/ipaserver/rpcserver.py --- a/ipaserver/rpcserver.py
+++ b/ipaserver/rpcserver.py +++ b/ipaserver/rpcserver.py
@@ -156,6 +156,19 @@ _success_template = """<html> @@ -156,6 +156,19 @@ _success_template = """<html>
@ -56,7 +57,7 @@ index 4e8a08b66..3555014ca 100644
class WSGIExecutioner(Executioner): class WSGIExecutioner(Executioner):
""" """
Base class for execution backends with a WSGI application interface. Base class for execution backends with a WSGI application interface.
@@ -897,6 +907,9 @@ class jsonserver_session(jsonserver, KerberosSession): @@ -898,6 +908,9 @@ class jsonserver_session(jsonserver, KerberosSession):
logger.debug('WSGI jsonserver_session.__call__:') logger.debug('WSGI jsonserver_session.__call__:')
@ -66,7 +67,7 @@ index 4e8a08b66..3555014ca 100644
# Redirect to login if no Kerberos credentials # Redirect to login if no Kerberos credentials
ccache_name = self.get_environ_creds(environ) ccache_name = self.get_environ_creds(environ)
if ccache_name is None: if ccache_name is None:
@@ -949,6 +962,9 @@ class KerberosLogin(Backend, KerberosSession): @@ -950,6 +963,9 @@ class KerberosLogin(Backend, KerberosSession):
def __call__(self, environ, start_response): def __call__(self, environ, start_response):
logger.debug('WSGI KerberosLogin.__call__:') logger.debug('WSGI KerberosLogin.__call__:')
@ -76,7 +77,7 @@ index 4e8a08b66..3555014ca 100644
# Redirect to login if no Kerberos credentials # Redirect to login if no Kerberos credentials
user_ccache_name = self.get_environ_creds(environ) user_ccache_name = self.get_environ_creds(environ)
if user_ccache_name is None: if user_ccache_name is None:
@@ -967,6 +983,9 @@ class login_x509(KerberosLogin): @@ -968,6 +984,9 @@ class login_x509(KerberosLogin):
def __call__(self, environ, start_response): def __call__(self, environ, start_response):
logger.debug('WSGI login_x509.__call__:') logger.debug('WSGI login_x509.__call__:')
@ -86,7 +87,7 @@ index 4e8a08b66..3555014ca 100644
if 'KRB5CCNAME' not in environ: if 'KRB5CCNAME' not in environ:
return self.unauthorized( return self.unauthorized(
environ, start_response, 'KRB5CCNAME not set', environ, start_response, 'KRB5CCNAME not set',
@@ -1015,6 +1034,9 @@ class login_password(Backend, KerberosSession): @@ -1016,6 +1035,9 @@ class login_password(Backend, KerberosSession):
logger.debug('WSGI login_password.__call__:') logger.debug('WSGI login_password.__call__:')
@ -96,7 +97,7 @@ index 4e8a08b66..3555014ca 100644
# Get the user and password parameters from the request # Get the user and password parameters from the request
content_type = environ.get('CONTENT_TYPE', '').lower() content_type = environ.get('CONTENT_TYPE', '').lower()
if not content_type.startswith('application/x-www-form-urlencoded'): if not content_type.startswith('application/x-www-form-urlencoded'):
@@ -1147,6 +1169,9 @@ class change_password(Backend, HTTP_Status): @@ -1148,6 +1170,9 @@ class change_password(Backend, HTTP_Status):
def __call__(self, environ, start_response): def __call__(self, environ, start_response):
logger.info('WSGI change_password.__call__:') logger.info('WSGI change_password.__call__:')
@ -106,7 +107,7 @@ index 4e8a08b66..3555014ca 100644
# Get the user and password parameters from the request # Get the user and password parameters from the request
content_type = environ.get('CONTENT_TYPE', '').lower() content_type = environ.get('CONTENT_TYPE', '').lower()
if not content_type.startswith('application/x-www-form-urlencoded'): if not content_type.startswith('application/x-www-form-urlencoded'):
@@ -1364,6 +1389,9 @@ class xmlserver_session(xmlserver, KerberosSession): @@ -1365,6 +1390,9 @@ class xmlserver_session(xmlserver, KerberosSession):
logger.debug('WSGI xmlserver_session.__call__:') logger.debug('WSGI xmlserver_session.__call__:')
@ -117,5 +118,5 @@ index 4e8a08b66..3555014ca 100644
# Redirect to /ipa/xml if no Kerberos credentials # Redirect to /ipa/xml if no Kerberos credentials
-- --
2.41.0 2.27.0

View File

@ -1,335 +0,0 @@
From 3bba254ccdcf9b62fdd8a6d71baecf37c97c300c Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Mon, 3 Apr 2023 08:37:28 +0200
Subject: [PATCH] ipatests: mark known failures for autoprivategroup
Two tests have known issues in test_trust.py with sssd 2.8.2+:
- TestNonPosixAutoPrivateGroup::test_idoverride_with_auto_private_group
(when called with the "hybrid" parameter)
- TestPosixAutoPrivateGroup::test_only_uid_number_auto_private_group_default
(when called with the "true" parameter)
Related: https://pagure.io/freeipa/issue/9295
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
---
ipatests/test_integration/test_trust.py | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/ipatests/test_integration/test_trust.py b/ipatests/test_integration/test_trust.py
index 0d5b71cb0..12f000c1a 100644
--- a/ipatests/test_integration/test_trust.py
+++ b/ipatests/test_integration/test_trust.py
@@ -1154,11 +1154,15 @@ class TestNonPosixAutoPrivateGroup(BaseTestTrust):
self.gid_override
):
self.mod_idrange_auto_private_group(type)
- (uid, gid) = self.get_user_id(self.clients[0], nonposixuser)
- assert (uid == self.uid_override and gid == self.gid_override)
+ sssd_version = tasks.get_sssd_version(self.clients[0])
+ bad_version = sssd_version >= tasks.parse_version("2.8.2")
+ cond = (type == 'hybrid') and bad_version
+ with xfail_context(condition=cond,
+ reason="https://pagure.io/freeipa/issue/9295"):
+ (uid, gid) = self.get_user_id(self.clients[0], nonposixuser)
+ assert (uid == self.uid_override and gid == self.gid_override)
test_group = self.clients[0].run_command(
["id", nonposixuser]).stdout_text
- # version = tasks.get_sssd_version(self.clients[0])
with xfail_context(type == "hybrid",
'https://github.com/SSSD/sssd/issues/5989'):
assert "domain users@{0}".format(self.ad_domain) in test_group
@@ -1232,8 +1236,11 @@ class TestPosixAutoPrivateGroup(BaseTestTrust):
posixuser = "testuser1@%s" % self.ad_domain
self.mod_idrange_auto_private_group(type)
if type == "true":
- (uid, gid) = self.get_user_id(self.clients[0], posixuser)
- assert uid == gid
+ sssd_version = tasks.get_sssd_version(self.clients[0])
+ with xfail_context(sssd_version >= tasks.parse_version("2.8.2"),
+ "https://pagure.io/freeipa/issue/9295"):
+ (uid, gid) = self.get_user_id(self.clients[0], posixuser)
+ assert uid == gid
else:
for host in [self.master, self.clients[0]]:
result = host.run_command(['id', posixuser], raiseonerr=False)
--
2.44.0
From ed2a8eb0cefadfe0544074114facfef381349ae0 Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Feb 12 2024 10:43:39 +0000
Subject: ipatests: add xfail for autoprivate group test with override
Because of SSSD issue 7169, secondary groups are not
retrieved when autoprivate group is set and an idoverride
replaces the user's primary group.
Mark the known issues as xfail.
Related: https://github.com/SSSD/sssd/issues/7169
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Anuja More <amore@redhat.com>
---
diff --git a/ipatests/test_integration/test_trust.py b/ipatests/test_integration/test_trust.py
index 3b9f0fb..2b94514 100644
--- a/ipatests/test_integration/test_trust.py
+++ b/ipatests/test_integration/test_trust.py
@@ -1164,8 +1164,12 @@ class TestNonPosixAutoPrivateGroup(BaseTestTrust):
assert (uid == self.uid_override and gid == self.gid_override)
test_group = self.clients[0].run_command(
["id", nonposixuser]).stdout_text
- with xfail_context(type == "hybrid",
- 'https://github.com/SSSD/sssd/issues/5989'):
+ cond2 = ((type == 'false'
+ and sssd_version >= tasks.parse_version("2.9.4"))
+ or type == 'hybrid')
+ with xfail_context(cond2,
+ 'https://github.com/SSSD/sssd/issues/5989 '
+ 'and 7169'):
assert "domain users@{0}".format(self.ad_domain) in test_group
@pytest.mark.parametrize('type', ['hybrid', 'true', "false"])
@@ -1287,5 +1291,9 @@ class TestPosixAutoPrivateGroup(BaseTestTrust):
assert(uid == self.uid_override
and gid == self.gid_override)
result = self.clients[0].run_command(['id', posixuser])
- assert "10047(testgroup@{0})".format(
- self.ad_domain) in result.stdout_text
+ sssd_version = tasks.get_sssd_version(self.clients[0])
+ bad_version = sssd_version >= tasks.parse_version("2.9.4")
+ with xfail_context(bad_version and type in ('false', 'hybrid'),
+ "https://github.com/SSSD/sssd/issues/7169"):
+ assert "10047(testgroup@{0})".format(
+ self.ad_domain) in result.stdout_text
From d5392300d77170ea3202ee80690ada8bf81b60b5 Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Feb 12 2024 10:44:47 +0000
Subject: ipatests: remove xfail thanks to sssd 2.9.4
SSSD 2.9.4 fixes some issues related to auto-private-group
Related: https://pagure.io/freeipa/issue/9295
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Anuja More <amore@redhat.com>
---
diff --git a/ipatests/test_integration/test_trust.py b/ipatests/test_integration/test_trust.py
index 12f000c..3b9f0fb 100644
--- a/ipatests/test_integration/test_trust.py
+++ b/ipatests/test_integration/test_trust.py
@@ -1155,7 +1155,8 @@ class TestNonPosixAutoPrivateGroup(BaseTestTrust):
):
self.mod_idrange_auto_private_group(type)
sssd_version = tasks.get_sssd_version(self.clients[0])
- bad_version = sssd_version >= tasks.parse_version("2.8.2")
+ bad_version = (tasks.parse_version("2.8.2") <= sssd_version
+ < tasks.parse_version("2.9.4"))
cond = (type == 'hybrid') and bad_version
with xfail_context(condition=cond,
reason="https://pagure.io/freeipa/issue/9295"):
@@ -1237,7 +1238,9 @@ class TestPosixAutoPrivateGroup(BaseTestTrust):
self.mod_idrange_auto_private_group(type)
if type == "true":
sssd_version = tasks.get_sssd_version(self.clients[0])
- with xfail_context(sssd_version >= tasks.parse_version("2.8.2"),
+ bad_version = (tasks.parse_version("2.8.2") <= sssd_version
+ < tasks.parse_version("2.9.4"))
+ with xfail_context(bad_version,
"https://pagure.io/freeipa/issue/9295"):
(uid, gid) = self.get_user_id(self.clients[0], posixuser)
assert uid == gid
From 34d048ede0c439b3a53e02f8ace96ff91aa1609d Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <flo@redhat.com>
Date: Mar 14 2023 16:50:25 +0000
Subject: ipatests: adapt for new automembership fixup behavior
The automembership fixup task now needs to be called
with --cleanup argument when the user expects automember
to remove user/hosts from automember groups.
Update the test to call create a cleanup task equivalent to
dsconf plugin automember fixup --cleanup
when it is needed.
Fixes: https://pagure.io/freeipa/issue/9313
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
diff --git a/ipatests/test_integration/test_automember.py b/ipatests/test_integration/test_automember.py
index 7acd0d7..8b27f4d 100644
--- a/ipatests/test_integration/test_automember.py
+++ b/ipatests/test_integration/test_automember.py
@@ -4,6 +4,7 @@
"""This covers tests for automemberfeature."""
from __future__ import absolute_import
+import uuid
from ipapython.dn import DN
@@ -211,11 +212,27 @@ class TestAutounmembership(IntegrationTest):
# Running automember-build so that user is part of correct group
result = self.master.run_command(['ipa', 'automember-rebuild',
'--users=%s' % user2])
+ assert msg in result.stdout_text
+
+ # The additional --cleanup argument is required
+ cleanup_ldif = (
+ "dn: cn={cn},cn=automember rebuild membership,"
+ "cn=tasks,cn=config\n"
+ "changetype: add\n"
+ "objectclass: top\n"
+ "objectclass: extensibleObject\n"
+ "basedn: cn=users,cn=accounts,{suffix}\n"
+ "filter: (uid={user})\n"
+ "cleanup: yes\n"
+ "scope: sub"
+ ).format(cn=str(uuid.uuid4()),
+ suffix=str(self.master.domain.basedn),
+ user=user2)
+ tasks.ldapmodify_dm(self.master, cleanup_ldif)
+
assert self.is_user_member_of_group(user2, group2)
assert not self.is_user_member_of_group(user2, group1)
- assert msg in result.stdout_text
-
finally:
# testcase cleanup
self.remove_user_automember(user2, raiseonerr=False)
@@ -248,11 +265,27 @@ class TestAutounmembership(IntegrationTest):
result = self.master.run_command(
['ipa', 'automember-rebuild', '--hosts=%s' % host2]
)
+ assert msg in result.stdout_text
+
+ # The additional --cleanup argument is required
+ cleanup_ldif = (
+ "dn: cn={cn},cn=automember rebuild membership,"
+ "cn=tasks,cn=config\n"
+ "changetype: add\n"
+ "objectclass: top\n"
+ "objectclass: extensibleObject\n"
+ "basedn: cn=computers,cn=accounts,{suffix}\n"
+ "filter: (fqdn={fqdn})\n"
+ "cleanup: yes\n"
+ "scope: sub"
+ ).format(cn=str(uuid.uuid4()),
+ suffix=str(self.master.domain.basedn),
+ fqdn=host2)
+ tasks.ldapmodify_dm(self.master, cleanup_ldif)
+
assert self.is_host_member_of_hostgroup(host2, hostgroup2)
assert not self.is_host_member_of_hostgroup(host2, hostgroup1)
- assert msg in result.stdout_text
-
finally:
# testcase cleanup
self.remove_host_automember(host2, raiseonerr=False)
From 9b777390fbb6d4c683bf7d3e5f74d5443209b1d5 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Fri, 24 Mar 2023 08:15:00 +0200
Subject: [PATCH] test_xmlrpc: adopt to automember plugin message changes in
389-ds
Another change in automember plugin messaging that breaks FreeIPA tests.
Use common substring to match.
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
ipatests/test_xmlrpc/xmlrpc_test.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ipatests/test_xmlrpc/xmlrpc_test.py b/ipatests/test_xmlrpc/xmlrpc_test.py
index cf11721bfca..5fe1245dc65 100644
--- a/ipatests/test_xmlrpc/xmlrpc_test.py
+++ b/ipatests/test_xmlrpc/xmlrpc_test.py
@@ -64,7 +64,7 @@ def test(xs):
# Matches an automember task finish message
fuzzy_automember_message = Fuzzy(
- r'^Automember rebuild task finished\. Processed \(\d+\) entries\.$'
+ r'^Automember rebuild task finished\. Processed \(\d+\) entries'
)
# Matches trusted domain GUID, like u'463bf2be-3456-4a57-979e-120304f2a0eb'
From 8e8b97a2251329aec9633a5c7c644bc5034bc8c2 Mon Sep 17 00:00:00 2001
From: Sudhir Menon <sumenon@redhat.com>
Date: Wed, 20 Mar 2024 14:29:46 +0530
Subject: [PATCH] ipatests: Fixes for test_ipahealthcheck_ipansschainvalidation
testcases.
Currently the test is using IPA_NSSDB_PWDFILE_TXT which is /etc/ipa/nssdb/pwdfile.txt
which causes error in STIG mode.
[root@master slapd-TESTRELM-TEST]# certutil -M -n 'TESTRELM.TEST IPA CA' -t ',,' -d . -f /etc/ipa/nssdb/pwdfile.txt
Incorrect password/PIN entered.
Hence modified the test to include paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE/pwd.txt.
Signed-off-by: Sudhir Menon <sumenon@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
ipatests/test_integration/test_ipahealthcheck.py | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py
index 8aae9fad776..a96de7088aa 100644
--- a/ipatests/test_integration/test_ipahealthcheck.py
+++ b/ipatests/test_integration/test_ipahealthcheck.py
@@ -2731,17 +2731,18 @@ def remove_server_cert(self):
Fixture to remove Server cert and revert the change.
"""
instance = realm_to_serverid(self.master.domain.realm)
+ instance_dir = paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance
self.master.run_command(
[
"certutil",
"-L",
"-d",
- paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance,
+ instance_dir,
"-n",
"Server-Cert",
"-a",
"-o",
- paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance
+ instance_dir
+ "/Server-Cert.pem",
]
)
@@ -2760,15 +2761,15 @@ def remove_server_cert(self):
[
"certutil",
"-d",
- paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance,
+ instance_dir,
"-A",
"-i",
- paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance
+ instance_dir
+ "/Server-Cert.pem",
"-t",
"u,u,u",
"-f",
- paths.IPA_NSSDB_PWDFILE_TXT,
+ "%s/pwdfile.txt" % instance_dir,
"-n",
"Server-Cert",
]

View File

@ -1,7 +1,7 @@
From f1f8b16def3e809f5773bb8aa40aefb21699347b Mon Sep 17 00:00:00 2001 From 48ec350051ead9c17e58a91405b3ab6935347f1b Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten@redhat.com> From: Rob Crittenden <rcritten@redhat.com>
Date: Thu, 12 Oct 2023 20:34:01 +0000 Date: Thu, 12 Oct 2023 20:34:01 +0000
Subject: [PATCH] Integration tests for verifying Referer header in the UI Subject: [PATCH 2/3] Integration tests for verifying Referer header in the UI
Validate that the change_password and login_password endpoints Validate that the change_password and login_password endpoints
verify the HTTP Referer header. There is some overlap in the verify the HTTP Referer header. There is some overlap in the
@ -31,6 +31,7 @@ expected.
CVE-2023-5455 CVE-2023-5455
Signed-off-by: Rob Crittenden <rcritten@redhat.com> Signed-off-by: Rob Crittenden <rcritten@redhat.com>
(cherry picked from commit ef158764a97490211b9fe2e53f40826c3acfb19b)
--- ---
ipatests/test_ipaserver/httptest.py | 7 +- ipatests/test_ipaserver/httptest.py | 7 +-
ipatests/test_ipaserver/test_changepw.py | 12 +- ipatests/test_ipaserver/test_changepw.py | 12 +-
@ -336,7 +337,7 @@ index 000000000..4eade8bba
+ +
+ assert_equal(response.status, 400, self.app_uri) + assert_equal(response.status, 400, self.app_uri)
diff --git a/ipatests/util.py b/ipatests/util.py diff --git a/ipatests/util.py b/ipatests/util.py
index 5c0152b90..c69d98790 100644 index 929c3e899..61af0c40d 100644
--- a/ipatests/util.py --- a/ipatests/util.py
+++ b/ipatests/util.py +++ b/ipatests/util.py
@@ -163,12 +163,12 @@ class ExceptionNotRaised(Exception): @@ -163,12 +163,12 @@ class ExceptionNotRaised(Exception):
@ -355,5 +356,5 @@ index 5c0152b90..c69d98790 100644
def assert_not_equal(val1, val2): def assert_not_equal(val1, val2):
-- --
2.41.0 2.27.0

View File

@ -1,341 +0,0 @@
From 0a48726e104282fb40d8f471ebb306bc9134cb0c Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Tue, 19 Mar 2024 12:24:40 +0100
Subject: [PATCH] kdb: fix vulnerability in GCD rules handling
The initial implementation of MS-SFU by MIT Kerberos was missing some
a condition for granting the "forwardable" flag on S4U2Self tickets.
Fixing this mistake required to add a special case for the
check_allowed_to_delegate() function: if the target service argument is
NULL, then it means the KDC is probing for general constrained
delegation rules, not actually checking a specific S4U2Proxy request.
In commit e86807b5, the behavior of ipadb_match_acl() was modified to
match the changes from upstream MIT Kerberos a441fbe3. However, a
mistake resulted in this mechanism to apply in cases where target
service argument is set AND unset. This results in S4U2Proxy requests to
be accepted regardless of the fact there is a matching service
delegation rule or not.
This vulnerability does not affect services having RBCD (resource-based
constrained delegation) rules.
This fixes CVE-2024-2698
Signed-off-by: Julien Rische <jrische@redhat.com>
---
daemons/ipa-kdb/README.s4u2proxy.txt | 19 ++-
daemons/ipa-kdb/ipa_kdb_delegation.c | 191 +++++++++++++++------------
2 files changed, 118 insertions(+), 92 deletions(-)
diff --git a/daemons/ipa-kdb/README.s4u2proxy.txt b/daemons/ipa-kdb/README.s4u2proxy.txt
index 254fcc4d1..ab34aff36 100644
--- a/daemons/ipa-kdb/README.s4u2proxy.txt
+++ b/daemons/ipa-kdb/README.s4u2proxy.txt
@@ -12,9 +12,7 @@ much more easily managed.
The grouping mechanism has been built so that lookup is highly optimized
and is basically reduced to a single search that uses the derefernce
-control. Speed is very important in this case because KDC operations
-time out very quickly and unless we add a caching layer in ipa-kdb we
-must keep the number of searches down to avoid client timeouts.
+control.
The grouping mechanism is very simple a groupOfPrincipals object is
introduced, this Auxiliary class have a single optional attribute called
@@ -112,8 +110,7 @@ kinit -kt /etc/httpd/conf/ipa.keytab HTTP/ipaserver.example.com
kvno -U admin HTTP/ipaserver.example.com
# Perform S4U2Proxy
-kvno -k /etc/httpd/conf/ipa.keytab -U admin -P HTTP/ipaserver.example.com
-ldap/ipaserver.example.com
+kvno -U admin -P ldap/ipaserver.example.com
If this works it means you successfully impersonated the admin user with
@@ -125,6 +122,18 @@ modprinc -ok_to_auth_as_delegate HTTP/ipaserver.example.com
Simo.
+If IPA is compiled with krb5 1.20 and newer (KDB DAL >= 9), then the
+behavior of S4U2Self changes: S4U2Self TGS-REQs produce forwardable
+tickets for all requesters, except if the requester principal is set as
+the proxy (impersonating service) in at least one `servicedelegation`
+rule. In this case, even if the rule has no target, the KDC will
+response to S4U2Self requests with a non-forwardable ticket. Hence,
+granting the `ok_to_auth_as_delegate` permission to the proxy service
+remains the only way for this service to obtain the evidence ticket
+required for general constrained delegation requests if this ticket is
+not provided by the client.
+
+
[1]
Note that here I use the term proxy in a different way than it is used in
the krb interfaces. It may seem a bit confusing but I think people will
diff --git a/daemons/ipa-kdb/ipa_kdb_delegation.c b/daemons/ipa-kdb/ipa_kdb_delegation.c
index de82174ad..3581f3c79 100644
--- a/daemons/ipa-kdb/ipa_kdb_delegation.c
+++ b/daemons/ipa-kdb/ipa_kdb_delegation.c
@@ -91,120 +91,110 @@ static bool ipadb_match_member(char *princ, LDAPDerefRes *dres)
return false;
}
-static krb5_error_code ipadb_match_acl(krb5_context kcontext,
- LDAPMessage *results,
- krb5_const_principal client,
- krb5_const_principal target)
+#if KRB5_KDB_DAL_MAJOR_VERSION >= 9
+static krb5_error_code
+ipadb_has_acl(krb5_context kcontext, LDAPMessage *ldap_acl, bool *res)
{
struct ipadb_context *ipactx;
- krb5_error_code kerr;
- LDAPMessage *lentry;
- LDAPDerefRes *deref_results;
- LDAPDerefRes *dres;
- char *client_princ = NULL;
- char *target_princ = NULL;
- bool client_missing;
- bool client_found;
- bool target_found;
- bool is_constraint_delegation = false;
- size_t nrules = 0;
- int ret;
+ bool in_res = false;
+ krb5_error_code kerr = 0;
ipactx = ipadb_get_context(kcontext);
- if (!ipactx) {
+ if (!ipactx)
return KRB5_KDB_DBNOTINITED;
- }
- if ((client != NULL) && (target != NULL)) {
- kerr = krb5_unparse_name(kcontext, client, &client_princ);
- if (kerr != 0) {
- goto done;
- }
- kerr = krb5_unparse_name(kcontext, target, &target_princ);
- if (kerr != 0) {
- goto done;
- }
- } else {
- is_constraint_delegation = true;
+ switch (ldap_count_entries(ipactx->lcontext, ldap_acl)) {
+ case 0:
+ break;
+ case -1:
+ kerr = EINVAL;
+ goto end;
+ default:
+ in_res = true;
+ goto end;
}
- lentry = ldap_first_entry(ipactx->lcontext, results);
- if (!lentry) {
- kerr = ENOENT;
- goto done;
- }
+end:
+ if (res)
+ *res = in_res;
+
+ return kerr;
+}
+#endif
+
+static krb5_error_code
+ipadb_match_acl(krb5_context kcontext, LDAPMessage *ldap_acl,
+ krb5_const_principal client, krb5_const_principal target)
+{
+ struct ipadb_context *ipactx;
+ LDAPMessage *rule;
+ LDAPDerefRes *acis, *aci;
+ char *client_princ = NULL, *target_princ= NULL;
+ bool client_missing, client_found, target_found;
+ int lerr;
+ krb5_error_code kerr;
+
+ ipactx = ipadb_get_context(kcontext);
+ if (!ipactx)
+ return KRB5_KDB_DBNOTINITED;
+
+ kerr = krb5_unparse_name(kcontext, client, &client_princ);
+ if (kerr)
+ goto end;
+
+ kerr = krb5_unparse_name(kcontext, target, &target_princ);
+ if (kerr)
+ goto end;
/* the default is that we fail */
- kerr = ENOENT;
+ kerr = KRB5KDC_ERR_BADOPTION;
- while (lentry) {
+ for (rule = ldap_first_entry(ipactx->lcontext, ldap_acl);
+ rule;
+ rule = ldap_next_entry(ipactx->lcontext, rule))
+ {
/* both client and target must be found in the same ACI */
client_missing = true;
client_found = false;
target_found = false;
- ret = ipadb_ldap_deref_results(ipactx->lcontext, lentry,
- &deref_results);
- switch (ret) {
+ lerr = ipadb_ldap_deref_results(ipactx->lcontext, rule, &acis);
+ switch (lerr) {
case 0:
- for (dres = deref_results; dres; dres = dres->next) {
- nrules++;
- if (is_constraint_delegation) {
- /*
- Microsoft revised the S4U2Proxy rules for forwardable
- tickets. All S4U2Proxy operations require forwardable
- evidence tickets, but S4U2Self should issue a
- forwardable ticket if the requesting service has no
- ok-to-auth-as-delegate bit but also no constrained
- delegation privileges for traditional S4U2Proxy.
- Implement these rules, extending the
- check_allowed_to_delegate() DAL method so that the KDC
- can ask if a principal has any delegation privileges.
-
- Since target principal is NULL and client principal is
- NULL in this case, we simply calculate number of rules associated
- with the server principal to decide whether to deny forwardable bit
- */
- continue;
- }
- if (client_found == false &&
- strcasecmp(dres->derefAttr, "ipaAllowToImpersonate") == 0) {
+ for (aci = acis; aci; aci = aci->next) {
+ if (!client_found &&
+ 0 == strcasecmp(aci->derefAttr, "ipaAllowToImpersonate"))
+ {
/* NOTE: client_missing is used to signal that the
* attribute was completely missing. This signals that
* ANY client is allowed to be impersonated.
* This logic is valid only for clients, not for targets */
client_missing = false;
- client_found = ipadb_match_member(client_princ, dres);
+ client_found = ipadb_match_member(client_princ, aci);
}
- if (target_found == false &&
- strcasecmp(dres->derefAttr, "ipaAllowedTarget") == 0) {
- target_found = ipadb_match_member(target_princ, dres);
+ if (!target_found &&
+ 0 == strcasecmp(aci->derefAttr, "ipaAllowedTarget"))
+ {
+ target_found = ipadb_match_member(target_princ, aci);
}
}
- ldap_derefresponse_free(deref_results);
+ ldap_derefresponse_free(acis);
break;
case ENOENT:
break;
default:
- kerr = ret;
- goto done;
+ kerr = lerr;
+ goto end;
}
- if ((client_found == true || client_missing == true) &&
- target_found == true) {
+ if ((client_found || client_missing) && target_found) {
kerr = 0;
- goto done;
+ goto end;
}
-
- lentry = ldap_next_entry(ipactx->lcontext, lentry);
- }
-
- if (nrules > 0) {
- kerr = 0;
}
-done:
+end:
krb5_free_unparsed_name(kcontext, client_princ);
krb5_free_unparsed_name(kcontext, target_princ);
return kerr;
@@ -223,7 +213,7 @@ krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext,
char *srv_principal = NULL;
krb5_db_entry *proxy_entry = NULL;
struct ipadb_e_data *ied_server, *ied_proxy;
- LDAPMessage *res = NULL;
+ LDAPMessage *ldap_gcd_acl = NULL;
if (proxy != NULL) {
/* Handle the case where server == proxy, this is allowed in S4U */
@@ -261,26 +251,53 @@ krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext,
goto done;
}
- kerr = ipadb_get_delegation_acl(kcontext, srv_principal, &res);
+ /* Load general constrained delegation rules */
+ kerr = ipadb_get_delegation_acl(kcontext, srv_principal, &ldap_gcd_acl);
if (kerr) {
goto done;
}
- kerr = ipadb_match_acl(kcontext, res, client, proxy);
- if (kerr) {
- goto done;
+#if KRB5_KDB_DAL_MAJOR_VERSION >= 9
+ /*
+ * Microsoft revised the S4U2Proxy rules for forwardable tickets. All
+ * S4U2Proxy operations require forwardable evidence tickets, but
+ * S4U2Self should issue a forwardable ticket if the requesting service
+ * has no ok-to-auth-as-delegate bit but also no constrained delegation
+ * privileges for traditional S4U2Proxy. Implement these rules,
+ * extending the check_allowed_to_delegate() DAL method so that the KDC
+ * can ask if a principal has any delegation privileges.
+ *
+ * If target service principal is NULL, and the impersonating service has
+ * at least one GCD rule, then succeed.
+ */
+ if (!proxy) {
+ bool has_gcd_rules;
+
+ kerr = ipadb_has_acl(kcontext, ldap_gcd_acl, &has_gcd_rules);
+ if (!kerr)
+ kerr = has_gcd_rules ? 0 : KRB5KDC_ERR_BADOPTION;
+ } else if (client) {
+#else
+ if (client && proxy) {
+#endif
+ kerr = ipadb_match_acl(kcontext, ldap_gcd_acl, client, proxy);
+ } else {
+ /* client and/or proxy is missing */
+ kerr = KRB5KDC_ERR_BADOPTION;
}
+ if (kerr)
+ goto done;
done:
if (kerr) {
-#if KRB5_KDB_DAL_MAJOR_VERSION < 9
- kerr = KRB5KDC_ERR_POLICY;
-#else
+#if KRB5_KDB_DAL_MAJOR_VERSION >= 9
kerr = KRB5KDC_ERR_BADOPTION;
+#else
+ kerr = KRB5KDC_ERR_POLICY;
#endif
}
ipadb_free_principal(kcontext, proxy_entry);
krb5_free_unparsed_name(kcontext, srv_principal);
- ldap_msgfree(res);
+ ldap_msgfree(ldap_gcd_acl);
return kerr;
}
--
2.44.0

View File

@ -1,615 +0,0 @@
From 542e12325afc2f64298f90296760235bfdcef04a Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Mon, 25 Mar 2024 18:25:52 +0200
Subject: [PATCH] kdb: apply combinatorial logic for ticket flags
The initial design for ticket flags was implementing this logic:
* If a ticket policy is defined for the principal entry, use flags from
this policy if they are set. Otherwise, use default ticket flags.
* If no ticket policy is defined for the principal entry, but there is a
global one, use flags from the global ticket policy if they are set.
Otherwise, use default ticket flags.
* If no policy (principal nor global) is defined, use default ticket
flags.
However, this logic was broken by a1165ffb which introduced creation of
a principal-level ticket policy in case the ticket flag set is modified.
This was typically the case for the -allow_tix flag, which was set
virtually by the KDB driver when a user was locked until they initialize
their password on first kinit pre-authentication.
This was causing multiple issues, which are mitigated by the new
approach:
Now flags from each level are combined together. There flags like
+requires_preauth which are set systematically by the KDB diver, as
well as -allow_tix which is set based on the value of "nsAccountLock".
This commit also adds the implicit -allow_svr ticket flag for user
principals to protect users against Kerberoast-type attacks. None of
these flags are stored in the LDAP database, they are hard-coded in the
KDB driver.
In addition to these "virtual" ticket flags, flags from both global and
principal ticket policies are applied (if these policies exist).
Principal ticket policies are not supported for hosts and services, but
this is only an HTTP API limitation. The "krbTicketPolicyAux" object
class is supported for all account types. This is required for ticket
flags like +ok_to_auth_as_delegate. Such flags can be set using "ipa
host-mod" and "ipa serivce-mod", or using kadmin's "modprinc".
It is possible to ignore flags from the global ticket policy or default
flags like -allow_svr for a user principal by setting the
"final_user_tkt_flags" string attribute to "true" in kadmin. In this
case, any ticket flag can be configured in the principal ticket policy,
except requires_preauth and allow_tix.
When in IPA setup mode (using the "ipa-setup-override-restrictions" KDB
argument), all the system described above is disabled and ticket flags
are written in the principal ticket policy as they are provided. This is
required to initialize the Kerberos LDAP container during IPA server
installation.
This fixes CVE-2024-3183
Signed-off-by: Julien Rische <jrische@redhat.com>
---
daemons/ipa-kdb/ipa_kdb.h | 43 ++++
daemons/ipa-kdb/ipa_kdb_principals.c | 353 +++++++++++++++++++++++----
util/ipa_krb5.c | 18 ++
util/ipa_krb5.h | 4 +
4 files changed, 365 insertions(+), 53 deletions(-)
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
index 7baf4697f..85cabe142 100644
--- a/daemons/ipa-kdb/ipa_kdb.h
+++ b/daemons/ipa-kdb/ipa_kdb.h
@@ -94,6 +94,34 @@
#define IPA_KRB_AUTHZ_DATA_ATTR "ipaKrbAuthzData"
#define IPA_USER_AUTH_TYPE "ipaUserAuthType"
+/* Virtual managed ticket flags like "-allow_tix", are always controlled by the
+ * "nsAccountLock" attribute, such flags should never be set in the database.
+ * The following expression combine all of them, and is used to filter them
+ * out. */
+#define IPA_KDB_TKTFLAGS_VIRTUAL_MANAGED_ALL (KRB5_KDB_DISALLOW_ALL_TIX)
+
+/* Virtual static ticket flags are hard-coded in the KDB driver. */
+/* Virtual static mandatory flags are set systematically and implicitly for all
+ * principals. They are filtered out from database ticket flags updates.
+ * (However, "KRB5_KDB_REQUIRES_PRE_AUTH" can still be unset by the
+ * "KDC:Disable Default Preauth for SPNs" global setting) */
+#define IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_MANDATORY (KRB5_KDB_REQUIRES_PRE_AUTH)
+/* Virtual static default ticket flags are implicitly set for user and non-user
+ * (SPN) principals, and not stored in the database.
+ * (Except if the "IPA_KDB_STRATTR_FINAL_TKTFLAGS" string attribute is "true"
+ * the principal) */
+/* Virtual static default user ticket flags are set for users only. The
+ * "-allow_svr" flag is set to protect them from CVE-2024-3183. */
+#define IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_DEFAULTS_USER (KRB5_KDB_DISALLOW_SVR)
+#define IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_DEFAULTS_SPN (0)
+
+/* If this string attribute is set to "true", then only the virtual managed and
+ * virtual static mandatory ticket flags are applied and filtered out from
+ * database read and write operations for the concerned user principal.
+ * Configurable principal ticket flags are applied, but not the configurable
+ * global ticket policy flags. */
+#define IPA_KDB_STRATTR_FINAL_USER_TKTFLAGS "final_user_tkt_flags"
+
struct ipadb_mspac;
struct dom_sid;
@@ -178,6 +206,21 @@ struct ipadb_e_data {
struct dom_sid *sid;
};
+inline static krb5_error_code
+ipadb_get_edata(krb5_db_entry *entry, struct ipadb_e_data **ied)
+{
+ struct ipadb_e_data *in_ied;
+
+ in_ied = (struct ipadb_e_data *)entry->e_data;
+ if (!in_ied || in_ied->magic != IPA_E_DATA_MAGIC)
+ return EINVAL;
+
+ if (ied)
+ *ied = in_ied;
+
+ return 0;
+}
+
struct ipadb_context *ipadb_get_context(krb5_context kcontext);
int ipadb_get_connection(struct ipadb_context *ipactx);
diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c
index 07cc87746..6eb542d4f 100644
--- a/daemons/ipa-kdb/ipa_kdb_principals.c
+++ b/daemons/ipa-kdb/ipa_kdb_principals.c
@@ -706,9 +706,12 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
"krbTicketFlags", &result);
if (ret == 0) {
entry->attributes = result;
- } else {
- *polmask |= TKTFLAGS_BIT;
}
+ /* Since principal, global policy, and virtual ticket flags are combined,
+ * they must always be resolved, except if we are in IPA setup mode (because
+ * ticket policies and virtual ticket flags are irrelevant in this case). */
+ if (!ipactx->override_restrictions)
+ *polmask |= TKTFLAGS_BIT;
ret = ipadb_ldap_attr_to_int(lcontext, lentry,
"krbMaxTicketLife", &result);
@@ -912,7 +915,12 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
goto done;
}
if (ret == 0) {
- ied->ipa_user = true;
+ if (1 == krb5_princ_size(kcontext, entry->princ)) {
+ /* A principal must be a POSIX account AND have only one element to
+ * be considered a user (this is to filter out CIFS principals). */
+ ied->ipa_user = true;
+ }
+
ret = ipadb_ldap_attr_to_str(lcontext, lentry,
"uid", &uidstring);
if (ret != 0 && ret != ENOENT) {
@@ -1251,23 +1259,150 @@ done:
return ret;
}
-static krb5_flags maybe_require_preauth(struct ipadb_context *ipactx,
- krb5_db_entry *entry)
+static krb5_error_code
+are_final_tktflags(struct ipadb_context *ipactx, krb5_db_entry *entry,
+ bool *final_tktflags)
{
- const struct ipadb_global_config *config;
+ krb5_error_code kerr;
struct ipadb_e_data *ied;
+ char *str = NULL;
+ bool in_final_tktflags = false;
- config = ipadb_get_global_config(ipactx);
- if (config && config->disable_preauth_for_spns) {
- ied = (struct ipadb_e_data *)entry->e_data;
- if (ied && ied->ipa_user != true) {
- /* not a user, assume SPN */
- return 0;
- }
+ kerr = ipadb_get_edata(entry, &ied);
+ if (kerr)
+ goto end;
+
+ if (!ied->ipa_user) {
+ kerr = 0;
+ goto end;
}
- /* By default require preauth for all principals */
- return KRB5_KDB_REQUIRES_PRE_AUTH;
+ kerr = krb5_dbe_get_string(ipactx->kcontext, entry,
+ IPA_KDB_STRATTR_FINAL_USER_TKTFLAGS, &str);
+ if (kerr)
+ goto end;
+
+ in_final_tktflags = str && ipa_krb5_parse_bool(str);
+
+end:
+ if (final_tktflags)
+ *final_tktflags = in_final_tktflags;
+
+ krb5_dbe_free_string(ipactx->kcontext, str);
+ return kerr;
+}
+
+static krb5_error_code
+add_virtual_static_tktflags(struct ipadb_context *ipactx, krb5_db_entry *entry,
+ krb5_flags *tktflags)
+{
+ krb5_error_code kerr;
+ krb5_flags vsflg;
+ bool final_tktflags;
+ const struct ipadb_global_config *gcfg;
+ struct ipadb_e_data *ied;
+
+ vsflg = IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_MANDATORY;
+
+ kerr = ipadb_get_edata(entry, &ied);
+ if (kerr)
+ goto end;
+
+ kerr = are_final_tktflags(ipactx, entry, &final_tktflags);
+ if (kerr)
+ goto end;
+
+ /* In practice, principal ticket flags cannot be final for SPNs. */
+ if (!final_tktflags)
+ vsflg |= ied->ipa_user ? IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_DEFAULTS_USER
+ : IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_DEFAULTS_SPN;
+
+ if (!ied->ipa_user) {
+ gcfg = ipadb_get_global_config(ipactx);
+ if (gcfg && gcfg->disable_preauth_for_spns)
+ vsflg &= ~KRB5_KDB_REQUIRES_PRE_AUTH;
+ }
+
+ if (tktflags)
+ *tktflags |= vsflg;
+
+end:
+ return kerr;
+}
+
+static krb5_error_code
+get_virtual_static_tktflags_mask(struct ipadb_context *ipactx,
+ krb5_db_entry *entry, krb5_flags *mask)
+{
+ krb5_error_code kerr;
+ krb5_flags flags = IPA_KDB_TKTFLAGS_VIRTUAL_MANAGED_ALL;
+
+ kerr = add_virtual_static_tktflags(ipactx, entry, &flags);
+ if (kerr)
+ goto end;
+
+ if (mask)
+ *mask = ~flags;
+
+ kerr = 0;
+
+end:
+ return kerr;
+}
+
+/* Add ticket flags from the global ticket policy if it exists, otherwise
+ * succeed. If the global ticket policy is set, the "exists" parameter is set to
+ * true. */
+static krb5_error_code
+add_global_ticket_policy_flags(struct ipadb_context *ipactx,
+ bool *gtpol_exists, krb5_flags *tktflags)
+{
+ krb5_error_code kerr;
+ char *policy_dn;
+ char *tktflags_attr[] = { "krbticketflags", NULL };
+ LDAPMessage *res = NULL, *first;
+ int ec, ldap_tktflags;
+ bool in_gtpol_exists = false;
+
+ ec = asprintf(&policy_dn, "cn=%s,cn=kerberos,%s", ipactx->realm,
+ ipactx->base);
+ if (-1 == ec) {
+ kerr = ENOMEM;
+ goto end;
+ }
+
+ kerr = ipadb_simple_search(ipactx, policy_dn, LDAP_SCOPE_BASE,
+ "(objectclass=krbticketpolicyaux)",
+ tktflags_attr, &res);
+ if (kerr) {
+ if (KRB5_KDB_NOENTRY == kerr)
+ kerr = 0;
+ goto end;
+ }
+
+ first = ldap_first_entry(ipactx->lcontext, res);
+ if (!first) {
+ kerr = 0;
+ goto end;
+ }
+
+ in_gtpol_exists = true;
+
+ ec = ipadb_ldap_attr_to_int(ipactx->lcontext, first, "krbticketflags",
+ &ldap_tktflags);
+ if (0 == ec && tktflags) {
+ *tktflags |= (krb5_flags)ldap_tktflags;
+ }
+
+ kerr = 0;
+
+end:
+ if (gtpol_exists)
+ *gtpol_exists = in_gtpol_exists;
+
+ ldap_msgfree(res);
+ free(policy_dn);
+ return kerr;
}
static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
@@ -1280,6 +1415,7 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
char *policy_dn = NULL;
LDAPMessage *res = NULL;
LDAPMessage *first;
+ bool final_tktflags, has_local_tktpolicy = true;
int result;
int ret;
@@ -1288,12 +1424,18 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
return KRB5_KDB_DBNOTINITED;
}
+ kerr = are_final_tktflags(ipactx, entry, &final_tktflags);
+ if (kerr)
+ goto done;
+
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
"krbticketpolicyreference", &policy_dn);
switch (ret) {
case 0:
break;
case ENOENT:
+ /* If no principal ticket policy, fallback to the global one. */
+ has_local_tktpolicy = false;
ret = asprintf(&policy_dn, "cn=%s,cn=kerberos,%s",
ipactx->realm, ipactx->base);
if (ret == -1) {
@@ -1337,12 +1479,13 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
}
}
if (polmask & TKTFLAGS_BIT) {
- ret = ipadb_ldap_attr_to_int(ipactx->lcontext, first,
- "krbticketflags", &result);
- if (ret == 0) {
- entry->attributes |= result;
- } else {
- entry->attributes |= maybe_require_preauth(ipactx, entry);
+ /* If global ticket policy is being applied, set flags only if
+ * user principal ticket flags are not final. */
+ if (has_local_tktpolicy || !final_tktflags) {
+ ret = ipadb_ldap_attr_to_int(ipactx->lcontext, first,
+ "krbticketflags", &result);
+ if (ret == 0)
+ entry->attributes |= result;
}
}
@@ -1366,13 +1509,27 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
if (polmask & MAXRENEWABLEAGE_BIT) {
entry->max_renewable_life = 604800;
}
- if (polmask & TKTFLAGS_BIT) {
- entry->attributes |= maybe_require_preauth(ipactx, entry);
- }
kerr = 0;
}
+ if (polmask & TKTFLAGS_BIT) {
+ /* If the principal ticket flags were applied, then flags from the
+ * global ticket policy has to be applied atop of them if user principal
+ * ticket flags are not final. */
+ if (has_local_tktpolicy && !final_tktflags) {
+ kerr = add_global_ticket_policy_flags(ipactx, NULL,
+ &entry->attributes);
+ if (kerr)
+ goto done;
+ }
+
+ /* Virtual static ticket flags are set regardless of database content */
+ kerr = add_virtual_static_tktflags(ipactx, entry, &entry->attributes);
+ if (kerr)
+ goto done;
+ }
+
done:
ldap_msgfree(res);
free(policy_dn);
@@ -1864,6 +2021,36 @@ static void ipadb_mods_free_tip(struct ipadb_mods *imods)
imods->tip--;
}
+/* Use LDAP REPLACE operation to remove an attribute.
+ * Contrary to the DELETE operation, it will not fail if the attribute does not
+ * exist. */
+static krb5_error_code
+ipadb_ldap_replace_remove(struct ipadb_mods *imods, char *attribute)
+{
+ krb5_error_code kerr;
+ LDAPMod *m = NULL;
+
+ kerr = ipadb_mods_new(imods, &m);
+ if (kerr)
+ return kerr;
+
+ m->mod_op = LDAP_MOD_REPLACE;
+ m->mod_type = strdup(attribute);
+ if (!m->mod_type) {
+ kerr = ENOMEM;
+ goto end;
+ }
+
+ m->mod_values = NULL;
+
+ kerr = 0;
+
+end:
+ if (kerr)
+ ipadb_mods_free_tip(imods);
+ return kerr;
+}
+
static krb5_error_code ipadb_get_ldap_mod_str(struct ipadb_mods *imods,
char *attribute, char *value,
int mod_op)
@@ -2275,6 +2462,93 @@ static krb5_error_code ipadb_get_ldap_mod_auth_ind(krb5_context kcontext,
return ret;
}
+static krb5_error_code
+update_tktflags(krb5_context kcontext, struct ipadb_mods *imods,
+ krb5_db_entry *entry, int mod_op)
+{
+ krb5_error_code kerr;
+ struct ipadb_context *ipactx;
+ struct ipadb_e_data *ied;
+ bool final_tktflags;
+ krb5_flags tktflags_mask;
+ int tktflags;
+
+ ipactx = ipadb_get_context(kcontext);
+ if (!ipactx) {
+ kerr = KRB5_KDB_DBNOTINITED;
+ goto end;
+ }
+
+ if (ipactx->override_restrictions) {
+ /* In IPA setup mode, IPA edata might not be available. In this mode,
+ * ticket flags are written as they are provided. */
+ tktflags = (int)entry->attributes;
+ } else {
+ kerr = ipadb_get_edata(entry, &ied);
+ if (kerr)
+ goto end;
+
+ kerr = get_virtual_static_tktflags_mask(ipactx, entry, &tktflags_mask);
+ if (kerr)
+ goto end;
+
+ kerr = are_final_tktflags(ipactx, entry, &final_tktflags);
+ if (kerr)
+ goto end;
+
+ /* Flags from the global ticket policy are filtered out only if the user
+ * principal flags are not final. */
+ if (!final_tktflags) {
+ krb5_flags gbl_tktflags = 0;
+
+ kerr = add_global_ticket_policy_flags(ipactx, NULL, &gbl_tktflags);
+ if (kerr)
+ goto end;
+
+ tktflags_mask &= ~gbl_tktflags;
+ }
+
+ tktflags = (int)(entry->attributes & tktflags_mask);
+
+ if (LDAP_MOD_REPLACE == mod_op && ied && !ied->has_tktpolaux) {
+ if (0 == tktflags) {
+ /* No point initializing principal ticket policy if there are no
+ * flags left after filtering out virtual and global ticket
+ * policy ones. */
+ kerr = 0;
+ goto end;
+ }
+
+ /* if the object does not have the krbTicketPolicyAux class
+ * we need to add it or this will fail, only for modifications.
+ * We always add this objectclass by default when doing an add
+ * from scratch. */
+ kerr = ipadb_get_ldap_mod_str(imods, "objectclass",
+ "krbTicketPolicyAux", LDAP_MOD_ADD);
+ if (kerr)
+ goto end;
+ }
+ }
+
+ if (tktflags != 0) {
+ kerr = ipadb_get_ldap_mod_int(imods, "krbTicketFlags", tktflags,
+ mod_op);
+ if (kerr)
+ goto end;
+ } else if (LDAP_MOD_REPLACE == mod_op) {
+ /* If the principal is not being created, and there are no custom ticket
+ * flags to be set, remove the "krbTicketFlags" attribute. */
+ kerr = ipadb_ldap_replace_remove(imods, "krbTicketFlags");
+ if (kerr)
+ goto end;
+ }
+
+ kerr = 0;
+
+end:
+ return kerr;
+}
+
static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext,
struct ipadb_mods *imods,
krb5_db_entry *entry,
@@ -2350,36 +2624,9 @@ static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext,
/* KADM5_ATTRIBUTES */
if (entry->mask & KMASK_ATTRIBUTES) {
- /* if the object does not have the krbTicketPolicyAux class
- * we need to add it or this will fail, only for modifications.
- * We always add this objectclass by default when doing an add
- * from scratch. */
- if ((mod_op == LDAP_MOD_REPLACE) && entry->e_data) {
- struct ipadb_e_data *ied;
-
- ied = (struct ipadb_e_data *)entry->e_data;
- if (ied->magic != IPA_E_DATA_MAGIC) {
- kerr = EINVAL;
- goto done;
- }
-
- if (!ied->has_tktpolaux) {
- kerr = ipadb_get_ldap_mod_str(imods, "objectclass",
- "krbTicketPolicyAux",
- LDAP_MOD_ADD);
- if (kerr) {
- goto done;
- }
- }
- }
-
- kerr = ipadb_get_ldap_mod_int(imods,
- "krbTicketFlags",
- (int)entry->attributes,
- mod_op);
- if (kerr) {
+ kerr = update_tktflags(kcontext, imods, entry, mod_op);
+ if (kerr)
goto done;
- }
}
/* KADM5_MAX_LIFE */
diff --git a/util/ipa_krb5.c b/util/ipa_krb5.c
index 1ba6d25ee..2e663c506 100644
--- a/util/ipa_krb5.c
+++ b/util/ipa_krb5.c
@@ -38,6 +38,12 @@ const char *ipapwd_password_max_len_errmsg = \
TOSTR(IPAPWD_PASSWORD_MAX_LEN) \
" chars)!";
+/* Case-insensitive string values to by parsed as boolean true */
+static const char *const conf_yes[] = {
+ "y", "yes", "true", "t", "1", "on",
+ NULL,
+};
+
/* Salt types */
#define KRB5P_SALT_SIZE 16
@@ -1237,3 +1243,15 @@ done:
}
return ret;
}
+
+bool ipa_krb5_parse_bool(const char *str)
+{
+ const char *const *p;
+
+ for (p = conf_yes; *p; p++) {
+ if (!strcasecmp(*p, str))
+ return true;
+ }
+
+ return false;
+}
diff --git a/util/ipa_krb5.h b/util/ipa_krb5.h
index 7d2ebae98..d0280940a 100644
--- a/util/ipa_krb5.h
+++ b/util/ipa_krb5.h
@@ -174,3 +174,7 @@ static inline bool
krb5_ts_after(krb5_timestamp a, krb5_timestamp b) {
return (uint32_t)a > (uint32_t)b;
}
+
+/* Implement boolean string parsing function from MIT krb5:
+ * src/lib/krb5/krb/libdef_parse.c:_krb5_conf_boolean() */
+bool ipa_krb5_parse_bool(const char *str);
--
2.45.1

View File

@ -1,127 +0,0 @@
diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py
index 6f5e349..febc22f 100644
--- a/ipaserver/plugins/user.py
+++ b/ipaserver/plugins/user.py
@@ -144,8 +144,7 @@ PROTECTED_USERS = ('admin',)
def check_protected_member(user, protected_group_name=u'admins'):
'''
Ensure admin and the last enabled member of a protected group cannot
- be deleted or disabled by raising ProtectedEntryError or
- LastMemberError as appropriate.
+ be deleted.
'''
if user in PROTECTED_USERS:
@@ -155,6 +154,12 @@ def check_protected_member(user, protected_group_name=u'admins'):
reason=_("privileged user"),
)
+
+def check_last_member(user, protected_group_name=u'admins'):
+ '''
+ Ensure the last enabled member of a protected group cannot
+ be disabled.
+ '''
# Get all users in the protected group
result = api.Command.user_find(in_group=protected_group_name)
@@ -796,6 +801,7 @@ class user_del(baseuser_del):
# If the target entry is a Delete entry, skip the orphaning/removal
# of OTP tokens.
check_protected_member(keys[-1])
+ check_last_member(keys[-1])
preserve = options.get('preserve', False)
@@ -1128,7 +1134,7 @@ class user_disable(LDAPQuery):
def execute(self, *keys, **options):
ldap = self.obj.backend
- check_protected_member(keys[-1])
+ check_last_member(keys[-1])
dn, _oc = self.obj.get_either_dn(*keys, **options)
ldap.deactivate_entry(dn)
diff --git a/ipatests/test_integration/test_commands.py b/ipatests/test_integration/test_commands.py
index c0cb4d0..c2a55b8 100644
--- a/ipatests/test_integration/test_commands.py
+++ b/ipatests/test_integration/test_commands.py
@@ -1530,6 +1530,30 @@ class TestIPACommand(IntegrationTest):
assert 'Discovered server %s' % self.master.hostname in result
+ def test_delete_last_enabled_admin(self):
+ """
+ The admin user may be disabled. Don't allow all other
+ members of admins to be removed if the admin user is
+ disabled which would leave the install with no
+ usable admins users
+ """
+ user = 'adminuser2'
+ passwd = 'Secret123'
+ tasks.create_active_user(self.master, user, passwd)
+ tasks.kinit_admin(self.master)
+ self.master.run_command(['ipa', 'group-add-member', 'admins',
+ '--users', user])
+ tasks.kinit_user(self.master, user, passwd)
+ self.master.run_command(['ipa', 'user-disable', 'admin'])
+ result = self.master.run_command(
+ ['ipa', 'user-del', user],
+ raiseonerr=False
+ )
+ self.master.run_command(['ipa', 'user-enable', 'admin'])
+ tasks.kdestroy_all(self.master)
+ assert result.returncode == 1
+ assert 'cannot be deleted or disabled' in result.stderr_text
+
class TestIPACommandWithoutReplica(IntegrationTest):
"""
diff --git a/ipatests/test_xmlrpc/test_user_plugin.py b/ipatests/test_xmlrpc/test_user_plugin.py
index 3c58845..68c6c48 100644
--- a/ipatests/test_xmlrpc/test_user_plugin.py
+++ b/ipatests/test_xmlrpc/test_user_plugin.py
@@ -1045,8 +1045,8 @@ class TestAdmins(XMLRPC_test):
tracker = Tracker()
command = tracker.make_command('user_disable', admin1)
- with raises_exact(errors.ProtectedEntryError(label=u'user',
- key=admin1, reason='privileged user')):
+ with raises_exact(errors.LastMemberError(label=u'group',
+ key=admin1, container=admin_group)):
command()
def test_create_admin2(self, admin2):
@@ -1064,8 +1064,8 @@ class TestAdmins(XMLRPC_test):
admin2.disable()
tracker = Tracker()
- with raises_exact(errors.ProtectedEntryError(label=u'user',
- key=admin1, reason='privileged user')):
+ with raises_exact(errors.LastMemberError(label=u'group',
+ key=admin1, container=admin_group)):
tracker.run_command('user_disable', admin1)
admin2.delete()
diff --git a/ipatests/test_webui/test_user.py b/ipatests/test_webui/test_user.py
index a8a92d0..9083e50 100644
--- a/ipatests/test_webui/test_user.py
+++ b/ipatests/test_webui/test_user.py
@@ -50,6 +50,8 @@ 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_DISABLE = ('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'
@@ -546,7 +548,7 @@ class test_user(user_tasks):
self.select_record('admin')
self.facet_button_click('disable')
self.dialog_button_click('ok')
- self.assert_last_error_dialog(ERR_ADMIN_DEL, details=True)
+ self.assert_last_error_dialog(ERR_ADMIN_DISABLE, details=True)
self.dialog_button_click('ok')
self.assert_record('admin')

View File

@ -1,13 +0,0 @@
diff --git a/ipaserver/install/ipa_otptoken_import.py b/ipaserver/install/ipa_otptoken_import.py
index b3f9347..75e8680 100644
--- a/ipaserver/install/ipa_otptoken_import.py
+++ b/ipaserver/install/ipa_otptoken_import.py
@@ -539,7 +539,7 @@ class OTPTokenImport(admintool.AdminTool):
# Load the keyfile.
keyfile = self.safe_options.keyfile
- with open(keyfile) as f:
+ with open(keyfile, "rb") as f:
self.doc.setKey(f.read())
def run(self):

View File

@ -1,114 +0,0 @@
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 38693c9..35cec89 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -1327,6 +1327,8 @@ class CAInstance(DogtagInstance):
generation master:
- in CS.cfg ca.crl.MasterCRL.enableCRLCache=true
- in CS.cfg ca.crl.MasterCRL.enableCRLUpdates=true
+ - in CS.cfg ca.listenToCloneModifications=true
+ - in CS.cfg ca.certStatusUpdateInterval != 0
- in /etc/httpd/conf.d/ipa-pki-proxy.conf the RewriteRule
^/ipa/crl/MasterCRL.bin is disabled (commented or removed)
@@ -1342,15 +1344,30 @@ class CAInstance(DogtagInstance):
updates = directivesetter.get_directive(
self.config, 'ca.crl.MasterCRL.enableCRLUpdates', '=')
enableCRLUpdates = updates.lower() == 'true'
+ listen = directivesetter.get_directive(
+ self.config, 'ca.listenToCloneModifications', '=')
+ enableToClone = listen.lower() == 'true'
+ updateinterval = directivesetter.get_directive(
+ self.config, 'ca.certStatusUpdateInterval', '=')
# If the values are different, the config is inconsistent
- if enableCRLCache != enableCRLUpdates:
+ if not (enableCRLCache == enableCRLUpdates == enableToClone):
raise InconsistentCRLGenConfigException(
"Configuration is inconsistent, please check "
- "ca.crl.MasterCRL.enableCRLCache and "
- "ca.crl.MasterCRL.enableCRLUpdates in {} and "
+ "ca.crl.MasterCRL.enableCRLCache, "
+ "ca.crl.MasterCRL.enableCRLUpdates and "
+ "ca.listenToCloneModifications in {} and "
"run ipa-crlgen-manage [enable|disable] to repair".format(
self.config))
+ # If they are the same then we are the CRL renewal master. Ensure
+ # the update task is configured.
+ if enableCRLCache and updateinterval == '0':
+ raise InconsistentCRLGenConfigException(
+ "Configuration is inconsistent, please check "
+ "ca.certStatusUpdateInterval in {}. It should "
+ "be either not present or not zero. Run "
+ "ipa-crlgen-manage [enable|disable] to repair".format(
+ self.config))
except IOError:
raise RuntimeError(
"Unable to read {}".format(self.config))
@@ -1407,6 +1424,11 @@ class CAInstance(DogtagInstance):
str_value = str(setup_crlgen).lower()
ds.set('ca.crl.MasterCRL.enableCRLCache', str_value)
ds.set('ca.crl.MasterCRL.enableCRLUpdates', str_value)
+ ds.set('ca.listenToCloneModifications', str_value)
+ if setup_crlgen:
+ ds.set('ca.certStatusUpdateInterval', None)
+ else:
+ ds.set('ca.certStatusUpdateInterval', '0')
# Start pki-tomcat
logger.info("Starting %s", self.service_name)
diff --git a/ipatests/test_integration/test_crlgen_manage.py b/ipatests/test_integration/test_crlgen_manage.py
index 2a733bd..c6f41eb 100644
--- a/ipatests/test_integration/test_crlgen_manage.py
+++ b/ipatests/test_integration/test_crlgen_manage.py
@@ -61,6 +61,16 @@ def check_crlgen_status(host, rc=0, msg=None, enabled=True, check_crl=False):
ext.value.crl_number)
assert number_msg in result.stdout_text
+ try:
+ value = get_CS_cfg_value(host, 'ca.certStatusUpdateInterval')
+ except IOError:
+ return
+
+ if enabled:
+ assert value is None
+ else:
+ assert value == '0'
+
def check_crlgen_enable(host, rc=0, msg=None, check_crl=False):
"""Check ipa-crlgen-manage enable command
@@ -125,6 +135,23 @@ def break_crlgen_with_CS_cfg(host):
check_crlgen_status(host, rc=1, msg="Configuration is inconsistent")
+def get_CS_cfg_value(host, directive):
+ """Retrieve and return the a directive from the CA CS.cfg
+
+ This returns None if the directives is not found.
+ """
+ content = host.get_file_contents(paths.CA_CS_CFG_PATH,
+ encoding='utf-8')
+ value = None
+ for line in content.split('\n'):
+ l = line.lower()
+
+ if l.startswith(directive.lower()):
+ value = line.split('=', 1)[1]
+
+ return value
+
+
class TestCRLGenManage(IntegrationTest):
"""Tests the ipa-crlgen-manage command.
@@ -196,6 +223,9 @@ class TestCRLGenManage(IntegrationTest):
Install a CA clone and enable CRLgen"""
tasks.install_ca(self.replicas[0])
+ value = get_CS_cfg_value(self.replicas[0],
+ 'ca.certStatusUpdateInterval')
+ assert value == '0'
check_crlgen_enable(
self.replicas[0], rc=0,
msg="make sure to have only a single CRL generation master",

View File

@ -1,337 +0,0 @@
diff --git a/ipaserver/plugins/idrange.py b/ipaserver/plugins/idrange.py
index d5b184f..b38ea73 100644
--- a/ipaserver/plugins/idrange.py
+++ b/ipaserver/plugins/idrange.py
@@ -549,6 +549,12 @@ class idrange_add(LDAPCreate):
self.obj.handle_ipabaserid(entry_attrs, options)
self.obj.handle_iparangetype(entry_attrs, options,
keep_objectclass=True)
+ self.add_message(
+ messages.ServiceRestartRequired(
+ service=services.knownservices.dirsrv.service_instance(""),
+ server=_('<all IPA servers>')
+ )
+ )
return dn
diff --git a/ipatests/test_xmlrpc/test_range_plugin.py b/ipatests/test_xmlrpc/test_range_plugin.py
index f912e04..e3f4c23 100644
--- a/ipatests/test_xmlrpc/test_range_plugin.py
+++ b/ipatests/test_xmlrpc/test_range_plugin.py
@@ -372,6 +372,8 @@ IPA_LOCAL_RANGE_MOD_ERR = (
"domain. Run `ipa help idrange` for more information"
)
+dirsrv_instance = services.knownservices.dirsrv.service_instance("")
+
@pytest.mark.tier1
class test_range(Declarative):
@@ -464,6 +466,11 @@ class test_range(Declarative):
),
value=testrange1,
summary=u'Added ID range "%s"' % (testrange1),
+ messages=(
+ messages.ServiceRestartRequired(
+ service=dirsrv_instance,
+ server='<all IPA servers>').to_dict(),
+ ),
),
),
@@ -633,6 +640,11 @@ class test_range(Declarative):
),
value=testrange2,
summary=u'Added ID range "%s"' % (testrange2),
+ messages=(
+ messages.ServiceRestartRequired(
+ service=dirsrv_instance,
+ server='<all IPA servers>').to_dict(),
+ ),
),
),
@@ -792,6 +804,11 @@ class test_range(Declarative):
),
value=unicode(domain7range1),
summary=u'Added ID range "%s"' % (domain7range1),
+ messages=(
+ messages.ServiceRestartRequired(
+ service=dirsrv_instance,
+ server='<all IPA servers>').to_dict(),
+ ),
),
),
@@ -1079,6 +1096,11 @@ class test_range(Declarative):
),
value=testrange9,
summary=u'Added ID range "%s"' % (testrange9),
+ messages=(
+ messages.ServiceRestartRequired(
+ service=dirsrv_instance,
+ server='<all IPA servers>').to_dict(),
+ ),
),
),
diff --git a/ipaserver/plugins/idrange.py b/ipaserver/plugins/idrange.py
index b38ea73..b12e1b8 100644
--- a/ipaserver/plugins/idrange.py
+++ b/ipaserver/plugins/idrange.py
@@ -549,12 +549,15 @@ class idrange_add(LDAPCreate):
self.obj.handle_ipabaserid(entry_attrs, options)
self.obj.handle_iparangetype(entry_attrs, options,
keep_objectclass=True)
- self.add_message(
- messages.ServiceRestartRequired(
- service=services.knownservices.dirsrv.service_instance(""),
- server=_('<all IPA servers>')
+
+ if entry_attrs.single_value.get('iparangetype') in (
+ 'ipa-local', self.obj.range_types.get('ipa-local', None)):
+ self.add_message(
+ messages.ServiceRestartRequired(
+ service=services.knownservices.dirsrv.service_instance(""),
+ server=_('<all IPA servers>')
+ )
)
- )
return dn
@@ -568,7 +571,8 @@ class idrange_del(LDAPDelete):
try:
old_attrs = ldap.get_entry(dn, ['ipabaseid',
'ipaidrangesize',
- 'ipanttrusteddomainsid'])
+ 'ipanttrusteddomainsid',
+ 'iparangetype'])
except errors.NotFound:
raise self.obj.handle_not_found(*keys)
@@ -602,6 +606,20 @@ class idrange_del(LDAPDelete):
key=keys[0],
dependent=trust_domains[0].dn[0].value)
+ self.add_message(
+ messages.ServiceRestartRequired(
+ service=services.knownservices['sssd'].systemd_name,
+ server=_('<all IPA servers>')
+ )
+ )
+
+ if old_attrs.single_value.get('iparangetype') == 'ipa-local':
+ self.add_message(
+ messages.ServiceRestartRequired(
+ service=services.knownservices.dirsrv.service_instance(""),
+ server=_('<all IPA servers>')
+ )
+ )
return dn
@@ -804,10 +822,20 @@ class idrange_mod(LDAPUpdate):
assert isinstance(dn, DN)
self.obj.handle_ipabaserid(entry_attrs, options)
self.obj.handle_iparangetype(entry_attrs, options)
+
+ if entry_attrs.single_value.get('iparangetype') in (
+ 'ipa-local', self.obj.range_types.get('ipa-local', None)):
+ self.add_message(
+ messages.ServiceRestartRequired(
+ service=services.knownservices.dirsrv.service_instance(""),
+ server=_('<all IPA servers>')
+ )
+ )
+
self.add_message(
messages.ServiceRestartRequired(
service=services.knownservices['sssd'].systemd_name,
- server=keys[0]
+ server=_('<all IPA servers>')
)
)
return dn
diff --git a/ipatests/test_xmlrpc/test_range_plugin.py b/ipatests/test_xmlrpc/test_range_plugin.py
index e3f4c23..531fe4a 100644
--- a/ipatests/test_xmlrpc/test_range_plugin.py
+++ b/ipatests/test_xmlrpc/test_range_plugin.py
@@ -26,7 +26,8 @@ import six
from ipalib import api, errors, messages
from ipalib import constants
from ipaplatform import services
-from ipatests.test_xmlrpc.xmlrpc_test import Declarative, fuzzy_uuid
+from ipatests.test_xmlrpc.xmlrpc_test import (
+ Declarative, fuzzy_uuid, Fuzzy, fuzzy_sequence_of)
from ipatests.test_xmlrpc import objectclasses
from ipatests.util import MockLDAP
from ipapython.dn import DN
@@ -374,6 +375,8 @@ IPA_LOCAL_RANGE_MOD_ERR = (
dirsrv_instance = services.knownservices.dirsrv.service_instance("")
+fuzzy_restart_messages = fuzzy_sequence_of(Fuzzy(type=dict))
+
@pytest.mark.tier1
class test_range(Declarative):
@@ -610,7 +613,8 @@ class test_range(Declarative):
desc='Delete ID range %r' % testrange1,
command=('idrange_del', [testrange1], {}),
expected=dict(
- result=dict(failed=[]),
+ result=dict(failed=[],
+ messages=fuzzy_restart_messages),
value=[testrange1],
summary=u'Deleted ID range "%s"' % testrange1,
),
@@ -714,7 +718,8 @@ class test_range(Declarative):
desc='Delete ID range %r' % testrange2,
command=('idrange_del', [testrange2], {}),
expected=dict(
- result=dict(failed=[]),
+ result=dict(failed=[],
+ messages=fuzzy_restart_messages),
value=[testrange2],
summary=u'Deleted ID range "%s"' % testrange2,
),
diff --git a/ipatests/test_xmlrpc/test_range_plugin.py b/ipatests/test_xmlrpc/test_range_plugin.py
index 531fe4a..3646952 100644
--- a/ipatests/test_xmlrpc/test_range_plugin.py
+++ b/ipatests/test_xmlrpc/test_range_plugin.py
@@ -613,8 +613,8 @@ class test_range(Declarative):
desc='Delete ID range %r' % testrange1,
command=('idrange_del', [testrange1], {}),
expected=dict(
- result=dict(failed=[],
- messages=fuzzy_restart_messages),
+ result=dict(failed=[]),
+ messages=fuzzy_restart_messages,
value=[testrange1],
summary=u'Deleted ID range "%s"' % testrange1,
),
@@ -718,8 +718,8 @@ class test_range(Declarative):
desc='Delete ID range %r' % testrange2,
command=('idrange_del', [testrange2], {}),
expected=dict(
- result=dict(failed=[],
- messages=fuzzy_restart_messages),
+ result=dict(failed=[]),
+ messages=fuzzy_restart_messages,
value=[testrange2],
summary=u'Deleted ID range "%s"' % testrange2,
),
@@ -809,11 +809,6 @@ class test_range(Declarative):
),
value=unicode(domain7range1),
summary=u'Added ID range "%s"' % (domain7range1),
- messages=(
- messages.ServiceRestartRequired(
- service=dirsrv_instance,
- server='<all IPA servers>').to_dict(),
- ),
),
),
@@ -836,6 +831,7 @@ class test_range(Declarative):
result=dict(failed=[]),
value=[domain1range1],
summary=u'Deleted ID range "%s"' % domain1range1,
+ messages=fuzzy_restart_messages,
),
),
@@ -862,12 +858,7 @@ class test_range(Declarative):
command=('idrange_mod', [domain3range2],
dict(ipabaseid=domain3range1_base_id)),
expected=dict(
- messages=(
- messages.ServiceRestartRequired(
- service=services.knownservices['sssd'].systemd_name,
- server=domain3range2
- ).to_dict(),
- ),
+ messages=fuzzy_restart_messages,
result=dict(
cn=[domain3range2],
ipabaseid=[unicode(domain3range1_base_id)],
@@ -933,12 +924,7 @@ class test_range(Declarative):
command=('idrange_mod', [domain2range1],
dict(ipabaserid=domain5range1_base_rid)),
expected=dict(
- messages=(
- messages.ServiceRestartRequired(
- service=services.knownservices['sssd'].systemd_name,
- server=domain2range1
- ).to_dict(),
- ),
+ messages=fuzzy_restart_messages,
result=dict(
cn=[domain2range1],
ipabaseid=[unicode(domain2range1_base_id)],
@@ -973,12 +959,7 @@ class test_range(Declarative):
command=('idrange_mod', [domain2range1],
dict(ipaautoprivategroups='true')),
expected=dict(
- messages=(
- messages.ServiceRestartRequired(
- service=services.knownservices['sssd'].systemd_name,
- server=domain2range1
- ).to_dict(),
- ),
+ messages=fuzzy_restart_messages,
result=dict(
cn=[domain2range1],
ipabaseid=[unicode(domain2range1_base_id)],
@@ -1000,12 +981,7 @@ class test_range(Declarative):
command=('idrange_mod', [domain2range1],
dict(ipaautoprivategroups='false')),
expected=dict(
- messages=(
- messages.ServiceRestartRequired(
- service=services.knownservices['sssd'].systemd_name,
- server=domain2range1
- ).to_dict(),
- ),
+ messages=fuzzy_restart_messages,
result=dict(
cn=[domain2range1],
ipabaseid=[unicode(domain2range1_base_id)],
@@ -1027,12 +1003,7 @@ class test_range(Declarative):
command=('idrange_mod', [domain2range1],
dict(ipaautoprivategroups='hybrid')),
expected=dict(
- messages=(
- messages.ServiceRestartRequired(
- service=services.knownservices['sssd'].systemd_name,
- server=domain2range1
- ).to_dict(),
- ),
+ messages=fuzzy_restart_messages,
result=dict(
cn=[domain2range1],
ipabaseid=[unicode(domain2range1_base_id)],
@@ -1054,12 +1025,7 @@ class test_range(Declarative):
command=('idrange_mod', [domain2range1],
dict(ipaautoprivategroups='')),
expected=dict(
- messages=(
- messages.ServiceRestartRequired(
- service=services.knownservices['sssd'].systemd_name,
- server=domain2range1
- ).to_dict(),
- ),
+ messages=fuzzy_restart_messages,
result=dict(
cn=[domain2range1],
ipabaseid=[unicode(domain2range1_base_id)],
@@ -1116,6 +1082,7 @@ class test_range(Declarative):
result=dict(failed=[]),
value=[testrange9],
summary=u'Deleted ID range "%s"' % testrange9,
+ messages=fuzzy_restart_messages,
),
),

View File

@ -1,58 +0,0 @@
diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py
index 619be83..9be1b67 100644
--- a/ipaserver/plugins/cert.py
+++ b/ipaserver/plugins/cert.py
@@ -55,7 +55,7 @@ from ipapython.dn import DN
from ipapython.ipautil import datetime_from_utctimestamp
from ipaserver.plugins.service import normalize_principal, validate_realm
from ipaserver.masters import (
- ENABLED_SERVICE, CONFIGURED_SERVICE, is_service_enabled
+ ENABLED_SERVICE, CONFIGURED_SERVICE, HIDDEN_SERVICE, is_service_enabled
)
try:
@@ -300,7 +300,7 @@ def caacl_check(principal, ca, profile_id):
def ca_kdc_check(api_instance, hostname):
master_dn = api_instance.Object.server.get_dn(unicode(hostname))
kdc_dn = DN(('cn', 'KDC'), master_dn)
- wanted = {ENABLED_SERVICE, CONFIGURED_SERVICE}
+ wanted = {ENABLED_SERVICE, CONFIGURED_SERVICE, HIDDEN_SERVICE}
try:
kdc_entry = api_instance.Backend.ldap2.get_entry(
kdc_dn, ['ipaConfigString'])
diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py
index b71f2d5..7ef44c5 100644
--- a/ipatests/test_integration/test_replica_promotion.py
+++ b/ipatests/test_integration/test_replica_promotion.py
@@ -26,6 +26,7 @@ from ipalib.constants import (
)
from ipaplatform.paths import paths
from ipapython import certdb
+from ipatests.test_integration.test_cert import get_certmonger_fs_id
from ipatests.test_integration.test_dns_locations import (
resolve_records_from_server, IPA_DEFAULT_MASTER_SRV_REC
)
@@ -1241,6 +1242,23 @@ class TestHiddenReplicaPromotion(IntegrationTest):
'ipa-crlgen-manage', 'status'])
assert "CRL generation: enabled" in result.stdout_text
+ def test_hidden_replica_renew_pkinit_cert(self):
+ """Renew the PKINIT cert on a hidden replica.
+
+ Test for https://pagure.io/freeipa/issue/9611
+ """
+ # Get Request ID
+ cmd = ['getcert', 'list', '-f', paths.KDC_CERT]
+ result = self.replicas[0].run_command(cmd)
+ req_id = get_certmonger_fs_id(result.stdout_text)
+
+ self.replicas[0].run_command([
+ 'getcert', 'resubmit', '-f', paths.KDC_CERT
+ ])
+ tasks.wait_for_certmonger_status(
+ self.replicas[0], ('MONITORING'), req_id, timeout=600
+ )
+
class TestHiddenReplicaKRA(IntegrationTest):
"""Test KRA & hidden replica features.

View File

@ -1,69 +0,0 @@
From 0d44e959e5bbe822b51137a8e7cf48fa25533805 Mon Sep 17 00:00:00 2001
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
Date: Fri, 10 Dec 2021 12:15:36 -0300
Subject: [PATCH] Revert "freeipa.spec: depend on bind-dnssec-utils"
This reverts commit f89d59b6e18b54967682f6a37ce92ae67ab3fcda.
---
freeipa.spec.in | 4 +---
ipaplatform/base/paths.py | 2 +-
ipaplatform/fedora/paths.py | 1 +
ipaserver/dnssec/bindmgr.py | 1 -
4 files changed, 3 insertions(+), 5 deletions(-)
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}
Requires: bind-dyndb-ldap >= 11.2-2
Requires: bind >= %{bind_version}
Requires: bind-utils >= %{bind_version}
-# bind-dnssec-utils is required by the OpenDNSSec integration
-# https://pagure.io/freeipa/issue/9026
-Requires: bind-dnssec-utils >= %{bind_version}
%if %{with bind_pkcs11}
Requires: bind-pkcs11 >= %{bind_version}
+Requires: bind-pkcs11-utils >= %{bind_version}
%else
Requires: softhsm >= %{softhsm_version}
Requires: openssl-pkcs11 >= %{openssl_pkcs11_version}
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:
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"
GETSEBOOL = "/usr/sbin/getsebool"
GROUPADD = "/usr/sbin/groupadd"
diff --git a/ipaplatform/fedora/paths.py b/ipaplatform/fedora/paths.py
index 4e993c063..92a948966 100644
--- a/ipaplatform/fedora/paths.py
+++ b/ipaplatform/fedora/paths.py
@@ -36,6 +36,7 @@ class FedoraPathNamespace(RedHatPathNamespace):
NAMED_CRYPTO_POLICY_FILE = "/etc/crypto-policies/back-ends/bind.config"
if HAS_NFS_CONF:
SYSCONFIG_NFS = '/etc/nfs.conf'
+ DNSSEC_KEYFROMLABEL = "/usr/sbin/dnssec-keyfromlabel"
paths = FedoraPathNamespace()
diff --git a/ipaserver/dnssec/bindmgr.py b/ipaserver/dnssec/bindmgr.py
index 0c79cc03d..a15c0e601 100644
--- a/ipaserver/dnssec/bindmgr.py
+++ b/ipaserver/dnssec/bindmgr.py
@@ -127,7 +127,6 @@ class BINDMgr:
)
cmd = [
paths.DNSSEC_KEYFROMLABEL,
- '-E', 'pkcs11',
'-K', workdir,
'-a', attrs['idnsSecAlgorithm'][0],
'-l', uri
--
2.31.1

View File

@ -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

View File

@ -1,120 +0,0 @@
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.
diff --git a/ipapython/dnsutil.py b/ipapython/dnsutil.py
index 58de365ab..4baeaf8cc 100644
--- a/ipapython/dnsutil.py 2023-05-19 05:12:52.471239297 -0300
+++ b/ipapython/dnsutil.py 2023-05-24 12:20:13.588867053 -0300
@@ -145,55 +145,6 @@
nameservers.remove(ipv4_loopback)
self.nameservers = nameservers
- @property
- def nameservers(self):
- return self._nameservers
-
- @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
- if hasattr(dns.resolver.Resolver, "nameservers"):
- dns.resolver.Resolver.nameservers.__set__(self, nameservers)
- else:
- # old dnspython (<2) doesn't have 'nameservers' property
- self._nameservers = 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 9070d89ad..5e7a46197 100644
--- a/ipatests/test_ipapython/test_dnsutil.py
+++ b/ipatests/test_ipapython/test_dnsutil.py
@@ -101,48 +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:
- @pytest.fixture(name="res")
- def resolver(self):
- """Resolver that doesn't read /etc/resolv.conf
-
- /etc/resolv.conf is not mandatory on systems
- """
- return dnsutil.DNSResolver(configure=False)
-
- def test_nameservers(self, res):
- 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):
- 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):
- 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")

View File

@ -0,0 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEE11Z2TU1+KXxtrRFyaYdvcqbi008FAmR+6S4ACgkQaYdvcqbi
008kvQ/9HuW6rWRJPY9/bqfaaeTKAT9JPCdq6jwDj7rSxpzJRE2r8vuwL3XxvXEa
8qW3qwx4qcBV3hrOPX3annilCgfyUN0ayF72rfDxGmVzTifooEVd0mmaDJOd9JHy
wLVYbImvsitC59luFF/XTIx5Xgo8Msu7BtAC5Tf5+mws0/i6ZxmyufYBPEmydgVM
jdpVSZfq4hd4HwfYH0Ej5c8sWfv2OTTENyBWn5x9LiWvC6rJi42u7ubcnWoCi6If
kXzJCRf7JTDzDvmMDVZMoTJCQa0EwlST7Yr9V7rLJViUGDwqxVO7VoeQi2WoV5PN
zDSoLoCVEgLdDt0EAYRlBxPzoe65kNBdGFhC3eT0uIO676NZuTMVEXaRtId1wfnU
o52xx3r5OPvRrjRLhKsAsMSiqX0Cr/wgH1L8QuSpriM1gMO6jZTkFpGtjD1XEvWd
VsiSVqR0y+E8U3bkLOTHvByPvWk9QlmN0e6WDyV0FvGPaPlD2VCGNLqraldeEKvr
wQxVvMWMqX+CKs2ZWYlzfgzFd0ZlUfsYhTcDaliJIh5Tcn5Ow+CSX/vWMXS6Msyh
80fS5k7NswIsa3bA0QSoFpAcSkNxxovKyIWpXamL/MgX/nqZqJE74aUtchANl9jd
j5yAU2s4eUuvbTMQkQjEJHl97a/jjGCGKnCunF/RO3WLaGdi9Dk=
=Bq0h
-----END PGP SIGNATURE-----

View File

@ -1,16 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEE11Z2TU1+KXxtrRFyaYdvcqbi008FAmVbZU0ACgkQaYdvcqbi
009Fgw/+PzHGNOJPs67TtoYITV/3ZCzMyrYTcazVACjD61Zw7JBgbZzZpQXxBSbj
7QWpNJa3P2JFtv2qOUXJto40mOGpMynyYpuYs4CtyJ86eHTUJyYTFppBmCzzozhT
2C2BeKKjzV8OOWQ7yO/2BTEZ7KtOcIr4ZI7iZCnLJF9Yt8x7TURjGRqxsHwT62Ip
vcrtm0LkkYv/fQ6pFZZfinKU1OBrZphwHMCU4Mlv411iQg4+NOxLSsVU/kegeKIO
adp4Y9g5dfAfdXEXb2Zt7gkmLaWMgf+XNSFDL/wkzRYt74HKwvbIPJQlTZ6pqLxQ
yTtiHGuMb7xNDWolpoueo1/lbxaHRRGJaSPs7zUht3IBxb7hiF65Gm3UaJhoeAXc
gVleZf/+0titOdkRfTD2N0P0hli7gaiRrbpw8K4joxMFpYrQGUxD8SI376gkOj6o
5RWSioPoG9txNM7Co+lVpci7WHhL+Tmhf1SlHyVJGKoNe/z4VHnjHeYlFWRVdDEI
OOupZzJQoLnso3lTwR5VEN8xGURnhbGV4MdUfD/6FhwmyHiPlYkytdZIsGsNDOab
978PPaKcIpbsZ4gUhshcbn7qaY809lNSpMtg8saYOP4J/5Nu+i9X5bJqOmoX0rKa
gAJDY5har+lExRnTEdYEGVB8qen5lqi8r1oYjnDpkSpq6BRoAHA=
=uQom
-----END PGP SIGNATURE-----

View File

@ -0,0 +1,39 @@
From f123b01d81696c52e9a4008d46e549864e4a8069 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Wed, 3 May 2023 10:47:19 +0300
Subject: [PATCH] updates: add ACIs for RBCD self-management
Fixes: https://pagure.io/freeipa/issue/9354
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Julien Rische <jrische@redhat.com>
---
install/updates/73-service-rbcd.update | 5 +++++
install/updates/Makefile.am | 1 +
2 files changed, 6 insertions(+)
create mode 100644 install/updates/73-service-rbcd.update
diff --git a/install/updates/73-service-rbcd.update b/install/updates/73-service-rbcd.update
new file mode 100644
index 00000000000..08a8b0f84a7
--- /dev/null
+++ b/install/updates/73-service-rbcd.update
@@ -0,0 +1,5 @@
+dn: $SUFFIX
+add:aci: (targetattr = "memberPrincipal")(targattrfilters="add=objectclass:(objectclass=resourcedelegation)")(version 3.0;acl "permission:RBCD:Kerberos principals can manage resource-based constrained delegation for themselves";allow (write) userdn = "ldap:///self";)
+add:aci: (targetattr = "memberPrincipal")(targattrfilters="add=objectclass:(objectclass=resourcedelegation)")(version 3.0;acl "permission:RBCD:Managing principals can manage resource-based constrained delegation for other principals";allow (write) userattr = "managedby#GROUPDN" or userattr = "managedby#USERDN";)
+add:aci: (targetattr = "memberPrincipal")(targattrfilters="add=objectclass:(objectclass=resourcedelegation)")(version 3.0;acl "permission:RBCD:Delegated permission to manage resource-based constrained delegation for other principals";allow (write) userattr="ipaAllowedToPerform;write_delegation#GROUPDN" or userattr="ipaAllowedToPerform;write_delegation#USERDN" ;)
+
diff --git a/install/updates/Makefile.am b/install/updates/Makefile.am
index fbc1b76ae4e..fd96831d8fd 100644
--- a/install/updates/Makefile.am
+++ b/install/updates/Makefile.am
@@ -66,6 +66,7 @@ app_DATA = \
73-subid.update \
73-winsync.update \
73-certmap.update \
+ 73-service-rbcd.update \
75-user-trust-attributes.update \
80-schema_compat.update \
81-externalmembers.update \

3309
SPECS/freeipa.spec Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff