diff --git a/.gitignore b/.gitignore index 6174b45..26693ca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -SOURCES/freeipa-4.5.4.tar.gz +SOURCES/freeipa-4.6.4.tar.gz SOURCES/header-logo.png SOURCES/login-screen-background.jpg SOURCES/login-screen-logo.png diff --git a/.ipa.metadata b/.ipa.metadata index 7ed498a..2d52a52 100644 --- a/.ipa.metadata +++ b/.ipa.metadata @@ -1,4 +1,4 @@ -2707c6f6de4ab05e1cbd741297b655e1d1ef1c24 SOURCES/freeipa-4.5.4.tar.gz +a3be356b119c9c5e223e4c077fad21e1dbc0ce92 SOURCES/freeipa-4.6.4.tar.gz 77c318cf1f4fc25cf847de0692a77859a767c0e3 SOURCES/header-logo.png 8727245558422bf966d60677568925f081b8e299 SOURCES/login-screen-background.jpg 24a29d79efbd0906777be4639957abda111fca4b SOURCES/login-screen-logo.png diff --git a/SOURCES/0001-Use-replace-instead-of-add-to-set-new-default-ipaSEL.patch b/SOURCES/0001-Use-replace-instead-of-add-to-set-new-default-ipaSEL.patch new file mode 100644 index 0000000..d3d5c74 --- /dev/null +++ b/SOURCES/0001-Use-replace-instead-of-add-to-set-new-default-ipaSEL.patch @@ -0,0 +1,89 @@ +From 463e5e73a27bb31e3549c9204efe20555b7cb8dd Mon Sep 17 00:00:00 2001 +From: Rob Crittenden <rcritten@redhat.com> +Date: Fri, 1 Jun 2018 15:19:35 -0400 +Subject: [PATCH] Use replace instead of add to set new default + ipaSELinuxUserMapOrder + +The add was in effect replacing whatever data was already there +causing any custom order to be lost on each run of +ipa-server-upgrade. + +https://pagure.io/freeipa/issue/6610 + +Signed-off-by: Rob Crittenden <rcritten@redhat.com> +Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> +Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> +--- + install/updates/50-ipaconfig.update | 2 +- + ipatests/test_integration/test_commands.py | 48 ++++++++++++++++++++++++++++++ + 2 files changed, 49 insertions(+), 1 deletion(-) + create mode 100644 ipatests/test_integration/test_commands.py + +diff --git a/install/updates/50-ipaconfig.update b/install/updates/50-ipaconfig.update +index 23d2919dbd976c34d9217fc31cca88a0df6c7f5b..18501cb7b8a87377a76bc53b7fe3c469c23e2d41 100644 +--- a/install/updates/50-ipaconfig.update ++++ b/install/updates/50-ipaconfig.update +@@ -1,5 +1,5 @@ + dn: cn=ipaConfig,cn=etc,$SUFFIX +-add:ipaSELinuxUserMapOrder: guest_u:s0$$xguest_u:s0$$user_u:s0$$staff_u:s0-s0:c0.c1023$$unconfined_u:s0-s0:c0.c1023 ++replace: ipaSELinuxUserMapOrder: guest_u:s0$$xguest_u:s0$$user_u:s0-s0:c0.c1023$$staff_u:s0-s0:c0.c1023$$unconfined_u:s0-s0:c0.c1023::ipaSELinuxUserMapOrder: guest_u:s0$$xguest_u:s0$$user_u:s0$$staff_u:s0-s0:c0.c1023$$unconfined_u:s0-s0:c0.c1023 + add:ipaSELinuxUserMapDefault: unconfined_u:s0-s0:c0.c1023 + add:ipaUserObjectClasses: ipasshuser + remove:ipaConfigString:AllowLMhash +diff --git a/ipatests/test_integration/test_commands.py b/ipatests/test_integration/test_commands.py +new file mode 100644 +index 0000000000000000000000000000000000000000..b2c0d5c710c9810cfd74216983f793808f4cf3c4 +--- /dev/null ++++ b/ipatests/test_integration/test_commands.py +@@ -0,0 +1,48 @@ ++# ++# Copyright (C) 2018 FreeIPA Contributors see COPYING for license ++# ++"""Misc test for 'ipa' CLI regressions ++""" ++from __future__ import absolute_import ++ ++from ipatests.test_integration.base import IntegrationTest ++ ++ ++class TestIPACommand(IntegrationTest): ++ """ ++ A lot of commands can be executed against a single IPA installation ++ so provide a generic class to execute one-off commands that need to be ++ tested without having to fire up a full server to run one command. ++ """ ++ topology = 'line' ++ ++ def test_change_selinuxusermaporder(self): ++ """ ++ An update file meant to ensure a more sane default was ++ overriding any customization done to the order. ++ """ ++ maporder = "unconfined_u:s0-s0:c0.c1023" ++ ++ # set a new default ++ result = self.master.run_command( ++ ["ipa", "config-mod", ++ "--ipaselinuxusermaporder={}".format(maporder)], ++ raiseonerr=False ++ ) ++ assert result.returncode == 0 ++ ++ # apply the update ++ result = self.master.run_command( ++ ["ipa-server-upgrade"], ++ raiseonerr=False ++ ) ++ assert result.returncode == 0 ++ ++ # ensure result is the same ++ result = self.master.run_command( ++ ["ipa", "config-show"], ++ raiseonerr=False ++ ) ++ assert result.returncode == 0 ++ assert "SELinux user map order: {}".format( ++ maporder) in result.stdout_text +-- +2.14.4 + diff --git a/SOURCES/0001-ds-ignore-time-skew-during-initial-replication-step.patch b/SOURCES/0001-ds-ignore-time-skew-during-initial-replication-step.patch deleted file mode 100644 index d641eb3..0000000 --- a/SOURCES/0001-ds-ignore-time-skew-during-initial-replication-step.patch +++ /dev/null @@ -1,86 +0,0 @@ -From a3bcb05ce1c554aa98af9343bec7335521db3a3e Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy <abokovoy@redhat.com> -Date: Mon, 16 Oct 2017 13:32:38 +0300 -Subject: [PATCH] ds: ignore time skew during initial replication step - -Initial replica creation can go with ignoring time skew checks. -We should, however, force time skew checks during normal operation. - -Fixes https://pagure.io/freeipa/issue/7211 - -Reviewed-By: Rob Crittenden <rcritten@redhat.com> ---- - install/share/Makefile.am | 1 + - install/share/replica-prevent-time-skew.ldif | 4 ++++ - ipaserver/install/dsinstance.py | 24 ++++++++++++++++++++++++ - 3 files changed, 29 insertions(+) - create mode 100644 install/share/replica-prevent-time-skew.ldif - -diff --git a/install/share/Makefile.am b/install/share/Makefile.am -index 85a061c6976dcc55b0ba2250423a344e14f2ce97..46b3d77663113f770765c8bd1d8a916791d628f4 100644 ---- a/install/share/Makefile.am -+++ b/install/share/Makefile.am -@@ -38,6 +38,7 @@ dist_app_DATA = \ - default-trust-view.ldif \ - delegation.ldif \ - replica-acis.ldif \ -+ replica-prevent-time-skew.ldif \ - ds-nfiles.ldif \ - dns.ldif \ - dnssec.ldif \ -diff --git a/install/share/replica-prevent-time-skew.ldif b/install/share/replica-prevent-time-skew.ldif -new file mode 100644 -index 0000000000000000000000000000000000000000..5d301feddb56347f3b35be89edaae1a7d91e07de ---- /dev/null -+++ b/install/share/replica-prevent-time-skew.ldif -@@ -0,0 +1,4 @@ -+dn: cn=config -+changetype: modify -+replace: nsslapd-ignore-time-skew -+nsslapd-ignore-time-skew: $SKEWVALUE -diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py -index c9db8ac28c3ca10539b745ca09f4d8aaece02e0c..7a88612997a3fa96cf394852401fb01e5e4501d5 100644 ---- a/ipaserver/install/dsinstance.py -+++ b/ipaserver/install/dsinstance.py -@@ -392,7 +392,21 @@ class DsInstance(service.Service): - self.step("restarting directory server", self.__restart_instance) - - self.step("creating DS keytab", self.request_service_keytab) -+ -+ # 389-ds allows to ignore time skew during replication. It is disabled -+ # by default to avoid issues with non-contiguous CSN values which -+ # derived from a time stamp when the change occurs. However, there are -+ # cases when we are interested only in the changes coming from the -+ # other side and should therefore allow ignoring the time skew. -+ # -+ # This helps with initial replication or force-sync because -+ # the receiving side has no valuable changes itself yet. -+ self.step("ignore time skew for initial replication", -+ self.__replica_ignore_initial_time_skew) -+ - self.step("setting up initial replication", self.__setup_replica) -+ self.step("prevent time skew after initial replication", -+ self.replica_manage_time_skew) - self.step("adding sasl mappings to the directory", self.__configure_sasl_mappings) - self.step("updating schema", self.__update_schema) - # See LDIFs for automember configuration during replica install -@@ -929,6 +943,16 @@ class DsInstance(service.Service): - def __add_replication_acis(self): - self._ldap_mod("replica-acis.ldif", self.sub_dict) - -+ def __replica_ignore_initial_time_skew(self): -+ self.replica_manage_time_skew(prevent=False) -+ -+ def replica_manage_time_skew(self, prevent=True): -+ if prevent: -+ self.sub_dict['SKEWVALUE'] = 'off' -+ else: -+ self.sub_dict['SKEWVALUE'] = 'on' -+ self._ldap_mod("replica-prevent-time-skew.ldif", self.sub_dict) -+ - def __setup_s4u2proxy(self): - self._ldap_mod("replica-s4u2proxy.ldif", self.sub_dict) - --- -2.9.5 - diff --git a/SOURCES/0002-Sort-and-shuffle-SRV-record-by-priority-and-weight.patch b/SOURCES/0002-Sort-and-shuffle-SRV-record-by-priority-and-weight.patch new file mode 100644 index 0000000..23b67a9 --- /dev/null +++ b/SOURCES/0002-Sort-and-shuffle-SRV-record-by-priority-and-weight.patch @@ -0,0 +1,438 @@ +From a56b9ef37dde90a593da6adbae2525048c5c8627 Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Fri, 15 Jun 2018 17:03:29 +0200 +Subject: [PATCH] Sort and shuffle SRV record by priority and weight + +On multiple occasions, SRV query answers were not properly sorted by +priority. Records with same priority weren't randomized and shuffled. +This caused FreeIPA to contact the same remote peer instead of +distributing the load across all available servers. + +Two new helper functions now take care of SRV queries. sort_prio_weight() +sorts SRV and URI records. query_srv() combines SRV lookup with +sort_prio_weight(). + +Fixes: https://pagure.io/freeipa/issue/7475 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +--- + ipaclient/install/ipadiscovery.py | 5 +- + ipalib/rpc.py | 21 +++---- + ipalib/util.py | 11 ++-- + ipapython/config.py | 8 +-- + ipapython/dnsutil.py | 92 ++++++++++++++++++++++++++- + ipaserver/dcerpc.py | 4 +- + ipatests/test_ipapython/test_dnsutil.py | 106 ++++++++++++++++++++++++++++++++ + 7 files changed, 217 insertions(+), 30 deletions(-) + create mode 100644 ipatests/test_ipapython/test_dnsutil.py + +diff --git a/ipaclient/install/ipadiscovery.py b/ipaclient/install/ipadiscovery.py +index 363970c86ba65b7ec49e403adc745fe61b2242aa..a8283d8e6ad070a8b6626a187ff55485bb74eba4 100644 +--- a/ipaclient/install/ipadiscovery.py ++++ b/ipaclient/install/ipadiscovery.py +@@ -20,7 +20,6 @@ + from __future__ import absolute_import + + import logging +-import operator + import socket + + import six +@@ -28,6 +27,7 @@ import six + from dns import resolver, rdatatype + from dns.exception import DNSException + from ipalib import errors ++from ipapython.dnsutil import query_srv + from ipapython import ipaldap + from ipaplatform.paths import paths + from ipapython.ipautil import valid_ip, realm_to_suffix +@@ -498,8 +498,7 @@ class IPADiscovery(object): + logger.debug("Search DNS for SRV record of %s", qname) + + try: +- answers = resolver.query(qname, rdatatype.SRV) +- answers = sorted(answers, key=operator.attrgetter('priority')) ++ answers = query_srv(qname) + except DNSException as e: + logger.debug("DNS record not found: %s", e.__class__.__name__) + answers = [] +diff --git a/ipalib/rpc.py b/ipalib/rpc.py +index c6a8989f5dc157f4c4e59637e6e7d114c5fa952c..17368f160148d6b821ec4934d31b4b4034a7e67b 100644 +--- a/ipalib/rpc.py ++++ b/ipalib/rpc.py +@@ -45,7 +45,6 @@ import gzip + from cryptography import x509 as crypto_x509 + + import gssapi +-from dns import resolver, rdatatype + from dns.exception import DNSException + from ssl import SSLError + import six +@@ -61,7 +60,7 @@ from ipalib.x509 import Encoding as x509_Encoding + from ipapython import ipautil + from ipapython import session_storage + from ipapython.cookie import Cookie +-from ipapython.dnsutil import DNSName ++from ipapython.dnsutil import DNSName, query_srv + from ipalib.text import _ + from ipalib.util import create_https_connection + from ipalib.krb_utils import KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN, KRB5KRB_AP_ERR_TKT_EXPIRED, \ +@@ -878,7 +877,7 @@ class RPCClient(Connectible): + name = '_ldap._tcp.%s.' % self.env.domain + + try: +- answers = resolver.query(name, rdatatype.SRV) ++ answers = query_srv(name) + except DNSException: + answers = [] + +@@ -886,17 +885,11 @@ class RPCClient(Connectible): + server = str(answer.target).rstrip(".") + servers.append('https://%s%s' % (ipautil.format_netloc(server), path)) + +- servers = list(set(servers)) +- # the list/set conversion won't preserve order so stick in the +- # local config file version here. +- cfg_server = rpc_uri +- if cfg_server in servers: +- # make sure the configured master server is there just once and +- # it is the first one +- servers.remove(cfg_server) +- servers.insert(0, cfg_server) +- else: +- servers.insert(0, cfg_server) ++ # make sure the configured master server is there just once and ++ # it is the first one. ++ if rpc_uri in servers: ++ servers.remove(rpc_uri) ++ servers.insert(0, rpc_uri) + + return servers + +diff --git a/ipalib/util.py b/ipalib/util.py +index ebf6eb3faf91cefc02514afa84ad9b63d0f82b0b..592821f9ff4f9c16fb2589d697e3e202443d0eba 100644 +--- a/ipalib/util.py ++++ b/ipalib/util.py +@@ -973,14 +973,13 @@ def detect_dns_zone_realm_type(api, domain): + + try: + # The presence of this record is enough, return foreign in such case +- result = resolver.query(ad_specific_record_name, rdatatype.SRV) +- return 'foreign' +- ++ resolver.query(ad_specific_record_name, rdatatype.SRV) + except DNSException: +- pass ++ # If we could not detect type with certainty, return unknown ++ return 'unknown' ++ else: ++ return 'foreign' + +- # If we could not detect type with certainity, return unknown +- return 'unknown' + + def has_managed_topology(api): + domainlevel = api.Command['domainlevel_get']().get('result', DOMAIN_LEVEL_0) +diff --git a/ipapython/config.py b/ipapython/config.py +index c3360779f1320e7d41f4d98b317d930a1d0b8242..f701122bd4828693a41848668e49052912042837 100644 +--- a/ipapython/config.py ++++ b/ipapython/config.py +@@ -26,7 +26,6 @@ from copy import copy + import socket + import functools + +-from dns import resolver, rdatatype + from dns.exception import DNSException + import dns.name + # pylint: disable=import-error +@@ -36,6 +35,7 @@ from six.moves.urllib.parse import urlsplit + + from ipaplatform.paths import paths + from ipapython.dn import DN ++from ipapython.dnsutil import query_srv + from ipapython.ipautil import CheckedIPAddress, CheckedIPAddressLoopback + + +@@ -210,7 +210,7 @@ def __discover_config(discover_server = True): + name = "_ldap._tcp." + domain + + try: +- servers = resolver.query(name, rdatatype.SRV) ++ servers = query_srv(name) + except DNSException: + # try cycling on domain components of FQDN + try: +@@ -225,7 +225,7 @@ def __discover_config(discover_server = True): + return False + name = "_ldap._tcp.%s" % domain + try: +- servers = resolver.query(name, rdatatype.SRV) ++ servers = query_srv(name) + break + except DNSException: + pass +@@ -236,7 +236,7 @@ def __discover_config(discover_server = True): + if not servers: + name = "_ldap._tcp.%s." % config.default_domain + try: +- servers = resolver.query(name, rdatatype.SRV) ++ servers = query_srv(name) + except DNSException: + pass + +diff --git a/ipapython/dnsutil.py b/ipapython/dnsutil.py +index b40302d0efbb32108626d2cc1216ad4858343407..6157183a0fa5802a5fb772f078ee4c1688857fc8 100644 +--- a/ipapython/dnsutil.py ++++ b/ipapython/dnsutil.py +@@ -17,12 +17,17 @@ + # along with this program. If not, see <http://www.gnu.org/licenses/>. + # + ++import copy + import logging ++import operator ++import random + + import dns.name + import dns.exception + import dns.resolver +-import copy ++import dns.rdataclass ++import dns.rdatatype ++ + + import six + +@@ -373,3 +378,88 @@ def check_zone_overlap(zone, raise_on_error=True): + if ns: + msg += u" and is handled by server(s): {0}".format(', '.join(ns)) + raise ValueError(msg) ++ ++ ++def _mix_weight(records): ++ """Weighted population sorting for records with same priority ++ """ ++ # trivial case ++ if len(records) <= 1: ++ return records ++ ++ # Optimization for common case: If all weights are the same (e.g. 0), ++ # just shuffle the records, which is about four times faster. ++ if all(rr.weight == records[0].weight for rr in records): ++ random.shuffle(records) ++ return records ++ ++ noweight = 0.01 # give records with 0 weight a small chance ++ result = [] ++ records = set(records) ++ while len(records) > 1: ++ # Compute the sum of the weights of those RRs. Then choose a ++ # uniform random number between 0 and the sum computed (inclusive). ++ urn = random.uniform(0, sum(rr.weight or noweight for rr in records)) ++ # Select the RR whose running sum value is the first in the selected ++ # order which is greater than or equal to the random number selected. ++ acc = 0. ++ for rr in records.copy(): ++ acc += rr.weight or noweight ++ if acc >= urn: ++ records.remove(rr) ++ result.append(rr) ++ if records: ++ result.append(records.pop()) ++ return result ++ ++ ++def sort_prio_weight(records): ++ """RFC 2782 sorting algorithm for SRV and URI records ++ ++ RFC 2782 defines a sorting algorithms for SRV records, that is also used ++ for sorting URI records. Records are sorted by priority and than randomly ++ shuffled according to weight. ++ ++ This implementation also removes duplicate entries. ++ """ ++ # order records by priority ++ records = sorted(records, key=operator.attrgetter("priority")) ++ ++ # remove duplicate entries ++ uniquerecords = [] ++ seen = set() ++ for rr in records: ++ # A SRV record has target and port, URI just has target. ++ target = (rr.target, getattr(rr, "port", None)) ++ if target not in seen: ++ uniquerecords.append(rr) ++ seen.add(target) ++ ++ # weighted randomization of entries with same priority ++ result = [] ++ sameprio = [] ++ for rr in uniquerecords: ++ # add all items with same priority in a bucket ++ if not sameprio or sameprio[0].priority == rr.priority: ++ sameprio.append(rr) ++ else: ++ # got different priority, shuffle bucket ++ result.extend(_mix_weight(sameprio)) ++ # start a new priority list ++ sameprio = [rr] ++ # add last batch of records with same priority ++ if sameprio: ++ result.extend(_mix_weight(sameprio)) ++ return result ++ ++ ++def query_srv(qname, resolver=None, **kwargs): ++ """Query SRV records and sort reply according to RFC 2782 ++ ++ :param qname: query name, _service._proto.domain. ++ :return: list of dns.rdtypes.IN.SRV.SRV instances ++ """ ++ if resolver is None: ++ resolver = dns.resolver ++ answer = resolver.query(qname, rdtype=dns.rdatatype.SRV, **kwargs) ++ return sort_prio_weight(answer) +diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py +index e3aa9f6a6c239f8606f09bde06f21cb9cf64eb14..1e2d6fbbb5372bea7c6d68b73acededfe714a56a 100644 +--- a/ipaserver/dcerpc.py ++++ b/ipaserver/dcerpc.py +@@ -32,6 +32,7 @@ from ipalib import api, _ + from ipalib import errors + from ipapython import ipautil + from ipapython.dn import DN ++from ipapython.dnsutil import query_srv + from ipapython.ipaldap import ldap_initialize + from ipaserver.install import installutils + from ipaserver.dcerpc_common import (TRUST_BIDIRECTIONAL, +@@ -55,7 +56,6 @@ import samba + import ldap as _ldap + from ipapython import ipaldap + from ipapython.dnsutil import DNSName +-from dns import resolver, rdatatype + from dns.exception import DNSException + import pysss_nss_idmap + import pysss +@@ -802,7 +802,7 @@ class DomainValidator(object): + gc_name = '_gc._tcp.%s.' % info['dns_domain'] + + try: +- answers = resolver.query(gc_name, rdatatype.SRV) ++ answers = query_srv(gc_name) + except DNSException as e: + answers = [] + +diff --git a/ipatests/test_ipapython/test_dnsutil.py b/ipatests/test_ipapython/test_dnsutil.py +new file mode 100644 +index 0000000000000000000000000000000000000000..36adb077cf38f6d036aa1048b201dee7d08eb310 +--- /dev/null ++++ b/ipatests/test_ipapython/test_dnsutil.py +@@ -0,0 +1,106 @@ ++# ++# Copyright (C) 2018 FreeIPA Contributors. See COPYING for license ++# ++import dns.name ++import dns.rdataclass ++import dns.rdatatype ++from dns.rdtypes.IN.SRV import SRV ++from dns.rdtypes.ANY.URI import URI ++ ++from ipapython import dnsutil ++ ++import pytest ++ ++ ++def mksrv(priority, weight, port, target): ++ return SRV( ++ rdclass=dns.rdataclass.IN, ++ rdtype=dns.rdatatype.SRV, ++ priority=priority, ++ weight=weight, ++ port=port, ++ target=dns.name.from_text(target) ++ ) ++ ++ ++def mkuri(priority, weight, target): ++ return URI( ++ rdclass=dns.rdataclass.IN, ++ rdtype=dns.rdatatype.URI, ++ priority=priority, ++ weight=weight, ++ target=target ++ ) ++ ++ ++class TestSortSRV(object): ++ def test_empty(self): ++ assert dnsutil.sort_prio_weight([]) == [] ++ ++ def test_one(self): ++ h1 = mksrv(1, 0, 443, u"host1") ++ assert dnsutil.sort_prio_weight([h1]) == [h1] ++ ++ h2 = mksrv(10, 5, 443, u"host2") ++ assert dnsutil.sort_prio_weight([h2]) == [h2] ++ ++ def test_prio(self): ++ h1 = mksrv(1, 0, 443, u"host1") ++ h2 = mksrv(2, 0, 443, u"host2") ++ h3 = mksrv(3, 0, 443, u"host3") ++ 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] ++ ++ h380 = mksrv(4, 0, 80, u"host3") ++ assert dnsutil.sort_prio_weight([h1, h3, h380]) == [h1, h3, h380] ++ ++ hs = mksrv(-1, 0, 443, u"special") ++ assert dnsutil.sort_prio_weight([h1, h2, hs]) == [hs, h1, h2] ++ ++ def assert_permutations(self, answers, permutations): ++ seen = set() ++ for _unused in range(1000): ++ result = tuple(dnsutil.sort_prio_weight(answers)) ++ assert result in permutations ++ seen.add(result) ++ if seen == permutations: ++ break ++ else: ++ pytest.fail("sorting didn't exhaust all permutations.") ++ ++ def test_sameprio(self): ++ h1 = mksrv(1, 0, 443, u"host1") ++ h2 = mksrv(1, 0, 443, u"host2") ++ permutations = { ++ (h1, h2), ++ (h2, h1), ++ } ++ self.assert_permutations([h1, h2], permutations) ++ ++ def test_weight(self): ++ h1 = mksrv(1, 0, 443, u"host1") ++ h2_w15 = mksrv(2, 15, 443, u"host2") ++ h3_w10 = mksrv(2, 10, 443, u"host3") ++ ++ permutations = { ++ (h1, h2_w15, h3_w10), ++ (h1, h3_w10, h2_w15), ++ } ++ self.assert_permutations([h1, h2_w15, h3_w10], permutations) ++ ++ def test_large(self): ++ records = tuple( ++ mksrv(1, i, 443, "host{}".format(i)) for i in range(1000) ++ ) ++ assert len(dnsutil.sort_prio_weight(records)) == len(records) ++ ++ ++class TestSortURI(object): ++ def test_prio(self): ++ h1 = mkuri(1, 0, u"https://host1/api") ++ h2 = mkuri(2, 0, u"https://host2/api") ++ h3 = mkuri(3, 0, u"https://host3/api") ++ 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] +-- +2.14.4 + diff --git a/SOURCES/0002-ipa-replica-manage-implicitly-ignore-initial-time-sk.patch b/SOURCES/0002-ipa-replica-manage-implicitly-ignore-initial-time-sk.patch deleted file mode 100644 index ecde808..0000000 --- a/SOURCES/0002-ipa-replica-manage-implicitly-ignore-initial-time-sk.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 469f8ba59eb369267a9d404291ce7794f996d9f4 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy <abokovoy@redhat.com> -Date: Mon, 16 Oct 2017 13:46:38 +0300 -Subject: [PATCH] ipa-replica-manage: implicitly ignore initial time skew in - force-sync - -When performing force synchronization, implicitly ignore initial -time skew (if any) and restore it afterwards. - -This also changes semantics of force-sync by waiting until the end of -the initial replication. - -Fixes https://pagure.io/freeipa/issue/7211 - -Reviewed-By: Rob Crittenden <rcritten@redhat.com> ---- - install/tools/ipa-replica-manage | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage -index f802201b7f93facb1e78463aa02eab66a1ae23ea..c00d8ca3a0fa8228c5aa782a270991f14ee16974 100755 ---- a/install/tools/ipa-replica-manage -+++ b/install/tools/ipa-replica-manage -@@ -1231,8 +1231,14 @@ def force_sync(realm, thishost, fromhost, dirman_passwd, nolookup=False): - repl = replication.ReplicationManager(realm, thishost, dirman_passwd) - repl.force_sync(repl.conn, fromhost) - else: -+ ds = dsinstance.DsInstance(realm_name=realm) -+ ds.ldapi = os.getegid() == 0 -+ ds.replica_manage_time_skew(prevent=False) - repl = replication.ReplicationManager(realm, fromhost, dirman_passwd) - repl.force_sync(repl.conn, thishost) -+ agreement = repl.get_replication_agreement(thishost) -+ repl.wait_for_repl_init(repl.conn, agreement.dn) -+ ds.replica_manage_time_skew(prevent=True) - - def show_DNA_ranges(hostname, master, realm, dirman_passwd, nextrange=False, - nolookup=False): --- -2.9.5 - diff --git a/SOURCES/0003-Checks-if-replica-s4u2proxy.ldif-should-be-applied.patch b/SOURCES/0003-Checks-if-replica-s4u2proxy.ldif-should-be-applied.patch deleted file mode 100644 index 475d399..0000000 --- a/SOURCES/0003-Checks-if-replica-s4u2proxy.ldif-should-be-applied.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 17fab4982fcb8b8af6c20130907dd3d4bad7f699 Mon Sep 17 00:00:00 2001 -From: Felipe Barreto <fbarreto@redhat.com> -Date: Fri, 13 Oct 2017 09:19:43 +0200 -Subject: [PATCH] Checks if replica-s4u2proxy.ldif should be applied - -Before applying replica-s3u2proxy.ldif, we check -if the values are already there. The values can be -there if a replica installation was done in the past -and some info was left behind. Also, the code checks -the values independently. - -https://pagure.io/freeipa/issue/7174 - -Reviewed-By: Rob Crittenden <rcritten@redhat.com> ---- - ipaserver/install/dsinstance.py | 19 ++++++++++++++++++- - 1 file changed, 18 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py -index 7a88612997a3fa96cf394852401fb01e5e4501d5..923f483340a26a614001701ce6c235dd73501501 100644 ---- a/ipaserver/install/dsinstance.py -+++ b/ipaserver/install/dsinstance.py -@@ -954,7 +954,24 @@ class DsInstance(service.Service): - self._ldap_mod("replica-prevent-time-skew.ldif", self.sub_dict) - - def __setup_s4u2proxy(self): -- self._ldap_mod("replica-s4u2proxy.ldif", self.sub_dict) -+ -+ def __add_principal(last_cn, principal, self): -+ dn = DN(('cn', last_cn), ('cn', 's4u2proxy'), -+ ('cn', 'etc'), self.suffix) -+ -+ value = '{principal}/{fqdn}@{realm}'.format(fqdn=self.fqdn, -+ realm=self.realm, -+ principal=principal) -+ -+ entry = api.Backend.ldap2.get_entry(dn, ['memberPrincipal']) -+ try: -+ entry['memberPrincipal'].append(value) -+ api.Backend.ldap2.update_entry(entry) -+ except errors.EmptyModlist: -+ pass -+ -+ __add_principal('ipa-http-delegation', 'HTTP', self) -+ __add_principal('ipa-ldap-delegation-targets', 'ldap', self) - - def __create_indices(self): - self._ldap_mod("indices.ldif") --- -2.9.5 - diff --git a/SOURCES/0003-Increase-WSGI-process-count-to-5-on-64bit.patch b/SOURCES/0003-Increase-WSGI-process-count-to-5-on-64bit.patch new file mode 100644 index 0000000..2c1575f --- /dev/null +++ b/SOURCES/0003-Increase-WSGI-process-count-to-5-on-64bit.patch @@ -0,0 +1,91 @@ +From f9d883b97b24efaf82e510601a4711bc9c0ea9c7 Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Thu, 14 Jun 2018 17:04:13 +0200 +Subject: [PATCH] Increase WSGI process count to 5 on 64bit + +Increase the WSGI daemon worker process count from 2 processes to 5 +processes. This allows IPA RPC to handle more parallel requests. The +additional processes increase memory consumption by approximante 250 MB +in total. + +Since memory is scarce on 32bit platforms, only 64bit platforms are +bumped to 5 workers. + +Fixes: https://pagure.io/freeipa/issue/7587 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> +--- + install/conf/ipa.conf | 2 +- + ipaplatform/base/constants.py | 5 +++++ + ipaserver/install/httpinstance.py | 1 + + ipaserver/install/server/upgrade.py | 3 ++- + 4 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/install/conf/ipa.conf b/install/conf/ipa.conf +index 696e5aab1aca1875eb711b91351f41987a8379d1..912a63c2240e0681dfbeeac223a902b15b304716 100644 +--- a/install/conf/ipa.conf ++++ b/install/conf/ipa.conf +@@ -47,7 +47,7 @@ WSGISocketPrefix /run/httpd/wsgi + + + # Configure mod_wsgi handler for /ipa +-WSGIDaemonProcess ipa processes=2 threads=1 maximum-requests=500 \ ++WSGIDaemonProcess ipa processes=$WSGI_PROCESSES threads=1 maximum-requests=500 \ + user=ipaapi group=ipaapi display-name=%{GROUP} socket-timeout=2147483647 \ + lang=C.UTF-8 locale=C.UTF-8 + WSGIImportScript /usr/share/ipa/wsgi.py process-group=ipa application-group=ipa +diff --git a/ipaplatform/base/constants.py b/ipaplatform/base/constants.py +index ca4a12ec017e81b32dc796062608a96ce65a0235..075a3ba774e1286e50258b464bd7687d484f6029 100644 +--- a/ipaplatform/base/constants.py ++++ b/ipaplatform/base/constants.py +@@ -5,9 +5,11 @@ + ''' + This base platform module exports platform dependant constants. + ''' ++import sys + + + class BaseConstantsNamespace(object): ++ IS_64BITS = sys.maxsize > 2 ** 32 + DS_USER = 'dirsrv' + DS_GROUP = 'dirsrv' + HTTPD_USER = "apache" +@@ -42,6 +44,9 @@ class BaseConstantsNamespace(object): + # WSGI module override, only used on Fedora + MOD_WSGI_PYTHON2 = None + MOD_WSGI_PYTHON3 = None ++ # WSGIDaemonProcess process count. On 64bit platforms, each process ++ # consumes about 110 MB RSS, from which are about 35 MB shared. ++ WSGI_PROCESSES = 5 if IS_64BITS else 2 + + + constants = BaseConstantsNamespace() +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index 231bffa2c6ec1fd124738649912e4bd958e802b7..3764870ee77f2ba0da18ec004664e6f66c13bba1 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -148,6 +148,7 @@ class HTTPInstance(service.Service): + DOMAIN=self.domain, + AUTOREDIR='' if auto_redirect else '#', + CRL_PUBLISH_PATH=paths.PKI_CA_PUBLISH_DIR, ++ WSGI_PROCESSES=constants.WSGI_PROCESSES, + ) + self.ca_file = ca_file + if ca_is_configured is not None: +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index ab09b98406df251f769c4747c9250075ab610362..ee3cedd78a2f45f33665bf562e9426cf68325544 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1681,7 +1681,8 @@ def upgrade_configuration(): + AUTOREDIR='' if auto_redirect else '#', + CRL_PUBLISH_PATH=paths.PKI_CA_PUBLISH_DIR, + DOGTAG_PORT=8009, +- CLONE='#' ++ CLONE='#', ++ WSGI_PROCESSES=constants.WSGI_PROCESSES, + ) + + subject_base = find_subject_base() +-- +2.14.4 + diff --git a/SOURCES/0004-Always-set-ca_host-when-installing-replica.patch b/SOURCES/0004-Always-set-ca_host-when-installing-replica.patch new file mode 100644 index 0000000..2023e60 --- /dev/null +++ b/SOURCES/0004-Always-set-ca_host-when-installing-replica.patch @@ -0,0 +1,43 @@ +From 5a5b232b721a68e37de2e25f134b8e585ad71393 Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Tue, 19 Jun 2018 19:10:27 +0200 +Subject: [PATCH] Always set ca_host when installing replica + +ipa-replica-install only set ca_host in its temporary +/etc/ipa/default.conf, when it wasn't installing a replica with CA. As a +consequence, the replica installer was picking a random CA server from +LDAP. + +Always set the replication peer as ca_host. This will ensure that the +installer uses the same replication peer for CA. In case the replication +peer is not a CA master, the installer will automatically pick another +host later. + +See: https://pagure.io/freeipa/issue/7566 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> +--- + ipaserver/install/server/replicainstall.py | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index e2a37bc4c8305c525f224f2fb80cb2629e8ece24..33f3ae9e616b34a3ab0ff8e4257552855e817e7c 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -241,11 +241,9 @@ def create_ipa_conf(fstore, config, ca_enabled, master=None): + gopts.extend([ + ipaconf.setOption('enable_ra', 'True'), + ipaconf.setOption('ra_plugin', 'dogtag'), +- ipaconf.setOption('dogtag_version', '10') ++ ipaconf.setOption('dogtag_version', '10'), ++ ipaconf.setOption('ca_host', config.ca_host_name) + ]) +- +- if not config.setup_ca: +- gopts.append(ipaconf.setOption('ca_host', config.ca_host_name)) + else: + gopts.extend([ + ipaconf.setOption('enable_ra', 'False'), +-- +2.14.4 + diff --git a/SOURCES/0004-ldap-limit-the-retro-changelog-to-dns-subtree.patch b/SOURCES/0004-ldap-limit-the-retro-changelog-to-dns-subtree.patch deleted file mode 100644 index 5fa10b1..0000000 --- a/SOURCES/0004-ldap-limit-the-retro-changelog-to-dns-subtree.patch +++ /dev/null @@ -1,32 +0,0 @@ -From d3c36fb83314c3fd1b87572a1c80687f06d7e2d5 Mon Sep 17 00:00:00 2001 -From: Tomas Krizek <tkrizek@redhat.com> -Date: Mon, 23 Oct 2017 14:06:20 +0200 -Subject: [PATCH] ldap: limit the retro changelog to dns subtree - -The content synchronization plugin can be limited to the dns subtree in -Directory Server. This increases performance and helps to prevent some -potential issues. - -Fixes: https://pagure.io/freeipa/issue/6515 -Signed-off-by: Tomas Krizek <tkrizek@redhat.com> -Reviewed-By: Rob Crittenden <rcritten@redhat.com> ---- - install/updates/20-syncrepl.update | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/install/updates/20-syncrepl.update b/install/updates/20-syncrepl.update -index faa13f645f492ea35824fe57632b56d52afa8a6e..318eda16870afa06d6c6d9098cbffdc085f2dba2 100644 ---- a/install/updates/20-syncrepl.update -+++ b/install/updates/20-syncrepl.update -@@ -4,7 +4,7 @@ only:nsslapd-pluginEnabled: on - # Remember original nsuniqueid for objects referenced from cn=changelog - add:nsslapd-attribute: nsuniqueid:targetUniqueId - add:nsslapd-changelogmaxage: 2d --add:nsslapd-exclude-suffix: o=ipaca -+add:nsslapd-include-suffix: cn=dns,$SUFFIX - - # Keep memberOf and referential integrity plugins away from cn=changelog. - # It is necessary for performance reasons because we don't have appropriate --- -2.9.5 - diff --git a/SOURCES/0005-Fix-ipa-replica-conncheck-when-called-with-principal.patch b/SOURCES/0005-Fix-ipa-replica-conncheck-when-called-with-principal.patch deleted file mode 100644 index f3f0bd7..0000000 --- a/SOURCES/0005-Fix-ipa-replica-conncheck-when-called-with-principal.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 20f2650a8a23d288571fde552ed1c242cd972d88 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud <flo@redhat.com> -Date: Fri, 27 Oct 2017 09:05:20 +0200 -Subject: [PATCH] Fix ipa-replica-conncheck when called with --principal - -ipa-replica-conncheck can be called with --principal / --password or -with an existing Kerberos credential cache in order to supply the -authorized identity logging in to the master machine (in -auto-master-check mode). - -In domain-level 0, the tool is called with --principal and password -and tries to obtain a TGT by performing kinit, but does not set the -env var KRB5CCNAME. Subsequent calls to IPA API do not use the -credential cache and fail. In this case, ipa-replica-conncheck falls -back to using SSH to check master connectivity instead of IPA API, -and the ssh check is less robust. - -The code should set the KRB5CCNAME env var for IPA API to use the -credential cache. - -Fixes: -https://pagure.io/freeipa/issue/7221 - -Reviewed-By: Rob Crittenden <rcritten@redhat.com> ---- - install/tools/ipa-replica-conncheck | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/install/tools/ipa-replica-conncheck b/install/tools/ipa-replica-conncheck -index 03281d1c7b6ee9f1d4cabebceb0c7e64b09601c0..545cdf00ca74289e6532a40de4c9abad5af4cee0 100755 ---- a/install/tools/ipa-replica-conncheck -+++ b/install/tools/ipa-replica-conncheck -@@ -534,6 +534,9 @@ def main(): - if result.returncode != 0: - raise RuntimeError("Could not get ticket for master server: %s" % - result.error_output) -+ # Now that the cred cache file is initialized, -+ # use it for the IPA API calls -+ os.environ['KRB5CCNAME'] = CCACHE_FILE - - try: - root_logger.info("Check RPC connection to remote master") --- -2.9.5 - diff --git a/SOURCES/0005-ipaserver-config-plugin-Increase-search-records-mini.patch b/SOURCES/0005-ipaserver-config-plugin-Increase-search-records-mini.patch new file mode 100644 index 0000000..0944ea8 --- /dev/null +++ b/SOURCES/0005-ipaserver-config-plugin-Increase-search-records-mini.patch @@ -0,0 +1,139 @@ +From 2461d69242108fe6f4bc067cc8255e41f66c58aa Mon Sep 17 00:00:00 2001 +From: Armando Neto <neto.armando@gmail.com> +Date: Mon, 18 Jun 2018 18:26:01 -0300 +Subject: [PATCH] ipaserver config plugin: Increase search records minimum + limit + +Check if the given search records value is greater than an arbitrary number that is not so close to zero. + +https://pagure.io/freeipa/issue/6617 + +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +--- + ipaserver/plugins/config.py | 14 +++++- + ipatests/test_xmlrpc/test_config_plugin.py | 76 ++++++++++++++++++++++++++++++ + 2 files changed, 89 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/plugins/config.py b/ipaserver/plugins/config.py +index 33ed38ba016567b9df57503f2f8418cf7c7fc794..d367c3c5aa421bb22d1630c88bbac846e7d84386 100644 +--- a/ipaserver/plugins/config.py ++++ b/ipaserver/plugins/config.py +@@ -85,6 +85,18 @@ EXAMPLES: + + register = Registry() + ++ ++def validate_search_records_limit(ugettext, value): ++ """Check if value is greater than a realistic minimum. ++ ++ Values 0 and -1 are valid, as they represent unlimited. ++ """ ++ if value in {-1, 0}: ++ return ++ if value < 10: ++ return _('must be at least 10') ++ ++ + @register() + class config(LDAPObject): + """ +@@ -161,10 +173,10 @@ class config(LDAPObject): + minvalue=-1, + ), + Int('ipasearchrecordslimit', ++ validate_search_records_limit, + cli_name='searchrecordslimit', + label=_('Search size limit'), + doc=_('Maximum number of records to search (-1 or 0 is unlimited)'), +- minvalue=-1, + ), + IA5Str('ipausersearchfields', + cli_name='usersearch', +diff --git a/ipatests/test_xmlrpc/test_config_plugin.py b/ipatests/test_xmlrpc/test_config_plugin.py +index c037224162e2c29f6dd76eabefe7fededc6f882d..666b7c2c87b4f0a1f7bde18c78780a1ea6072b71 100644 +--- a/ipatests/test_xmlrpc/test_config_plugin.py ++++ b/ipatests/test_xmlrpc/test_config_plugin.py +@@ -211,4 +211,80 @@ class test_config(Declarative): + summary=None, + ), + ), ++ dict( ++ desc='Set the number of search records to -1 (unlimited)', ++ command=( ++ 'config_mod', [], { ++ 'ipasearchrecordslimit': u'-1', ++ }, ++ ), ++ expected={ ++ 'result': lambda d: d['ipasearchrecordslimit'] == (u'-1',), ++ 'summary': None, ++ 'value': None, ++ }, ++ ), ++ dict( ++ desc='Set the number of search records to greater than 10', ++ command=( ++ 'config_mod', [], { ++ 'ipasearchrecordslimit': u'100', ++ }, ++ ), ++ expected={ ++ 'result': lambda d: d['ipasearchrecordslimit'] == (u'100',), ++ 'summary': None, ++ 'value': None, ++ }, ++ ), ++ dict( ++ desc='Set the number of search records to lower than -1', ++ command=( ++ 'config_mod', [], { ++ 'ipasearchrecordslimit': u'-10', ++ }, ++ ), ++ expected=errors.ValidationError( ++ name=u'searchrecordslimit', ++ error=u'must be at least 10', ++ ), ++ ), ++ dict( ++ desc='Set the number of search records to lower than 10', ++ command=( ++ 'config_mod', [], { ++ 'ipasearchrecordslimit': u'1', ++ }, ++ ), ++ expected=errors.ValidationError( ++ name=u'searchrecordslimit', ++ error=u'must be at least 10', ++ ), ++ ), ++ dict( ++ desc='Set the number of search records to zero (unlimited)', ++ command=( ++ 'config_mod', [], { ++ 'ipasearchrecordslimit': u'0', ++ }, ++ ), ++ expected={ ++ 'result': lambda d: d['ipasearchrecordslimit'] == (u'-1',), ++ 'summary': None, ++ 'value': None, ++ }, ++ ), ++ dict( ++ desc='Set the number of search records back to 100', ++ command=( ++ 'config_mod', [], { ++ 'ipasearchrecordslimit': u'100', ++ }, ++ ), ++ expected={ ++ 'result': lambda d: d['ipasearchrecordslimit'] == (u'100',), ++ 'summary': None, ++ 'value': None, ++ }, ++ ), + ] +-- +2.14.4 + diff --git a/SOURCES/0006-Improve-and-fix-timeout-bug-in-wait_for_entry.patch b/SOURCES/0006-Improve-and-fix-timeout-bug-in-wait_for_entry.patch new file mode 100644 index 0000000..dcff4e2 --- /dev/null +++ b/SOURCES/0006-Improve-and-fix-timeout-bug-in-wait_for_entry.patch @@ -0,0 +1,107 @@ +From b17a85bded822c4078a9b817720652807a939bc8 Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Fri, 22 Jun 2018 09:39:26 +0200 +Subject: [PATCH] Improve and fix timeout bug in wait_for_entry() + +replication.wait_for_entry() now can wait for an attribute value to +appear on a replica. + +Fixed timeout handling caused by bad rounding and comparison. For small +timeouts, the actual time was rounded down. For example for 60 seconds +timeout and fast replica, the query accumulated to about 0.45 seconds +plus 60 seconds sleep. 60.45 is large enough to terminate the loop +"while int(time.time()) < timeout", but not large enough to trigger the +exception in "if int(time.time()) > timeout", because int(60.65) == 60. + +See: https://pagure.io/freeipa/issue/7593 +Fixes: https://pagure.io/freeipa/issue/7595 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> +--- + ipaserver/install/replication.py | 54 +++++++++++++++++++++------------------- + 1 file changed, 29 insertions(+), 25 deletions(-) + +diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py +index 2e7ce53fef89093a7f661d846aa138ee330961e6..6d9878e16faab1b88a5ab79649571de6802c8536 100644 +--- a/ipaserver/install/replication.py ++++ b/ipaserver/install/replication.py +@@ -20,6 +20,7 @@ + from __future__ import print_function, absolute_import + + import logging ++import itertools + + import six + import time +@@ -160,40 +161,43 @@ def wait_for_task(conn, dn): + return exit_code + + +-def wait_for_entry(connection, dn, timeout=7200, attr='', quiet=True): +- """Wait for entry and/or attr to show up""" +- +- filter = "(objectclass=*)" ++def wait_for_entry(connection, dn, timeout=7200, attr=None, attrvalue='*', ++ quiet=True): ++ """Wait for entry and/or attr to show up ++ """ ++ log = logger.debug if quiet else logger.info + attrlist = [] +- if attr: +- filter = "(%s=*)" % attr ++ if attr is not None: ++ filterstr = ipaldap.LDAPClient.make_filter_from_attr(attr, attrvalue) + attrlist.append(attr) +- timeout += int(time.time()) +- +- if not quiet: +- sys.stdout.write("Waiting for %s %s:%s " % (connection, dn, attr)) +- sys.stdout.flush() +- entry = None +- while not entry and int(time.time()) < timeout: ++ else: ++ filterstr = "(objectclass=*)" ++ log("Waiting for replication (%s) %s %s", connection, dn, filterstr) ++ entry = [] ++ deadline = time.time() + timeout ++ for i in itertools.count(start=1): + try: +- [entry] = connection.get_entries( +- dn, ldap.SCOPE_BASE, filter, attrlist) ++ entry = connection.get_entries( ++ dn, ldap.SCOPE_BASE, filterstr, attrlist) + except errors.NotFound: + pass # no entry yet + except Exception as e: # badness + logger.error("Error reading entry %s: %s", dn, e) + raise +- if not entry: +- if not quiet: +- sys.stdout.write(".") +- sys.stdout.flush() +- time.sleep(1) + +- if not entry and int(time.time()) > timeout: +- raise errors.NotFound( +- reason="wait_for_entry timeout for %s for %s" % (connection, dn)) +- elif entry and not quiet: +- logger.error("The waited for entry is: %s", entry) ++ if entry: ++ log("Entry found %r", entry) ++ return ++ elif time.time() > deadline: ++ raise errors.NotFound( ++ reason="wait_for_entry timeout on {} for {}".format( ++ connection, dn ++ ) ++ ) ++ else: ++ if i % 10 == 0: ++ logger.debug("Still waiting for replication of %s", dn) ++ time.sleep(1) + + + class ReplicationManager(object): +-- +2.14.4 + diff --git a/SOURCES/0006-Include-the-CA-basic-constraint-in-CSRs-when-renewin.patch b/SOURCES/0006-Include-the-CA-basic-constraint-in-CSRs-when-renewin.patch deleted file mode 100644 index 794cb5f..0000000 --- a/SOURCES/0006-Include-the-CA-basic-constraint-in-CSRs-when-renewin.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 148e78d74206730c31dd7bc87eece5c5bd1440ac Mon Sep 17 00:00:00 2001 -From: Rob Crittenden <rcritten@redhat.com> -Date: Wed, 9 Aug 2017 17:28:35 -0400 -Subject: [PATCH] Include the CA basic constraint in CSRs when renewing a CA - -The CSR generated by `ipa-cacert-manage renew --external-ca` did -not include the CA basic constraint: - - X509v3 Basic Constraints: critical - CA:TRUE - -Add a flag to certmonger::resubmit_request to specify that a -CA is being requested. - -Note that this also sets pathlen to -1 which means an unlimited -pathlen. Leave it up to the issuing CA to set this. - -https://pagure.io/freeipa/issue/7088 - -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> ---- - ipalib/install/certmonger.py | 13 +++++++++++-- - ipaserver/install/ipa_cacert_manage.py | 3 ++- - 2 files changed, 13 insertions(+), 3 deletions(-) - -diff --git a/ipalib/install/certmonger.py b/ipalib/install/certmonger.py -index c286996ee2318e241b4af190d1a01f42e28aa9f3..d2b782ddb0c746a3dfd96d0222bb31c6a960fdff 100644 ---- a/ipalib/install/certmonger.py -+++ b/ipalib/install/certmonger.py -@@ -519,16 +519,25 @@ def modify(request_id, ca=None, profile=None): - request.obj_if.modify(update) - - --def resubmit_request(request_id, ca=None, profile=None): -+def resubmit_request(request_id, ca=None, profile=None, is_ca=False): -+ """ -+ :param request_id: the certmonger numeric request ID -+ :param ca: the nickname for the certmonger CA, e.g. IPA or SelfSign -+ :param profile: the dogtag template profile to use, e.g. SubCA -+ :param is_ca: boolean that if True adds the CA basic constraint -+ """ - request = _get_request({'nickname': request_id}) - if request: -- if ca or profile: -+ if ca or profile or is_ca: - update = {} - if ca is not None: - cm = _certmonger() - update['CA'] = cm.obj_if.find_ca_by_nickname(ca) - if profile is not None: - update['template-profile'] = profile -+ if is_ca: -+ update['template-is-ca'] = True -+ update['template-ca-path-length'] = -1 # no path length - request.obj_if.modify(update) - request.obj_if.resubmit() - -diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py -index fcbf09155a3abc9ce9481aa2519ed39aaa6aa9bb..9607620d6c3e63b70b9e586f94282bf478c8c53e 100644 ---- a/ipaserver/install/ipa_cacert_manage.py -+++ b/ipaserver/install/ipa_cacert_manage.py -@@ -310,7 +310,8 @@ class CACertManage(admintool.AdminTool): - timeout = api.env.startup_timeout + 60 - - self.log.debug("resubmitting certmonger request '%s'", self.request_id) -- certmonger.resubmit_request(self.request_id, ca=ca, profile=profile) -+ certmonger.resubmit_request(self.request_id, ca=ca, profile=profile, -+ is_ca=True) - try: - state = certmonger.wait_for_request(self.request_id, timeout) - except RuntimeError: --- -2.9.5 - diff --git a/SOURCES/0007-Use-common-replication-wait-timeout-of-5min.patch b/SOURCES/0007-Use-common-replication-wait-timeout-of-5min.patch new file mode 100644 index 0000000..d09ecc8 --- /dev/null +++ b/SOURCES/0007-Use-common-replication-wait-timeout-of-5min.patch @@ -0,0 +1,123 @@ +From 08d27e373976f82e054d17a76b8653221c56225c Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Fri, 22 Jun 2018 10:00:24 +0200 +Subject: [PATCH] Use common replication wait timeout of 5min + +Instead of multiple timeout values all over the code base, all +replication waits now use a common timeout value from api.env of 5 +minutes. Waiting for HTTP/replica principal takes 90 to 120 seconds, so +5 minutes seem like a sufficient value for slow setups. + +Fixes: https://pagure.io/freeipa/issue/7595 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> +--- + ipalib/constants.py | 2 ++ + ipaserver/install/custodiainstance.py | 4 +++- + ipaserver/install/httpinstance.py | 6 +++++- + ipaserver/install/krbinstance.py | 13 ++++++++----- + ipaserver/install/replication.py | 6 ++++-- + 5 files changed, 22 insertions(+), 9 deletions(-) + +diff --git a/ipalib/constants.py b/ipalib/constants.py +index 9ae6e0aaaee0577372fe458feb7660e05c7fed4d..38ed57b3cc35afe536f90b1f4245fd73ad4d3740 100644 +--- a/ipalib/constants.py ++++ b/ipalib/constants.py +@@ -149,6 +149,8 @@ DEFAULT_CONFIG = ( + ('startup_timeout', 300), + # How long http connection should wait for reply [seconds]. + ('http_timeout', 30), ++ # How long to wait for an entry to appear on a replica ++ ('replication_wait_timeout', 300), + + # Web Application mount points + ('mount_ipa', '/ipa/'), +diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py +index c87306d2f48367031e888613b07c1091fc1a70f4..fcfe0908426bf71243974c384b0147eb763ad32f 100644 +--- a/ipaserver/install/custodiainstance.py ++++ b/ipaserver/install/custodiainstance.py +@@ -5,6 +5,7 @@ from __future__ import print_function, absolute_import + import enum + import logging + ++from ipalib import api + from ipaserver.secrets.kem import IPAKEMKeys, KEMLdap + from ipaserver.secrets.client import CustodiaClient + from ipaplatform.paths import paths +@@ -214,7 +215,8 @@ class CustodiaInstance(SimpleServiceInstance): + cli = self._get_custodia_client() + cli.fetch_key('dm/DMHash') + +- def _wait_keys(self, timeout=300): ++ def _wait_keys(self): ++ timeout = api.env.replication_wait_timeout + deadline = int(time.time()) + timeout + logger.info("Waiting up to %s seconds to see our keys " + "appear on host %s", timeout, self.ldap_uri) +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index 3764870ee77f2ba0da18ec004664e6f66c13bba1..bdd79b1dafda7de664eed664a18bf36c541212bc 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -644,4 +644,8 @@ class HTTPInstance(service.Service): + else: + remote_ldap.simple_bind(ipaldap.DIRMAN_DN, + self.dm_password) +- replication.wait_for_entry(remote_ldap, service_dn, timeout=60) ++ replication.wait_for_entry( ++ remote_ldap, ++ service_dn, ++ timeout=api.env.replication_wait_timeout ++ ) +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index 4a5a52dcc831c4edfe0cd52c44fb18bcb6adaef7..a356d5e0c1b96dc6511c335fc22a326a2133bdd8 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -399,13 +399,16 @@ class KrbInstance(service.Service): + def _wait_for_replica_kdc_entry(self): + master_dn = self.api.Object.server.get_dn(self.fqdn) + kdc_dn = DN(('cn', 'KDC'), master_dn) +- +- ldap_uri = 'ldap://{}'.format(self.master_fqdn) +- ++ ldap_uri = ipaldap.get_ldap_uri(self.master_fqdn) + with ipaldap.LDAPClient( +- ldap_uri, cacert=paths.IPA_CA_CRT) as remote_ldap: ++ ldap_uri, cacert=paths.IPA_CA_CRT, start_tls=True ++ ) as remote_ldap: + remote_ldap.gssapi_bind() +- replication.wait_for_entry(remote_ldap, kdc_dn, timeout=60) ++ replication.wait_for_entry( ++ remote_ldap, ++ kdc_dn, ++ timeout=api.env.replication_wait_timeout ++ ) + + def _call_certmonger(self, certmonger_ca='IPA'): + subject = str(DN(('cn', self.fqdn), self.subject_base)) +diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py +index 6d9878e16faab1b88a5ab79649571de6802c8536..5ce8fa689c1a6fd3b9d4cbddbd5454d36334b729 100644 +--- a/ipaserver/install/replication.py ++++ b/ipaserver/install/replication.py +@@ -161,7 +161,7 @@ def wait_for_task(conn, dn): + return exit_code + + +-def wait_for_entry(connection, dn, timeout=7200, attr=None, attrvalue='*', ++def wait_for_entry(connection, dn, timeout, attr=None, attrvalue='*', + quiet=True): + """Wait for entry and/or attr to show up + """ +@@ -751,7 +751,9 @@ class ReplicationManager(object): + # that we will have to set the memberof fixup task + self.need_memberof_fixup = True + +- wait_for_entry(a_conn, entry.dn) ++ wait_for_entry( ++ a_conn, entry.dn, timeout=api.env.replication_wait_timeout ++ ) + + def needs_memberof_fixup(self): + return self.need_memberof_fixup +-- +2.14.4 + diff --git a/SOURCES/0007-ipa-extdom-extop-refactor-nsswitch-operations.patch b/SOURCES/0007-ipa-extdom-extop-refactor-nsswitch-operations.patch deleted file mode 100644 index b98db3e..0000000 --- a/SOURCES/0007-ipa-extdom-extop-refactor-nsswitch-operations.patch +++ /dev/null @@ -1,1728 +0,0 @@ -From 8a80363e07b5c9309d785bf3b41f506f32a750a5 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy <abokovoy@redhat.com> -Date: Tue, 14 Nov 2017 12:44:02 +0200 -Subject: [PATCH] ipa-extdom-extop: refactor nsswitch operations - -Refactor nsswitch operations in ipa-extdom-extop plugin to allow use -of timeout-enabled nsswitch calls provided by libsss_nss_idmap. - -Standard POSIX nsswitch API has no way to cancel requests which may -cause ipa-extdom-extop requests to hang far too long and potentially -exhaust LDAP server workers. In addition, glibc nsswitch API iterates -through all nsswitch modules one by one and with multiple parallel -requests a lock up may happen in an unrelated nsswitch module like -nss_files.so.2. - -A solution to the latter issue is to directly load nss_sss.so.2 plugin -and utilize it. This, however, does not solve a problem with lack of -cancellable API. - -With SSSD 1.16.1, libsss_nss_idmap provides a timeout-enabled variant of -nsswitch API that is directly integrated with SSSD client side machinery -used by nss_sss.so.2. As result, this API can be used instead of loading -nss_sss.so.2 directly. - -To support older SSSD version, both direct loading of nss_sss.so.2 and -new timeout-enabled API are supported by this changeset. An API to -abstract both is designed to be a mix between internal glibc nsswitch -API and external nsswitch API that libsss_nss_idmap mimics. API does not -expose per-call timeout. Instead, it allows to set a timeout per -nsswitch operation context to reduce requirements on information -a caller has to maintain. - -A choice which API to use is made at configure time. - -In order to test the API, a cmocka test is updated to explicitly load -nss_files.so.2 as a backend. Since use of nss_sss.so.2 would always -depend on availablility of SSSD, predictable testing would not be -possible without it otherwise. Also, cmocka test does not use -nss_wrapper anymore because nss_wrapper overrides higher level glibc -nsswitch API while we are loading an individual nsswitch module -directly. - -As result, cmocka test overrides fopen() call used by nss_files.so.2 to -load /etc/passwd and /etc/group. An overridden version changes paths to -/etc/passwd and /etc/group to a local test_data/passwd and -test_data/group. This way we can continue testing a backend API for -ipa-extdom-extop with the same data as with nss_wrapper. - -Fixes https://pagure.io/freeipa/issue/5464 - -Reviewed-By: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Simo Sorce <ssorce@redhat.com> -Reviewed-By: Robbie Harwood <rharwood@redhat.com> ---- - configure.ac | 25 +- - .../ipa-slapi-plugins/ipa-extdom-extop/Makefile.am | 17 +- - .../ipa-extdom-extop/back_extdom.h | 79 ++++++ - .../ipa-extdom-extop/back_extdom_nss_sss.c | 276 +++++++++++++++++++++ - .../ipa-extdom-extop/back_extdom_sss_idmap.c | 260 +++++++++++++++++++ - .../ipa-extdom-extop/ipa_extdom.h | 13 +- - .../ipa-extdom-extop/ipa_extdom_cmocka_tests.c | 241 +++++++++++++++--- - .../ipa-extdom-extop/ipa_extdom_common.c | 242 +++++++++--------- - .../ipa-extdom-extop/ipa_extdom_extop.c | 17 ++ - .../ipa-extdom-extop/test_data/test_setup.sh | 3 - - freeipa.spec.in | 1 - - server.m4 | 10 + - 12 files changed, 994 insertions(+), 190 deletions(-) - create mode 100644 daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom.h - create mode 100644 daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_nss_sss.c - create mode 100644 daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c - delete mode 100644 daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/test_setup.sh - -diff --git a/configure.ac b/configure.ac -index e7a8b11153209fdfb4903cd3876e21a871a92f03..8a99b028886790aca211ddf164772920221f3ec7 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -140,30 +140,6 @@ PKG_CHECK_EXISTS(cmocka, - ) - AM_CONDITIONAL([HAVE_CMOCKA], [test x$have_cmocka = xyes]) - --dnl A macro to check presence of a cwrap (http://cwrap.org) wrapper on the system --dnl Usage: --dnl AM_CHECK_WRAPPER(name, conditional) --dnl If the cwrap library is found, sets the HAVE_$name conditional --AC_DEFUN([AM_CHECK_WRAPPER], --[ -- FOUND_WRAPPER=0 -- -- AC_MSG_CHECKING([for $1]) -- PKG_CHECK_EXISTS([$1], -- [ -- AC_MSG_RESULT([yes]) -- FOUND_WRAPPER=1 -- ], -- [ -- AC_MSG_RESULT([no]) -- AC_MSG_WARN([cwrap library $1 not found, some tests will not run]) -- ]) -- -- AM_CONDITIONAL($2, [ test x$FOUND_WRAPPER = x1]) --]) -- --AM_CHECK_WRAPPER(nss_wrapper, HAVE_NSS_WRAPPER) -- - dnl --------------------------------------------------------------------------- - dnl - Check for POPT - dnl --------------------------------------------------------------------------- -@@ -235,6 +211,7 @@ dnl --------------------------------------------------------------------------- - AM_COND_IF([ENABLE_SERVER], [ - m4_include(server.m4) - ]) -+AM_CONDITIONAL([USE_SSS_NSS_TIMEOUT], [test "x$ac_cv_have_decl_sss_nss_getpwnam_timeout" = xyes]) - - dnl --------------------------------------------------------------------------- - dnl - Check if IPA certauth plugin can be build -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am b/daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am -index 1213965c96607bf14c6c92ce592585aed1a125db..cbdd570eabeb12b95fdc26213a64749f9ba9fdde 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am -@@ -25,6 +25,7 @@ libipa_extdom_extop_la_SOURCES = \ - ipa_extdom.h \ - ipa_extdom_extop.c \ - ipa_extdom_common.c \ -+ back_extdom.h \ - $(NULL) - - libipa_extdom_extop_la_LDFLAGS = -avoid-version -@@ -34,20 +35,29 @@ libipa_extdom_extop_la_LIBADD = \ - $(SSSNSSIDMAP_LIBS) \ - $(NULL) - -+# We have two backends for nss operations: -+# (1) directly loading nss_sss.so.2 -+# (2) using timeout-enabled API from libsss_nss_idmap -+# We prefer (2) if available -+if USE_SSS_NSS_TIMEOUT -+libipa_extdom_extop_la_SOURCES += back_extdom_sss_idmap.c -+else -+libipa_extdom_extop_la_SOURCES += back_extdom_nss_sss.c -+endif -+ -+ - TESTS = - check_PROGRAMS = - - if HAVE_CMOCKA --if HAVE_NSS_WRAPPER --TESTS_ENVIRONMENT = . ./test_data/test_setup.sh; - TESTS += extdom_cmocka_tests - check_PROGRAMS += extdom_cmocka_tests - endif --endif - - extdom_cmocka_tests_SOURCES = \ - ipa_extdom_cmocka_tests.c \ - ipa_extdom_common.c \ -+ back_extdom_nss_sss.c \ - $(NULL) - extdom_cmocka_tests_CFLAGS = $(CMOCKA_CFLAGS) - extdom_cmocka_tests_LDFLAGS = \ -@@ -58,6 +68,7 @@ extdom_cmocka_tests_LDADD = \ - $(LDAP_LIBS) \ - $(DIRSRV_LIBS) \ - $(SSSNSSIDMAP_LIBS) \ -+ -ldl \ - $(NULL) - - -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom.h b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom.h -new file mode 100644 -index 0000000000000000000000000000000000000000..d2937c8c8ecf8b960b5b31e9449c719bfda86de4 ---- /dev/null -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom.h -@@ -0,0 +1,79 @@ -+/* -+ * Copyright 2017 Red Hat, Inc. -+ * -+ * This Program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License. -+ * -+ * This Program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this Program; if not, write to the -+ * -+ * Free Software Foundation, Inc. -+ * 59 Temple Place, Suite 330 -+ * Boston, MA 02111-1307 USA -+ * -+ */ -+ -+#ifndef BACK_EXTDOM_H -+#define BACK_EXTDOM_H -+#include <unistd.h> -+#include <pwd.h> -+#include <grp.h> -+ -+/* Possible results of lookup using a nss_* function. -+ * Note: don't include nss.h as its path gets overriden by NSS library */ -+enum nss_status { -+ NSS_STATUS_TRYAGAIN = -2, -+ NSS_STATUS_UNAVAIL, -+ NSS_STATUS_NOTFOUND, -+ NSS_STATUS_SUCCESS, -+ NSS_STATUS_RETURN -+}; -+ -+/* NSS backend operations implemented using either nss_sss.so.2 or libsss_nss_idmap API */ -+struct nss_ops_ctx; -+ -+int back_extdom_init_context(struct nss_ops_ctx **nss_context); -+void back_extdom_free_context(struct nss_ops_ctx **nss_context); -+void back_extdom_set_timeout(struct nss_ops_ctx *nss_context, -+ unsigned int timeout); -+void back_extdom_evict_user(struct nss_ops_ctx *nss_context, -+ const char *name); -+void back_extdom_evict_group(struct nss_ops_ctx *nss_context, -+ const char *name); -+ -+enum nss_status back_extdom_getpwnam(struct nss_ops_ctx *nss_context, -+ const char *name, struct passwd *pwd, -+ char *buffer, size_t buflen, -+ struct passwd **result, -+ int *lerrno); -+ -+enum nss_status back_extdom_getpwuid(struct nss_ops_ctx *nss_context, -+ uid_t uid, struct passwd *pwd, -+ char *buffer, size_t buflen, -+ struct passwd **result, -+ int *lerrno); -+ -+enum nss_status back_extdom_getgrnam(struct nss_ops_ctx *nss_context, -+ const char *name, struct group *grp, -+ char *buffer, size_t buflen, -+ struct group **result, -+ int *lerrno); -+ -+enum nss_status back_extdom_getgrgid(struct nss_ops_ctx *nss_context, -+ gid_t gid, struct group *grp, -+ char *buffer, size_t buflen, -+ struct group **result, -+ int *lerrno); -+ -+enum nss_status back_extdom_getgrouplist(struct nss_ops_ctx *nss_context, -+ const char *name, gid_t group, -+ gid_t *groups, int *ngroups, -+ int *lerrno); -+ -+#endif /* BACK_EXTDOM_H */ -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_nss_sss.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_nss_sss.c -new file mode 100644 -index 0000000000000000000000000000000000000000..346c7d4301a607c7bc07ca5a9c53fe84618ac8ad ---- /dev/null -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_nss_sss.c -@@ -0,0 +1,276 @@ -+/* -+ * Copyright 2013-2017 Red Hat, Inc. -+ * -+ * This Program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License. -+ * -+ * This Program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this Program; if not, write to the -+ * -+ * Free Software Foundation, Inc. -+ * 59 Temple Place, Suite 330 -+ * Boston, MA 02111-1307 USA -+ * -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif -+ -+#include <sys/types.h> -+#include <stdlib.h> -+#include <string.h> -+#include <time.h> -+#include <unistd.h> -+#include <dlfcn.h> -+#include <errno.h> -+#include <pwd.h> -+#include <grp.h> -+#include <sys/param.h> -+#include "back_extdom.h" -+ -+struct nss_ops_ctx { -+ void *dl_handle; -+ long int initgroups_start; -+ -+ enum nss_status (*getpwnam_r)(const char *name, struct passwd *result, -+ char *buffer, size_t buflen, int *errnop); -+ enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result, -+ char *buffer, size_t buflen, int *errnop); -+ enum nss_status (*getgrnam_r)(const char *name, struct group *result, -+ char *buffer, size_t buflen, int *errnop); -+ enum nss_status (*getgrgid_r)(gid_t gid, struct group *result, -+ char *buffer, size_t buflen, int *errnop); -+ enum nss_status (*initgroups_dyn)(const char *user, gid_t group, -+ long int *start, long int *size, -+ gid_t **groups, long int limit, -+ int *errnop); -+}; -+ -+void back_extdom_free_context(struct nss_ops_ctx **nss_context) -+{ -+ if ((nss_context == NULL) || (*nss_context == NULL)) { -+ return; -+ } -+ -+ if ((*nss_context)->dl_handle != NULL) { -+ dlclose((*nss_context)->dl_handle); -+ } -+ -+ free((*nss_context)); -+ *nss_context = NULL; -+} -+ -+int back_extdom_init_context(struct nss_ops_ctx **nss_context) -+{ -+ struct nss_ops_ctx *ctx = NULL; -+ -+ if (nss_context == NULL) { -+ return EINVAL; -+ } -+ -+ ctx = calloc(1, sizeof(struct nss_ops_ctx)); -+ if (ctx == NULL) { -+ return ENOMEM; -+ } -+ *nss_context = ctx; -+ -+ ctx->dl_handle = dlopen("libnss_sss.so.2", RTLD_NOW); -+ if (ctx->dl_handle == NULL) { -+ goto fail; -+ } -+ -+ ctx->getpwnam_r = dlsym(ctx->dl_handle, "_nss_sss_getpwnam_r"); -+ if (ctx->getpwnam_r == NULL) { -+ goto fail; -+ } -+ -+ ctx->getpwuid_r = dlsym(ctx->dl_handle, "_nss_sss_getpwuid_r"); -+ if (ctx->getpwuid_r == NULL) { -+ goto fail; -+ } -+ -+ ctx->getgrnam_r = dlsym(ctx->dl_handle, "_nss_sss_getgrnam_r"); -+ if (ctx->getgrnam_r == NULL) { -+ goto fail; -+ } -+ -+ ctx->getgrgid_r = dlsym(ctx->dl_handle, "_nss_sss_getgrgid_r"); -+ if (ctx->getgrgid_r == NULL) { -+ goto fail; -+ } -+ -+ ctx->initgroups_dyn = dlsym(ctx->dl_handle, "_nss_sss_initgroups_dyn"); -+ if (ctx->initgroups_dyn == NULL) { -+ goto fail; -+ } -+ -+ return 0; -+ -+fail: -+ back_extdom_free_context(nss_context); -+ -+ return EINVAL; -+} -+ -+ -+/* Following three functions cannot be implemented with nss_sss.so.2 -+ * As result, we simply do nothing here */ -+ -+void back_extdom_set_timeout(struct nss_ops_ctx *nss_context, -+ unsigned int timeout) { -+ /* no operation */ -+} -+ -+void back_extdom_evict_user(struct nss_ops_ctx *nss_context, -+ const char *name) { -+ /* no operation */ -+} -+ -+void back_extdom_evict_group(struct nss_ops_ctx *nss_context, -+ const char *name) { -+ /* no operation */ -+} -+ -+enum nss_status back_extdom_getpwnam(struct nss_ops_ctx *nss_context, -+ const char *name, struct passwd *pwd, -+ char *buffer, size_t buflen, -+ struct passwd **result, -+ int *lerrno) { -+ enum nss_status ret; -+ -+ if (nss_context == NULL) { -+ return NSS_STATUS_UNAVAIL; -+ } -+ -+ ret = nss_context->getpwnam_r(name, pwd, -+ buffer, buflen, -+ lerrno); -+ -+ if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) { -+ *result = pwd; -+ *lerrno = 0; -+ } -+ -+ return ret; -+} -+ -+enum nss_status back_extdom_getpwuid(struct nss_ops_ctx *nss_context, -+ uid_t uid, struct passwd *pwd, -+ char *buffer, size_t buflen, -+ struct passwd **result, -+ int *lerrno) { -+ enum nss_status ret; -+ -+ if (nss_context == NULL) { -+ return NSS_STATUS_UNAVAIL; -+ } -+ -+ ret = nss_context->getpwuid_r(uid, pwd, -+ buffer, buflen, -+ lerrno); -+ -+ if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) { -+ *result = pwd; -+ *lerrno = 0; -+ } -+ -+ return ret; -+} -+ -+enum nss_status back_extdom_getgrnam(struct nss_ops_ctx *nss_context, -+ const char *name, struct group *grp, -+ char *buffer, size_t buflen, -+ struct group **result, -+ int *lerrno) { -+ enum nss_status ret; -+ -+ if (nss_context == NULL) { -+ return NSS_STATUS_UNAVAIL; -+ } -+ -+ ret = nss_context->getgrnam_r(name, grp, -+ buffer, buflen, -+ lerrno); -+ -+ if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) { -+ *result = grp; -+ *lerrno = 0; -+ } -+ -+ return ret; -+} -+ -+enum nss_status back_extdom_getgrgid(struct nss_ops_ctx *nss_context, -+ gid_t gid, struct group *grp, -+ char *buffer, size_t buflen, -+ struct group **result, -+ int *lerrno) { -+ -+ enum nss_status ret; -+ -+ if (nss_context == NULL) { -+ return NSS_STATUS_UNAVAIL; -+ } -+ -+ ret = nss_context->getgrgid_r(gid, grp, -+ buffer, buflen, -+ lerrno); -+ -+ if ((ret == NSS_STATUS_SUCCESS) && (result != NULL)) { -+ *result = grp; -+ *lerrno = 0; -+ } -+ -+ return ret; -+} -+ -+enum nss_status back_extdom_getgrouplist(struct nss_ops_ctx *nss_context, -+ const char *name, gid_t group, -+ gid_t *groups, int *ngroups, -+ int *lerrno) { -+ -+ enum nss_status ret = NSS_STATUS_UNAVAIL; -+ long int tsize = MAX (1, *ngroups); -+ gid_t *newgroups = NULL; -+ -+ if (nss_context == NULL) { -+ return NSS_STATUS_UNAVAIL; -+ } -+ -+ newgroups = (gid_t *) calloc (tsize, sizeof (gid_t)); -+ if (newgroups == NULL) { -+ *lerrno = ENOMEM; -+ return NSS_STATUS_TRYAGAIN; -+ } -+ -+ newgroups[0] = group; -+ nss_context->initgroups_start = 1; -+ -+ ret = nss_context->initgroups_dyn(name, group, -+ &nss_context->initgroups_start, -+ &tsize, &newgroups, -+ -1, lerrno); -+ -+ (void) memcpy(groups, newgroups, -+ MIN(*ngroups, nss_context->initgroups_start) * sizeof(gid_t)); -+ free(newgroups); -+ -+ if (*ngroups < nss_context->initgroups_start) { -+ ret = NSS_STATUS_TRYAGAIN; -+ *lerrno = ERANGE; -+ } -+ -+ *ngroups = (int) nss_context->initgroups_start; -+ -+ nss_context->initgroups_start = 0; -+ -+ return ret; -+} -+ -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c -new file mode 100644 -index 0000000000000000000000000000000000000000..89c58ca2de333b26954d916836b57aed5d7e18fb ---- /dev/null -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c -@@ -0,0 +1,260 @@ -+/* -+ * Copyright 2013-2017 Red Hat, Inc. -+ * -+ * This Program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License. -+ * -+ * This Program is distributed in the hope that it will be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this Program; if not, write to the -+ * -+ * Free Software Foundation, Inc. -+ * 59 Temple Place, Suite 330 -+ * Boston, MA 02111-1307 USA -+ * -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif -+ -+#include <sys/types.h> -+#include <stdlib.h> -+#include <string.h> -+#include <time.h> -+#include <unistd.h> -+#include <errno.h> -+#include <pwd.h> -+#include <grp.h> -+#include "back_extdom.h" -+ -+/* SSSD only exposes *_timeout() variants if the following symbol is defined */ -+#define IPA_389DS_PLUGIN_HELPER_CALLS -+#include <sss_nss_idmap.h> -+ -+struct nss_ops_ctx { -+ unsigned int timeout; -+}; -+ -+static enum nss_status __convert_sss_nss2nss_status(int errcode) { -+ switch(errcode) { -+ case 0: -+ return NSS_STATUS_SUCCESS; -+ case ENOENT: -+ return NSS_STATUS_NOTFOUND; -+ case ETIME: -+ /* fall-through */ -+ case ERANGE: -+ return NSS_STATUS_TRYAGAIN; -+ case ETIMEDOUT: -+ /* fall-through */ -+ default: -+ return NSS_STATUS_UNAVAIL; -+ } -+ return NSS_STATUS_UNAVAIL; -+} -+ -+int back_extdom_init_context(struct nss_ops_ctx **nss_context) -+{ -+ struct nss_ops_ctx *ctx = NULL; -+ -+ if (nss_context == NULL) { -+ return EINVAL; -+ } -+ -+ ctx = calloc(1, sizeof(struct nss_ops_ctx)); -+ -+ if (ctx == NULL) { -+ return ENOMEM; -+ } -+ *nss_context = ctx; -+ return 0; -+} -+ -+void back_extdom_free_context(struct nss_ops_ctx **nss_context) -+{ -+ if ((nss_context == NULL) || (*nss_context == NULL)) { -+ return; -+ } -+ -+ free((*nss_context)); -+ *nss_context = NULL; -+} -+ -+ -+void back_extdom_set_timeout(struct nss_ops_ctx *nss_context, -+ unsigned int timeout) { -+ if (nss_context == NULL) { -+ return; -+ } -+ -+ nss_context->timeout = timeout; -+} -+ -+void back_extdom_evict_user(struct nss_ops_ctx *nss_context, -+ const char *name) { -+ if (nss_context == NULL) { -+ return; -+ } -+ -+ (void) sss_nss_getpwnam_timeout(name, NULL, -+ NULL, 0, -+ NULL, -+ SSS_NSS_EX_FLAG_INVALIDATE_CACHE, -+ nss_context->timeout); -+} -+ -+void back_extdom_evict_group(struct nss_ops_ctx *nss_context, -+ const char *name) { -+ if (nss_context == NULL) { -+ return; -+ } -+ -+ (void) sss_nss_getgrnam_timeout(name, NULL, -+ NULL, 0, -+ NULL, -+ SSS_NSS_EX_FLAG_INVALIDATE_CACHE, -+ nss_context->timeout); -+} -+ -+enum nss_status back_extdom_getpwnam(struct nss_ops_ctx *nss_context, -+ const char *name, struct passwd *pwd, -+ char *buffer, size_t buflen, -+ struct passwd **result, -+ int *lerrno) { -+ int ret = 0; -+ -+ if (nss_context == NULL) { -+ return NSS_STATUS_UNAVAIL; -+ } -+ -+ ret = sss_nss_getpwnam_timeout(name, pwd, -+ buffer, buflen, -+ result, -+ SSS_NSS_EX_FLAG_NO_FLAGS, -+ nss_context->timeout); -+ -+ /* SSSD uses the same infrastructure to handle sss_nss_get* calls -+ * as nss_sss.so.2 module where 'int *errno' is passed to the helper -+ * but writes down errno into return code so we propagate it in case -+ * of error and translate the return code */ -+ if (lerrno != NULL) { -+ *lerrno = ret; -+ } -+ return __convert_sss_nss2nss_status(ret); -+} -+ -+enum nss_status back_extdom_getpwuid(struct nss_ops_ctx *nss_context, -+ uid_t uid, struct passwd *pwd, -+ char *buffer, size_t buflen, -+ struct passwd **result, -+ int *lerrno) { -+ -+ int ret = 0; -+ -+ if (nss_context == NULL) { -+ return NSS_STATUS_UNAVAIL; -+ } -+ -+ ret = sss_nss_getpwuid_timeout(uid, pwd, -+ buffer, buflen, -+ result, -+ SSS_NSS_EX_FLAG_NO_FLAGS, -+ nss_context->timeout); -+ -+ /* SSSD uses the same infrastructure to handle sss_nss_get* calls -+ * as nss_sss.so.2 module where 'int *errno' is passed to the helper -+ * but writes down errno into return code so we propagate it in case -+ * of error and translate the return code */ -+ if (lerrno != NULL) { -+ *lerrno = ret; -+ } -+ return __convert_sss_nss2nss_status(ret); -+} -+ -+enum nss_status back_extdom_getgrnam(struct nss_ops_ctx *nss_context, -+ const char *name, struct group *grp, -+ char *buffer, size_t buflen, -+ struct group **result, -+ int *lerrno) { -+ -+ int ret = 0; -+ -+ if (nss_context == NULL) { -+ return NSS_STATUS_UNAVAIL; -+ } -+ -+ ret = sss_nss_getgrnam_timeout(name, grp, -+ buffer, buflen, -+ result, -+ SSS_NSS_EX_FLAG_NO_FLAGS, -+ nss_context->timeout); -+ -+ /* SSSD uses the same infrastructure to handle sss_nss_get* calls -+ * as nss_sss.so.2 module where 'int *errno' is passed to the helper -+ * but writes down errno into return code so we propagate it in case -+ * of error and translate the return code */ -+ if (lerrno != NULL) { -+ *lerrno = ret; -+ } -+ return __convert_sss_nss2nss_status(ret); -+} -+ -+enum nss_status back_extdom_getgrgid(struct nss_ops_ctx *nss_context, -+ gid_t gid, struct group *grp, -+ char *buffer, size_t buflen, -+ struct group **result, -+ int *lerrno) { -+ -+ int ret = 0; -+ -+ if (nss_context == NULL) { -+ return NSS_STATUS_UNAVAIL; -+ } -+ -+ ret = sss_nss_getgrgid_timeout(gid, grp, -+ buffer, buflen, -+ result, -+ SSS_NSS_EX_FLAG_NO_FLAGS, -+ nss_context->timeout); -+ -+ /* SSSD uses the same infrastructure to handle sss_nss_get* calls -+ * as nss_sss.so.2 module where 'int *errno' is passed to the helper -+ * but writes down errno into return code so we propagate it in case -+ * of error and translate the return code */ -+ if (lerrno != NULL) { -+ *lerrno = ret; -+ } -+ return __convert_sss_nss2nss_status(ret); -+} -+ -+enum nss_status back_extdom_getgrouplist(struct nss_ops_ctx *nss_context, -+ const char *name, gid_t group, -+ gid_t *groups, int *ngroups, -+ int *lerrno) { -+ int ret = 0; -+ -+ if (nss_context == NULL) { -+ return NSS_STATUS_UNAVAIL; -+ } -+ -+ ret = sss_nss_getgrouplist_timeout(name, group, -+ groups, ngroups, -+ SSS_NSS_EX_FLAG_NO_FLAGS, -+ nss_context->timeout); -+ -+ /* SSSD uses the same infrastructure to handle sss_nss_get* calls -+ * as nss_sss.so.2 module where 'int *errno' is passed to the helper -+ * but writes down errno into return code so we propagate it in case -+ * of error and translate the return code */ -+ if (lerrno != NULL) { -+ *lerrno = ret; -+ } -+ return __convert_sss_nss2nss_status(ret); -+} -+ -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h -index bc29f069816b0ce13578c9ae14c61edb832d44e4..bbc574747e8bbe045dfc9882198cb34b0bb8cab9 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h -@@ -150,10 +150,13 @@ struct extdom_res { - } data; - }; - -+struct nss_ops_ctx; -+ - struct ipa_extdom_ctx { - Slapi_ComponentId *plugin_id; - char *base_dn; - size_t max_nss_buf_size; -+ struct nss_ops_ctx *nss_ctx; - }; - - struct domain_info { -@@ -179,15 +182,15 @@ int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req, - struct berval **berval); - int pack_response(struct extdom_res *res, struct berval **ret_val); - int get_buffer(size_t *_buf_len, char **_buf); --int getpwnam_r_wrapper(size_t buf_max, const char *name, -+int getpwnam_r_wrapper(struct ipa_extdom_ctx *ctx, const char *name, - struct passwd *pwd, char **_buf, size_t *_buf_len); --int getpwuid_r_wrapper(size_t buf_max, uid_t uid, -+int getpwuid_r_wrapper(struct ipa_extdom_ctx *ctx, uid_t uid, - struct passwd *pwd, char **_buf, size_t *_buf_len); --int getgrnam_r_wrapper(size_t buf_max, const char *name, -+int getgrnam_r_wrapper(struct ipa_extdom_ctx *ctx, const char *name, - struct group *grp, char **_buf, size_t *_buf_len); --int getgrgid_r_wrapper(size_t buf_max, gid_t gid, -+int getgrgid_r_wrapper(struct ipa_extdom_ctx *ctx, gid_t gid, - struct group *grp, char **_buf, size_t *_buf_len); --int get_user_grouplist(const char *name, gid_t gid, -+int get_user_grouplist(struct ipa_extdom_ctx *ctx, const char *name, gid_t gid, - size_t *_ngroups, gid_t **_groups); - int pack_ber_sid(const char *sid, struct berval **berval); - int pack_ber_name(const char *domain_name, const char *name, -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c -index 526f903d2416e62ee5781909c234bd5ee2d89183..29699cfa390f5469d7c009388b90e68616cbf984 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c -@@ -19,6 +19,7 @@ - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -+#define _GNU_SOURCE - - #include <errno.h> - #include <stdarg.h> -@@ -31,24 +32,166 @@ - - - #include "ipa_extdom.h" -+#include "back_extdom.h" -+#include <stdio.h> -+#include <dlfcn.h> - - #define MAX_BUF (1024*1024*1024) -+struct test_data { -+ struct extdom_req *req; -+ struct ipa_extdom_ctx *ctx; -+}; -+ -+/* -+ * redefine logging for mocks -+ */ -+#ifdef __GNUC__ -+ __attribute__((format(printf, 3, 4))) -+#endif -+int slapi_log_error(int loglevel, char *subsystem, char *fmt, ...) -+{ -+ va_list ap; -+ va_start(ap, fmt); -+ vprint_error(fmt, ap); -+ va_end(ap); -+ return 0; -+} -+ -+ -+/* -+ * We cannot run cmocka tests against SSSD as that would require to set up SSSD -+ * and the rest of environment. Instead, we compile cmocka tests against -+ * back_extdom_nss_sss.c and re-define context initialization to use -+ * nsswrapper with our test data. -+ * -+ * This means we have to keep struct nss_ops_ctx definition in sync with tests! -+ */ -+ -+struct nss_ops_ctx { -+ void *dl_handle; -+ long int initgroups_start; -+ -+ enum nss_status (*getpwnam_r)(const char *name, struct passwd *result, -+ char *buffer, size_t buflen, int *errnop); -+ enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result, -+ char *buffer, size_t buflen, int *errnop); -+ enum nss_status (*getgrnam_r)(const char *name, struct group *result, -+ char *buffer, size_t buflen, int *errnop); -+ enum nss_status (*getgrgid_r)(gid_t gid, struct group *result, -+ char *buffer, size_t buflen, int *errnop); -+ enum nss_status (*initgroups_dyn)(const char *user, gid_t group, -+ long int *start, long int *size, -+ gid_t **groups, long int limit, -+ int *errnop); -+}; -+ -+int cmocka_extdom_init_context(struct nss_ops_ctx **nss_context) -+{ -+ struct nss_ops_ctx *ctx = NULL; -+ -+ if (nss_context == NULL) { -+ return -1; -+ } -+ -+ ctx = calloc(1, sizeof(struct nss_ops_ctx)); -+ -+ if (ctx == NULL) { -+ return ENOMEM; -+ } -+ *nss_context = ctx; -+ -+ ctx->dl_handle = dlopen("libnss_files.so.2", RTLD_NOW); -+ if (ctx->dl_handle == NULL) { -+ goto fail; -+ } -+ -+ ctx->getpwnam_r = dlsym(ctx->dl_handle, "_nss_files_getpwnam_r"); -+ if (ctx->getpwnam_r == NULL) { -+ goto fail; -+ } -+ -+ ctx->getpwuid_r = dlsym(ctx->dl_handle, "_nss_files_getpwuid_r"); -+ if (ctx->getpwuid_r == NULL) { -+ goto fail; -+ } -+ -+ ctx->getgrnam_r = dlsym(ctx->dl_handle, "_nss_files_getgrnam_r"); -+ if (ctx->getgrnam_r == NULL) { -+ goto fail; -+ } -+ -+ ctx->getgrgid_r = dlsym(ctx->dl_handle, "_nss_files_getgrgid_r"); -+ if (ctx->getgrgid_r == NULL) { -+ goto fail; -+ } -+ -+ ctx->initgroups_dyn = dlsym(ctx->dl_handle, "_nss_files_initgroups_dyn"); -+ if (ctx->initgroups_dyn == NULL) { -+ goto fail; -+ } -+ -+ return 0; -+ -+fail: -+ back_extdom_free_context(nss_context); -+ -+ return -1; -+} -+ -+struct { -+ const char *o, *n; -+} path_table[] = { -+ { .o = "/etc/passwd", .n = "./test_data/passwd"}, -+ { .o = "/etc/group", .n = "./test_data/group"}, -+ { .o = NULL, .n = NULL}}; -+ -+FILE *(*original_fopen)(const char*, const char*) = NULL; -+ -+FILE *fopen(const char *path, const char *mode) { -+ const char *_path = NULL; -+ -+ /* Do not handle before-main() cases */ -+ if (original_fopen == NULL) { -+ return NULL; -+ } -+ for(int i=0; path_table[i].o != NULL; i++) { -+ if (strcmp(path, path_table[i].o) == 0) { -+ _path = path_table[i].n; -+ break; -+ } -+ } -+ return (*original_fopen)(_path ? _path : path, mode); -+} -+ -+/* Attempt to initialize original_fopen before main() -+ * There is no explicit order when all initializers are called, -+ * so we might still be late here compared to a code in a shared -+ * library initializer, like libselinux */ -+void redefined_fopen_ctor (void) __attribute__ ((constructor)); -+void redefined_fopen_ctor(void) { -+ original_fopen = dlsym(RTLD_NEXT, "fopen"); -+} - - void test_getpwnam_r_wrapper(void **state) - { - int ret; - struct passwd pwd; - char *buf; -- size_t buf_len; -+ size_t buf_len, max_big_buf_len; -+ struct test_data *test_data; -+ -+ test_data = (struct test_data *) *state; - - ret = get_buffer(&buf_len, &buf); - assert_int_equal(ret, 0); - -- ret = getpwnam_r_wrapper(MAX_BUF, "non_exisiting_user", &pwd, &buf, -- &buf_len); -+ ret = getpwnam_r_wrapper(test_data->ctx, -+ "non_exisiting_user", &pwd, -+ &buf, &buf_len); - assert_int_equal(ret, ENOENT); - -- ret = getpwnam_r_wrapper(MAX_BUF, "user", &pwd, &buf, &buf_len); -+ ret = getpwnam_r_wrapper(test_data->ctx, -+ "user", &pwd, &buf, &buf_len); - assert_int_equal(ret, 0); - assert_string_equal(pwd.pw_name, "user"); - assert_string_equal(pwd.pw_passwd, "x"); -@@ -62,7 +205,8 @@ void test_getpwnam_r_wrapper(void **state) - ret = get_buffer(&buf_len, &buf); - assert_int_equal(ret, 0); - -- ret = getpwnam_r_wrapper(MAX_BUF, "user_big", &pwd, &buf, &buf_len); -+ ret = getpwnam_r_wrapper(test_data->ctx, -+ "user_big", &pwd, &buf, &buf_len); - assert_int_equal(ret, 0); - assert_string_equal(pwd.pw_name, "user_big"); - assert_string_equal(pwd.pw_passwd, "x"); -@@ -76,7 +220,11 @@ void test_getpwnam_r_wrapper(void **state) - ret = get_buffer(&buf_len, &buf); - assert_int_equal(ret, 0); - -- ret = getpwnam_r_wrapper(1024, "user_big", &pwd, &buf, &buf_len); -+ max_big_buf_len = test_data->ctx->max_nss_buf_size; -+ test_data->ctx->max_nss_buf_size = 1024; -+ ret = getpwnam_r_wrapper(test_data->ctx, -+ "user_big", &pwd, &buf, &buf_len); -+ test_data->ctx->max_nss_buf_size = max_big_buf_len; - assert_int_equal(ret, ERANGE); - free(buf); - } -@@ -86,15 +234,18 @@ void test_getpwuid_r_wrapper(void **state) - int ret; - struct passwd pwd; - char *buf; -- size_t buf_len; -+ size_t buf_len, max_big_buf_len; -+ struct test_data *test_data; -+ -+ test_data = (struct test_data *) *state; - - ret = get_buffer(&buf_len, &buf); - assert_int_equal(ret, 0); - -- ret = getpwuid_r_wrapper(MAX_BUF, 99999, &pwd, &buf, &buf_len); -+ ret = getpwuid_r_wrapper(test_data->ctx, 99999, &pwd, &buf, &buf_len); - assert_int_equal(ret, ENOENT); - -- ret = getpwuid_r_wrapper(MAX_BUF, 12345, &pwd, &buf, &buf_len); -+ ret = getpwuid_r_wrapper(test_data->ctx, 12345, &pwd, &buf, &buf_len); - assert_int_equal(ret, 0); - assert_string_equal(pwd.pw_name, "user"); - assert_string_equal(pwd.pw_passwd, "x"); -@@ -108,7 +259,7 @@ void test_getpwuid_r_wrapper(void **state) - ret = get_buffer(&buf_len, &buf); - assert_int_equal(ret, 0); - -- ret = getpwuid_r_wrapper(MAX_BUF, 12346, &pwd, &buf, &buf_len); -+ ret = getpwuid_r_wrapper(test_data->ctx, 12346, &pwd, &buf, &buf_len); - assert_int_equal(ret, 0); - assert_string_equal(pwd.pw_name, "user_big"); - assert_string_equal(pwd.pw_passwd, "x"); -@@ -122,7 +273,10 @@ void test_getpwuid_r_wrapper(void **state) - ret = get_buffer(&buf_len, &buf); - assert_int_equal(ret, 0); - -- ret = getpwuid_r_wrapper(1024, 12346, &pwd, &buf, &buf_len); -+ max_big_buf_len = test_data->ctx->max_nss_buf_size; -+ test_data->ctx->max_nss_buf_size = 1024; -+ ret = getpwuid_r_wrapper(test_data->ctx, 12346, &pwd, &buf, &buf_len); -+ test_data->ctx->max_nss_buf_size = max_big_buf_len; - assert_int_equal(ret, ERANGE); - free(buf); - } -@@ -132,15 +286,19 @@ void test_getgrnam_r_wrapper(void **state) - int ret; - struct group grp; - char *buf; -- size_t buf_len; -+ size_t buf_len, max_big_buf_len; -+ struct test_data *test_data; -+ -+ test_data = (struct test_data *) *state; - - ret = get_buffer(&buf_len, &buf); - assert_int_equal(ret, 0); - -- ret = getgrnam_r_wrapper(MAX_BUF, "non_exisiting_group", &grp, &buf, &buf_len); -+ ret = getgrnam_r_wrapper(test_data->ctx, -+ "non_exisiting_group", &grp, &buf, &buf_len); - assert_int_equal(ret, ENOENT); - -- ret = getgrnam_r_wrapper(MAX_BUF, "group", &grp, &buf, &buf_len); -+ ret = getgrnam_r_wrapper(test_data->ctx, "group", &grp, &buf, &buf_len); - assert_int_equal(ret, 0); - assert_string_equal(grp.gr_name, "group"); - assert_string_equal(grp.gr_passwd, "x"); -@@ -153,7 +311,7 @@ void test_getgrnam_r_wrapper(void **state) - ret = get_buffer(&buf_len, &buf); - assert_int_equal(ret, 0); - -- ret = getgrnam_r_wrapper(MAX_BUF, "group_big", &grp, &buf, &buf_len); -+ ret = getgrnam_r_wrapper(test_data->ctx, "group_big", &grp, &buf, &buf_len); - assert_int_equal(ret, 0); - assert_string_equal(grp.gr_name, "group_big"); - assert_string_equal(grp.gr_passwd, "x"); -@@ -165,7 +323,10 @@ void test_getgrnam_r_wrapper(void **state) - ret = get_buffer(&buf_len, &buf); - assert_int_equal(ret, 0); - -- ret = getgrnam_r_wrapper(1024, "group_big", &grp, &buf, &buf_len); -+ max_big_buf_len = test_data->ctx->max_nss_buf_size; -+ test_data->ctx->max_nss_buf_size = 1024; -+ ret = getgrnam_r_wrapper(test_data->ctx, "group_big", &grp, &buf, &buf_len); -+ test_data->ctx->max_nss_buf_size = max_big_buf_len; - assert_int_equal(ret, ERANGE); - free(buf); - } -@@ -175,15 +336,18 @@ void test_getgrgid_r_wrapper(void **state) - int ret; - struct group grp; - char *buf; -- size_t buf_len; -+ size_t buf_len, max_big_buf_len; -+ struct test_data *test_data; -+ -+ test_data = (struct test_data *) *state; - - ret = get_buffer(&buf_len, &buf); - assert_int_equal(ret, 0); - -- ret = getgrgid_r_wrapper(MAX_BUF, 99999, &grp, &buf, &buf_len); -+ ret = getgrgid_r_wrapper(test_data->ctx, 99999, &grp, &buf, &buf_len); - assert_int_equal(ret, ENOENT); - -- ret = getgrgid_r_wrapper(MAX_BUF, 11111, &grp, &buf, &buf_len); -+ ret = getgrgid_r_wrapper(test_data->ctx, 11111, &grp, &buf, &buf_len); - assert_int_equal(ret, 0); - assert_string_equal(grp.gr_name, "group"); - assert_string_equal(grp.gr_passwd, "x"); -@@ -196,7 +360,7 @@ void test_getgrgid_r_wrapper(void **state) - ret = get_buffer(&buf_len, &buf); - assert_int_equal(ret, 0); - -- ret = getgrgid_r_wrapper(MAX_BUF, 22222, &grp, &buf, &buf_len); -+ ret = getgrgid_r_wrapper(test_data->ctx, 22222, &grp, &buf, &buf_len); - assert_int_equal(ret, 0); - assert_string_equal(grp.gr_name, "group_big"); - assert_string_equal(grp.gr_passwd, "x"); -@@ -208,7 +372,10 @@ void test_getgrgid_r_wrapper(void **state) - ret = get_buffer(&buf_len, &buf); - assert_int_equal(ret, 0); - -- ret = getgrgid_r_wrapper(1024, 22222, &grp, &buf, &buf_len); -+ max_big_buf_len = test_data->ctx->max_nss_buf_size; -+ test_data->ctx->max_nss_buf_size = 1024; -+ ret = getgrgid_r_wrapper(test_data->ctx, 22222, &grp, &buf, &buf_len); -+ test_data->ctx->max_nss_buf_size = max_big_buf_len; - assert_int_equal(ret, ERANGE); - free(buf); - } -@@ -219,16 +386,21 @@ void test_get_user_grouplist(void **state) - size_t ngroups; - gid_t *groups; - size_t c; -+ struct test_data *test_data; -+ -+ test_data = (struct test_data *) *state; - - /* This is a bit odd behaviour of getgrouplist() it does not check if the - * user exists, only if memberships of the user can be found. */ -- ret = get_user_grouplist("non_exisiting_user", 23456, &ngroups, &groups); -+ ret = get_user_grouplist(test_data->ctx, -+ "non_exisiting_user", 23456, &ngroups, &groups); - assert_int_equal(ret, LDAP_SUCCESS); - assert_int_equal(ngroups, 1); - assert_int_equal(groups[0], 23456); - free(groups); - -- ret = get_user_grouplist("member0001", 23456, &ngroups, &groups); -+ ret = get_user_grouplist(test_data->ctx, -+ "member0001", 23456, &ngroups, &groups); - assert_int_equal(ret, LDAP_SUCCESS); - assert_int_equal(ngroups, 3); - assert_int_equal(groups[0], 23456); -@@ -236,14 +408,16 @@ void test_get_user_grouplist(void **state) - assert_int_equal(groups[2], 22222); - free(groups); - -- ret = get_user_grouplist("member0003", 23456, &ngroups, &groups); -+ ret = get_user_grouplist(test_data->ctx, -+ "member0003", 23456, &ngroups, &groups); - assert_int_equal(ret, LDAP_SUCCESS); - assert_int_equal(ngroups, 2); - assert_int_equal(groups[0], 23456); - assert_int_equal(groups[1], 22222); - free(groups); - -- ret = get_user_grouplist("user_big", 23456, &ngroups, &groups); -+ ret = get_user_grouplist(test_data->ctx, -+ "user_big", 23456, &ngroups, &groups); - assert_int_equal(ret, LDAP_SUCCESS); - assert_int_equal(ngroups, 1001); - assert_int_equal(groups[0], 23456); -@@ -253,11 +427,6 @@ void test_get_user_grouplist(void **state) - free(groups); - } - --struct test_data { -- struct extdom_req *req; -- struct ipa_extdom_ctx *ctx; --}; -- - static int extdom_req_setup(void **state) - { - struct test_data *test_data; -@@ -269,8 +438,14 @@ static int extdom_req_setup(void **state) - assert_non_null(test_data->req); - - test_data->ctx = calloc(sizeof(struct ipa_extdom_ctx), 1); -- assert_non_null(test_data->req); -+ assert_non_null(test_data->ctx); -+ -+ test_data->ctx->max_nss_buf_size = MAX_BUF; -+ -+ assert_int_equal(cmocka_extdom_init_context(&test_data->ctx->nss_ctx), 0); -+ assert_non_null(test_data->ctx->nss_ctx); - -+ back_extdom_set_timeout(test_data->ctx->nss_ctx, 10000); - *state = test_data; - - return 0; -@@ -283,6 +458,7 @@ static int extdom_req_teardown(void **state) - test_data = (struct test_data *) *state; - - free_req_data(test_data->req); -+ back_extdom_free_context(&test_data->ctx->nss_ctx); - free(test_data->ctx); - free(test_data); - -@@ -450,5 +626,6 @@ int main(int argc, const char *argv[]) - cmocka_unit_test(test_decode), - }; - -- return cmocka_run_group_tests(tests, NULL, NULL); -+ assert_non_null(original_fopen); -+ return cmocka_run_group_tests(tests, extdom_req_setup, extdom_req_teardown); - } -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c -index fe225fa86669a6728bec5014be41d80275f10717..86c6638ba73c2f59aff29191e3e68dc5c85d50fc 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c -@@ -43,11 +43,12 @@ - - #include <errno.h> - #include <stdio.h> -+#include <sys/param.h> - - #include "ipa_extdom.h" -+#include "back_extdom.h" - #include "util.h" - --#define MAX(a,b) (((a)>(b))?(a):(b)) - #define SSSD_DOMAIN_SEPARATOR '@' - - int get_buffer(size_t *_buf_len, char **_buf) -@@ -97,134 +98,137 @@ static int inc_buffer(size_t buf_max, size_t *_buf_len, char **_buf) - return 0; - } - --int getpwnam_r_wrapper(size_t buf_max, const char *name, -- struct passwd *pwd, char **_buf, size_t *_buf_len) -+int __nss_to_err(enum nss_status errcode) - { -- char *buf = NULL; -- size_t buf_len = 0; -- int ret; -- struct passwd *result = NULL; -+ switch(errcode) { -+ case NSS_STATUS_SUCCESS: -+ return 0; -+ case NSS_STATUS_NOTFOUND: -+ return ENOENT; -+ case NSS_STATUS_TRYAGAIN: -+ return ERANGE; -+ case NSS_STATUS_UNAVAIL: -+ return ETIMEDOUT; -+ } - -- buf = *_buf; -- buf_len = *_buf_len; -+ return -1; -+} - -- while (buf != NULL -- && (ret = getpwnam_r(name, pwd, buf, buf_len, &result)) == ERANGE) { -- ret = inc_buffer(buf_max, &buf_len, &buf); -- if (ret != 0) { -- if (ret == ERANGE) { -- LOG("Buffer too small, increase ipaExtdomMaxNssBufSize.\n"); -- } -- goto done; -+int getpwnam_r_wrapper(struct ipa_extdom_ctx *ctx, const char *name, -+ struct passwd *pwd, char **buf, size_t *buf_len) -+{ -+ int ret, lerrno = 0; -+ struct passwd *result = NULL; -+ enum nss_status rc; -+ -+ for(rc = NSS_STATUS_TRYAGAIN; rc == NSS_STATUS_TRYAGAIN;) { -+ rc = back_extdom_getpwnam(ctx->nss_ctx, name, pwd, *buf, *buf_len, &result, &lerrno); -+ ret = __nss_to_err(rc); -+ if (ret == ERANGE) { -+ ret = inc_buffer(ctx->max_nss_buf_size, buf_len, buf); -+ if (ret != 0) goto done; - } - } - -- if (ret == 0 && result == NULL) { -- ret = ENOENT; -- } -- - done: -- *_buf = buf; -- *_buf_len = buf_len; -- -+ switch(ret) { -+ case 0: -+ if (result == NULL) ret = ENOENT; -+ break; -+ case ERANGE: -+ LOG("Buffer too small, increase ipaExtdomMaxNssBufSize.\n"); -+ default: -+ break; -+ } - return ret; - } - --int getpwuid_r_wrapper(size_t buf_max, uid_t uid, -- struct passwd *pwd, char **_buf, size_t *_buf_len) -+int getpwuid_r_wrapper(struct ipa_extdom_ctx *ctx, uid_t uid, -+ struct passwd *pwd, char **buf, size_t *buf_len) - { -- char *buf = NULL; -- size_t buf_len = 0; -- int ret; -+ int ret, lerrno; - struct passwd *result = NULL; -- -- buf = *_buf; -- buf_len = *_buf_len; -- -- while (buf != NULL -- && (ret = getpwuid_r(uid, pwd, buf, buf_len, &result)) == ERANGE) { -- ret = inc_buffer(buf_max, &buf_len, &buf); -- if (ret != 0) { -- if (ret == ERANGE) { -- LOG("Buffer too small, increase ipaExtdomMaxNssBufSize.\n"); -- } -- goto done; -+ enum nss_status rc; -+ -+ for(rc = NSS_STATUS_TRYAGAIN; rc == NSS_STATUS_TRYAGAIN;) { -+ rc = back_extdom_getpwuid(ctx->nss_ctx, uid, pwd, *buf, *buf_len, &result, &lerrno); -+ ret = __nss_to_err(rc); -+ if (ret == ERANGE) { -+ ret = inc_buffer(ctx->max_nss_buf_size, buf_len, buf); -+ if (ret != 0) goto done; - } - } - -- if (ret == 0 && result == NULL) { -- ret = ENOENT; -- } -- - done: -- *_buf = buf; -- *_buf_len = buf_len; -+ switch(ret) { -+ case 0: -+ if (result == NULL) ret = ENOENT; -+ break; -+ case ERANGE: -+ LOG("Buffer too small, increase ipaExtdomMaxNssBufSize.\n"); -+ default: -+ break; -+ } - - return ret; - } - --int getgrnam_r_wrapper(size_t buf_max, const char *name, -- struct group *grp, char **_buf, size_t *_buf_len) -+int getgrnam_r_wrapper(struct ipa_extdom_ctx *ctx, const char *name, -+ struct group *grp, char **buf, size_t *buf_len) - { -- char *buf = NULL; -- size_t buf_len = 0; -- int ret; -+ int ret, lerrno; - struct group *result = NULL; -- -- buf = *_buf; -- buf_len = *_buf_len; -- -- while (buf != NULL -- && (ret = getgrnam_r(name, grp, buf, buf_len, &result)) == ERANGE) { -- ret = inc_buffer(buf_max, &buf_len, &buf); -- if (ret != 0) { -- if (ret == ERANGE) { -- LOG("Buffer too small, increase ipaExtdomMaxNssBufSize.\n"); -- } -- goto done; -+ enum nss_status rc; -+ -+ for(rc = NSS_STATUS_TRYAGAIN; rc == NSS_STATUS_TRYAGAIN;) { -+ rc = back_extdom_getgrnam(ctx->nss_ctx, name, grp, *buf, *buf_len, &result, &lerrno); -+ ret = __nss_to_err(rc); -+ if (ret == ERANGE) { -+ ret = inc_buffer(ctx->max_nss_buf_size, buf_len, buf); -+ if (ret != 0) goto done; - } - } - -- if (ret == 0 && result == NULL) { -- ret = ENOENT; -- } -- - done: -- *_buf = buf; -- *_buf_len = buf_len; -+ switch(ret) { -+ case 0: -+ if (result == NULL) ret = ENOENT; -+ break; -+ case ERANGE: -+ LOG("Buffer too small, increase ipaExtdomMaxNssBufSize.\n"); -+ default: -+ break; -+ } - - return ret; - } - --int getgrgid_r_wrapper(size_t buf_max, gid_t gid, -- struct group *grp, char **_buf, size_t *_buf_len) -+int getgrgid_r_wrapper(struct ipa_extdom_ctx *ctx, gid_t gid, -+ struct group *grp, char **buf, size_t *buf_len) - { -- char *buf = NULL; -- size_t buf_len = 0; -- int ret; -+ int ret, lerrno; - struct group *result = NULL; -- -- buf = *_buf; -- buf_len = *_buf_len; -- -- while (buf != NULL -- && (ret = getgrgid_r(gid, grp, buf, buf_len, &result)) == ERANGE) { -- ret = inc_buffer(buf_max, &buf_len, &buf); -- if (ret != 0) { -- if (ret == ERANGE) { -- LOG("Buffer too small, increase ipaExtdomMaxNssBufSize.\n"); -- } -- goto done; -+ enum nss_status rc; -+ -+ for(rc = NSS_STATUS_TRYAGAIN; rc == NSS_STATUS_TRYAGAIN;) { -+ rc = back_extdom_getgrgid(ctx->nss_ctx, gid, grp, *buf, *buf_len, &result, &lerrno); -+ ret = __nss_to_err(rc); -+ if (ret == ERANGE) { -+ ret = inc_buffer(ctx->max_nss_buf_size, buf_len, buf); -+ if (ret != 0) goto done; - } - } - -- if (ret == 0 && result == NULL) { -- ret = ENOENT; -- } -- - done: -- *_buf = buf; -- *_buf_len = buf_len; -+ switch(ret) { -+ case 0: -+ if (result == NULL) ret = ENOENT; -+ break; -+ case ERANGE: -+ LOG("Buffer too small, increase ipaExtdomMaxNssBufSize.\n"); -+ default: -+ break; -+ } - - return ret; - } -@@ -406,13 +410,14 @@ int check_request(struct extdom_req *req, enum extdom_version version) - return LDAP_SUCCESS; - } - --int get_user_grouplist(const char *name, gid_t gid, -+int get_user_grouplist(struct ipa_extdom_ctx *ctx, const char *name, gid_t gid, - size_t *_ngroups, gid_t **_groups) - { -- int ret; -+ int lerrno; - int ngroups; - gid_t *groups; - gid_t *new_groups; -+ enum nss_status rc; - - ngroups = 128; - groups = malloc(ngroups * sizeof(gid_t)); -@@ -420,19 +425,18 @@ int get_user_grouplist(const char *name, gid_t gid, - return LDAP_OPERATIONS_ERROR; - } - -- ret = getgrouplist(name, gid, groups, &ngroups); -- if (ret == -1) { -- new_groups = realloc(groups, ngroups * sizeof(gid_t)); -- if (new_groups == NULL) { -- free(groups); -- return LDAP_OPERATIONS_ERROR; -- } -- groups = new_groups; -- -- ret = getgrouplist(name, gid, groups, &ngroups); -- if (ret == -1) { -- free(groups); -- return LDAP_OPERATIONS_ERROR; -+ for(rc = NSS_STATUS_TRYAGAIN; rc == NSS_STATUS_TRYAGAIN;) { -+ rc = back_extdom_getgrouplist(ctx->nss_ctx, name, gid, groups, &ngroups, &lerrno); -+ if (rc == NSS_STATUS_TRYAGAIN) { -+ new_groups = NULL; -+ if (lerrno == ERANGE) { -+ new_groups = realloc(groups, ngroups * sizeof(gid_t)); -+ } -+ if ((new_groups == NULL) || (lerrno == ENOMEM)) { -+ free(groups); -+ return LDAP_OPERATIONS_ERROR; -+ } -+ groups = new_groups; - } - } - -@@ -538,7 +542,7 @@ int pack_ber_user(struct ipa_extdom_ctx *ctx, - } - - if (response_type == RESP_USER_GROUPLIST) { -- ret = get_user_grouplist(user_name, gid, &ngroups, &groups); -+ ret = get_user_grouplist(ctx, user_name, gid, &ngroups, &groups); - if (ret != LDAP_SUCCESS) { - goto done; - } -@@ -561,7 +565,7 @@ int pack_ber_user(struct ipa_extdom_ctx *ctx, - } - - for (c = 0; c < ngroups; c++) { -- ret = getgrgid_r_wrapper(ctx->max_nss_buf_size, -+ ret = getgrgid_r_wrapper(ctx, - groups[c], &grp, &buf, &buf_len); - if (ret != 0) { - if (ret == ENOMEM || ret == ERANGE) { -@@ -841,8 +845,7 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx, - - ret = pack_ber_sid(sid_str, berval); - } else { -- ret = getpwuid_r_wrapper(ctx->max_nss_buf_size, uid, &pwd, &buf, -- &buf_len); -+ ret = getpwuid_r_wrapper(ctx, uid, &pwd, &buf, &buf_len); - if (ret != 0) { - if (ret == ENOMEM || ret == ERANGE) { - ret = LDAP_OPERATIONS_ERROR; -@@ -913,8 +916,7 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx, - - ret = pack_ber_sid(sid_str, berval); - } else { -- ret = getgrgid_r_wrapper(ctx->max_nss_buf_size, gid, &grp, &buf, -- &buf_len); -+ ret = getgrgid_r_wrapper(ctx, gid, &grp, &buf, &buf_len); - if (ret != 0) { - if (ret == ENOMEM || ret == ERANGE) { - ret = LDAP_OPERATIONS_ERROR; -@@ -1053,8 +1055,7 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx, - switch(id_type) { - case SSS_ID_TYPE_UID: - case SSS_ID_TYPE_BOTH: -- ret = getpwnam_r_wrapper(ctx->max_nss_buf_size, fq_name, &pwd, &buf, -- &buf_len); -+ ret = getpwnam_r_wrapper(ctx, fq_name, &pwd, &buf, &buf_len); - if (ret != 0) { - if (ret == ENOMEM || ret == ERANGE) { - ret = LDAP_OPERATIONS_ERROR; -@@ -1086,8 +1087,7 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx, - pwd.pw_shell, kv_list, berval); - break; - case SSS_ID_TYPE_GID: -- ret = getgrnam_r_wrapper(ctx->max_nss_buf_size, fq_name, &grp, &buf, -- &buf_len); -+ ret = getgrnam_r_wrapper(ctx, fq_name, &grp, &buf, &buf_len); - if (ret != 0) { - if (ret == ENOMEM || ret == ERANGE) { - ret = LDAP_OPERATIONS_ERROR; -@@ -1181,8 +1181,7 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx, - goto done; - } - -- ret = getpwnam_r_wrapper(ctx->max_nss_buf_size, fq_name, &pwd, &buf, -- &buf_len); -+ ret = getpwnam_r_wrapper(ctx, fq_name, &pwd, &buf, &buf_len); - if (ret == 0) { - if (request_type == REQ_FULL_WITH_GROUPS) { - ret = sss_nss_getorigbyname(pwd.pw_name, &kv_list, &id_type); -@@ -1211,8 +1210,7 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx, - * error codes which can indicate that the user was not found. To - * be on the safe side we fail back to the group lookup on all - * errors. */ -- ret = getgrnam_r_wrapper(ctx->max_nss_buf_size, fq_name, &grp, &buf, -- &buf_len); -+ ret = getgrnam_r_wrapper(ctx, fq_name, &grp, &buf, &buf_len); - if (ret != 0) { - if (ret == ENOMEM || ret == ERANGE) { - ret = LDAP_OPERATIONS_ERROR; -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -index 5bc8c2f571e311c5ae4cc56e2e1ae7d4e2f77ee6..83c30e7e6aad72af603c0b4ed1c49b80fa57560f 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -@@ -38,9 +38,11 @@ - * END COPYRIGHT BLOCK **/ - - #include "ipa_extdom.h" -+#include "back_extdom.h" - #include "util.h" - - #define DEFAULT_MAX_NSS_BUFFER (128*1024*1024) -+#define DEFAULT_MAX_NSS_TIMEOUT (10*1000) - - Slapi_PluginDesc ipa_extdom_plugin_desc = { - IPA_EXTDOM_FEATURE_DESC, -@@ -166,6 +168,7 @@ static int ipa_extdom_init_ctx(Slapi_PBlock *pb, struct ipa_extdom_ctx **_ctx) - struct ipa_extdom_ctx *ctx; - Slapi_Entry *e; - int ret; -+ unsigned int timeout; - - ctx = calloc(1, sizeof(struct ipa_extdom_ctx)); - if (!ctx) { -@@ -202,6 +205,20 @@ static int ipa_extdom_init_ctx(Slapi_PBlock *pb, struct ipa_extdom_ctx **_ctx) - } - LOG("Maximal nss buffer size set to [%zu]!\n", ctx->max_nss_buf_size); - -+ -+ ret = back_extdom_init_context(&ctx->nss_ctx); -+ if (ret != 0) { -+ LOG("Unable to initialize nss interface: returned [%d]!\n", ret); -+ goto done; -+ } -+ -+ timeout = slapi_entry_attr_get_uint(e, "ipaExtdomMaxNssTimeout"); -+ if (timeout == 0) { -+ timeout = DEFAULT_MAX_NSS_TIMEOUT; -+ } -+ back_extdom_set_timeout(ctx->nss_ctx, timeout); -+ LOG("Maximal nss timeout (in ms) set to [%u]!\n", timeout); -+ - ret = 0; - - done: -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/test_setup.sh b/daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/test_setup.sh -deleted file mode 100644 -index ad839f340efe989a91cd6902f59c9a41483f68e0..0000000000000000000000000000000000000000 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/test_setup.sh -+++ /dev/null -@@ -1,3 +0,0 @@ --export LD_PRELOAD=$(pkg-config --libs nss_wrapper) --export NSS_WRAPPER_PASSWD=./test_data/passwd --export NSS_WRAPPER_GROUP=./test_data/group -diff --git a/freeipa.spec.in b/freeipa.spec.in -index a8b5ce81fcf9bdb61cd3707e6b68b6f2196e0776..80ae98c5515f64a8df8d981ad5e91b05c84e31c1 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -246,7 +246,6 @@ BuildRequires: python3-augeas - # - %if ! %{ONLY_CLIENT} - BuildRequires: libcmocka-devel --BuildRequires: nss_wrapper - # Required by ipa_kdb_tests - BuildRequires: %{_libdir}/krb5/plugins/kdb/db2.so - %endif # ONLY_CLIENT -diff --git a/server.m4 b/server.m4 -index a9670c87372bb7b92d08dad634c0bda123a02597..f0a8bbcc778596dade89d9332abb2939b8a44143 100644 ---- a/server.m4 -+++ b/server.m4 -@@ -35,6 +35,16 @@ AC_CHECK_LIB([sss_nss_idmap], - [AC_MSG_ERROR([Required sss_nss_getlistbycert symbol in sss_nss_idmap not found])], - []) - -+dnl --- if sss_nss_idmap provides _timeout() API, use it -+bck_cflags="$CFLAGS" -+CFLAGS="$CFLAGS -DIPA_389DS_PLUGIN_HELPER_CALLS" -+AC_CHECK_DECLS([sss_nss_getpwnam_timeout], [], [], [[#include <sss_nss_idmap.h>]]) -+CFLAGS="$bck_cflags" -+ -+if test "x$ac_cv_have_decl_sss_nss_getpwnam_timeout" = xyes ; then -+ AC_DEFINE(USE_SSS_NSS_TIMEOUT,1,[Use extended NSS API provided by SSSD]) -+fi -+ - dnl -- sss_certmap and certauth.h are needed by the IPA KDB certauth plugin -- - PKG_CHECK_EXISTS([sss_certmap], - [PKG_CHECK_MODULES([SSSCERTMAP], [sss_certmap])], --- -2.14.3 - diff --git a/SOURCES/0008-Add-the-sub-operation-for-fqdn-index-config.patch b/SOURCES/0008-Add-the-sub-operation-for-fqdn-index-config.patch deleted file mode 100644 index b7f8792..0000000 --- a/SOURCES/0008-Add-the-sub-operation-for-fqdn-index-config.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 8a1e04abede4c0bd5730781ef8c42c8a2e1bbcf9 Mon Sep 17 00:00:00 2001 -From: Stanislav Laznicka <slaznick@redhat.com> -Date: Fri, 3 Nov 2017 09:23:10 +0100 -Subject: [PATCH] Add the sub operation for fqdn index config - -This should improve performance of the host-find command. - -https://pagure.io/freeipa/issue/6371 - -Reviewed-By: Rob Crittenden <rcritten@redhat.com> ---- - install/share/indices.ldif | 1 + - install/updates/20-indices.update | 5 +++-- - 2 files changed, 4 insertions(+), 2 deletions(-) - -diff --git a/install/share/indices.ldif b/install/share/indices.ldif -index d853266025ae350dd7de83e11e463c6bb1ab9429..adb041d374d8fc48fff9d4b40208e7eda82857b3 100644 ---- a/install/share/indices.ldif -+++ b/install/share/indices.ldif -@@ -108,6 +108,7 @@ cn: fqdn - nsSystemIndex: false - nsIndexType: eq - nsIndexType: pres -+nsIndexType: sub - - dn: cn=macAddress,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config - changetype: add -diff --git a/install/updates/20-indices.update b/install/updates/20-indices.update -index 74961d77875515d680f34af739c984a6533eb252..fb588b9ba8a2a89c9e7eab87ab5f224ca438645a 100644 ---- a/install/updates/20-indices.update -+++ b/install/updates/20-indices.update -@@ -70,8 +70,9 @@ default:cn: fqdn - default:ObjectClass: top - default:ObjectClass: nsIndex - default:nsSystemIndex: false --default:nsIndexType: eq --default:nsIndexType: pres -+only:nsIndexType: eq -+only:nsIndexType: pres -+only:nsIndexType: sub - - dn: cn=macAddress,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config - default:cn: macAddress --- -2.14.3 - diff --git a/SOURCES/0008-Fix-replication-races-in-Dogtag-admin-code.patch b/SOURCES/0008-Fix-replication-races-in-Dogtag-admin-code.patch new file mode 100644 index 0000000..fccb1fd --- /dev/null +++ b/SOURCES/0008-Fix-replication-races-in-Dogtag-admin-code.patch @@ -0,0 +1,204 @@ +From ecd1fa6b42c6ae76ce620c5ac949e64ba11d375a Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Fri, 22 Jun 2018 10:04:38 +0200 +Subject: [PATCH] Fix replication races in Dogtag admin code + +DogtagInstance.setup_admin and related methods have multiple LDAP +replication race conditions. The bugs can cause parallel +ipa-replica-install to fail. + +The code from __add_admin_to_group() has been changed to use MOD_ADD +ather than search + MOD_REPLACE. The MOD_REPLACE approach can lead to +data loss, when more than one writer changes a group. + +setup_admin() now waits until both admin user and group membership have +been replicated to the master peer. The method also adds a new ACI to +allow querying group member in the replication check. + +Fixes: https://pagure.io/freeipa/issue/7593 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> +--- + ipaserver/install/cainstance.py | 1 + + ipaserver/install/dogtaginstance.py | 96 +++++++++++++++++++++++++++++-------- + ipaserver/install/krainstance.py | 1 + + 3 files changed, 77 insertions(+), 21 deletions(-) + +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index 5bdac82a57c2228b1b196337a2ceadb062fdc13c..b58fbb4c881d247d6b5fb661f4085ec82c3cc811 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -392,6 +392,7 @@ class CAInstance(DogtagInstance): + # Setup Database + self.step("creating certificate server db", self.__create_ds_db) + self.step("setting up initial replication", self.__setup_replication) ++ self.step("creating ACIs for admin", self.add_ipaca_aci) + self.step("creating installation admin user", self.setup_admin) + self.step("configuring certificate server instance", + self.__spawn_instance) +diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py +index 07e63024c6e138269634f0206b14c6a1710df936..5b2c30f8a1b7e932ce1cca3ca38f5962a3d54266 100644 +--- a/ipaserver/install/dogtaginstance.py ++++ b/ipaserver/install/dogtaginstance.py +@@ -21,6 +21,7 @@ from __future__ import absolute_import + + import base64 + import logging ++import time + + import ldap + import os +@@ -90,6 +91,16 @@ class DogtagInstance(service.Service): + tracking_reqs = None + server_cert_name = None + ++ ipaca_groups = DN(('ou', 'groups'), ('o', 'ipaca')) ++ ipaca_people = DN(('ou', 'people'), ('o', 'ipaca')) ++ groups_aci = ( ++ b'(targetfilter="(objectClass=groupOfUniqueNames)")' ++ b'(targetattr="cn || description || objectclass || uniquemember")' ++ b'(version 3.0; acl "Allow users from o=ipaca to read groups"; ' ++ b'allow (read, search, compare) ' ++ b'userdn="ldap:///uid=*,ou=people,o=ipaca";)' ++ ) ++ + def __init__(self, realm, subsystem, service_desc, host_name=None, + nss_db=paths.PKI_TOMCAT_ALIAS_DIR, service_prefix=None, + config=None): +@@ -108,10 +119,11 @@ class DogtagInstance(service.Service): + self.pkcs12_info = None + self.clone = False + +- self.basedn = DN(('o', 'ipa%s' % subsystem.lower())) ++ self.basedn = DN(('o', 'ipaca')) + self.admin_user = "admin" +- self.admin_dn = DN(('uid', self.admin_user), +- ('ou', 'people'), ('o', 'ipaca')) ++ self.admin_dn = DN( ++ ('uid', self.admin_user), self.ipaca_people ++ ) + self.admin_groups = None + self.tmp_agent_db = None + self.subsystem = subsystem +@@ -393,27 +405,31 @@ class DogtagInstance(service.Service): + + raise RuntimeError("%s configuration failed." % self.subsystem) + +- def __add_admin_to_group(self, group): +- dn = DN(('cn', group), ('ou', 'groups'), ('o', 'ipaca')) +- entry = api.Backend.ldap2.get_entry(dn) +- members = entry.get('uniqueMember', []) +- members.append(self.admin_dn) +- mod = [(ldap.MOD_REPLACE, 'uniqueMember', members)] ++ def add_ipaca_aci(self): ++ """Add ACI to allow ipaca users to read their own group information ++ ++ Dogtag users aren't allowed to enumerate their own groups. The ++ setup_admin() method needs the permission to wait, until all group ++ information has been replicated. ++ """ ++ dn = self.ipaca_groups ++ mod = [(ldap.MOD_ADD, 'aci', [self.groups_aci])] + try: + api.Backend.ldap2.modify_s(dn, mod) + except ldap.TYPE_OR_VALUE_EXISTS: +- # already there +- pass ++ logger.debug("%s already has ACI to read group information", dn) ++ else: ++ logger.debug("Added ACI to read groups to %s", dn) + + def setup_admin(self): + self.admin_user = "admin-%s" % self.fqdn + self.admin_password = ipautil.ipa_generate_password() +- self.admin_dn = DN(('uid', self.admin_user), +- ('ou', 'people'), ('o', 'ipaca')) +- ++ self.admin_dn = DN( ++ ('uid', self.admin_user), self.ipaca_people ++ ) + # remove user if left-over exists + try: +- entry = api.Backend.ldap2.delete_entry(self.admin_dn) ++ api.Backend.ldap2.delete_entry(self.admin_dn) + except errors.NotFound: + pass + +@@ -432,18 +448,56 @@ class DogtagInstance(service.Service): + ) + api.Backend.ldap2.add_entry(entry) + ++ wait_groups = [] + for group in self.admin_groups: +- self.__add_admin_to_group(group) ++ group_dn = DN(('cn', group), self.ipaca_groups) ++ mod = [(ldap.MOD_ADD, 'uniqueMember', [self.admin_dn])] ++ try: ++ api.Backend.ldap2.modify_s(group_dn, mod) ++ except ldap.TYPE_OR_VALUE_EXISTS: ++ # already there ++ return None ++ else: ++ wait_groups.append(group_dn) + + # Now wait until the other server gets replicated this data + ldap_uri = ipaldap.get_ldap_uri(self.master_host) +- master_conn = ipaldap.LDAPClient(ldap_uri) +- master_conn.gssapi_bind() +- replication.wait_for_entry(master_conn, entry.dn) +- del master_conn ++ master_conn = ipaldap.LDAPClient(ldap_uri, start_tls=True) ++ logger.debug( ++ "Waiting for %s to appear on %s", self.admin_dn, master_conn ++ ) ++ deadline = time.time() + api.env.replication_wait_timeout ++ while time.time() < deadline: ++ time.sleep(1) ++ try: ++ master_conn.simple_bind(self.admin_dn, self.admin_password) ++ except ldap.INVALID_CREDENTIALS: ++ pass ++ else: ++ logger.debug("Successfully logged in as %s", self.admin_dn) ++ break ++ else: ++ logger.error( ++ "Unable to log in as %s on %s", self.admin_dn, master_conn ++ ) ++ raise errors.NotFound( ++ reason="{} did not replicate to {}".format( ++ self.admin_dn, master_conn ++ ) ++ ) ++ ++ # wait for group membership ++ for group_dn in wait_groups: ++ replication.wait_for_entry( ++ master_conn, ++ group_dn, ++ timeout=api.env.replication_wait_timeout, ++ attr='uniqueMember', ++ attrvalue=self.admin_dn ++ ) + + def __remove_admin_from_group(self, group): +- dn = DN(('cn', group), ('ou', 'groups'), ('o', 'ipaca')) ++ dn = DN(('cn', group), self.ipaca_groups) + mod = [(ldap.MOD_DELETE, 'uniqueMember', self.admin_dn)] + try: + api.Backend.ldap2.modify_s(dn, mod) +diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py +index b959398706d051a2584e722e176a9f2b0a9a0dc7..9483f0ec4edbabea0f7eff0dd5dd223377653536 100644 +--- a/ipaserver/install/krainstance.py ++++ b/ipaserver/install/krainstance.py +@@ -115,6 +115,7 @@ class KRAInstance(DogtagInstance): + "A Dogtag CA must be installed first") + + if promote: ++ self.step("creating ACIs for admin", self.add_ipaca_aci) + self.step("creating installation admin user", self.setup_admin) + self.step("configuring KRA instance", self.__spawn_instance) + if not self.clone: +-- +2.14.4 + diff --git a/SOURCES/0009-Add-indexing-to-improve-host-find-performance.patch b/SOURCES/0009-Add-indexing-to-improve-host-find-performance.patch deleted file mode 100644 index 8bc6e7f..0000000 --- a/SOURCES/0009-Add-indexing-to-improve-host-find-performance.patch +++ /dev/null @@ -1,121 +0,0 @@ -From ff597260ef2f5e953b55ae1a8511191853becca8 Mon Sep 17 00:00:00 2001 -From: Stanislav Laznicka <slaznick@redhat.com> -Date: Fri, 27 Oct 2017 09:34:38 +0200 -Subject: [PATCH] Add indexing to improve host-find performance - -host-find <host_name> command performance gets deteriorated when -there's way too many hosts in the LDAP tree. We're adding indices -to try and mitigate this behavior. - -https://pagure.io/freeipa/issue/6371 - -Reviewed-By: Rob Crittenden <rcritten@redhat.com> ---- - install/share/indices.ldif | 45 +++++++++++++++++++++++++++++++++++++++ - install/updates/20-indices.update | 40 ++++++++++++++++++++++++++++++++++ - 2 files changed, 85 insertions(+) - -diff --git a/install/share/indices.ldif b/install/share/indices.ldif -index adb041d374d8fc48fff9d4b40208e7eda82857b3..7bd59d2774df9bdf56f6b8034236aa2c5658b366 100644 ---- a/install/share/indices.ldif -+++ b/install/share/indices.ldif -@@ -279,3 +279,48 @@ objectClass: nsIndex - nsSystemIndex: false - nsIndexType: eq - nsIndexType: sub -+ -+dn: cn=description,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config -+changetype: add -+cn: description -+objectClass: top -+objectClass: nsindex -+nssystemindex: false -+nsindextype: eq -+nsindextype: sub -+ -+dn: cn=l,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config -+changetype: add -+cn: l -+objectClass: top -+objectClass: nsindex -+nssystemindex: false -+nsindextype: eq -+nsindextype: sub -+ -+dn: cn=nsOsVersion,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config -+changetype: add -+cn: nsOsVersion -+objectClass: top -+objectClass: nsindex -+nssystemindex: false -+nsindextype: eq -+nsindextype: sub -+ -+dn: cn=nsHardwarePlatform,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config -+changetype: add -+cn: nsHardwarePlatform -+objectClass: top -+objectClass: nsindex -+nssystemindex: false -+nsindextype: eq -+nsindextype: sub -+ -+dn: cn=nsHostLocation,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config -+changetype: add -+cn: nsHostLocation -+objectClass: top -+objectClass: nsindex -+nssystemindex: false -+nsindextype: eq -+nsindextype: sub -diff --git a/install/updates/20-indices.update b/install/updates/20-indices.update -index fb588b9ba8a2a89c9e7eab87ab5f224ca438645a..016fbb6bedb6af69fba0a8a84f8c1c6622d4368c 100644 ---- a/install/updates/20-indices.update -+++ b/install/updates/20-indices.update -@@ -260,3 +260,43 @@ default: objectClass: nsIndex - only: nsSystemIndex: false - only: nsIndexType: eq - only: nsIndexType: sub -+ -+dn: cn=description,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config -+default: cn: description -+default: objectclass: top -+default: objectclass: nsindex -+default: nssystemindex: false -+default: nsindextype: eq -+default: nsindextype: sub -+ -+dn: cn=l,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config -+default: cn: l -+default: objectclass: top -+default: objectclass: nsindex -+default: nssystemindex: false -+default: nsindextype: eq -+default: nsindextype: sub -+ -+dn: cn=nsOsVersion,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config -+default: cn: nsOsVersion -+default: objectclass: top -+default: objectclass: nsindex -+default: nssystemindex: false -+default: nsindextype: eq -+default: nsindextype: sub -+ -+dn: cn=nsHardwarePlatform,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config -+default: cn: nsHardwarePlatform -+default: objectclass: top -+default: objectclass: nsindex -+default: nssystemindex: false -+default: nsindextype: eq -+default: nsindextype: sub -+ -+dn: cn=nsHostLocation,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config -+default: cn: nsHostLocation -+default: objectclass: top -+default: objectclass: nsindex -+default: nssystemindex: false -+default: nsindextype: eq -+default: nsindextype: sub --- -2.14.3 - diff --git a/SOURCES/0009-Allow-anonymous-access-to-ParentID-attribute.patch b/SOURCES/0009-Allow-anonymous-access-to-ParentID-attribute.patch new file mode 100644 index 0000000..94179ab --- /dev/null +++ b/SOURCES/0009-Allow-anonymous-access-to-ParentID-attribute.patch @@ -0,0 +1,43 @@ +From 34d06b2be71823bc8898732f1ced0185f83afb01 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy <abokovoy@redhat.com> +Date: Wed, 28 Mar 2018 12:39:12 +0300 +Subject: [PATCH] Allow anonymous access to parentID attribute + +Due to optimizations in 389-ds performed as result of +https://pagure.io/389-ds-base/issue/49372, LDAP search filter +is rewritten to include parentID information. It implies that parentID +has to be readable for a bound identity performing the search. This is +what 389-ds expects right now but FreeIPA DS instance does not allow it. + +As result, searches with a one-level scope fail to return results that +otherwise are matched in a sub scope search. + +While 389-ds developers are working on the fix for issue +https://pagure.io/389-ds-base/issue/49617, we can fix it by adding an +explicit ACI to allow reading parentID attribute at the suffix level. + +Fixes: https://pagure.io/freeipa/issue/7466 +Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com> +Reviewed-By: Christian Heimes <cheimes@redhat.com> +--- + install/updates/20-aci.update | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/install/updates/20-aci.update b/install/updates/20-aci.update +index dec2e16ee..b8a172eb5 100644 +--- a/install/updates/20-aci.update ++++ b/install/updates/20-aci.update +@@ -21,6 +21,10 @@ add:aci:(targetattr="ipasshpubkey")(version 3.0; acl "Hosts can manage other hos + dn: $SUFFIX + add:aci:(targetfilter="(objectclass=domain)")(targetattr="objectclass || dc || info || nisDomain || associatedDomain")(version 3.0; acl "Anonymous read access to DIT root"; allow(read, search, compare) userdn = "ldap:///anyone";) + ++# Read access to parentID information to allow filter optimizations in 389-ds ++dn: $SUFFIX ++add:aci:(targetattr="parentid")(version 3.0; acl "Anonymous read access to parentID information"; allow(read, search, compare) userdn = "ldap:///anyone";) ++ + # Read access to containers + dn: $SUFFIX + add:aci:(targetfilter="(&(objectclass=nsContainer)(!(objectclass=krbPwdPolicy)))")(target!="ldap:///cn=masters,cn=ipa,cn=etc,$SUFFIX")(targetattr="objectclass || cn")(version 3.0; acl "Anonymous read access to containers"; allow(read, search, compare) userdn = "ldap:///anyone";) +-- +2.17.1 + diff --git a/SOURCES/0010-Use-4-WSGI-workers-on-64bit-systems.patch b/SOURCES/0010-Use-4-WSGI-workers-on-64bit-systems.patch new file mode 100644 index 0000000..212eb15 --- /dev/null +++ b/SOURCES/0010-Use-4-WSGI-workers-on-64bit-systems.patch @@ -0,0 +1,32 @@ +From bf539f80ed34c30bc852a6061ce6444c5c308a26 Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Mon, 25 Jun 2018 10:59:18 +0200 +Subject: [PATCH] Use 4 WSGI workers on 64bit systems + +Commit f1d5ab3a03191dbb02e5f95308cf8c4f1971cdcf increases WSGI worker +count to five. This turned out to be a bit much for our test systems. +Four workers are good enough and still double the old amount. + +See: https://pagure.io/freeipa/issue/7587 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> +--- + ipaplatform/base/constants.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaplatform/base/constants.py b/ipaplatform/base/constants.py +index 075a3ba774e1286e50258b464bd7687d484f6029..e9ce4378892a5cd498398e37cc52f295608152cd 100644 +--- a/ipaplatform/base/constants.py ++++ b/ipaplatform/base/constants.py +@@ -46,7 +46,7 @@ class BaseConstantsNamespace(object): + MOD_WSGI_PYTHON3 = None + # WSGIDaemonProcess process count. On 64bit platforms, each process + # consumes about 110 MB RSS, from which are about 35 MB shared. +- WSGI_PROCESSES = 5 if IS_64BITS else 2 ++ WSGI_PROCESSES = 4 if IS_64BITS else 2 + + + constants = BaseConstantsNamespace() +-- +2.17.1 + diff --git a/SOURCES/0010-ipa-getkeytab-man-page-add-more-details-about-the-r-.patch b/SOURCES/0010-ipa-getkeytab-man-page-add-more-details-about-the-r-.patch deleted file mode 100644 index f3509c2..0000000 --- a/SOURCES/0010-ipa-getkeytab-man-page-add-more-details-about-the-r-.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 30e55883bd4822d4d3af061d646e7b1044880d52 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud <flo@redhat.com> -Date: Tue, 7 Nov 2017 09:31:19 +0100 -Subject: [PATCH] ipa-getkeytab man page: add more details about the -r option - -The man page does not provide enough information about replicated -environments and the use of the -r option. -This fix adds an example how to use the same keytab on 2 different -hosts, and points to ipa {service/host}-allow-retrieve-keytab. - -Fixes: -https://pagure.io/freeipa/issue/7237 - -Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> ---- - client/man/ipa-getkeytab.1 | 35 ++++++++++++++++++++++++++++++++++- - 1 file changed, 34 insertions(+), 1 deletion(-) - -diff --git a/client/man/ipa-getkeytab.1 b/client/man/ipa-getkeytab.1 -index 08f6ec40d362b88a974e6ec735ed37c271e01882..39ff0d5da85b5a641328a512feeb06bc9c1ab9d7 100644 ---- a/client/man/ipa-getkeytab.1 -+++ b/client/man/ipa-getkeytab.1 -@@ -44,10 +44,15 @@ provided, so the principal name is just the service - name and hostname (ldap/foo.example.com from the - example above). - -+ipa-getkeytab is used during IPA client enrollment to retrieve a host service principal and store it in /etc/krb5.keytab. It is possible to retrieve the keytab without Kerberos credentials if the host was pre\-created with a one\-time password. The keytab can be retrieved by binding as the host and authenticating with this one\-time password. The \fB\-D|\-\-binddn\fR and \fB\-w|\-\-bindpw\fR options are used for this authentication. -+ - \fBWARNING:\fR retrieving the keytab resets the secret for the Kerberos principal. - This renders all other keytabs for that principal invalid. -+When multiple hosts or services need to share the same key (for instance in high availability or load balancing clusters), the \fB\-r\fR option must be used to retrieve the existing key instead of generating a new one (please refer to the EXAMPLES section). -+ -+Note that the user or host calling \fBipa-getkeytab\fR needs to be allowed to generate the key with \fBipa host\-allow\-create\-keytab\fR or \fBipa service\-allow\-create\-keytab\fR, -+and the user or host calling \fBipa-getkeytab \-r\fR needs to be allowed to retrieve the keytab for the host or service with \fBipa host\-allow\-retrieve\-keytab\fR or \fBipa service\-allow\-retrieve\-keytab\fR. - --This is used during IPA client enrollment to retrieve a host service principal and store it in /etc/krb5.keytab. It is possible to retrieve the keytab without Kerberos credentials if the host was pre\-created with a one\-time password. The keytab can be retrieved by binding as the host and authenticating with this one\-time password. The \fB\-D|\-\-binddn\fR and \fB\-w|\-\-bindpw\fR options are used for this authentication. - .SH "OPTIONS" - .TP - \fB\-p principal\-name\fR -@@ -118,16 +123,44 @@ keytab must have access to the keys for this operation to succeed. - Add and retrieve a keytab for the NFS service principal on - the host foo.example.com and save it in the file /tmp/nfs.keytab and retrieve just the des\-cbc\-crc key. - -+.nf - # ipa\-getkeytab \-p nfs/foo.example.com \-k /tmp/nfs.keytab \-e des\-cbc\-crc -+.fi - - Add and retrieve a keytab for the ldap service principal on - the host foo.example.com and save it in the file /tmp/ldap.keytab. - -+.nf - # ipa\-getkeytab \-s ipaserver.example.com \-p ldap/foo.example.com \-k /tmp/ldap.keytab -+.fi - - Retrieve a keytab using LDAP credentials (this will typically be done by \fBipa\-join(1)\fR when enrolling a client using the \fBipa\-client\-install(1)\fR command: - -+.nf - # ipa\-getkeytab \-s ipaserver.example.com \-p host/foo.example.com \-k /etc/krb5.keytab \-D fqdn=foo.example.com,cn=computers,cn=accounts,dc=example,dc=com \-w password -+.fi -+ -+Add and retrieve a keytab for a clustered HTTP service deployed on client1.example.com and client2.example.com (already enrolled), using the client-frontend.example.com host name: -+ -+.nf -+ # ipa host-add client-frontend.example.com --ip-address 10.1.2.3 -+ # ipa service-add HTTP/client-frontend.example.com -+ # ipa service-allow-retrieve-keytab HTTP/client-frontend.example.com --hosts={client1.example.com,client2.example.com} -+ # ipa server-allow-create-keytab HTTP/client-frontend.example.com --hosts=client1.example.com -+.fi -+ -+ On client1, generate and retrieve a new keytab for client-frontend.example.com: -+.nf -+ # kinit -k -+ # ipa-getkeytab -p HTTP/client-frontend.example.com -k /tmp/http.keytab -+ -+.fi -+ On client2, retrieve the existing keytab for client-frontend.example.com: -+.nf -+ # kinit -k -+ # ipa-getkeytab -r -p HTTP/client-frontend.example.com -k /tmp/http.keytab -+.fi -+ - .SH "EXIT STATUS" - The exit status is 0 on success, nonzero on error. - --- -2.13.6 - diff --git a/SOURCES/0011-Don-t-allow-OTP-or-RADIUS-in-FIPS-mode.patch b/SOURCES/0011-Don-t-allow-OTP-or-RADIUS-in-FIPS-mode.patch deleted file mode 100644 index 74e0d92..0000000 --- a/SOURCES/0011-Don-t-allow-OTP-or-RADIUS-in-FIPS-mode.patch +++ /dev/null @@ -1,83 +0,0 @@ -From be18d6c15a2557e8f45e41efc81f1c005958c690 Mon Sep 17 00:00:00 2001 -From: Stanislav Laznicka <slaznick@redhat.com> -Date: Tue, 7 Nov 2017 14:42:12 +0100 -Subject: [PATCH] Don't allow OTP or RADIUS in FIPS mode - -RADIUS, which is also internally used in the process of OTP -authentication by ipa-otpd, requires MD5 checksums which -makes it impossible to be used in FIPS mode. Don't allow users -setting OTP or RADIUS authentication if in FIPS mode. - -https://pagure.io/freeipa/issue/7168 - -Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> ---- - ipaserver/plugins/baseuser.py | 3 +++ - ipaserver/plugins/config.py | 16 ++++++++++++++++ - 2 files changed, 19 insertions(+) - -diff --git a/ipaserver/plugins/baseuser.py b/ipaserver/plugins/baseuser.py -index bf24dbf542d3b481671dfe4e8cee14a2edcc26e0..bb8a73ded0fed135d5829ec0b0829a936f2196fb 100644 ---- a/ipaserver/plugins/baseuser.py -+++ b/ipaserver/plugins/baseuser.py -@@ -32,6 +32,7 @@ from .baseldap import ( - add_missing_object_class) - from ipaserver.plugins.service import ( - validate_certificate, validate_realm, normalize_principal) -+from ipaserver.plugins.config import check_fips_auth_opts - from ipalib.request import context - from ipalib import _ - from ipalib.constants import PATTERN_GROUPUSER_NAME -@@ -477,6 +478,7 @@ class baseuser_add(LDAPCreate): - **options): - assert isinstance(dn, DN) - set_krbcanonicalname(entry_attrs) -+ check_fips_auth_opts(fips_mode=self.api.env.fips_mode, **options) - self.obj.convert_usercertificate_pre(entry_attrs) - - def post_common_callback(self, ldap, dn, entry_attrs, *keys, **options): -@@ -600,6 +602,7 @@ class baseuser_mod(LDAPUpdate): - assert isinstance(dn, DN) - add_sshpubkey_to_attrs_pre(self.context, attrs_list) - -+ check_fips_auth_opts(fips_mode=self.api.env.fips_mode, **options) - self.check_namelength(ldap, **options) - - self.check_mail(entry_attrs) -diff --git a/ipaserver/plugins/config.py b/ipaserver/plugins/config.py -index ce15e6096f5b84dc45ee21d5aecc73ecf86eba07..c9033fa8e7a2a0bfe77464fa4f9c62278bd814f6 100644 ---- a/ipaserver/plugins/config.py -+++ b/ipaserver/plugins/config.py -@@ -85,6 +85,20 @@ EXAMPLES: - - register = Registry() - -+ -+def check_fips_auth_opts(fips_mode, **options): -+ """ -+ OTP and RADIUS are not allowed in FIPS mode since they use MD5 -+ checksums (OTP uses our RADIUS responder daemon ipa-otpd). -+ """ -+ if 'ipauserauthtype' in options and fips_mode: -+ if ('otp' in options['ipauserauthtype'] or -+ 'radius' in options['ipauserauthtype']): -+ raise errors.InvocationError( -+ 'OTP and RADIUS authentication in FIPS is ' -+ 'not yet supported') -+ -+ - @register() - class config(LDAPObject): - """ -@@ -398,6 +412,8 @@ class config_mod(LDAPUpdate): - - def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): - assert isinstance(dn, DN) -+ check_fips_auth_opts(fips_mode=self.api.env.fips_mode, **options) -+ - if 'ipadefaultprimarygroup' in entry_attrs: - group=entry_attrs['ipadefaultprimarygroup'] - try: --- -2.13.6 - diff --git a/SOURCES/0011-Query-for-server-role-IPA-master.patch b/SOURCES/0011-Query-for-server-role-IPA-master.patch new file mode 100644 index 0000000..f592f40 --- /dev/null +++ b/SOURCES/0011-Query-for-server-role-IPA-master.patch @@ -0,0 +1,108 @@ +From ef7fe9e24844f73a27650d4d2a4f118cc364caac Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Thu, 5 Jul 2018 23:50:37 +0200 +Subject: [PATCH] Query for server role IPA master + +server_find and server_role plugin were hiding IPA master role +information. It's now possible to fetch IPA master role information and +to filter by IPA master role, e.g. to ignore servers that have some +services configured but not (yet) enabled. + +See: https://pagure.io/freeipa/issue/7566 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> +--- + API.txt | 3 ++- + ipaserver/plugins/server.py | 9 +++++++-- + ipaserver/plugins/serverrole.py | 18 +++++++++++++++--- + 3 files changed, 24 insertions(+), 6 deletions(-) + +diff --git a/API.txt b/API.txt +index 96c1548331750577e899f397f6f5a9a9d863248a..0e09e58a6ecaa4f724fb0c92b4faaf64df9fab5a 100644 +--- a/API.txt ++++ b/API.txt +@@ -4421,9 +4421,10 @@ output: Entry('result') + output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) + output: PrimaryKey('value') + command: server_role_find/1 +-args: 1,8,4 ++args: 1,9,4 + arg: Str('criteria?') + option: Flag('all', autofill=True, cli_name='all', default=False) ++option: Flag('include_master', autofill=True, default=False) + option: Flag('raw', autofill=True, cli_name='raw', default=False) + option: Str('role_servrole?', autofill=False, cli_name='role') + option: Str('server_server?', autofill=False, cli_name='server') +diff --git a/ipaserver/plugins/server.py b/ipaserver/plugins/server.py +index 4ea6f5b4b458db701c6c041d1c05cf4a7c6bc8a4..e265883e3637938e3df5ecf132f4add62413a997 100644 +--- a/ipaserver/plugins/server.py ++++ b/ipaserver/plugins/server.py +@@ -205,7 +205,10 @@ class server(LDAPObject): + return + + enabled_roles = self.api.Command.server_role_find( +- server_server=entry_attrs['cn'][0], status=ENABLED)['result'] ++ server_server=entry_attrs['cn'][0], ++ status=ENABLED, ++ include_master=True, ++ )['result'] + + enabled_role_names = [r[u'role_servrole'] for r in enabled_roles] + +@@ -339,7 +342,9 @@ class server_find(LDAPSearch): + role_status = self.api.Command.server_role_find( + server_server=None, + role_servrole=role, +- status=ENABLED)['result'] ++ status=ENABLED, ++ include_master=True, ++ )['result'] + + return set( + r[u'server_server'] for r in role_status) +diff --git a/ipaserver/plugins/serverrole.py b/ipaserver/plugins/serverrole.py +index 1b19c7e867a0223d1c2e72372d9f3dc65fc5f771..5b7ccfb342d0a54bfd6f2cdc53c7d31201ed5989 100644 +--- a/ipaserver/plugins/serverrole.py ++++ b/ipaserver/plugins/serverrole.py +@@ -5,7 +5,7 @@ + from ipalib.crud import Retrieve, Search + from ipalib.errors import NotFound + from ipalib.frontend import Object +-from ipalib.parameters import Int, Str, StrEnum ++from ipalib.parameters import Flag, Int, Str, StrEnum + from ipalib.plugable import Registry + from ipalib import _, ngettext + +@@ -129,6 +129,10 @@ class server_role_find(Search): + minvalue=0, + autofill=False, + ), ++ Flag( ++ 'include_master', ++ doc=_('Include IPA master entries'), ++ ) + ) + + def execute(self, *keys, **options): +@@ -151,8 +155,16 @@ class server_role_find(Search): + role_servrole=role_name, + status=status) + +- result = [ +- r for r in role_status if r[u'role_servrole'] != "IPA master"] ++ # Don't display "IPA master" information unless the role is ++ # requested explicitly. All servers are considered IPA masters, ++ # except for replicas during installation. ++ if options.get('include_master') or role_name == "IPA master": ++ result = role_status ++ else: ++ result = [ ++ r for r in role_status ++ if r[u'role_servrole'] != "IPA master" ++ ] + return dict( + result=result, + count=len(result), +-- +2.17.1 + diff --git a/SOURCES/0012-Fix-cert-find-for-CA-less-installations.patch b/SOURCES/0012-Fix-cert-find-for-CA-less-installations.patch deleted file mode 100644 index 106cea6..0000000 --- a/SOURCES/0012-Fix-cert-find-for-CA-less-installations.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 6049b791567dad33be050b05bb08ef2040f473ee Mon Sep 17 00:00:00 2001 -From: Rob Crittenden <rcritten@redhat.com> -Date: Tue, 24 Oct 2017 15:43:08 -0400 -Subject: [PATCH] Fix cert-find for CA-less installations - -Change 49f9d799c171c7ae2ac546a33a353c2c40b4719c deferred the -detailed lookup until all certs were collected but introduced -a bug where the ra backend was always retrieved. This generated a -backtrace in a CA-less install because there is no ra backend in -the CA-less case. - -The deferral also removes the certificate value from the LDAP -search output resulting in only the serial number being displayed -unless --all is provided. Add a new class variable, -self.ca_enabled, to add an exception for the CA-less case. - -Fixes https://pagure.io/freeipa/issue/7202 - -Signed-off-by: Rob Crittenden <rcritten@redhat.com> -Reviewed-By: Stanislav Laznicka <slaznick@redhat.com> ---- - ipaserver/plugins/cert.py | 22 ++++++++++++++++++++-- - 1 file changed, 20 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index bb11713317abad55577b1c280253ab5d6d68c508..c1d389217265f44e646ac27d9adc8d5524c74ce7 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -1453,6 +1453,7 @@ class cert_find(Search, CertMethod): - - truncated = bool(truncated) - -+ ca_enabled = getattr(context, 'ca_enabled') - for entry in entries: - for attr in ('usercertificate', 'usercertificate;binary'): - for cert in entry.get(attr, []): -@@ -1466,7 +1467,12 @@ class cert_find(Search, CertMethod): - obj = result[issuer, serial_number] - except KeyError: - obj = {'serial_number': serial_number} -- if not pkey_only and all: -+ if not pkey_only and (all or not ca_enabled): -+ # Retrieving certificate details is now deferred -+ # until after all certificates are collected. -+ # For the case of CA-less we need to keep -+ # the certificate because getting it again later -+ # would require unnecessary LDAP searches. - obj['certificate'] = ( - base64.b64encode(cert).decode('ascii')) - result[issuer, serial_number] = obj -@@ -1480,6 +1486,11 @@ class cert_find(Search, CertMethod): - - def execute(self, criteria=None, all=False, raw=False, pkey_only=False, - no_members=True, timelimit=None, sizelimit=None, **options): -+ # Store ca_enabled status in the context to save making the API -+ # call multiple times. -+ ca_enabled = self.api.Command.ca_is_enabled()['result'] -+ setattr(context, 'ca_enabled', ca_enabled) -+ - if 'cacn' in options: - ca_obj = api.Command.ca_show(options['cacn'])['result'] - ca_sdn = unicode(ca_obj['ipacasubjectdn'][0]) -@@ -1534,7 +1545,8 @@ class cert_find(Search, CertMethod): - - if not pkey_only: - ca_objs = {} -- ra = self.api.Backend.ra -+ if ca_enabled: -+ ra = self.api.Backend.ra - - for key, obj in six.iteritems(result): - if all and 'cacn' in obj: -@@ -1561,6 +1573,12 @@ class cert_find(Search, CertMethod): - - if not raw: - self.obj._parse(obj, all) -+ if not ca_enabled and not all: -+ # For the case of CA-less don't display the full -+ # certificate unless requested. It is kept in the -+ # entry from _ldap_search() so its attributes can -+ # be retrieved. -+ obj.pop('certificate', None) - self.obj._fill_owners(obj) - - result = list(six.itervalues(result)) --- -2.13.6 - diff --git a/SOURCES/0012-Only-create-DNS-SRV-records-for-ready-server.patch b/SOURCES/0012-Only-create-DNS-SRV-records-for-ready-server.patch new file mode 100644 index 0000000..25c3bb8 --- /dev/null +++ b/SOURCES/0012-Only-create-DNS-SRV-records-for-ready-server.patch @@ -0,0 +1,49 @@ +From 7297060d59534cff6a703ad95c68bf20e53c14ae Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Thu, 5 Jul 2018 23:59:06 +0200 +Subject: [PATCH] Only create DNS SRV records for ready server + +When installing multiple replicas in parallel, one replica may create +SRV entries for other replicas, although the replicas aren't fully +installed yet. This may cause some services to connect to a server, that +isn't ready to serve requests. + +The DNS IPASystemRecords framework now skips all servers that aren't +ready IPA masters. + +See: https://pagure.io/freeipa/issue/7566 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> +--- + ipaserver/dns_data_management.py | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/dns_data_management.py b/ipaserver/dns_data_management.py +index bdf83de0cd76d8b571b5c2190ef8c4d63bcbf2d7..675dd481b461aa14d8adf8393a2168ac84ecac86 100644 +--- a/ipaserver/dns_data_management.py ++++ b/ipaserver/dns_data_management.py +@@ -96,7 +96,9 @@ class IPASystemRecords(object): + self.servers_data = {} + + servers_result = self.api_instance.Command.server_find( +- no_members=False)['result'] ++ no_members=False, ++ servrole=u"IPA master", # only active, fully installed masters ++ )['result'] + for s in servers_result: + weight, location, roles = self.__get_server_attrs(s) + self.servers_data[s['cn'][0]] = { +@@ -348,7 +350,9 @@ class IPASystemRecords(object): + zone_obj = zone.Zone(self.domain_abs, relativize=False) + if servers is None: + servers_result = self.api_instance.Command.server_find( +- pkey_only=True)['result'] ++ pkey_only=True, ++ servrole=u"IPA master", # only fully installed masters ++ )['result'] + servers = [s['cn'][0] for s in servers_result] + + locations_result = self.api_instance.Command.location_find()['result'] +-- +2.17.1 + diff --git a/SOURCES/0013-Delay-enabling-services-until-end-of-installer.patch b/SOURCES/0013-Delay-enabling-services-until-end-of-installer.patch new file mode 100644 index 0000000..b44176e --- /dev/null +++ b/SOURCES/0013-Delay-enabling-services-until-end-of-installer.patch @@ -0,0 +1,601 @@ +From 4caf0c14ad38a1dae494489b13f4109cdb3ba340 Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Fri, 6 Jul 2018 00:04:39 +0200 +Subject: [PATCH] Delay enabling services until end of installer + +Service entries in cn=FQDN,cn=masters,cn=ipa,cn=etc are no longer +created as enabled. Instead they are flagged as configuredService. At +the very end of the installer, the service entries are switched from +configured to enabled service. + +- SRV records are created at the very end of the installer. +- Dogtag installer only picks fully installed servers +- Certmonger ignores all configured but not yet enabled servers. + +Fixes: https://pagure.io/freeipa/issue/7566 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> +--- + install/tools/ipa-adtrust-install | 6 +- + install/tools/ipa-ca-install | 12 ++- + install/tools/ipa-dns-install | 4 + + ipaserver/dns_data_management.py | 18 +++-- + ipaserver/install/adtrustinstance.py | 6 +- + ipaserver/install/bindinstance.py | 8 +- + ipaserver/install/cainstance.py | 2 +- + ipaserver/install/dnskeysyncinstance.py | 4 +- + ipaserver/install/httpinstance.py | 4 +- + ipaserver/install/ipa_kra_install.py | 7 ++ + ipaserver/install/krainstance.py | 2 +- + ipaserver/install/krbinstance.py | 4 +- + ipaserver/install/odsexporterinstance.py | 4 +- + ipaserver/install/opendnssecinstance.py | 6 +- + ipaserver/install/server/install.py | 18 +++-- + ipaserver/install/server/replicainstall.py | 8 +- + ipaserver/install/service.py | 88 ++++++++++++++++++++-- + ipaserver/plugins/serverrole.py | 7 +- + 18 files changed, 161 insertions(+), 47 deletions(-) + +diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install +index d4e5d4c09cf6b7c1521bcecb79bb6fd7235fc799..a870d136e242affe6627cd4c44a173a80a9ab1c6 100755 +--- a/install/tools/ipa-adtrust-install ++++ b/install/tools/ipa-adtrust-install +@@ -32,7 +32,7 @@ import six + from optparse import SUPPRESS_HELP # pylint: disable=deprecated-module + + from ipalib.install import sysrestore +-from ipaserver.install import adtrust ++from ipaserver.install import adtrust, service + from ipaserver.install.installutils import ( + read_password, + check_server_configuration, +@@ -212,6 +212,10 @@ def main(): + adtrust.install_check(True, options, api) + adtrust.install(True, options, fstore, api) + ++ # Enable configured services and update DNS SRV records ++ service.enable_services(api.env.host) ++ api.Command.dns_update_system_records() ++ + print(""" + ============================================================================= + Setup complete +diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install +index e4e24fb8c5261e77dd9d3e89cbe42dba519b932e..f78f43d94981d29939a247f3c492c5e7340298ea 100755 +--- a/install/tools/ipa-ca-install ++++ b/install/tools/ipa-ca-install +@@ -332,18 +332,26 @@ def main(): + ) + api.finalize() + api.Backend.ldap2.connect() +- + domain_level = dsinstance.get_domain_level(api) ++ + if domain_level > DOMAIN_LEVEL_0: + promote(safe_options, options, filename) + else: + install(safe_options, options, filename) + ++ # pki-spawn restarts 389-DS, reconnect ++ api.Backend.ldap2.close() ++ api.Backend.ldap2.connect() ++ ++ # Enable configured services and update DNS SRV records ++ service.enable_services(api.env.host) ++ api.Command.dns_update_system_records() ++ api.Backend.ldap2.disconnect() ++ + # execute ipactl to refresh services status + ipautil.run(['ipactl', 'start', '--ignore-service-failures'], + raiseonerr=False) + +- api.Backend.ldap2.disconnect() + + fail_message = ''' + Your system may be partly configured. +diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install +index a7f136b16ab4871518f5fd776d49e55c2364c54e..57dde5a5da4fad162c93e9e0416b54961de4c1e3 100755 +--- a/install/tools/ipa-dns-install ++++ b/install/tools/ipa-dns-install +@@ -37,6 +37,7 @@ from ipapython.config import IPAOptionParser + from ipapython.ipa_log_manager import standard_logging_setup + + from ipaserver.install import dns as dns_installer ++from ipaserver.install import service + + logger = logging.getLogger(os.path.basename(__file__)) + +@@ -148,6 +149,9 @@ def main(): + + dns_installer.install_check(True, api, False, options, hostname=api.env.host) + dns_installer.install(True, False, options) ++ # Enable configured services and update DNS SRV records ++ service.enable_services(api.env.host) ++ api.Command.dns_update_system_records() + + # execute ipactl to refresh services status + ipautil.run(['ipactl', 'start', '--ignore-service-failures'], +diff --git a/ipaserver/dns_data_management.py b/ipaserver/dns_data_management.py +index 675dd481b461aa14d8adf8393a2168ac84ecac86..673397ef2b2252f431eec1f3e1f71dc45ff87511 100644 +--- a/ipaserver/dns_data_management.py ++++ b/ipaserver/dns_data_management.py +@@ -68,11 +68,11 @@ class IPASystemRecords(object): + PRIORITY_HIGH = 0 + PRIORITY_LOW = 50 + +- def __init__(self, api_instance): ++ def __init__(self, api_instance, all_servers=False): + self.api_instance = api_instance + self.domain_abs = DNSName(self.api_instance.env.domain).make_absolute() + self.servers_data = {} +- self.__init_data() ++ self.__init_data(all_servers=all_servers) + + def reload_data(self): + """ +@@ -92,14 +92,16 @@ class IPASystemRecords(object): + def __get_location_suffix(self, location): + return location + DNSName('_locations') + self.domain_abs + +- def __init_data(self): ++ def __init_data(self, all_servers=False): + self.servers_data = {} + +- servers_result = self.api_instance.Command.server_find( +- no_members=False, +- servrole=u"IPA master", # only active, fully installed masters +- )['result'] +- for s in servers_result: ++ kwargs = dict(no_members=False) ++ if not all_servers: ++ # only active, fully installed masters] ++ kwargs["servrole"] = u"IPA master" ++ servers = self.api_instance.Command.server_find(**kwargs) ++ ++ for s in servers['result']: + weight, location, roles = self.__get_server_attrs(s) + self.servers_data[s['cn'][0]] = { + 'weight': weight, +diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py +index a075801ebec20ea8277445e0bac788c06e0b0a91..2da46d67495014fb38e5ee8c6a98ede93ef8762d 100644 +--- a/ipaserver/install/adtrustinstance.py ++++ b/ipaserver/install/adtrustinstance.py +@@ -581,7 +581,7 @@ class ADTRUSTInstance(service.Service): + self.print_msg(err_msg) + self.print_msg("Add the following service records to your DNS " \ + "server for DNS zone %s: " % zone) +- system_records = IPASystemRecords(api) ++ system_records = IPASystemRecords(api, all_servers=True) + adtrust_records = system_records.get_base_records( + [self.fqdn], ["AD trust controller"], + include_master_role=False, include_kerberos_realm=False) +@@ -736,12 +736,12 @@ class ADTRUSTInstance(service.Service): + # Note that self.dm_password is None for ADTrustInstance because + # we ensure to be called as root and using ldapi to use autobind + try: +- self.ldap_enable('ADTRUST', self.fqdn, None, self.suffix) ++ self.ldap_configure('ADTRUST', self.fqdn, None, self.suffix) + except (ldap.ALREADY_EXISTS, errors.DuplicateEntry): + logger.info("ADTRUST Service startup entry already exists.") + + try: +- self.ldap_enable('EXTID', self.fqdn, None, self.suffix) ++ self.ldap_configure('EXTID', self.fqdn, None, self.suffix) + except (ldap.ALREADY_EXISTS, errors.DuplicateEntry): + logger.info("EXTID Service startup entry already exists.") + +diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py +index 203a6405f815d47c0dc33977e77012a2c85916ff..7c858aab4417ccf3a4999fcaaa1c7e0f93464e4d 100644 +--- a/ipaserver/install/bindinstance.py ++++ b/ipaserver/install/bindinstance.py +@@ -669,7 +669,7 @@ class BindInstance(service.Service): + return normalize_zone(self.host_domain) == normalize_zone(self.domain) + + def create_file_with_system_records(self): +- system_records = IPASystemRecords(self.api) ++ system_records = IPASystemRecords(self.api, all_servers=True) + text = u'\n'.join( + IPASystemRecords.records_list_from_zone( + system_records.get_base_records() +@@ -746,7 +746,7 @@ class BindInstance(service.Service): + # Instead we reply on the IPA init script to start only enabled + # components as found in our LDAP configuration tree + try: +- self.ldap_enable('DNS', self.fqdn, None, self.suffix) ++ self.ldap_configure('DNS', self.fqdn, None, self.suffix) + except errors.DuplicateEntry: + # service already exists (forced DNS reinstall) + # don't crash, just report error +@@ -1180,7 +1180,9 @@ class BindInstance(service.Service): + except ValueError as error: + logger.debug('%s', error) + +- # disabled by default, by ldap_enable() ++ installutils.rmtree(paths.BIND_LDAP_DNS_IPA_WORKDIR) ++ ++ # disabled by default, by ldap_configure() + if enabled: + self.enable() + else: +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index b58fbb4c881d247d6b5fb661f4085ec82c3cc811..51fdbe9c61e06ab9d72d78aee8786f9bceca137b 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -1258,7 +1258,7 @@ class CAInstance(DogtagInstance): + config = ['caRenewalMaster'] + else: + config = [] +- self.ldap_enable('CA', self.fqdn, None, basedn, config) ++ self.ldap_configure('CA', self.fqdn, None, basedn, config) + + def setup_lightweight_ca_key_retrieval(self): + if sysupgrade.get_upgrade_state('dogtag', 'setup_lwca_key_retrieval'): +diff --git a/ipaserver/install/dnskeysyncinstance.py b/ipaserver/install/dnskeysyncinstance.py +index b865ee8aa79c17502a3784878f8f6f45d05213a6..2e773f3adae8130f578e6f3fbfe8c3a414d523cb 100644 +--- a/ipaserver/install/dnskeysyncinstance.py ++++ b/ipaserver/install/dnskeysyncinstance.py +@@ -382,8 +382,8 @@ class DNSKeySyncInstance(service.Service): + + def __enable(self): + try: +- self.ldap_enable('DNSKeySync', self.fqdn, None, +- self.suffix, self.extra_config) ++ self.ldap_configure('DNSKeySync', self.fqdn, None, ++ self.suffix, self.extra_config) + except errors.DuplicateEntry: + logger.error("DNSKeySync service already exists") + +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index bdd79b1dafda7de664eed664a18bf36c541212bc..0b7023c2f1b0feb996e0dd0adbefbd49c51da757 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -196,7 +196,7 @@ class HTTPInstance(service.Service): + # We do not let the system start IPA components on its own, + # Instead we reply on the IPA init script to start only enabled + # components as found in our LDAP configuration tree +- self.ldap_enable('HTTP', self.fqdn, None, self.suffix) ++ self.ldap_configure('HTTP', self.fqdn, None, self.suffix) + + def configure_selinux_for_httpd(self): + try: +@@ -609,7 +609,7 @@ class HTTPInstance(service.Service): + if running: + self.restart() + +- # disabled by default, by ldap_enable() ++ # disabled by default, by ldap_configure() + if enabled: + self.enable() + +diff --git a/ipaserver/install/ipa_kra_install.py b/ipaserver/install/ipa_kra_install.py +index 07e11ea69ded8832015dd69ea43ff338c5f9df95..b536685f5f1f3fccab07fd37aa001958e2d38420 100644 +--- a/ipaserver/install/ipa_kra_install.py ++++ b/ipaserver/install/ipa_kra_install.py +@@ -227,4 +227,11 @@ class KRAInstaller(KRAInstall): + logger.error('%s', dedent(self.FAIL_MESSAGE)) + raise + ++ # pki-spawn restarts 389-DS, reconnect ++ api.Backend.ldap2.close() ++ api.Backend.ldap2.connect() ++ ++ # Enable configured services and update DNS SRV records ++ service.enable_services(api.env.host) ++ api.Command.dns_update_system_records() + api.Backend.ldap2.disconnect() +diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py +index 9483f0ec4edbabea0f7eff0dd5dd223377653536..c1daa2869b7cba79e29d2db61c090c145304397f 100644 +--- a/ipaserver/install/krainstance.py ++++ b/ipaserver/install/krainstance.py +@@ -392,4 +392,4 @@ class KRAInstance(DogtagInstance): + directives[nickname], cert) + + def __enable_instance(self): +- self.ldap_enable('KRA', self.fqdn, None, self.suffix) ++ self.ldap_configure('KRA', self.fqdn, None, self.suffix) +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index a356d5e0c1b96dc6511c335fc22a326a2133bdd8..33d66fb94b0a1f7571b22120e5159a0e0ad2e675 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -242,7 +242,7 @@ class KrbInstance(service.Service): + # We do not let the system start IPA components on its own, + # Instead we reply on the IPA init script to start only enabled + # components as found in our LDAP configuration tree +- self.ldap_enable('KDC', self.fqdn, None, self.suffix) ++ self.ldap_configure('KDC', self.fqdn, None, self.suffix) + + def __start_instance(self): + try: +@@ -607,7 +607,7 @@ class KrbInstance(service.Service): + except ValueError as error: + logger.debug("%s", error) + +- # disabled by default, by ldap_enable() ++ # disabled by default, by ldap_configure() + if enabled: + self.enable() + +diff --git a/ipaserver/install/odsexporterinstance.py b/ipaserver/install/odsexporterinstance.py +index b301a167f80d171c0dd0e6282a6021fcbdca8f9e..4856f5642d8e2c4c9e9089cd44a85e759c4c6ca0 100644 +--- a/ipaserver/install/odsexporterinstance.py ++++ b/ipaserver/install/odsexporterinstance.py +@@ -73,8 +73,8 @@ class ODSExporterInstance(service.Service): + def __enable(self): + + try: +- self.ldap_enable('DNSKeyExporter', self.fqdn, None, +- self.suffix) ++ self.ldap_configure('DNSKeyExporter', self.fqdn, None, ++ self.suffix) + except errors.DuplicateEntry: + logger.error("DNSKeyExporter service already exists") + +diff --git a/ipaserver/install/opendnssecinstance.py b/ipaserver/install/opendnssecinstance.py +index d608294cbbab9179d95b2333323f5d378940a936..0337bb22fea44f95ee9077423136353a991325db 100644 +--- a/ipaserver/install/opendnssecinstance.py ++++ b/ipaserver/install/opendnssecinstance.py +@@ -140,8 +140,8 @@ class OpenDNSSECInstance(service.Service): + + def __enable(self): + try: +- self.ldap_enable('DNSSEC', self.fqdn, None, +- self.suffix, self.extra_config) ++ self.ldap_configure('DNSSEC', self.fqdn, None, ++ self.suffix, self.extra_config) + except errors.DuplicateEntry: + logger.error("DNSSEC service already exists") + +@@ -372,7 +372,7 @@ class OpenDNSSECInstance(service.Service): + + self.restore_state("kasp_db_configured") # just eat state + +- # disabled by default, by ldap_enable() ++ # disabled by default, by ldap_configure() + if enabled: + self.enable() + +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index e96ae97c74ee1598683d1ef3f2570e8de93c9943..a341408f78f24055d807ae49c8a0cda81bfb3ec4 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -870,14 +870,6 @@ def install(installer): + + if options.setup_dns: + dns.install(False, False, options) +- else: +- # Create a BIND instance +- bind = bindinstance.BindInstance(fstore) +- bind.setup(host_name, ip_addresses, realm_name, +- domain_name, (), 'first', (), +- zonemgr=options.zonemgr, +- no_dnssec_validation=options.no_dnssec_validation) +- bind.create_file_with_system_records() + + if options.setup_adtrust: + adtrust.install(False, options, fstore, api) +@@ -906,6 +898,16 @@ def install(installer): + except Exception: + raise ScriptError("Configuration of client side components failed!") + ++ # Enable configured services and update DNS SRV records ++ service.enable_services(host_name) ++ api.Command.dns_update_system_records() ++ ++ if not options.setup_dns: ++ # After DNS and AD trust are configured and services are ++ # enabled, create a dummy instance to dump DNS configuration. ++ bind = bindinstance.BindInstance(fstore) ++ bind.create_file_with_system_records() ++ + # Everything installed properly, activate ipa service. + services.knownservices.ipa.enable() + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 33f3ae9e616b34a3ab0ff8e4257552855e817e7c..0bf3568a300a133fa505dc8fc339c6677f9c5f73 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -1520,14 +1520,11 @@ def install(installer): + + if options.setup_dns: + dns.install(False, True, options, api) +- else: +- api.Command.dns_update_system_records() + + if options.setup_adtrust: + adtrust.install(False, options, fstore, api) + + ca_servers = service.find_providing_servers('CA', api.Backend.ldap2, api) +- api.Backend.ldap2.disconnect() + + if not promote: + # Call client install script +@@ -1556,6 +1553,11 @@ def install(installer): + # remove the extracted replica file + remove_replica_info_dir(installer) + ++ # Enable configured services and update DNS SRV records ++ service.enable_services(config.host_name) ++ api.Command.dns_update_system_records() ++ api.Backend.ldap2.disconnect() ++ + # Everything installed properly, activate ipa service. + services.knownservices.ipa.enable() + +diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py +index 4c320de9d64676373cd41ff839889f2448a19a46..0106379ea38e4a3fef8436256d6f315f524b8dee 100644 +--- a/ipaserver/install/service.py ++++ b/ipaserver/install/service.py +@@ -27,6 +27,7 @@ import socket + import datetime + import traceback + import tempfile ++import warnings + + import six + +@@ -62,6 +63,10 @@ SERVICE_LIST = { + 'DNSKeySync': ('ipa-dnskeysyncd', 110), + } + ++CONFIGURED_SERVICE = u'configuredService' ++ENABLED_SERVICE = 'enabledService' ++ ++ + def print_msg(message, output_fd=sys.stdout): + logger.debug("%s", message) + output_fd.write(message) +@@ -123,7 +128,7 @@ def find_providing_servers(svcname, conn, api): + """ + dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) + query_filter = conn.make_filter({'objectClass': 'ipaConfigObject', +- 'ipaConfigString': 'enabledService', ++ 'ipaConfigString': ENABLED_SERVICE, + 'cn': svcname}, rules='&') + try: + entries, _trunc = conn.find_entries(filter=query_filter, base_dn=dn) +@@ -232,6 +237,51 @@ def set_service_entry_config(name, fqdn, config_values, + raise e + + ++def enable_services(fqdn): ++ """Change all configured services to enabled ++ ++ Server.ldap_configure() only marks a service as configured. Services ++ are enabled at the very end of installation. ++ ++ Note: DNS records must be updated with dns_update_system_records, too. ++ ++ :param fqdn: hostname of server ++ """ ++ ldap2 = api.Backend.ldap2 ++ search_base = DN(('cn', fqdn), api.env.container_masters, api.env.basedn) ++ search_filter = ldap2.make_filter( ++ { ++ 'objectClass': 'ipaConfigObject', ++ 'ipaConfigString': CONFIGURED_SERVICE ++ }, ++ rules='&' ++ ) ++ entries = ldap2.get_entries( ++ search_base, ++ filter=search_filter, ++ scope=api.Backend.ldap2.SCOPE_ONELEVEL, ++ attrs_list=['cn', 'ipaConfigString'] ++ ) ++ for entry in entries: ++ name = entry['cn'] ++ cfgstrings = entry.setdefault('ipaConfigString', []) ++ for value in list(cfgstrings): ++ if value.lower() == CONFIGURED_SERVICE.lower(): ++ cfgstrings.remove(value) ++ if not case_insensitive_attr_has_value(cfgstrings, ENABLED_SERVICE): ++ cfgstrings.append(ENABLED_SERVICE) ++ ++ try: ++ ldap2.update_entry(entry) ++ except errors.EmptyModlist: ++ logger.debug("Nothing to do for service %s", name) ++ except Exception: ++ logger.exception("failed to set service %s config values", name) ++ raise ++ else: ++ logger.debug("Enabled service %s for %s", name, fqdn) ++ ++ + class Service(object): + def __init__(self, service_name, service_desc=None, sstore=None, + fstore=None, api=api, realm_name=None, +@@ -538,7 +588,35 @@ class Service(object): + self.steps = [] + + def ldap_enable(self, name, fqdn, dm_password=None, ldap_suffix='', +- config=[]): ++ config=()): ++ """Legacy function, all services should use ldap_configure() ++ """ ++ warnings.warn( ++ "ldap_enable is deprecated, use ldap_configure instead.", ++ DeprecationWarning, ++ stacklevel=2 ++ ) ++ self._ldap_enable(ENABLED_SERVICE, name, fqdn, ldap_suffix, config) ++ ++ def ldap_configure(self, name, fqdn, dm_password=None, ldap_suffix='', ++ config=()): ++ """Create or modify service entry in cn=masters,cn=ipa,cn=etc ++ ++ Contrary to ldap_enable(), the method only sets ++ ipaConfigString=configuredService. ipaConfigString=enabledService ++ is set at the very end of the installation process, to ensure that ++ other machines see this master/replica after it is fully installed. ++ ++ To switch all configured services to enabled, use:: ++ ++ ipaserver.install.service.enable_services(api.env.host) ++ api.Command.dns_update_system_records() ++ """ ++ self._ldap_enable( ++ CONFIGURED_SERVICE, name, fqdn, ldap_suffix, config ++ ) ++ ++ def _ldap_enable(self, value, name, fqdn, ldap_suffix, config): + extra_config_opts = [ + ' '.join([u'startOrder', unicode(SERVICE_LIST[name][1])]) + ] +@@ -549,7 +627,7 @@ class Service(object): + set_service_entry_config( + name, + fqdn, +- [u'enabledService'], ++ [value], + ldap_suffix=ldap_suffix, + post_add_config=extra_config_opts) + +@@ -575,7 +653,7 @@ class Service(object): + + # case insensitive + for value in entry.get('ipaConfigString', []): +- if value.lower() == u'enabledservice': ++ if value.lower() == ENABLED_SERVICE: + entry['ipaConfigString'].remove(value) + break + +@@ -688,7 +766,7 @@ class SimpleServiceInstance(Service): + if self.gensvc_name == None: + self.enable() + else: +- self.ldap_enable(self.gensvc_name, self.fqdn, None, self.suffix) ++ self.ldap_configure(self.gensvc_name, self.fqdn, None, self.suffix) + + def is_installed(self): + return self.service.is_installed() +diff --git a/ipaserver/plugins/serverrole.py b/ipaserver/plugins/serverrole.py +index 5b7ccfb342d0a54bfd6f2cdc53c7d31201ed5989..199978000ce8cf783bda50c46b7c9fa109f70ad6 100644 +--- a/ipaserver/plugins/serverrole.py ++++ b/ipaserver/plugins/serverrole.py +@@ -15,16 +15,21 @@ IPA server roles + """) + _(""" + Get status of roles (DNS server, CA, etc.) provided by IPA masters. + """) + _(""" ++The status of a role is either enabled, configured, or absent. ++""") + _(""" + EXAMPLES: + """) + _(""" + Show status of 'DNS server' role on a server: + ipa server-role-show ipa.example.com "DNS server" + """) + _(""" + Show status of all roles containing 'AD' on a server: +- ipa server-role-find --server ipa.example.com --role='AD' ++ ipa server-role-find --server ipa.example.com --role="AD trust controller" + """) + _(""" + Show status of all configured roles on a server: + ipa server-role-find ipa.example.com ++""") + _(""" ++ Show implicit IPA master role: ++ ipa server-role-find --include-master + """) + + +-- +2.17.1 + diff --git a/SOURCES/0013-Fix-ipa-restore-python2.patch b/SOURCES/0013-Fix-ipa-restore-python2.patch deleted file mode 100644 index 573fb00..0000000 --- a/SOURCES/0013-Fix-ipa-restore-python2.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 276a0dfa90be417a0ce37b15027f716baa97a453 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud <flo@redhat.com> -Date: Thu, 2 Nov 2017 09:34:43 +0100 -Subject: [PATCH] Fix ipa-restore (python2) - -In order to stop tracking LDAP server cert, ipa-restore is using -dse.ldif to find the certificate name. But when ipa-server-install ---uninstall has been called, the file does not exist, leading to a -IOError exception (regression introduced by 87540fe). - -The ipa-restore code properly catches the exception in python3 because -IOError is a subclass of OSError, but in python2 this is not the case. -The fix catches IOError and OSError to work properly with both version. - -Fixes: -https://pagure.io/freeipa/issue/7231 - -Reviewed-By: Rob Crittenden <rcritten@redhat.com> -Reviewed-By: Tomas Krizek <tkrizek@redhat.com> ---- - ipaserver/install/ipa_restore.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index 96fc493c774f5de4c8149bf477cb66ec4960de4f..923b1d6696d33c0bb07ca018b53dd3dabcc191aa 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -815,7 +815,7 @@ class Restore(admintool.AdminTool): - try: - dsinstance.DsInstance().stop_tracking_certificates( - installutils.realm_to_serverid(api.env.realm)) -- except OSError: -+ except (OSError, IOError): - # When IPA is not installed, DS NSS DB does not exist - pass - --- -2.13.6 - diff --git a/SOURCES/0014-Backup-ipa-custodia-conf-and-keys.patch b/SOURCES/0014-Backup-ipa-custodia-conf-and-keys.patch deleted file mode 100644 index fb72527..0000000 --- a/SOURCES/0014-Backup-ipa-custodia-conf-and-keys.patch +++ /dev/null @@ -1,154 +0,0 @@ -From 0e1b5a65ed06b2213deebb0ea1e5fb8422223426 Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Wed, 8 Nov 2017 15:15:30 +0100 -Subject: [PATCH] Backup ipa-custodia conf and keys - -https://pagure.io/freeipa/issue/7247 - -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Simo Sorce <ssorce@redhat.com> ---- - install/share/custodia.conf.template | 2 +- - ipaplatform/base/paths.py | 1 + - ipapython/ipautil.py | 19 +++++++++++++++++++ - ipaserver/install/custodiainstance.py | 24 +++++++++++++----------- - ipaserver/install/ipa_backup.py | 2 ++ - ipatests/test_ipapython/test_ipautil.py | 7 +++++++ - 6 files changed, 43 insertions(+), 12 deletions(-) - -diff --git a/install/share/custodia.conf.template b/install/share/custodia.conf.template -index 855a1b3ba206e4ded8de80758b02473040096c7f..ee3c43ca7ec265aa09d250426bf4138bcfdf62b6 100644 ---- a/install/share/custodia.conf.template -+++ b/install/share/custodia.conf.template -@@ -16,7 +16,7 @@ header = GSS_NAME - handler = ipaserver.secrets.kem.IPAKEMKeys - paths = /keys - store = ipa --server_keys = $IPA_CUSTODIA_CONF_DIR/server.keys -+server_keys = $IPA_CUSTODIA_KEYS - - [store:ipa] - handler = ipaserver.secrets.store.IPASecStore -diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py -index 804fddee60f787e161947bbe4b1914995257ceb4..42240a71066599ca8b36d10a9e5b23625f868977 100644 ---- a/ipaplatform/base/paths.py -+++ b/ipaplatform/base/paths.py -@@ -349,6 +349,7 @@ class BasePathNamespace(object): - NETWORK_MANAGER_CONFIG_DIR = '/etc/NetworkManager/conf.d' - IPA_CUSTODIA_CONF_DIR = '/etc/ipa/custodia' - IPA_CUSTODIA_CONF = '/etc/ipa/custodia/custodia.conf' -+ IPA_CUSTODIA_KEYS = '/etc/ipa/custodia/server.keys' - IPA_CUSTODIA_SOCKET = '/run/httpd/ipa-custodia.sock' - IPA_CUSTODIA_AUDIT_LOG = '/var/log/ipa-custodia.audit.log' - IPA_GETKEYTAB = '/usr/sbin/ipa-getkeytab' -diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py -index cc52af6d9235cfbd597679231f63667b81a200b4..426b32ef05ab00dcbf37b1e58b6390accee33cb1 100644 ---- a/ipapython/ipautil.py -+++ b/ipapython/ipautil.py -@@ -307,6 +307,25 @@ def write_tmp_file(txt): - - return fd - -+ -+def flush_sync(f): -+ """Flush and fsync file to disk -+ -+ :param f: a file object with fileno and name -+ """ -+ # flush file buffer to file descriptor -+ f.flush() -+ # flush Kernel buffer to disk -+ os.fsync(f.fileno()) -+ # sync metadata in directory -+ dirname = os.path.dirname(os.path.abspath(f.name)) -+ dirfd = os.open(dirname, os.O_RDONLY | os.O_DIRECTORY) -+ try: -+ os.fsync(dirfd) -+ finally: -+ os.close(dirfd) -+ -+ - def shell_quote(string): - if isinstance(string, str): - return "'" + string.replace("'", "'\\''") + "'" -diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py -index bc3cea7063dff183c85b4f6e8ced7567f691001d..0a90bb3954486b9773e3553e9981d2a8d0d4e44a 100644 ---- a/ipaserver/install/custodiainstance.py -+++ b/ipaserver/install/custodiainstance.py -@@ -25,8 +25,7 @@ class CustodiaInstance(SimpleServiceInstance): - def __init__(self, host_name=None, realm=None): - super(CustodiaInstance, self).__init__("ipa-custodia") - self.config_file = paths.IPA_CUSTODIA_CONF -- self.server_keys = os.path.join(paths.IPA_CUSTODIA_CONF_DIR, -- 'server.keys') -+ self.server_keys = paths.IPA_CUSTODIA_KEYS - self.ldap_uri = None - self.fqdn = host_name - self.realm = realm -@@ -35,16 +34,19 @@ class CustodiaInstance(SimpleServiceInstance): - template_file = os.path.basename(self.config_file) + '.template' - template = os.path.join(paths.USR_SHARE_IPA_DIR, template_file) - httpd_info = pwd.getpwnam(constants.HTTPD_USER) -- sub_dict = dict(IPA_CUSTODIA_CONF_DIR=paths.IPA_CUSTODIA_CONF_DIR, -- IPA_CUSTODIA_SOCKET=paths.IPA_CUSTODIA_SOCKET, -- IPA_CUSTODIA_AUDIT_LOG=paths.IPA_CUSTODIA_AUDIT_LOG, -- LDAP_URI=installutils.realm_to_ldapi_uri(self.realm), -- UID=httpd_info.pw_uid, GID=httpd_info.pw_gid) -+ sub_dict = dict( -+ IPA_CUSTODIA_CONF_DIR=paths.IPA_CUSTODIA_CONF_DIR, -+ IPA_CUSTODIA_KEYS=paths.IPA_CUSTODIA_KEYS, -+ IPA_CUSTODIA_SOCKET=paths.IPA_CUSTODIA_SOCKET, -+ IPA_CUSTODIA_AUDIT_LOG=paths.IPA_CUSTODIA_AUDIT_LOG, -+ LDAP_URI=installutils.realm_to_ldapi_uri(self.realm), -+ UID=httpd_info.pw_uid, -+ GID=httpd_info.pw_gid -+ ) - conf = ipautil.template_file(template, sub_dict) -- fd = open(self.config_file, "w+") -- fd.write(conf) -- fd.flush() -- fd.close() -+ with open(self.config_file, "w") as f: -+ f.write(conf) -+ ipautil.flush_sync(f) - - def create_instance(self): - suffix = ipautil.realm_to_suffix(self.realm) -diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py -index f8cdd56d26636678279ba5afb423c5eef10c33d0..93b154330d3e6c8700c98860eb0c08f6841774bb 100644 ---- a/ipaserver/install/ipa_backup.py -+++ b/ipaserver/install/ipa_backup.py -@@ -181,6 +181,8 @@ class Backup(admintool.AdminTool): - paths.DNSSEC_SOFTHSM_PIN_SO, - paths.IPA_ODS_EXPORTER_KEYTAB, - paths.IPA_DNSKEYSYNCD_KEYTAB, -+ paths.IPA_CUSTODIA_KEYS, -+ paths.IPA_CUSTODIA_CONF, - paths.HOSTS, - ) + tuple( - os.path.join(paths.IPA_NSSDB_DIR, file) -diff --git a/ipatests/test_ipapython/test_ipautil.py b/ipatests/test_ipapython/test_ipautil.py -index 9c351bd0ed9cd96488ac74deadf97996668a75d2..5e1f58003e9f3cae2f0819ecc348ade2c367548b 100644 ---- a/ipatests/test_ipapython/test_ipautil.py -+++ b/ipatests/test_ipapython/test_ipautil.py -@@ -25,6 +25,7 @@ Test the `ipapython/ipautil.py` module. - import nose - import pytest - import six -+import tempfile - - from ipapython import ipautil - -@@ -478,3 +479,9 @@ def test_backcompat(): - assert rc is result.returncode - assert out is result.output - assert err is result.error_output -+ -+ -+def test_flush_sync(): -+ with tempfile.NamedTemporaryFile('wb+') as f: -+ f.write(b'data') -+ ipautil.flush_sync(f) --- -2.13.6 - diff --git a/SOURCES/0014-ipa-client-uninstall-clean-the-state-store-when-rest.patch b/SOURCES/0014-ipa-client-uninstall-clean-the-state-store-when-rest.patch new file mode 100644 index 0000000..4cd9653 --- /dev/null +++ b/SOURCES/0014-ipa-client-uninstall-clean-the-state-store-when-rest.patch @@ -0,0 +1,44 @@ +From 7f6f620ec43b5606413524d25d3cae1003930f55 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud <flo@redhat.com> +Date: Fri, 6 Jul 2018 12:47:34 +0200 +Subject: [PATCH] ipa client uninstall: clean the state store when restoring + hostname + +When ipa client was installed with the --hostname= option, it stores +[network] +hostname = (current hostname) +in /var/lib/ipa-client/sysrestore/sysrestore.state and changes the hostname +from (current hostname) to the value provided in --hostname. + +During uninstall, the previous hostname is restored but the entry does +not get removed from sysrestore.state. As the uninstaller checks if all +entries from sysrestore.state have been restored, it warns that some +state has not been restored. + +The fix calls statestore.restore_state() instead of statestore.get_state() +as this method also clears the entry. + +https://pagure.io/freeipa/issue/7620 + +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +--- + ipaplatform/redhat/tasks.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaplatform/redhat/tasks.py b/ipaplatform/redhat/tasks.py +index dcafd735c0161e5cd979ccb113863e7885a14ab3..6a4270defc9f444f76677bdf08d2a680649664bb 100644 +--- a/ipaplatform/redhat/tasks.py ++++ b/ipaplatform/redhat/tasks.py +@@ -380,7 +380,7 @@ class RedHatTaskNamespace(BaseTaskNamespace): + statestore.backup_state('network', 'hostname', old_hostname) + + def restore_hostname(self, fstore, statestore): +- old_hostname = statestore.get_state('network', 'hostname') ++ old_hostname = statestore.restore_state('network', 'hostname') + + if old_hostname is not None: + try: +-- +2.17.1 + diff --git a/SOURCES/0015-Fix-CA-topology-warning.patch b/SOURCES/0015-Fix-CA-topology-warning.patch new file mode 100644 index 0000000..c053de1 --- /dev/null +++ b/SOURCES/0015-Fix-CA-topology-warning.patch @@ -0,0 +1,65 @@ +From f637bcbe1066eec41e90b99d7a4ab12288f08a74 Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Fri, 6 Jul 2018 15:07:27 +0200 +Subject: [PATCH] Fix CA topology warning + +Commit 7284097eedef70dd556270732e6ab8e23501ce09 kept +find_providing_servers('CA') call before enable_services(). Therefore the +list of known CA servers did not contain the current replica. +ipa-replica-install on the first replica with --setup-ca still printed +the CA topology warning. + +See: https://pagure.io/freeipa/issue/7566 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> +--- + ipaserver/install/server/replicainstall.py | 3 +-- + ipaserver/install/service.py | 4 ++-- + 2 files changed, 3 insertions(+), 4 deletions(-) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 0bf3568a300a133fa505dc8fc339c6677f9c5f73..387d4ca85d9ad41db3ce2d9bc2ae67ba11836ada 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -1524,8 +1524,6 @@ def install(installer): + if options.setup_adtrust: + adtrust.install(False, options, fstore, api) + +- ca_servers = service.find_providing_servers('CA', api.Backend.ldap2, api) +- + if not promote: + # Call client install script + service.print_msg("Configuring client side components") +@@ -1556,6 +1554,7 @@ def install(installer): + # Enable configured services and update DNS SRV records + service.enable_services(config.host_name) + api.Command.dns_update_system_records() ++ ca_servers = service.find_providing_servers('CA', api.Backend.ldap2, api) + api.Backend.ldap2.disconnect() + + # Everything installed properly, activate ipa service. +diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py +index 0106379ea38e4a3fef8436256d6f315f524b8dee..39dc49e872c82961defc09c7240604bc1cba2228 100644 +--- a/ipaserver/install/service.py ++++ b/ipaserver/install/service.py +@@ -64,7 +64,7 @@ SERVICE_LIST = { + } + + CONFIGURED_SERVICE = u'configuredService' +-ENABLED_SERVICE = 'enabledService' ++ENABLED_SERVICE = u'enabledService' + + + def print_msg(message, output_fd=sys.stdout): +@@ -636,7 +636,7 @@ class Service(object): + + entry_dn = DN(('cn', name), ('cn', fqdn), ('cn', 'masters'), + ('cn', 'ipa'), ('cn', 'etc'), ldap_suffix) +- search_kw = {'ipaConfigString': u'enabledService'} ++ search_kw = {'ipaConfigString': ENABLED_SERVICE} + filter = api.Backend.ldap2.make_filter(search_kw) + try: + entries, _truncated = api.Backend.ldap2.find_entries( +-- +2.17.1 + diff --git a/SOURCES/0015-adtrust-filter-out-subdomains-when-defining-our-topo.patch b/SOURCES/0015-adtrust-filter-out-subdomains-when-defining-our-topo.patch deleted file mode 100644 index 8e7bbe8..0000000 --- a/SOURCES/0015-adtrust-filter-out-subdomains-when-defining-our-topo.patch +++ /dev/null @@ -1,66 +0,0 @@ -From efdbea05f716700d8ed659430a6b501b41de0e54 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy <abokovoy@redhat.com> -Date: Thu, 19 Oct 2017 13:21:05 +0300 -Subject: [PATCH] adtrust: filter out subdomains when defining our topology to - AD - -When definining a topology of a forest to be visible over a cross-forest -trust, we set *.<forest name> as all-catch top level name already. - -This means that all DNS subdomains of the forest will already be matched -by this top level name (TLN). If we add more TLNs for subdomains, Active -Directory will respond with NT_STATUS_INVALID_PARAMETER. - -Filter out all subdomains of the forest root domain. All other realm -domains will be added with explicit TLN records. - -Also filter out single label domains. These aren't possible to add as -TLNs to Windows Server 2016 as it considers them incorrect. Given that -we do not allow single lable domains as part of freeIPA installs, this -is another layer of protection here. - -Fixes https://pagure.io/freeipa/issue/6666 - -Reviewed-By: Christian Heimes <cheimes@redhat.com> ---- - ipaserver/dcerpc.py | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index d684a17cabe43bbbd43d29f75f534b6e50fccd12..aa63cd9db0a1d47b5309cc6bed2ff7584760a39d 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -50,6 +50,7 @@ import samba - - import ldap as _ldap - from ipapython import ipaldap -+from ipapython.dnsutil import DNSName - from dns import resolver, rdatatype - from dns.exception import DNSException - import pysss_nss_idmap -@@ -1589,7 +1590,22 @@ class TrustDomainJoins(object): - entry.single_value.get('modifytimestamp').timetuple() - )*1e7+116444736000000000) - -+ forest = DNSName(self.local_domain.info['dns_forest']) -+ # tforest is IPA forest. keep the line below for future checks -+ # tforest = DNSName(self.remote_domain.info['dns_forest']) - for dom in realm_domains['associateddomain']: -+ d = DNSName(dom) -+ -+ # We should skip all DNS subdomains of our forest -+ # because we are going to add *.<forest> TLN anyway -+ if forest.is_superdomain(d) and forest != d: -+ continue -+ -+ # We also should skip single label TLDs as they -+ # cannot be added as TLNs -+ if len(d.labels) == 1: -+ continue -+ - ftinfo = dict() - ftinfo['rec_name'] = dom - ftinfo['rec_time'] = trust_timestamp --- -2.13.6 - diff --git a/SOURCES/0016-Fix-ca-less-IPA-install-on-fips-mode.patch b/SOURCES/0016-Fix-ca-less-IPA-install-on-fips-mode.patch deleted file mode 100644 index 1f8d3dc..0000000 --- a/SOURCES/0016-Fix-ca-less-IPA-install-on-fips-mode.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 8f35c1c705a7584cdcc9ad5c6fb15ba940ec3f4a Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud <flo@redhat.com> -Date: Thu, 23 Nov 2017 18:06:56 +0100 -Subject: [PATCH] Fix ca less IPA install on fips mode - -When ipa-server-install is run in fips mode and ca-less, the installer -fails when the keys are provided with --{http|dirsrv|pkinit}-cert-file -in a separate key file. - -The installer transforms the key into PKCS#8 format using -openssl pkcs8 -topk8 -but this command fails on a fips-enabled server, unless the options --v2 aes256 -v2prf hmacWithSHA256 -are also provided. - -Fixes: -https://pagure.io/freeipa/issue/7280 - -Reviewed-By: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Christian Heimes <cheimes@redhat.com> ---- - ipapython/certdb.py | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/ipapython/certdb.py b/ipapython/certdb.py -index 114c58340253141706afa461ecaf87797562ca1d..f198811e0fd02c8925f0dcfa8764535b35ed29ed 100644 ---- a/ipapython/certdb.py -+++ b/ipapython/certdb.py -@@ -499,9 +499,13 @@ class NSSDatabase(object): - "Can't load private key from both %s and %s" % - (key_file, filename)) - -+ # the args -v2 aes256 -v2prf hmacWithSHA256 are needed -+ # on OpenSSL 1.0.2 (fips mode). As soon as FreeIPA -+ # requires OpenSSL 1.1.0 we'll be able to drop them - args = [ - OPENSSL, 'pkcs8', - '-topk8', -+ '-v2', 'aes256', '-v2prf', 'hmacWithSHA256', - '-passout', 'file:' + self.pwd_file, - ] - if ((label != 'PRIVATE KEY' and key_password) or --- -2.13.6 - diff --git a/SOURCES/0016-replicainstall-DS-SSL-replica-install-pick-right-cer.patch b/SOURCES/0016-replicainstall-DS-SSL-replica-install-pick-right-cer.patch new file mode 100644 index 0000000..32a3d45 --- /dev/null +++ b/SOURCES/0016-replicainstall-DS-SSL-replica-install-pick-right-cer.patch @@ -0,0 +1,55 @@ +From 44ec2e641c809afbed96bcde2a31388a37a7ec32 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden <rcritten@redhat.com> +Date: Fri, 6 Jul 2018 09:26:19 -0400 +Subject: [PATCH] replicainstall: DS SSL replica install pick right certmonger + host + +Extend fix 0f31564b35aac250456233f98730811560eda664 to also move +the DS SSL setup so that the xmlrpc_uri is configured to point +to the remote master we are configuring against. + +https://pagure.io/freeipa/issue/7566 + +Signed-off-by: Rob Crittenden <rcritten@redhat.com> +Reviewed-By: Christian Heimes <cheimes@redhat.com> +--- + ipaserver/install/server/replicainstall.py | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 387d4ca85d9ad41db3ce2d9bc2ae67ba11836ada..542e1d4d145f266d6fd9ad8e0eaffcb12e8f6bc6 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -1448,15 +1448,12 @@ def install(installer): + pkcs12_info=pkinit_pkcs12_info, + promote=promote) + +- # we now need to enable ssl on the ds +- ds.enable_ssl() +- + if promote: + # We need to point to the master when certmonger asks for +- # HTTP certificate. +- # During http installation, the HTTP/hostname principal is created +- # locally then the installer waits for the entry to appear on the +- # master selected for the installation. ++ # a DS or HTTP certificate. ++ # During http installation, the <service>/hostname principal is ++ # created locally then the installer waits for the entry to appear ++ # on the master selected for the installation. + # In a later step, the installer requests a SSL certificate through + # Certmonger (and the op adds the principal if it does not exist yet). + # If xmlrpc_uri points to the soon-to-be replica, +@@ -1470,6 +1467,9 @@ def install(installer): + create_ipa_conf(fstore, config, ca_enabled, + master=config.master_host_name) + ++ # we now need to enable ssl on the ds ++ ds.enable_ssl() ++ + install_http( + config, + auto_redirect=not options.no_ui_redirect, +-- +2.17.1 + diff --git a/SOURCES/0017-Fix-race-condition-in-get_locations_records.patch b/SOURCES/0017-Fix-race-condition-in-get_locations_records.patch new file mode 100644 index 0000000..804894f --- /dev/null +++ b/SOURCES/0017-Fix-race-condition-in-get_locations_records.patch @@ -0,0 +1,80 @@ +From 72517c7b316f7cba93a3b2cdc6e2c69dad63a8b1 Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Fri, 6 Jul 2018 21:47:32 +0200 +Subject: [PATCH] Fix race condition in get_locations_records() + +The method IPASystemRecords.get_locations_records() has a race condition. +The IPASystemRecords object creates a mapping of server names to server +data. get_locations_records() uses server_find() again to get a list of +servers, but then operates on the cached dict of server names. + +In parallel replication case, the second server_find() call in +get_locations_records() can return additional servers. Since the rest of +the code operates on the cached data, the method then fails with a KeyError. + +server_data is now an OrderedDict to keep same sorting as with +server_find(). + +Fixes: https://pagure.io/freeipa/issue/7566 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> +--- + ipaserver/dns_data_management.py | 14 +++++--------- + 1 file changed, 5 insertions(+), 9 deletions(-) + +diff --git a/ipaserver/dns_data_management.py b/ipaserver/dns_data_management.py +index 673397ef2b2252f431eec1f3e1f71dc45ff87511..90c4d8536478599e5a35462c7f00ea4c958ff63a 100644 +--- a/ipaserver/dns_data_management.py ++++ b/ipaserver/dns_data_management.py +@@ -8,7 +8,7 @@ import logging + + import six + +-from collections import defaultdict ++from collections import defaultdict, OrderedDict + from dns import ( + rdata, + rdataclass, +@@ -71,7 +71,7 @@ class IPASystemRecords(object): + def __init__(self, api_instance, all_servers=False): + self.api_instance = api_instance + self.domain_abs = DNSName(self.api_instance.env.domain).make_absolute() +- self.servers_data = {} ++ self.servers_data = OrderedDict() + self.__init_data(all_servers=all_servers) + + def reload_data(self): +@@ -93,7 +93,7 @@ class IPASystemRecords(object): + return location + DNSName('_locations') + self.domain_abs + + def __init_data(self, all_servers=False): +- self.servers_data = {} ++ self.servers_data.clear() + + kwargs = dict(no_members=False) + if not all_servers: +@@ -328,7 +328,7 @@ class IPASystemRecords(object): + + zone_obj = zone.Zone(self.domain_abs, relativize=False) + if servers is None: +- servers = self.servers_data.keys() ++ servers = list(self.servers_data) + + for server in servers: + self._add_base_dns_records_for_server(zone_obj, server, +@@ -351,11 +351,7 @@ class IPASystemRecords(object): + """ + zone_obj = zone.Zone(self.domain_abs, relativize=False) + if servers is None: +- servers_result = self.api_instance.Command.server_find( +- pkey_only=True, +- servrole=u"IPA master", # only fully installed masters +- )['result'] +- servers = [s['cn'][0] for s in servers_result] ++ servers = list(self.servers_data) + + locations_result = self.api_instance.Command.location_find()['result'] + locations = [l['idnsname'][0] for l in locations_result] +-- +2.17.1 + diff --git a/SOURCES/0017-trust-detect-and-error-out-when-non-AD-trust-with-IP.patch b/SOURCES/0017-trust-detect-and-error-out-when-non-AD-trust-with-IP.patch deleted file mode 100644 index 8cf7475..0000000 --- a/SOURCES/0017-trust-detect-and-error-out-when-non-AD-trust-with-IP.patch +++ /dev/null @@ -1,281 +0,0 @@ -From a4e9e8f368c8a61d539e9da26e4a16a6234c138f Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy <abokovoy@redhat.com> -Date: Fri, 17 Nov 2017 17:19:25 +0200 -Subject: [PATCH] trust: detect and error out when non-AD trust with IPA domain - name exists - -Quite often users choose wrong type of trust on Active Directory side -when setting up a trust to freeIPA. The trust type supported by freeIPA -is just a normal forest trust to another Active Directory. However, -some people follow old internet recipes that force using a trust to MIT -Kerberos realm. - -This is a wrong type of trust. Unfortunately, when someone used MIT -Kerberos realm trust, there is no way to programmatically remote the -trust from freeIPA side. As result, we have to detect such situation and -report an error. - -To do proper reporting, we need reuse some constants and trust type -names we use in IPA CLI/Web UI. These common components were moved to -a separate ipaserver/dcerpc_common.py module that is imported by both -ipaserver/plugins/trust.py and ipaserver/dcerpc.py. - -Fixes https://pagure.io/freeipa/issue/7264 - -Reviewed-By: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Thierry Bordaz <tbordaz@redhat.com> ---- - ipaserver/dcerpc.py | 37 +++++++++++++++-------- - ipaserver/dcerpc_common.py | 73 ++++++++++++++++++++++++++++++++++++++++++++++ - ipaserver/plugins/trust.py | 65 ++++++++++------------------------------- - 3 files changed, 113 insertions(+), 62 deletions(-) - create mode 100644 ipaserver/dcerpc_common.py - -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index aa63cd9db0a1d47b5309cc6bed2ff7584760a39d..ac1b2a34784df491a3851aa21bbadbec2297241c 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -31,6 +31,10 @@ from ipapython import ipautil - from ipapython.ipa_log_manager import root_logger - from ipapython.dn import DN - from ipaserver.install import installutils -+from ipaserver.dcerpc_common import (TRUST_BIDIRECTIONAL, -+ TRUST_JOIN_EXTERNAL, -+ trust_type_string) -+ - from ipalib.util import normalize_name - - import os -@@ -77,15 +81,6 @@ The code in this module relies heavily on samba4-python package - and Samba4 python bindings. - """) - --# Both constants can be used as masks against trust direction --# because bi-directional has two lower bits set. --TRUST_ONEWAY = 1 --TRUST_BIDIRECTIONAL = 3 -- --# Trust join behavior --# External trust -- allow creating trust to a non-root domain in the forest --TRUST_JOIN_EXTERNAL = 1 -- - - def is_sid_valid(sid): - try: -@@ -151,6 +146,7 @@ pysss_type_key_translation_dict = { - pysss_nss_idmap.ID_BOTH: 'both', - } - -+ - class TrustTopologyConflictSolved(Exception): - """ - Internal trust error: raised when previously detected -@@ -1254,9 +1250,26 @@ class TrustDomainInstance(object): - dname = lsa.String() - dname.string = another_domain.info['dns_domain'] - res = self._pipe.QueryTrustedDomainInfoByName( -- self._policy_handle, -- dname, -- lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO) -+ self._policy_handle, -+ dname, -+ lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO -+ ) -+ if res.info_ex.trust_type != lsa.LSA_TRUST_TYPE_UPLEVEL: -+ msg = _('There is already a trust to {ipa_domain} with ' -+ 'unsupported type {trust_type}. Please remove ' -+ 'it manually on AD DC side.') -+ ttype = trust_type_string( -+ res.info_ex.trust_type, res.info_ex.trust_attributes -+ ) -+ err = unicode(msg).format( -+ ipa_domain=another_domain.info['dns_domain'], -+ trust_type=ttype) -+ -+ raise errors.ValidationError( -+ name=_('AD domain controller'), -+ error=err -+ ) -+ - self._pipe.DeleteTrustedDomain(self._policy_handle, - res.info_ex.sid) - except RuntimeError as e: -diff --git a/ipaserver/dcerpc_common.py b/ipaserver/dcerpc_common.py -new file mode 100644 -index 0000000000000000000000000000000000000000..526b025e3282c8a556088eb2ed1ba467b889b86c ---- /dev/null -+++ b/ipaserver/dcerpc_common.py -@@ -0,0 +1,73 @@ -+import six -+from ipalib import _ -+if six.PY3: -+ unicode = six.text_type -+ -+# Both constants can be used as masks against trust direction -+# because bi-directional has two lower bits set. -+TRUST_ONEWAY = 1 -+TRUST_BIDIRECTIONAL = 3 -+ -+# Trust join behavior -+# External trust -- allow creating trust to a non-root domain in the forest -+TRUST_JOIN_EXTERNAL = 1 -+ -+# We don't want to import any of Samba Python code here just for constants -+# Since these constants set in MS-ADTS, we can rely on their stability -+LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE = 0x00000001 -+ -+_trust_direction_dict = { -+ 1: _('Trusting forest'), -+ 2: _('Trusted forest'), -+ 3: _('Two-way trust') -+} -+ -+_trust_status_dict = { -+ True: _('Established and verified'), -+ False: _('Waiting for confirmation by remote side') -+} -+ -+_trust_type_dict_unknown = _('Unknown') -+ -+# Trust type is a combination of ipanttrusttype and ipanttrustattributes -+# We shift trust attributes by 3 bits to left so bit 0 becomes bit 3 and -+# 2+(1 << 3) becomes 10. -+_trust_type_dict = { -+ 1: _('Non-Active Directory domain'), -+ 2: _('Active Directory domain'), -+ 3: _('RFC4120-compliant Kerberos realm'), -+ 10: _('Non-transitive external trust to a domain in ' -+ 'another Active Directory forest'), -+ 11: _('Non-transitive external trust to an RFC4120-' -+ 'compliant Kerberos realm') -+} -+ -+ -+def trust_type_string(level, attrs): -+ """ -+ Returns a string representing a type of the trust. -+ The original field is an enum: -+ LSA_TRUST_TYPE_DOWNLEVEL = 0x00000001, -+ LSA_TRUST_TYPE_UPLEVEL = 0x00000002, -+ LSA_TRUST_TYPE_MIT = 0x00000003 -+ """ -+ transitive = int(attrs) & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE -+ string = _trust_type_dict.get(int(level) | (transitive << 3), -+ _trust_type_dict_unknown) -+ return unicode(string) -+ -+ -+def trust_direction_string(level): -+ """ -+ Returns a string representing a direction of the trust. -+ The original field is a bitmask taking two bits in use -+ LSA_TRUST_DIRECTION_INBOUND = 0x00000001, -+ LSA_TRUST_DIRECTION_OUTBOUND = 0x00000002 -+ """ -+ string = _trust_direction_dict.get(int(level), _trust_type_dict_unknown) -+ return unicode(string) -+ -+ -+def trust_status_string(level): -+ string = _trust_status_dict.get(level, _trust_type_dict_unknown) -+ return unicode(string) -diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py -index d0bbfbc47ca65c9c5229685fc9d202c293fe41cd..ecc5fa0b22f94de05cc5282758be093f0cfca13f 100644 ---- a/ipaserver/plugins/trust.py -+++ b/ipaserver/plugins/trust.py -@@ -44,6 +44,13 @@ from ipalib import errors - from ipalib import output - from ldap import SCOPE_SUBTREE - from time import sleep -+from ipaserver.dcerpc_common import (TRUST_ONEWAY, -+ TRUST_BIDIRECTIONAL, -+ TRUST_JOIN_EXTERNAL, -+ LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE, -+ trust_type_string, -+ trust_direction_string, -+ trust_status_string) - - if six.PY3: - unicode = str -@@ -63,9 +70,6 @@ except Exception as e: - if api.env.in_server and api.env.context in ['lite', 'server']: - try: - import ipaserver.dcerpc -- from ipaserver.dcerpc import (TRUST_ONEWAY, -- TRUST_BIDIRECTIONAL, -- TRUST_JOIN_EXTERNAL) - import dbus - import dbus.mainloop.glib - _bindings_installed = True -@@ -157,28 +161,14 @@ particular type. - - register = Registry() - --# Trust type is a combination of ipanttrusttype and ipanttrustattributes --# We shift trust attributes by 3 bits to left so bit 0 becomes bit 3 and --# 2+(1 << 3) becomes 10. --_trust_type_dict = {1 : _('Non-Active Directory domain'), -- 2 : _('Active Directory domain'), -- 3 : _('RFC4120-compliant Kerberos realm'), -- 10: _('Non-transitive external trust to a domain in another Active Directory forest')} -- --_trust_direction_dict = {1 : _('Trusting forest'), -- 2 : _('Trusted forest'), -- 3 : _('Two-way trust')} --_trust_status_dict = {True : _('Established and verified'), -- False : _('Waiting for confirmation by remote side')} --_trust_type_dict_unknown = _('Unknown') -- --_trust_type_option = StrEnum('trust_type', -- cli_name='type', -- label=_('Trust type (ad for Active Directory, default)'), -- values=(u'ad',), -- default=u'ad', -- autofill=True, -- ) -+_trust_type_option = StrEnum( -+ 'trust_type', -+ cli_name='type', -+ label=_('Trust type (ad for Active Directory, default)'), -+ values=(u'ad',), -+ default=u'ad', -+ autofill=True, -+ ) - - DEFAULT_RANGE_SIZE = 200000 - -@@ -187,31 +177,6 @@ DBUS_IFACE_TRUST = 'com.redhat.idm.trust' - CRED_STYLE_SAMBA = 1 - CRED_STYLE_KERBEROS = 2 - --LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE = 0x00000001 -- --def trust_type_string(level, attrs): -- """ -- Returns a string representing a type of the trust. The original field is an enum: -- LSA_TRUST_TYPE_DOWNLEVEL = 0x00000001, -- LSA_TRUST_TYPE_UPLEVEL = 0x00000002, -- LSA_TRUST_TYPE_MIT = 0x00000003 -- """ -- transitive = int(attrs) & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE -- string = _trust_type_dict.get(int(level) | (transitive << 3), _trust_type_dict_unknown) -- return unicode(string) -- --def trust_direction_string(level): -- """ -- Returns a string representing a direction of the trust. The original field is a bitmask taking two bits in use -- LSA_TRUST_DIRECTION_INBOUND = 0x00000001, -- LSA_TRUST_DIRECTION_OUTBOUND = 0x00000002 -- """ -- string = _trust_direction_dict.get(int(level), _trust_type_dict_unknown) -- return unicode(string) -- --def trust_status_string(level): -- string = _trust_status_dict.get(level, _trust_type_dict_unknown) -- return unicode(string) - - def make_trust_dn(env, trust_type, dn): - assert isinstance(dn, DN) --- -2.13.6 - diff --git a/SOURCES/0018-Tune-DS-replication-settings.patch b/SOURCES/0018-Tune-DS-replication-settings.patch new file mode 100644 index 0000000..bb37404 --- /dev/null +++ b/SOURCES/0018-Tune-DS-replication-settings.patch @@ -0,0 +1,336 @@ +From 4d99ab7ce65064aacf2a7429d8ebc956c5b43b34 Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Tue, 3 Jul 2018 19:40:05 +0200 +Subject: [PATCH] Tune DS replication settings + +Tune 389-DS replication settings to improve performance and avoid +timeouts. During installation of a replica, the value of +nsDS5ReplicaBindDnGroupCheckInterval is reduced to 2 seconds. At the end +of the installation, the value is increased sensible production +settings. This avoids long delays during replication. + +See: https://pagure.io/freeipa/issue/7617 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> +Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> +--- + ipaserver/install/cainstance.py | 8 +- + ipaserver/install/dsinstance.py | 48 ++++++---- + ipaserver/install/replication.py | 92 +++++++++++++++---- + ipaserver/install/server/replicainstall.py | 2 + + ipaserver/install/server/upgrade.py | 12 ++- + ipatests/test_integration/test_external_ca.py | 21 +++++ + 6 files changed, 140 insertions(+), 43 deletions(-) + +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index 51fdbe9c61e06ab9d72d78aee8786f9bceca137b..8193f3da854b3a20d175de523fbc453f5c5104d8 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -410,6 +410,9 @@ class CAInstance(DogtagInstance): + self.teardown_admin) + self.step("starting certificate server instance", + self.start_instance) ++ if promote: ++ self.step("Finalize replication settings", ++ self.finalize_replica_config) + # Step 1 of external is getting a CSR so we don't need to do these + # steps until we get a cert back from the external CA. + if self.external != 1: +@@ -1245,13 +1248,16 @@ class CAInstance(DogtagInstance): + api.Backend.ldap2.add_entry(entry) + + def __setup_replication(self): +- + repl = replication.CAReplicationManager(self.realm, self.fqdn) + repl.setup_cs_replication(self.master_host) + + # Activate Topology for o=ipaca segments + self.__update_topology() + ++ def finalize_replica_config(self): ++ repl = replication.CAReplicationManager(self.realm, self.fqdn) ++ repl.finalize_replica_config(self.master_host) ++ + def __enable_instance(self): + basedn = ipautil.realm_to_suffix(self.realm) + if not self.clone: +diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py +index 06c1273dc21a88f99a0f543cfd12bb6563c7e214..eefbde3356e1077d490d09c4ea47d961ce3ce8e6 100644 +--- a/ipaserver/install/dsinstance.py ++++ b/ipaserver/install/dsinstance.py +@@ -418,6 +418,20 @@ class DsInstance(service.Service): + + self.start_creation(runtime=30) + ++ def _get_replication_manager(self): ++ # Always connect to self over ldapi ++ ldap_uri = ipaldap.get_ldap_uri(protocol='ldapi', realm=self.realm) ++ conn = ipaldap.LDAPClient(ldap_uri) ++ conn.external_bind() ++ repl = replication.ReplicationManager( ++ self.realm, self.fqdn, self.dm_password, conn=conn ++ ) ++ if self.dm_password is not None and not self.promote: ++ bind_dn = DN(('cn', 'Directory Manager')) ++ bind_pw = self.dm_password ++ else: ++ bind_dn = bind_pw = None ++ return repl, bind_dn, bind_pw + + def __setup_replica(self): + """ +@@ -434,26 +448,24 @@ class DsInstance(service.Service): + self.realm, + self.dm_password) + +- # Always connect to self over ldapi +- ldap_uri = ipaldap.get_ldap_uri(protocol='ldapi', realm=self.realm) +- conn = ipaldap.LDAPClient(ldap_uri) +- conn.external_bind() +- repl = replication.ReplicationManager(self.realm, +- self.fqdn, +- self.dm_password, conn=conn) +- +- if self.dm_password is not None and not self.promote: +- bind_dn = DN(('cn', 'Directory Manager')) +- bind_pw = self.dm_password +- else: +- bind_dn = bind_pw = None +- +- repl.setup_promote_replication(self.master_fqdn, +- r_binddn=bind_dn, +- r_bindpw=bind_pw, +- cacert=self.ca_file) ++ repl, bind_dn, bind_pw = self._get_replication_manager() ++ repl.setup_promote_replication( ++ self.master_fqdn, ++ r_binddn=bind_dn, ++ r_bindpw=bind_pw, ++ cacert=self.ca_file ++ ) + self.run_init_memberof = repl.needs_memberof_fixup() + ++ def finalize_replica_config(self): ++ repl, bind_dn, bind_pw = self._get_replication_manager() ++ repl.finalize_replica_config( ++ self.master_fqdn, ++ r_binddn=bind_dn, ++ r_bindpw=bind_pw, ++ cacert=self.ca_file ++ ) ++ + def __configure_sasl_mappings(self): + # we need to remove any existing SASL mappings in the directory as otherwise they + # they may conflict. +diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py +index 5ce8fa689c1a6fd3b9d4cbddbd5454d36334b729..d0f92c76c108d237104a81c72567250583ac4ff1 100644 +--- a/ipaserver/install/replication.py ++++ b/ipaserver/install/replication.py +@@ -75,6 +75,20 @@ STRIP_ATTRS = ('modifiersName', + 'internalModifiersName', + 'internalModifyTimestamp') + ++# settings for cn=replica,cn=$DB,cn=mapping tree,cn=config ++# during replica installation ++REPLICA_CREATION_SETTINGS = { ++ "nsds5ReplicaReleaseTimeout": ["20"], ++ "nsds5ReplicaBackoffMax": ["3"], ++ "nsDS5ReplicaBindDnGroupCheckInterval": ["2"] ++} ++# after replica installation ++REPLICA_FINAL_SETTINGS = { ++ "nsds5ReplicaReleaseTimeout": ["60"], ++ "nsds5ReplicaBackoffMax": ["300"], # default ++ "nsDS5ReplicaBindDnGroupCheckInterval": ["60"] ++} ++ + + def replica_conn_check(master_host, host_name, realm, check_ca, + dogtag_master_ds_port, admin_password=None, +@@ -201,9 +215,13 @@ def wait_for_entry(connection, dn, timeout, attr=None, attrvalue='*', + + + class ReplicationManager(object): +- """Manage replication agreements between DS servers, and sync +- agreements with Windows servers""" +- def __init__(self, realm, hostname, dirman_passwd, port=PORT, starttls=False, conn=None): ++ """Manage replication agreements ++ ++ between DS servers, and sync agreements with Windows servers ++ """ ++ ++ def __init__(self, realm, hostname, dirman_passwd=None, port=PORT, ++ starttls=False, conn=None): + self.hostname = hostname + self.port = port + self.dirman_passwd = dirman_passwd +@@ -481,22 +499,16 @@ class ReplicationManager(object): + except errors.NotFound: + pass + else: +- managers = {DN(m) for m in entry.get('nsDS5ReplicaBindDN', [])} +- +- mods = [] +- if replica_binddn not in managers: ++ binddns = entry.setdefault('nsDS5ReplicaBindDN', []) ++ if replica_binddn not in {DN(m) for m in binddns}: + # Add the new replication manager +- mods.append( +- (ldap.MOD_ADD, 'nsDS5ReplicaBindDN', replica_binddn) +- ) +- if 'nsds5replicareleasetimeout' not in entry: +- # See https://pagure.io/freeipa/issue/7488 +- mods.append( +- (ldap.MOD_ADD, 'nsds5replicareleasetimeout', ['60']) +- ) +- +- if mods: +- conn.modify_s(dn, mods) ++ binddns.append(replica_binddn) ++ for key, value in REPLICA_CREATION_SETTINGS.items(): ++ entry[key] = value ++ try: ++ conn.update_entry(entry) ++ except errors.EmptyModlist: ++ pass + + self.set_replica_binddngroup(conn, entry) + +@@ -515,9 +527,8 @@ class ReplicationManager(object): + nsds5flags=["1"], + nsds5replicabinddn=[replica_binddn], + nsds5replicabinddngroup=[self.repl_man_group_dn], +- nsds5replicabinddngroupcheckinterval=["60"], +- nsds5replicareleasetimeout=["60"], + nsds5replicalegacyconsumer=["off"], ++ **REPLICA_CREATION_SETTINGS + ) + conn.add_entry(entry) + +@@ -543,6 +554,47 @@ class ReplicationManager(object): + except errors.DuplicateEntry: + return + ++ def _finalize_replica_settings(self, conn): ++ """Change replica settings to final values ++ ++ During replica installation, some settings are configured for faster ++ replication. ++ """ ++ dn = self.replica_dn() ++ entry = conn.get_entry(dn) ++ for key, value in REPLICA_FINAL_SETTINGS.items(): ++ entry[key] = value ++ try: ++ conn.update_entry(entry) ++ except errors.EmptyModlist: ++ pass ++ ++ def finalize_replica_config(self, r_hostname, r_binddn=None, ++ r_bindpw=None, cacert=paths.IPA_CA_CRT): ++ """Apply final cn=replica settings ++ ++ replica_config() sets several attribute to fast cache invalidation ++ and fast reconnects to optimize replicat installation. For ++ production, longer timeouts and less aggressive cache invalidation ++ is sufficient. finalize_replica_config() sets the values on new ++ replica and the master. ++ ++ When installing multiple replicas in parallel, one replica may ++ finalize the values while another is still installing. ++ ++ See https://pagure.io/freeipa/issue/7617 ++ """ ++ self._finalize_replica_settings(self.conn) ++ ++ ldap_uri = ipaldap.get_ldap_uri(r_hostname) ++ r_conn = ipaldap.LDAPClient(ldap_uri, cacert=cacert) ++ if r_bindpw: ++ r_conn.simple_bind(r_binddn, r_bindpw) ++ else: ++ r_conn.gssapi_bind() ++ self._finalize_replica_settings(r_conn) ++ r_conn.close() ++ + def setup_chaining_backend(self, conn): + chaindn = DN(('cn', 'chaining database'), ('cn', 'plugins'), ('cn', 'config')) + benamebase = "chaindb" +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 542e1d4d145f266d6fd9ad8e0eaffcb12e8f6bc6..8826da232a90380084b0e4f3dca783125a5500da 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -1506,6 +1506,8 @@ def install(installer): + # Apply any LDAP updates. Needs to be done after the replica is synced-up + service.print_msg("Applying LDAP updates") + ds.apply_updates() ++ service.print_msg("Finalize replication settings") ++ ds.finalize_replica_config() + + if kra_enabled: + kra.install(api, config, options, custodia=custodia) +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index ee3cedd78a2f45f33665bf562e9426cf68325544..4e5096e598cd10e3bd98f91946b4d26377d0de6e 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -45,6 +45,7 @@ from ipaserver.install import dnskeysyncinstance + from ipaserver.install import dogtaginstance + from ipaserver.install import krbinstance + from ipaserver.install import adtrustinstance ++from ipaserver.install import replication + from ipaserver.install.upgradeinstance import IPAUpgrade + from ipaserver.install.ldapupdate import BadSyntax + +@@ -1645,11 +1646,14 @@ def update_replica_config(db_suffix): + except ipalib.errors.NotFound: + return # entry does not exist until a replica is installed + +- if 'nsds5replicareleasetimeout' not in entry: +- # See https://pagure.io/freeipa/issue/7488 +- logger.info("Adding nsds5replicaReleaseTimeout=60 to %s", dn) +- entry['nsds5replicareleasetimeout'] = '60' ++ for key, value in replication.REPLICA_FINAL_SETTINGS.items(): ++ entry[key] = value ++ try: + api.Backend.ldap2.update_entry(entry) ++ except ipalib.errors.EmptyModlist: ++ pass ++ else: ++ logger.info("Updated entry %s", dn) + + + def upgrade_configuration(): +diff --git a/ipatests/test_integration/test_external_ca.py b/ipatests/test_integration/test_external_ca.py +index d21e6d543f51dcee1e548e322cbe01fbe0c13d48..2fc2478ae8bb49d95f7ec60270fb5bb6e582d6f5 100644 +--- a/ipatests/test_integration/test_external_ca.py ++++ b/ipatests/test_integration/test_external_ca.py +@@ -130,6 +130,27 @@ class TestExternalCA(IntegrationTest): + result = self.master.run_command(['ipa', 'user-show', 'admin']) + assert 'User login: admin' in result.stdout_text + ++ # check that we can also install replica ++ tasks.install_replica(self.master, self.replicas[0]) ++ ++ # check that nsds5ReplicaReleaseTimeout option was set ++ result = self.master.run_command([ ++ 'ldapsearch', ++ '-x', ++ '-D', ++ 'cn=directory manager', ++ '-w', self.master.config.dirman_password, ++ '-b', 'cn=mapping tree,cn=config', ++ '(cn=replica)', ++ '-LLL', ++ '-o', ++ 'ldif-wrap=no']) ++ # case insensitive match ++ text = result.stdout_text.lower() ++ # see ipaserver.install.replication.REPLICA_FINAL_SETTINGS ++ assert 'nsds5ReplicaReleaseTimeout: 60'.lower() in text ++ assert 'nsDS5ReplicaBindDnGroupCheckInterval: 60'.lower() in text ++ + def test_client_installation_with_otp(self): + # Test for issue 7526: client installation fails with one-time + # password when the master is installed with an externally signed +-- +2.17.1 + diff --git a/SOURCES/0018-ipaserver-plugins-trust.py-fix-some-indenting-issues.patch b/SOURCES/0018-ipaserver-plugins-trust.py-fix-some-indenting-issues.patch deleted file mode 100644 index a93887e..0000000 --- a/SOURCES/0018-ipaserver-plugins-trust.py-fix-some-indenting-issues.patch +++ /dev/null @@ -1,71 +0,0 @@ -From e553b66e54af3bf981501bca57fb22caaa8e8305 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy <abokovoy@redhat.com> -Date: Thu, 9 Nov 2017 09:57:47 +0200 -Subject: [PATCH] ipaserver/plugins/trust.py; fix some indenting issues - -Reviewed-By: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Thierry Bordaz <tbordaz@redhat.com> ---- - ipaserver/plugins/trust.py | 17 +++++++++-------- - 1 file changed, 9 insertions(+), 8 deletions(-) - -diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py -index ecc5fa0b22f94de05cc5282758be093f0cfca13f..d01529ee022d4a4f9b671a8f06156ed450326041 100644 ---- a/ipaserver/plugins/trust.py -+++ b/ipaserver/plugins/trust.py -@@ -280,15 +280,17 @@ def generate_creds(trustinstance, style, **options): - elif style == CRED_STYLE_KERBEROS: - sp = admin_name.split('\\') - if len(sp) > 1: -- sp = [sp[1]] -+ sp = [sp[1]] - else: -- sp = admin_name.split(sep) -+ sp = admin_name.split(sep) - if len(sp) == 1: -- sp.append(trustinstance.remote_domain.info['dns_domain'].upper()) -+ sp.append(trustinstance.remote_domain -+ .info['dns_domain'].upper()) - creds = u"{name}%{password}".format(name=sep.join(sp), - password=password) - return creds - -+ - def add_range(myapi, trustinstance, range_name, dom_sid, *keys, **options): - """ - First, we try to derive the parameters of the ID range based on the -@@ -319,7 +321,7 @@ def add_range(myapi, trustinstance, range_name, dom_sid, *keys, **options): - # CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System - info_filter = '(objectClass=msSFU30DomainInfo)' - info_dn = DN('CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System')\ -- + basedn -+ + basedn - - # Get the domain validator - domain_validator = ipaserver.dcerpc.DomainValidator(myapi) -@@ -367,7 +369,7 @@ def add_range(myapi, trustinstance, range_name, dom_sid, *keys, **options): - - base_id = int(info.get('msSFU30OrderNumber')[0]) - range_size = (1 + (max_id - base_id) // DEFAULT_RANGE_SIZE)\ -- * DEFAULT_RANGE_SIZE -+ * DEFAULT_RANGE_SIZE - - # Second, options given via the CLI options take precedence to discovery - if options.get('range_type', None): -@@ -595,11 +597,10 @@ class trust(LDAPObject): - pass - else: - for entry in entries: -- add_message( -+ add_message( - options['version'], - result, -- BrokenTrust(domain=entry.single_value['cn']) -- ) -+ BrokenTrust(domain=entry.single_value['cn'])) - - - @register() --- -2.13.6 - diff --git a/SOURCES/0019-Fix-DNSSEC-install-regression.patch b/SOURCES/0019-Fix-DNSSEC-install-regression.patch new file mode 100644 index 0000000..de4e93b --- /dev/null +++ b/SOURCES/0019-Fix-DNSSEC-install-regression.patch @@ -0,0 +1,68 @@ +From 8110958d141392014bf3e3eae01654e7864d7647 Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Tue, 10 Jul 2018 12:51:36 +0200 +Subject: [PATCH] Fix DNSSEC install regression + +7284097eedef70dd556270732e6ab8e23501ce09 introduced a regression in +DNSSEC master installation. For standalone and replica installation, +services have to be enabled before checking bind config. + +Fixes: https://pagure.io/freeipa/issue/7635 +See: https://pagure.io/freeipa/issue/7566 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> +Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> +--- + install/tools/ipa-dns-install | 5 +---- + ipaserver/install/dns.py | 5 +++++ + 2 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install +index 57dde5a5da4fad162c93e9e0416b54961de4c1e3..32a17d223ae2bdd9a1ded62defcc272a40d2627b 100755 +--- a/install/tools/ipa-dns-install ++++ b/install/tools/ipa-dns-install +@@ -37,7 +37,6 @@ from ipapython.config import IPAOptionParser + from ipapython.ipa_log_manager import standard_logging_setup + + from ipaserver.install import dns as dns_installer +-from ipaserver.install import service + + logger = logging.getLogger(os.path.basename(__file__)) + +@@ -149,9 +148,7 @@ def main(): + + dns_installer.install_check(True, api, False, options, hostname=api.env.host) + dns_installer.install(True, False, options) +- # Enable configured services and update DNS SRV records +- service.enable_services(api.env.host) +- api.Command.dns_update_system_records() ++ # Services are enabled in dns_installer.install() + + # execute ipactl to refresh services status + ipautil.run(['ipactl', 'start', '--ignore-service-failures'], +diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py +index e14b353e9cb655a6e7ef228d47dfc7a1badd7286..cac7a9213796d6618854b12da6c2a7fe60afdbf9 100644 +--- a/ipaserver/install/dns.py ++++ b/ipaserver/install/dns.py +@@ -44,6 +44,7 @@ from ipaserver.install import bindinstance + from ipaserver.install import dnskeysyncinstance + from ipaserver.install import odsexporterinstance + from ipaserver.install import opendnssecinstance ++from ipaserver.install import service + + if six.PY3: + unicode = str +@@ -357,6 +358,10 @@ def install(standalone, replica, options, api=api): + dnskeysyncd.start_dnskeysyncd() + bind.start_named() + ++ # Enable configured services for standalone check_global_configuration() ++ if standalone: ++ service.enable_services(api.env.host) ++ + # this must be done when bind is started and operational + bind.update_system_records() + +-- +2.17.1 + diff --git a/SOURCES/0019-ipaserver-plugins-trust.py-pep8-compliance.patch b/SOURCES/0019-ipaserver-plugins-trust.py-pep8-compliance.patch deleted file mode 100644 index 60c36be..0000000 --- a/SOURCES/0019-ipaserver-plugins-trust.py-pep8-compliance.patch +++ /dev/null @@ -1,786 +0,0 @@ -From aae0cc2fdaeead8ff33ade93e73d6aba25704659 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy <abokovoy@redhat.com> -Date: Fri, 17 Nov 2017 17:25:57 +0200 -Subject: [PATCH] ipaserver/plugins/trust.py: pep8 compliance - -Reviewed-By: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Thierry Bordaz <tbordaz@redhat.com> ---- - ipaserver/plugins/trust.py | 356 +++++++++++++++++++++++++++------------------ - 1 file changed, 214 insertions(+), 142 deletions(-) - -diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py -index d01529ee022d4a4f9b671a8f06156ed450326041..73e137abcec9625997a619fe64d4f615743247b1 100644 ---- a/ipaserver/plugins/trust.py -+++ b/ipaserver/plugins/trust.py -@@ -81,10 +81,10 @@ Cross-realm trusts - - Manage trust relationship between IPA and Active Directory domains. - --In order to allow users from a remote domain to access resources in IPA --domain, trust relationship needs to be established. Currently IPA supports --only trusts between IPA and Active Directory domains under control of Windows --Server 2008 or later, with functional level 2008 or later. -+In order to allow users from a remote domain to access resources in IPA domain, -+trust relationship needs to be established. Currently IPA supports only trusts -+between IPA and Active Directory domains under control of Windows Server 2008 -+or later, with functional level 2008 or later. - - Please note that DNS on both IPA and Active Directory domain sides should be - configured properly to discover each other. Trust relationship relies on -@@ -95,7 +95,8 @@ Examples: - 1. Establish cross-realm trust with Active Directory using AD administrator - credentials: - -- ipa trust-add --type=ad <ad.domain> --admin <AD domain administrator> --password -+ ipa trust-add --type=ad <ad.domain> --admin <AD domain administrator> \ -+ --password - - 2. List all existing trust relationships: - -@@ -110,35 +111,39 @@ Examples: - ipa trust-del <ad.domain> - - Once trust relationship is established, remote users will need to be mapped --to local POSIX groups in order to actually use IPA resources. The mapping should --be done via use of external membership of non-POSIX group and then this group --should be included into one of local POSIX groups. -+to local POSIX groups in order to actually use IPA resources. The mapping -+should be done via use of external membership of non-POSIX group and then -+this group should be included into one of local POSIX groups. - - Example: - --1. Create group for the trusted domain admins' mapping and their local POSIX group: -+1. Create group for the trusted domain admins' mapping and their local POSIX -+group: - -- ipa group-add --desc='<ad.domain> admins external map' ad_admins_external --external -+ ipa group-add --desc='<ad.domain> admins external map' \ -+ ad_admins_external --external - ipa group-add --desc='<ad.domain> admins' ad_admins - --2. Add security identifier of Domain Admins of the <ad.domain> to the ad_admins_external -- group: -+2. Add security identifier of Domain Admins of the <ad.domain> to the -+ ad_admins_external group: - - ipa group-add-member ad_admins_external --external 'AD\\Domain Admins' - --3. Allow members of ad_admins_external group to be associated with ad_admins POSIX group: -+3. Allow members of ad_admins_external group to be associated with -+ ad_admins POSIX group: - - ipa group-add-member ad_admins --groups ad_admins_external - --4. List members of external members of ad_admins_external group to see their SIDs: -+4. List members of external members of ad_admins_external group to see -+ their SIDs: - - ipa group-show ad_admins_external - - - GLOBAL TRUST CONFIGURATION - --When IPA AD trust subpackage is installed and ipa-adtrust-install is run, --a local domain configuration (SID, GUID, NetBIOS name) is generated. These -+When IPA AD trust subpackage is installed and ipa-adtrust-install is run, a -+local domain configuration (SID, GUID, NetBIOS name) is generated. These - identifiers are then used when communicating with a trusted domain of the - particular type. - -@@ -147,11 +152,11 @@ particular type. - ipa trustconfig-show --type ad - - 2. Modify global configuration for all trusts of Active Directory type and set -- a different fallback primary group (fallback primary group GID is used as -- a primary user GID if user authenticating to IPA domain does not have any other -- primary GID already set): -+ a different fallback primary group (fallback primary group GID is used as a -+ primary user GID if user authenticating to IPA domain does not have any -+ other primary GID already set): - -- ipa trustconfig-mod --type ad --fallback-primary-group "alternative AD group" -+ ipa trustconfig-mod --type ad --fallback-primary-group "another AD group" - - 3. Change primary fallback group back to default hidden group (any group with - posixGroup object class is allowed): -@@ -185,6 +190,7 @@ def make_trust_dn(env, trust_type, dn): - return DN(dn, container_dn) - return dn - -+ - def find_adtrust_masters(ldap, api): - """ - Returns a list of names of IPA servers with ADTRUST component configured. -@@ -200,6 +206,7 @@ def find_adtrust_masters(ldap, api): - - return [entry.dn[1].value for entry in entries] - -+ - def verify_samba_component_presence(ldap, api): - """ - Verifies that Samba is installed and configured on this particular master. -@@ -233,7 +240,7 @@ def verify_samba_component_presence(ldap, api): - - # First check for packages missing - elif not _bindings_installed: -- error_message=_( -+ error_message = _( - 'Cannot perform the selected command without Samba 4 support ' - 'installed. Make sure you have installed server-trust-ad ' - 'sub-package of IPA.' -@@ -243,7 +250,7 @@ def verify_samba_component_presence(ldap, api): - - # Packages present, but ADTRUST instance is not configured - elif not adtrust_present: -- error_message=_( -+ error_message = _( - 'Cannot perform the selected command without Samba 4 instance ' - 'configured on this machine. Make sure you have run ' - 'ipa-adtrust-install on this server.' -@@ -263,7 +270,8 @@ def generate_creds(trustinstance, style, **options): - **options -- options with realm_admin and realm_passwd keys - - Result: -- a string representing credentials with first % separating username and password -+ a string representing credentials with first % separating -+ username and password - None is returned if realm_passwd key returns nothing from options - """ - creds = None -@@ -284,8 +292,9 @@ def generate_creds(trustinstance, style, **options): - else: - sp = admin_name.split(sep) - if len(sp) == 1: -- sp.append(trustinstance.remote_domain -- .info['dns_domain'].upper()) -+ sp.append( -+ trustinstance.remote_domain.info['dns_domain'].upper() -+ ) - creds = u"{name}%{password}".format(name=sep.join(sp), - password=password) - return creds -@@ -334,7 +343,8 @@ def add_range(myapi, trustinstance, range_name, dom_sid, *keys, **options): - creds = None - if trustinstance: - # Re-use AD administrator credentials if they were provided -- creds = generate_creds(trustinstance, style=CRED_STYLE_KERBEROS, **options) -+ creds = generate_creds(trustinstance, -+ style=CRED_STYLE_KERBEROS, **options) - if creds: - domain_validator._admin_creds = creds - # KDC might not get refreshed data at the first time, -@@ -417,21 +427,32 @@ def fetch_trusted_domains_over_dbus(myapi, log, forest_name): - _stdout = '' - _stderr = '' - bus = dbus.SystemBus() -- intf = bus.get_object(DBUS_IFACE_TRUST,"/", follow_name_owner_changes=True) -- fetch_domains_method = intf.get_dbus_method('fetch_domains', dbus_interface=DBUS_IFACE_TRUST) -+ intf = bus.get_object(DBUS_IFACE_TRUST, "/", -+ follow_name_owner_changes=True) -+ fetch_domains_method = intf.get_dbus_method( -+ 'fetch_domains', -+ dbus_interface=DBUS_IFACE_TRUST) - (_ret, _stdout, _stderr) = fetch_domains_method(forest_name) - except dbus.DBusException as e: -- log.error('Failed to call %(iface)s.fetch_domains helper.' -- 'DBus exception is %(exc)s.' % dict(iface=DBUS_IFACE_TRUST, exc=str(e))) -+ log.error( -+ 'Failed to call %(iface)s.fetch_domains helper. ' -+ 'DBus exception is %(exc)s.' % dict(iface=DBUS_IFACE_TRUST, exc=str(e)) -+ ) - if _ret != 0: -- log.error('Helper was called for forest %(forest)s, return code is %(ret)d' % dict(forest=forest_name, ret=_ret)) -- log.error('Standard output from the helper:\n%s---\n' % (_stdout)) -- log.error('Error output from the helper:\n%s--\n' % (_stderr)) -- raise errors.ServerCommandError(server=myapi.env.host, -- error=_('Fetching domains from trusted forest failed. ' -- 'See details in the error_log')) -+ log.error( -+ 'Helper was called for forest %s, return code is %d', -+ forest_name, _ret -+ ) -+ log.error('Standard output from the helper:\n%s---\n', _stdout) -+ log.error('Error output from the helper:\n%s--\n', _stderr) -+ raise errors.ServerCommandError( -+ server=myapi.env.host, -+ error=_('Fetching domains from trusted forest failed. ' -+ 'See details in the error_log') -+ ) - return - -+ - @register() - class trust(LDAPObject): - """ -@@ -538,8 +559,8 @@ class trust(LDAPObject): - continue - for value in values: - if not ipaserver.dcerpc.is_sid_valid(value): -- raise errors.ValidationError(name=attr, -- error=_("invalid SID: %(value)s") % dict(value=value)) -+ err = unicode(_("invalid SID: {SID}")).format(SID=value) -+ raise errors.ValidationError(name=attr, error=err) - - def get_dn(self, *keys, **kwargs): - trust_type = kwargs.get('trust_type') -@@ -600,7 +621,8 @@ class trust(LDAPObject): - add_message( - options['version'], - result, -- BrokenTrust(domain=entry.single_value['cn'])) -+ BrokenTrust(domain=entry.single_value['cn']) -+ ) - - - @register() -@@ -622,7 +644,7 @@ sides. - range_types = { - u'ipa-ad-trust': unicode(_('Active Directory domain range')), - u'ipa-ad-trust-posix': unicode(_('Active Directory trust range with ' -- 'POSIX attributes')), -+ 'POSIX attributes')), - } - - takes_options = LDAPCreate.takes_options + ( -@@ -720,9 +742,10 @@ sides. - - trust_filter = "cn=%s" % result['value'] - trusts, _truncated = ldap.find_entries( -- base_dn=DN(self.api.env.container_trusts, self.api.env.basedn), -- filter=trust_filter, -- attrs_list=attrs_list) -+ base_dn=DN(self.api.env.container_trusts, self.api.env.basedn), -+ filter=trust_filter, -+ attrs_list=attrs_list -+ ) - - result['result'] = entry_to_dict(trusts[0], **options) - -@@ -731,10 +754,11 @@ sides. - # Note that add_new_domains_from_trust will add needed ranges for - # the algorithmic ID mapping case. - if (options.get('trust_type') == u'ad' and -- options.get('trust_secret') is None): -+ options.get('trust_secret') is None): -+ - if options.get('bidirectional') == True: -- # Bidirectional trust allows us to use cross-realm TGT, so we can -- # run the call under original user's credentials -+ # Bidirectional trust allows us to use cross-realm TGT, -+ # so we can run the call under original user's credentials - res = fetch_domains_from_trust(self.api, self.trustinstance, - **options) - add_new_domains_from_trust( -@@ -790,7 +814,9 @@ sides. - # If domain name and realm does not match, IPA server is not be able - # to establish trust with Active Directory. - -- realm_not_matching_domain = (self.api.env.domain.upper() != self.api.env.realm) -+ realm_not_matching_domain = ( -+ self.api.env.domain.upper() != self.api.env.realm -+ ) - - if options['trust_type'] == u'ad' and realm_not_matching_domain: - raise errors.ValidationError( -@@ -917,11 +943,12 @@ sides. - ) - - if range_type and range_type != old_range_type: -- raise errors.ValidationError(name=_('range type change'), -- error=_('ID range for the trusted domain already exists, ' -- 'but it has a different type. Please remove the ' -- 'old range manually, or do not enforce type ' -- 'via --range-type option.')) -+ raise errors.ValidationError( -+ name=_('range type change'), -+ error=_('ID range for the trusted domain already ' -+ 'exists, but it has a different type. Please ' -+ 'remove the old range manually, or do not ' -+ 'enforce type via --range-type option.')) - - return old_range, range_name, dom_sid - -@@ -956,33 +983,55 @@ sides. - trust_type - ) - except errors.NotFound: -- error_message=_("Unable to resolve domain controller for '%s' domain. ") % (keys[-1]) -- instructions=[] -+ _message = _("Unable to resolve domain controller for " -+ "{domain} domain. ") -+ error_message = unicode(_message).format(domain=keys[-1]) -+ instructions = [] -+ - if dns_container_exists(self.obj.backend): - try: -- dns_zone = self.api.Command.dnszone_show(keys[-1])['result'] -- if ('idnsforwardpolicy' in dns_zone) and dns_zone['idnsforwardpolicy'][0] == u'only': -- instructions.append(_("Forward policy is defined for it in IPA DNS, " -- "perhaps forwarder points to incorrect host?")) -+ dns_zone = self.api.Command.dnszone_show( -+ keys[-1])['result'] -+ -+ if (('idnsforwardpolicy' in dns_zone) and -+ dns_zone['idnsforwardpolicy'][0] == u'only'): -+ -+ instructions.append( -+ _("Forward policy is defined for it in " -+ "IPA DNS, perhaps forwarder points to " -+ "incorrect host?") -+ ) - except (errors.NotFound, KeyError): -- instructions.append(_("IPA manages DNS, please verify " -- "your DNS configuration and " -- "make sure that service records " -- "of the '%(domain)s' domain can " -- "be resolved. Examples how to " -- "configure DNS with CLI commands " -- "or the Web UI can be found in " -- "the documentation. " ) % -- dict(domain=keys[-1])) -+ _instruction = _( -+ "IPA manages DNS, please verify your DNS " -+ "configuration and make sure that service " -+ "records of the '{domain}' domain can be " -+ "resolved. Examples how to configure DNS " -+ "with CLI commands or the Web UI can be " -+ "found in the documentation. " -+ ) -+ instructions.append( -+ unicode(_instruction).format(domain=keys[-1]) -+ ) - else: -- instructions.append(_("Since IPA does not manage DNS records, ensure DNS " -- "is configured to resolve '%(domain)s' domain from " -- "IPA hosts and back.") % dict(domain=keys[-1])) -- raise errors.NotFound(reason=error_message, instructions=instructions) -+ _instruction = _( -+ "Since IPA does not manage DNS records, ensure " -+ "DNS is configured to resolve '{domain}' " -+ "domain from IPA hosts and back." -+ ) -+ instructions.append( -+ unicode(_instruction).format(domain=keys[-1]) -+ ) -+ raise errors.NotFound( -+ reason=error_message, -+ instructions=instructions -+ ) - - if result is None: -- raise errors.ValidationError(name=_('AD Trust setup'), -- error=_('Unable to verify write permissions to the AD')) -+ raise errors.ValidationError( -+ name=_('AD Trust setup'), -+ error=_('Unable to verify write permissions to the AD') -+ ) - - ret = dict( - value=pkey_to_value( -@@ -1019,12 +1068,14 @@ sides. - error=_('Not enough arguments specified to perform trust ' - 'setup')) - -+ - @register() - class trust_del(LDAPDelete): - __doc__ = _('Delete a trust.') - - msg_summary = _('Deleted trust "%(value)s"') - -+ - @register() - class trust_mod(LDAPUpdate): - __doc__ = _(""" -@@ -1037,13 +1088,14 @@ class trust_mod(LDAPUpdate): - msg_summary = _('Modified trust "%(value)s" ' - '(change will be effective in 60 seconds)') - -- def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): -+ def pre_callback(self, ldap, dn, e_attrs, attrs_list, *keys, **options): - assert isinstance(dn, DN) - -- self.obj.validate_sid_blacklists(entry_attrs) -+ self.obj.validate_sid_blacklists(e_attrs) - - return dn - -+ - @register() - class trust_find(LDAPSearch): - __doc__ = _('Search for trusts.') -@@ -1054,9 +1106,10 @@ class trust_find(LDAPSearch): - '%(count)d trust matched', '%(count)d trusts matched', 0 - ) - -- # Since all trusts types are stored within separate containers under 'cn=trusts', -- # search needs to be done on a sub-tree scope -- def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options): -+ # Since all trusts types are stored within separate containers -+ # under 'cn=trusts', search needs to be done on a sub-tree scope -+ def pre_callback(self, ldap, filters, attrs_list, -+ base_dn, scope, *args, **options): - # list only trust, not trust domains - return (filters, base_dn, ldap.SCOPE_SUBTREE) - -@@ -1076,13 +1129,16 @@ class trust_find(LDAPSearch): - trust_type = attrs.single_value.get('ipanttrusttype', None) - attributes = attrs.single_value.get('ipanttrustattributes', 0) - if not options.get('raw', False) and trust_type is not None: -- attrs['trusttype'] = [trust_type_string(trust_type, attributes)] -+ attrs['trusttype'] = [ -+ trust_type_string(trust_type, attributes) -+ ] - del attrs['ipanttrusttype'] - if attributes: - del attrs['ipanttrustattributes'] - - return truncated - -+ - @register() - class trust_show(LDAPRetrieve): - __doc__ = _('Display information about a trust.') -@@ -1098,7 +1154,7 @@ class trust_show(LDAPRetrieve): - - return result - -- def post_callback(self, ldap, dn, entry_attrs, *keys, **options): -+ def post_callback(self, ldap, dn, e_attrs, *keys, **options): - - assert isinstance(dn, DN) - # Translate ipanttrusttype to trusttype -@@ -1106,25 +1162,28 @@ class trust_show(LDAPRetrieve): - # if --raw not used - - if not options.get('raw', False): -- trust_type = entry_attrs.single_value.get('ipanttrusttype', None) -- attributes = entry_attrs.single_value.get('ipanttrustattributes', 0) -+ trust_type = e_attrs.single_value.get('ipanttrusttype', None) -+ attributes = e_attrs.single_value.get('ipanttrustattributes', 0) - if trust_type is not None: -- entry_attrs['trusttype'] = [trust_type_string(trust_type, attributes)] -- del entry_attrs['ipanttrusttype'] -+ e_attrs['trusttype'] = [ -+ trust_type_string(trust_type, attributes) -+ ] -+ del e_attrs['ipanttrusttype'] - -- dir_str = entry_attrs.single_value.get('ipanttrustdirection', None) -+ dir_str = e_attrs.single_value.get('ipanttrustdirection', None) - if dir_str is not None: -- entry_attrs['trustdirection'] = [trust_direction_string(dir_str)] -- del entry_attrs['ipanttrustdirection'] -+ e_attrs['trustdirection'] = [trust_direction_string(dir_str)] -+ del e_attrs['ipanttrustdirection'] - - if attributes: -- del entry_attrs['ipanttrustattributes'] -+ del e_attrs['ipanttrustattributes'] - - return dn - - - _trustconfig_dn = { -- u'ad': DN(('cn', api.env.domain), api.env.container_cifsdomains, api.env.basedn), -+ u'ad': DN(('cn', api.env.domain), -+ api.env.container_cifsdomains, api.env.basedn), - } - - -@@ -1184,8 +1243,10 @@ class trustconfig(LDAPObject): - try: - return _trustconfig_dn[kwargs['trust_type']] - except KeyError: -- raise errors.ValidationError(name='trust_type', -- error=_("unsupported trust type")) -+ raise errors.ValidationError( -+ name='trust_type', -+ error=_("unsupported trust type") -+ ) - - def _normalize_groupdn(self, entry_attrs): - """ -@@ -1254,8 +1315,8 @@ class trustconfig_mod(LDAPUpdate): - msg_summary = _('Modified "%(value)s" trust configuration') - has_output = output.simple_entry - -- def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): -- self.obj._normalize_groupdn(entry_attrs) -+ def pre_callback(self, ldap, dn, e_attrs, attrs_list, *keys, **options): -+ self.obj._normalize_groupdn(e_attrs) - return dn - - def execute(self, *keys, **options): -@@ -1263,14 +1324,13 @@ class trustconfig_mod(LDAPUpdate): - result['value'] = pkey_to_value(options['trust_type'], options) - return result - -- def post_callback(self, ldap, dn, entry_attrs, *keys, **options): -- self.obj._convert_groupdn(entry_attrs, options) -+ def post_callback(self, ldap, dn, e_attrs, *keys, **options): -+ self.obj._convert_groupdn(e_attrs, options) - self.api.Object.config.show_servroles_attributes( -- entry_attrs, "AD trust agent", "AD trust controller", **options) -+ e_attrs, "AD trust agent", "AD trust controller", **options) - return dn - - -- - @register() - class trustconfig_show(LDAPRetrieve): - __doc__ = _('Show global trust configuration.') -@@ -1293,18 +1353,21 @@ class trustconfig_show(LDAPRetrieve): - - if _nss_idmap_installed: - _idmap_type_dict = { -- pysss_nss_idmap.ID_USER : 'user', -- pysss_nss_idmap.ID_GROUP : 'group', -- pysss_nss_idmap.ID_BOTH : 'both', -+ pysss_nss_idmap.ID_USER: 'user', -+ pysss_nss_idmap.ID_GROUP: 'group', -+ pysss_nss_idmap.ID_BOTH: 'both', - } -+ - def idmap_type_string(level): - string = _idmap_type_dict.get(int(level), 'unknown') - return unicode(string) - -+ - @register() - class trust_resolve(Command): - NO_CLI = True -- __doc__ = _('Resolve security identifiers of users and groups in trusted domains') -+ __doc__ = _('Resolve security identifiers of users and groups ' -+ 'in trusted domains') - - takes_options = ( - Str('sids+', -@@ -1313,8 +1376,8 @@ class trust_resolve(Command): - ) - - has_output_params = ( -- Str('name', label= _('Name')), -- Str('sid', label= _('SID')), -+ Str('name', label=_('Name')), -+ Str('sid', label=_('SID')), - ) - - has_output = ( -@@ -1326,13 +1389,15 @@ class trust_resolve(Command): - if not _nss_idmap_installed: - return dict(result=result) - try: -+ NAME_KEY = pysss_nss_idmap.NAME_KEY -+ TYPE_KEY = pysss_nss_idmap.TYPE_KEY - sids = [str(x) for x in options['sids']] - xlate = pysss_nss_idmap.getnamebysid(sids) - for sid in xlate: - entry = dict() - entry['sid'] = [unicode(sid)] -- entry['name'] = [unicode(xlate[sid][pysss_nss_idmap.NAME_KEY])] -- entry['type'] = [idmap_type_string(xlate[sid][pysss_nss_idmap.TYPE_KEY])] -+ entry['name'] = [unicode(xlate[sid][NAME_KEY])] -+ entry['type'] = [idmap_type_string(xlate[sid][TYPE_KEY])] - result.append(entry) - except ValueError: - pass -@@ -1340,7 +1405,6 @@ class trust_resolve(Command): - return dict(result=result) - - -- - @register() - class adtrust_is_enabled(Command): - NO_CLI = True -@@ -1367,7 +1431,6 @@ class adtrust_is_enabled(Command): - return dict(result=True) - - -- - @register() - class compat_is_enabled(Command): - NO_CLI = True -@@ -1411,7 +1474,6 @@ class compat_is_enabled(Command): - return dict(result=True) - - -- - @register() - class sidgen_was_run(Command): - """ -@@ -1461,7 +1523,7 @@ class trustdomain(LDAPObject): - Object representing a domain of the AD trust. - """ - parent_object = 'trust' -- trust_type_idx = {'2':u'ad'} -+ trust_type_idx = {'2': u'ad'} - object_name = _('trust domain') - object_name_plural = _('trust domains') - object_class = ['ipaNTTrustedDomain'] -@@ -1478,40 +1540,39 @@ class trustdomain(LDAPObject): - Str('cn', - label=_('Domain name'), - cli_name='domain', -- primary_key=True -- ), -+ primary_key=True), - Str('ipantflatname?', - cli_name='flat_name', -- label=_('Domain NetBIOS name'), -- ), -+ label=_('Domain NetBIOS name')), - Str('ipanttrusteddomainsid?', - cli_name='sid', -- label=_('Domain Security Identifier'), -- ), -+ label=_('Domain Security Identifier')), - Flag('domain_enabled', -- label=_('Domain enabled'), -- flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'}, -- ), -+ label=_('Domain enabled'), -+ flags={'virtual_attribute', -+ 'no_create', 'no_update', 'no_search'}), - ) - -- # LDAPObject.get_dn() only passes all but last element of keys and no kwargs -- # to the parent object's get_dn() no matter what you pass to it. Make own get_dn() -- # as we really need all elements to construct proper dn. -+ # LDAPObject.get_dn() only passes all but last element of keys and no -+ # kwargs to the parent object's get_dn() no matter what you pass to it. -+ # Make own get_dn() as we really need all elements to construct proper dn. - def get_dn(self, *keys, **kwargs): - sdn = [('cn', x) for x in keys] - sdn.reverse() - trust_type = kwargs.get('trust_type') - if not trust_type: -- trust_type=u'ad' -+ trust_type = u'ad' - -- dn=make_trust_dn(self.env, trust_type, DN(*sdn)) -+ dn = make_trust_dn(self.env, trust_type, DN(*sdn)) - return dn - -+ - @register() - class trustdomain_find(LDAPSearch): - __doc__ = _('Search domains of the trust') - -- def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options): -+ def pre_callback(self, ldap, filters, attrs_list, base_dn, -+ scope, *args, **options): - return (filters, base_dn, ldap.SCOPE_SUBTREE) - - def post_callback(self, ldap, entries, truncated, *args, **options): -@@ -1532,7 +1593,6 @@ class trustdomain_find(LDAPSearch): - return truncated - - -- - @register() - class trustdomain_mod(LDAPUpdate): - __doc__ = _('Modify trustdomain of the trust') -@@ -1540,31 +1600,36 @@ class trustdomain_mod(LDAPUpdate): - NO_CLI = True - takes_options = LDAPUpdate.takes_options + (_trust_type_option,) - -+ - @register() - class trustdomain_add(LDAPCreate): - __doc__ = _('Allow access from the trusted domain') - NO_CLI = True - - takes_options = LDAPCreate.takes_options + (_trust_type_option,) -- def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): -- # ipaNTTrustPartner must always be set to the name of the trusted domain -- # See MS-ADTS 6.1.6.7.13 -- entry_attrs['ipanttrustpartner'] = [dn[0]['cn']] -+ -+ def pre_callback(self, ldap, dn, e_attrs, attrs_list, *keys, **options): -+ # ipaNTTrustPartner must always be set to the name of the trusted -+ # domain. See MS-ADTS 6.1.6.7.13 -+ e_attrs['ipanttrustpartner'] = [dn[0]['cn']] - return dn - - - @register() - class trustdomain_del(LDAPDelete): -- __doc__ = _('Remove information about the domain associated with the trust.') -+ __doc__ = _('Remove information about the domain associated ' -+ 'with the trust.') - -- msg_summary = _('Removed information about the trusted domain "%(value)s"') -+ msg_summary = _('Removed information about the trusted domain ' -+ '"%(value)s"') - - def execute(self, *keys, **options): - ldap = self.api.Backend.ldap2 - verify_samba_component_presence(ldap, self.api) - -- # Note that pre-/post- callback handling for LDAPDelete is causing pre_callback -- # to always receive empty keys. We need to catch the case when root domain is being deleted -+ # Note that pre-/post- callback handling for LDAPDelete is causing -+ # pre_callback to always receive empty keys. We need to catch the case -+ # when root domain is being deleted - - for domain in keys[1]: - try: -@@ -1603,10 +1668,10 @@ def fetch_domains_from_trust(myapi, trustinstance, **options): - forest_root_name = trustinstance.remote_domain.info['dns_forest'] - - # We want to use Kerberos if we have admin credentials even with SMB calls -- # as eventually use of NTLMSSP will be deprecated for trusted domain operations -- # If admin credentials are missing, 'creds' will be None and fetch_domains -- # will use HTTP/ipa.master@IPA.REALM principal, e.g. Kerberos authentication -- # as well. -+ # as eventually use of NTLMSSP will be deprecated for trusted domain -+ # operations If admin credentials are missing, 'creds' will be None and -+ # fetch_domains will use HTTP/ipa.master@IPA.REALM principal, e.g. Kerberos -+ # authentication as well. - creds = generate_creds(trustinstance, style=CRED_STYLE_KERBEROS, **options) - server = options.get('realm_server', None) - domains = ipaserver.dcerpc.fetch_domains( -@@ -1616,7 +1681,8 @@ def fetch_domains_from_trust(myapi, trustinstance, **options): - return domains - - --def add_new_domains_from_trust(myapi, trustinstance, trust_entry, domains, **options): -+def add_new_domains_from_trust(myapi, trustinstance, trust_entry, -+ domains, **options): - result = [] - if not domains: - return result -@@ -1728,8 +1794,11 @@ class trustdomain_enable(LDAPQuery): - verify_samba_component_presence(ldap, self.api) - - if keys[0].lower() == keys[1].lower(): -- raise errors.ValidationError(name='domain', -- error=_("Root domain of the trust is always enabled for the existing trust")) -+ raise errors.ValidationError( -+ name='domain', -+ error=_("Root domain of the trust is always enabled " -+ "for the existing trust") -+ ) - try: - trust_dn = self.obj.get_dn(keys[0], trust_type=u'ad') - trust_entry = ldap.get_entry(trust_dn) -@@ -1766,8 +1835,11 @@ class trustdomain_disable(LDAPQuery): - verify_samba_component_presence(ldap, self.api) - - if keys[0].lower() == keys[1].lower(): -- raise errors.ValidationError(name='domain', -- error=_("cannot disable root domain of the trust, use trust-del to delete the trust itself")) -+ raise errors.ValidationError( -+ name='domain', -+ error=_("cannot disable root domain of the trust, " -+ "use trust-del to delete the trust itself") -+ ) - try: - trust_dn = self.obj.get_dn(keys[0], trust_type=u'ad') - trust_entry = ldap.get_entry(trust_dn) --- -2.13.6 - diff --git a/SOURCES/0020-Don-t-use-admin-cert-during-KRA-installation.patch b/SOURCES/0020-Don-t-use-admin-cert-during-KRA-installation.patch deleted file mode 100644 index 3762985..0000000 --- a/SOURCES/0020-Don-t-use-admin-cert-during-KRA-installation.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 6e0720dedc113bf82f3b38f2afb76976ed4e8c12 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale <ftweedal@redhat.com> -Date: Wed, 15 Nov 2017 11:59:32 +1100 -Subject: [PATCH] Don't use admin cert during KRA installation - -KRA installation currently imports the admin cert. FreeIPA does not -track this cert and it may be expired, causing installation to fail. -Do not import the existing admin cert, and discard the new admin -cert that gets created during KRA installation. - -Part of: https://pagure.io/freeipa/issue/7287 - -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> ---- - ipaserver/install/krainstance.py | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - -diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py -index cdd25b9d05bcb1a30260475cc2341a258a3cf93c..990bb87ca2f0029d2450cbef47958399f534f2a6 100644 ---- a/ipaserver/install/krainstance.py -+++ b/ipaserver/install/krainstance.py -@@ -152,6 +152,10 @@ class KRAInstance(DogtagInstance): - prefix="tmp-", dir=paths.VAR_LIB_IPA) - tmp_agent_pwd = ipautil.ipa_generate_password() - -+ # Create a temporary file for the admin PKCS #12 file -+ (admin_p12_fd, admin_p12_file) = tempfile.mkstemp() -+ os.close(admin_p12_fd) -+ - # Create KRA configuration - config = ConfigParser() - config.optionxform = str -@@ -186,9 +190,8 @@ class KRAInstance(DogtagInstance): - config.set("KRA", "pki_admin_nickname", "ipa-ca-agent") - config.set("KRA", "pki_admin_subject_dn", - str(DN(('cn', 'ipa-ca-agent'), self.subject_base))) -- config.set("KRA", "pki_import_admin_cert", "True") -- config.set("KRA", "pki_admin_cert_file", paths.ADMIN_CERT_PATH) -- config.set("KRA", "pki_client_admin_cert_p12", paths.DOGTAG_ADMIN_P12) -+ config.set("KRA", "pki_import_admin_cert", "False") -+ config.set("KRA", "pki_client_admin_cert_p12", admin_p12_file) - - # Directory server - config.set("KRA", "pki_ds_ldap_port", "389") -@@ -291,6 +294,7 @@ class KRAInstance(DogtagInstance): - finally: - os.remove(p12_tmpfile_name) - os.remove(cfg_file) -+ os.remove(admin_p12_file) - - shutil.move(paths.KRA_BACKUP_KEYS_P12, paths.KRACERT_P12) - self.log.debug("completed creating KRA instance") --- -2.13.6 - diff --git a/SOURCES/0020-Handle-races-in-replica-config.patch b/SOURCES/0020-Handle-races-in-replica-config.patch new file mode 100644 index 0000000..466a33d --- /dev/null +++ b/SOURCES/0020-Handle-races-in-replica-config.patch @@ -0,0 +1,267 @@ +From 0598ed6e1c48c6600774c53065716aad759da5e7 Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Tue, 10 Jul 2018 14:03:28 +0200 +Subject: [PATCH] Handle races in replica config + +When multiple replicas are installed in parallel, two replicas may try +to create the cn=replica entry at the same time. This leads to a +conflict on one of the replicas. replica_config() and +ensure_replication_managers() now handle conflicts. + +ipaldap now maps TYPE_OR_VALUE_EXISTS to DuplicateEntry(). The type or +value exists exception is raised, when an attribute value or type is +already set. + +Fixes: https://pagure.io/freeipa/issue/7566 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Thierry Bordaz <tbordaz@redhat.com> +--- + ipapython/ipaldap.py | 5 ++ + ipaserver/install/replication.py | 123 ++++++++++++++++++------------- + ipaserver/plugins/ldap2.py | 3 +- + 3 files changed, 79 insertions(+), 52 deletions(-) + +diff --git a/ipapython/ipaldap.py b/ipapython/ipaldap.py +index dcac32c31c670753b83f99eac7f6483fbad2b14d..53fdf4967868961effea7f3f64dfb3c0edfc75f3 100644 +--- a/ipapython/ipaldap.py ++++ b/ipapython/ipaldap.py +@@ -1016,7 +1016,12 @@ class LDAPClient(object): + except ldap.NO_SUCH_OBJECT: + raise errors.NotFound(reason=arg_desc or 'no such entry') + except ldap.ALREADY_EXISTS: ++ # entry already exists + raise errors.DuplicateEntry() ++ except ldap.TYPE_OR_VALUE_EXISTS: ++ # attribute type or attribute value already exists, usually only ++ # occurs, when two machines try to write at the same time. ++ raise errors.DuplicateEntry(message=unicode(desc)) + except ldap.CONSTRAINT_VIOLATION: + # This error gets thrown by the uniqueness plugin + _msg = 'Another entry with the same attribute value already exists' +diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py +index d0f92c76c108d237104a81c72567250583ac4ff1..78c4a43cc9b8d9a6740d26209f347f64b879743e 100644 +--- a/ipaserver/install/replication.py ++++ b/ipaserver/install/replication.py +@@ -34,7 +34,7 @@ import ldap + from ipalib import api, errors + from ipalib.cli import textui + from ipalib.text import _ +-from ipapython import ipautil, ipaldap, kerberos ++from ipapython import ipautil, ipaldap + from ipapython.admintool import ScriptError + from ipapython.dn import DN + from ipapython.ipaldap import ldap_initialize +@@ -461,7 +461,7 @@ class ReplicationManager(object): + return DN(('cn', 'replica'), ('cn', self.db_suffix), + ('cn', 'mapping tree'), ('cn', 'config')) + +- def set_replica_binddngroup(self, r_conn, entry): ++ def _set_replica_binddngroup(self, r_conn, entry): + """ + Set nsds5replicabinddngroup attribute on remote master's replica entry. + Older masters (ipa < 3.3) may not support setting this attribute. In +@@ -476,11 +476,6 @@ class ReplicationManager(object): + mod.append((ldap.MOD_ADD, 'nsds5replicabinddngroup', + self.repl_man_group_dn)) + +- if 'nsds5replicabinddngroupcheckinterval' not in entry: +- mod.append( +- (ldap.MOD_ADD, +- 'nsds5replicabinddngroupcheckinterval', +- '60')) + if mod: + try: + r_conn.modify_s(entry.dn, mod) +@@ -488,49 +483,62 @@ class ReplicationManager(object): + logger.debug( + "nsds5replicabinddngroup attribute not supported on " + "remote master.") ++ except (ldap.ALREADY_EXISTS, ldap.CONSTRAINT_VIOLATION): ++ logger.debug("No update to %s necessary", entry.dn) + + def replica_config(self, conn, replica_id, replica_binddn): + assert isinstance(replica_binddn, DN) + dn = self.replica_dn() + assert isinstance(dn, DN) + ++ logger.debug("Add or update replica config %s", dn) + try: + entry = conn.get_entry(dn) + except errors.NotFound: +- pass +- else: +- binddns = entry.setdefault('nsDS5ReplicaBindDN', []) +- if replica_binddn not in {DN(m) for m in binddns}: +- # Add the new replication manager +- binddns.append(replica_binddn) +- for key, value in REPLICA_CREATION_SETTINGS.items(): +- entry[key] = value ++ # no entry, create new one ++ entry = conn.make_entry( ++ dn, ++ objectclass=["top", "nsds5replica", "extensibleobject"], ++ cn=["replica"], ++ nsds5replicaroot=[str(self.db_suffix)], ++ nsds5replicaid=[str(replica_id)], ++ nsds5replicatype=[self.get_replica_type()], ++ nsds5flags=["1"], ++ nsds5replicabinddn=[replica_binddn], ++ nsds5replicabinddngroup=[self.repl_man_group_dn], ++ nsds5replicalegacyconsumer=["off"], ++ **REPLICA_CREATION_SETTINGS ++ ) + try: +- conn.update_entry(entry) +- except errors.EmptyModlist: +- pass ++ conn.add_entry(entry) ++ except errors.DuplicateEntry: ++ logger.debug("Lost race against another replica, updating") ++ # fetch entry that have been added by another replica ++ entry = conn.get_entry(dn) ++ else: ++ logger.debug("Added replica config %s", dn) ++ # added entry successfully ++ return entry + +- self.set_replica_binddngroup(conn, entry) ++ # either existing entry or lost race ++ binddns = entry.setdefault('nsDS5ReplicaBindDN', []) ++ if replica_binddn not in {DN(m) for m in binddns}: ++ # Add the new replication manager ++ binddns.append(replica_binddn) + +- # replication is already configured +- return ++ for key, value in REPLICA_CREATION_SETTINGS.items(): ++ entry[key] = value + +- replica_type = self.get_replica_type() ++ try: ++ conn.update_entry(entry) ++ except errors.EmptyModlist: ++ logger.debug("No update to %s necessary", entry.dn) ++ else: ++ logger.debug("Update replica config %s", entry.dn) + +- entry = conn.make_entry( +- dn, +- objectclass=["top", "nsds5replica", "extensibleobject"], +- cn=["replica"], +- nsds5replicaroot=[str(self.db_suffix)], +- nsds5replicaid=[str(replica_id)], +- nsds5replicatype=[replica_type], +- nsds5flags=["1"], +- nsds5replicabinddn=[replica_binddn], +- nsds5replicabinddngroup=[self.repl_man_group_dn], +- nsds5replicalegacyconsumer=["off"], +- **REPLICA_CREATION_SETTINGS +- ) +- conn.add_entry(entry) ++ self._set_replica_binddngroup(conn, entry) ++ ++ return entry + + def setup_changelog(self, conn): + ent = conn.get_entry( +@@ -690,7 +698,10 @@ class ReplicationManager(object): + uid=["passsync"], + userPassword=[password], + ) +- conn.add_entry(entry) ++ try: ++ conn.add_entry(entry) ++ except errors.DuplicateEntry: ++ pass + + # Add the user to the list of users allowed to bypass password policy + extop_dn = DN(('cn', 'ipa_pwd_extop'), ('cn', 'plugins'), ('cn', 'config')) +@@ -1658,7 +1669,10 @@ class ReplicationManager(object): + objectclass=['top', 'groupofnames'], + cn=['replication managers'] + ) +- conn.add_entry(entry) ++ try: ++ conn.add_entry(entry) ++ except errors.DuplicateEntry: ++ pass + + def ensure_replication_managers(self, conn, r_hostname): + """ +@@ -1668,23 +1682,24 @@ class ReplicationManager(object): + On FreeIPA 3.x masters lacking support for nsds5ReplicaBinddnGroup + attribute, add replica bind DN directly into the replica entry. + """ +- my_princ = kerberos.Principal((u'ldap', unicode(self.hostname)), +- realm=self.realm) +- remote_princ = kerberos.Principal((u'ldap', unicode(r_hostname)), +- realm=self.realm) +- services_dn = DN(api.env.container_service, api.env.basedn) +- +- mydn, remote_dn = tuple( +- DN(('krbprincipalname', unicode(p)), services_dn) for p in ( +- my_princ, remote_princ)) ++ my_dn = DN( ++ ('krbprincipalname', u'ldap/%s@%s' % (self.hostname, self.realm)), ++ api.env.container_service, ++ api.env.basedn ++ ) ++ remote_dn = DN( ++ ('krbprincipalname', u'ldap/%s@%s' % (r_hostname, self.realm)), ++ api.env.container_service, ++ api.env.basedn ++ ) + + try: + conn.get_entry(self.repl_man_group_dn) + except errors.NotFound: +- self._add_replica_bind_dn(conn, mydn) ++ self._add_replica_bind_dn(conn, my_dn) + self._add_replication_managers(conn) + +- self._add_dn_to_replication_managers(conn, mydn) ++ self._add_dn_to_replication_managers(conn, my_dn) + self._add_dn_to_replication_managers(conn, remote_dn) + + def add_temp_sasl_mapping(self, conn, r_hostname): +@@ -1704,7 +1719,10 @@ class ReplicationManager(object): + + entry = conn.get_entry(self.replica_dn()) + entry['nsDS5ReplicaBindDN'].append(replica_binddn) +- conn.update_entry(entry) ++ try: ++ conn.update_entry(entry) ++ except errors.EmptyModlist: ++ pass + + entry = conn.make_entry( + DN(('cn', 'Peer Master'), ('cn', 'mapping'), ('cn', 'sasl'), +@@ -1716,7 +1734,10 @@ class ReplicationManager(object): + nsSaslMapFilterTemplate=['(cn=&@%s)' % self.realm], + nsSaslMapPriority=['1'], + ) +- conn.add_entry(entry) ++ try: ++ conn.add_entry(entry) ++ except errors.DuplicateEntry: ++ pass + + def remove_temp_replication_user(self, conn, r_hostname): + """ +diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py +index 8745866ad11cf6248d2b9dcff560c0a5ee6d109b..5d39cdf628d7e20ce5b259d97b479ef7c8ed88d5 100644 +--- a/ipaserver/plugins/ldap2.py ++++ b/ipaserver/plugins/ldap2.py +@@ -419,7 +419,8 @@ class ldap2(CrudBackend, LDAPClient): + modlist = [(a, b, self.encode(c)) + for a, b, c in modlist] + self.conn.modify_s(str(group_dn), modlist) +- except errors.DatabaseError: ++ except errors.DuplicateEntry: ++ # TYPE_OR_VALUE_EXISTS + raise errors.AlreadyGroupMember() + + def remove_entry_from_group(self, dn, group_dn, member_attr='member'): +-- +2.17.1 + diff --git a/SOURCES/0021-389-ds-base-crashed-as-part-of-ipa-server-intall-in-.patch b/SOURCES/0021-389-ds-base-crashed-as-part-of-ipa-server-intall-in-.patch deleted file mode 100644 index ef027e3..0000000 --- a/SOURCES/0021-389-ds-base-crashed-as-part-of-ipa-server-intall-in-.patch +++ /dev/null @@ -1,72 +0,0 @@ -From b047d30b8aabad424fa2bd30872721f9fab9e325 Mon Sep 17 00:00:00 2001 -From: Thierry Bordaz <tbordaz@redhat.com> -Date: Mon, 25 Sep 2017 16:41:51 +0200 -Subject: [PATCH] 389-ds-base crashed as part of ipa-server-intall in ipa-uuid - -Bug Description: - When adding an entry, ipa-uuid plugin may generate a unique value - for some of its attribute. - If the generated attribute is part of the RDN, the target DN - is replaced on the fly and the previous one freed. - Unfortunately, previous DN may be later used instead of - the new one. - -Fix Description: - Make sure to use only the current DN of the operation - -https://bugzilla.redhat.com/show_bug.cgi?id=1496226 -https://pagure.io/freeipa/issue/7227 - -Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> ---- - daemons/ipa-slapi-plugins/ipa-uuid/ipa_uuid.c | 12 +++++++++--- - 1 file changed, 9 insertions(+), 3 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-uuid/ipa_uuid.c b/daemons/ipa-slapi-plugins/ipa-uuid/ipa_uuid.c -index ffade14672e8cd9e3f3e18d45a0a7095a6341d30..87d8be2d88d9ff9bbf7d47eab57b765063f7a230 100644 ---- a/daemons/ipa-slapi-plugins/ipa-uuid/ipa_uuid.c -+++ b/daemons/ipa-slapi-plugins/ipa-uuid/ipa_uuid.c -@@ -911,6 +911,7 @@ static int ipauuid_pre_op(Slapi_PBlock *pb, int modtype) - list != ipauuid_global_config; - list = PR_NEXT_LINK(list)) { - cfgentry = (struct configEntry *) list; -+ char *current_dn = NULL; - - generate = false; - set_attr = false; -@@ -920,16 +921,21 @@ static int ipauuid_pre_op(Slapi_PBlock *pb, int modtype) - cfgentry->attr)) { - continue; - } -+ /* Current DN may have been reset by -+ * slapi_pblock_set(pb, SLAPI_ADD_TARGET,..) see below -+ * need to reread it -+ */ -+ current_dn = ipauuid_get_dn(pb); - - /* is the entry in scope? */ - if (cfgentry->scope) { -- if (!slapi_dn_issuffix(dn, cfgentry->scope)) { -+ if (!slapi_dn_issuffix(current_dn, cfgentry->scope)) { - continue; - } - } - - if (cfgentry->exclude_subtree) { -- if (slapi_dn_issuffix(dn, cfgentry->exclude_subtree)) { -+ if (slapi_dn_issuffix(current_dn, cfgentry->exclude_subtree)) { - continue; - } - } -@@ -1108,7 +1114,7 @@ static int ipauuid_pre_op(Slapi_PBlock *pb, int modtype) - ret = LDAP_OPERATIONS_ERROR; - goto done; - } -- sdn = slapi_sdn_new_dn_byval(dn); -+ sdn = slapi_sdn_new_dn_byval(current_dn); - if (!sdn) { - LOG_OOM(); - ret = LDAP_OPERATIONS_ERROR; --- -2.13.6 - diff --git a/SOURCES/0021-Fix-regression-Handle-unicode-where-str-is-expected.patch b/SOURCES/0021-Fix-regression-Handle-unicode-where-str-is-expected.patch new file mode 100644 index 0000000..5e8c1ab --- /dev/null +++ b/SOURCES/0021-Fix-regression-Handle-unicode-where-str-is-expected.patch @@ -0,0 +1,33 @@ +From d12aa9762dcd841661cc4fb384a4700d53b5bef2 Mon Sep 17 00:00:00 2001 +From: Armando Neto <abiagion@redhat.com> +Date: Tue, 17 Jul 2018 16:08:49 -0300 +Subject: [PATCH] Fix regression: Handle unicode where str is expected + +Regression caused by 947ac4bc1f6f4016cf5baf2ecb4577e893bc3948 when +trying to fix a similar issue for clients running Python 3. However, +that fix broke Python 2 clients. + +Issue: https://pagure.io/freeipa/issue/7626 + +Signed-off-by: Armando Neto <abiagion@redhat.com> +Reviewed-By: Christian Heimes <cheimes@redhat.com> +--- + ipaclient/remote_plugins/schema.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py +index 863d8f19923898c0a531c68189dd01b401e531b4..9d2c8ca9d1d3e820154425c4f9e4e39cd64d6fd1 100644 +--- a/ipaclient/remote_plugins/schema.py ++++ b/ipaclient/remote_plugins/schema.py +@@ -602,7 +602,7 @@ def get_package(server_info, client): + s = topic['topic_topic'] + if isinstance(s, bytes): + s = s.decode('utf-8') +- module.topic = s.partition('/')[0] ++ module.topic = str(s).partition('/')[0] + else: + module.topic = None + +-- +2.17.1 + diff --git a/SOURCES/0022-In-IPA-4.4-when-updating-userpassword-with-ldapmodif.patch b/SOURCES/0022-In-IPA-4.4-when-updating-userpassword-with-ldapmodif.patch new file mode 100644 index 0000000..c4131cb --- /dev/null +++ b/SOURCES/0022-In-IPA-4.4-when-updating-userpassword-with-ldapmodif.patch @@ -0,0 +1,48 @@ +From 8d72395890fc47d0ec6f1d810b0ea063e28575f5 Mon Sep 17 00:00:00 2001 +From: Thierry Bordaz <tbordaz@redhat.com> +Date: Tue, 24 Jul 2018 12:16:35 +0200 +Subject: [PATCH] In IPA 4.4 when updating userpassword with ldapmodify does + not update krbPasswordExpiration nor krbLastPwdChange + +When making ipa-pwd-extop TXN aware, some callbacks are call twice. +Particularily + ipapwd_pre_add is called during PRE_ADD and TXN_PRE_ADD + ipapwd_pre_mod is called during PRE_MOD and TXN_PRE_MOD + ipapwd_post_modadd is called during POST_ADD and TXN_POST_ADD + ipapwd_post_modadd is called during POST_MOD and TXN_POST_MOD +It is not the expected behavior and it results on some skipped updates krbPasswordExpiration +and krbLastPwdChange + +https://pagure.io/freeipa/issue/7601 + +Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> +--- + daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c +index c62eae33418f8368c831a91f611915addf7d423b..209d596255d05bfd03de432b7930e6406cc025dc 100644 +--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c ++++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c +@@ -1488,8 +1488,6 @@ int ipapwd_pre_init(Slapi_PBlock *pb) + ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_BIND_FN, (void *)ipapwd_pre_bind); +- if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_ADD_FN, (void *)ipapwd_pre_add); +- if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODIFY_FN, (void *)ipapwd_pre_mod); + + return ret; + } +@@ -1513,9 +1511,7 @@ int ipapwd_post_init(Slapi_PBlock *pb) + + ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc); +- if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN, (void *)ipapwd_post_modadd); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN, (void *)ipapwd_post_updatecfg); +- if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN, (void *)ipapwd_post_modadd); + if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN, (void *)ipapwd_post_updatecfg); + + return ret; +-- +2.17.1 + diff --git a/SOURCES/0022-Prevent-set_directive-from-clobbering-other-keys.patch b/SOURCES/0022-Prevent-set_directive-from-clobbering-other-keys.patch deleted file mode 100644 index 85e3e42..0000000 --- a/SOURCES/0022-Prevent-set_directive-from-clobbering-other-keys.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 8ea1652c64956eea6dd0708f61b3330befcf1a31 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale <ftweedal@redhat.com> -Date: Sat, 21 Nov 2020 08:47:57 +1100 -Subject: [PATCH] Prevent set_directive from clobbering other keys - -`set_directive` only looks for a prefix of the line matching the -given directive (key). If a directive is encountered for which the -given key is prefix, it will be vanquished. - -This occurs in the case of `{ca,kra}.sslserver.cert[req]`; the -`cert` directive gets updated after certificate renewal, and the -`certreq` directive gets clobbered. This can cause failures later -on during KRA installation, and possibly cloning. - -Match the whole directive to avoid this issue. - -Fixes: https://pagure.io/freeipa/issue/7288 -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> ---- - ipaserver/install/cainstance.py | 2 +- - ipaserver/install/dogtaginstance.py | 2 +- - ipaserver/install/installutils.py | 6 +++--- - 3 files changed, 5 insertions(+), 5 deletions(-) - -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index 62f79b28000b015edb66f4c39a270097ab3ed666..f45d2c8b89ba4b81be5acbbe85f256e85ef630fb 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -931,7 +931,7 @@ class CAInstance(DogtagInstance): - installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.enable', 'true', quotes=False, separator='=') - installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.mapper', 'NoMap', quotes=False, separator='=') - installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.pluginName', 'Rule', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.predicate=', '', quotes=False, separator='') -+ installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.predicate', '', quotes=False, separator='=') - installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.publisher', 'FileBaseCRLPublisher', quotes=False, separator='=') - installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.type', 'crl', quotes=False, separator='=') - -diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py -index 1fdc3e50a46877374e4f1aa8435d09f6b4e62180..9470e1a13608a8a84aab8a36c269a708e3f3e9f4 100644 ---- a/ipaserver/install/dogtaginstance.py -+++ b/ipaserver/install/dogtaginstance.py -@@ -212,7 +212,7 @@ class DogtagInstance(service.Service): - separator='=') - # Remove internaldb password as is not needed anymore - installutils.set_directive(paths.PKI_TOMCAT_PASSWORD_CONF, -- 'internaldb', None) -+ 'internaldb', None, separator='=') - - def uninstall(self): - if self.is_installed(): -diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py -index 01930c4de6f0edd16b31aeba1c926fe581e9635b..821609beb533fcc9064500a88ccd07b35142f1df 100644 ---- a/ipaserver/install/installutils.py -+++ b/ipaserver/install/installutils.py -@@ -433,7 +433,7 @@ def set_directive(filename, directive, value, quotes=True, separator=' '): - - A value of None means to drop the directive. - -- This has only been tested with nss.conf -+ Does not tolerate (or put) spaces around the separator. - - :param filename: input filename - :param directive: directive name -@@ -442,7 +442,7 @@ def set_directive(filename, directive, value, quotes=True, separator=' '): - any existing double quotes are first escaped to avoid - unparseable directives. - :param separator: character serving as separator between directive and -- value -+ value. Correct value required even when dropping a directive. - """ - - new_directive_value = "" -@@ -457,7 +457,7 @@ def set_directive(filename, directive, value, quotes=True, separator=' '): - fd = open(filename) - newfile = [] - for line in fd: -- if line.lstrip().startswith(directive): -+ if re.match(r'\s*{}'.format(re.escape(directive + separator)), line): - valueset = True - if value is not None: - newfile.append(new_directive_value) --- -2.13.6 - diff --git a/SOURCES/0023-Move-fips_enabled-to-a-common-library-to-share-acros.patch b/SOURCES/0023-Move-fips_enabled-to-a-common-library-to-share-acros.patch new file mode 100644 index 0000000..24c52bd --- /dev/null +++ b/SOURCES/0023-Move-fips_enabled-to-a-common-library-to-share-acros.patch @@ -0,0 +1,116 @@ +From 08ada3f8d7f80067a1b43e6172394d1326e3d178 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy <abokovoy@redhat.com> +Date: Wed, 8 Aug 2018 12:28:53 +0300 +Subject: [PATCH] Move fips_enabled to a common library to share across + different plugins + +Related: https://pagure.io/freeipa/issue/7659 +Reviewed-By: Robbie Harwood <rharwood@redhat.com> +--- + .../ipa-slapi-plugins/ipa-pwd-extop/common.c | 24 +----------------- + util/ipa_pwd.c | 25 +++++++++++++++++++ + util/ipa_pwd.h | 2 ++ + 3 files changed, 28 insertions(+), 23 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c +index 5efadac5b1fd57e5f91a886224fa2f1ab88305ac..db7183bf2b115dcb0c21f7a6bdb8e55db26224c4 100644 +--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c ++++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c +@@ -46,7 +46,6 @@ + /* Type of connection for this operation;*/ + #define LDAP_EXTOP_PASSMOD_CONN_SECURE + +-#define PROC_SYS_FIPS "/proc/sys/crypto/fips_enabled" + + /* Uncomment the following #undef FOR TESTING: + * allows non-SSL connections to use the password change extended op */ +@@ -64,27 +63,6 @@ static const char *ipapwd_def_encsalts[] = { + NULL + }; + +-static bool fips_enabled(void) +-{ +- int fd; +- ssize_t len; +- char buf[8]; +- +- fd = open(PROC_SYS_FIPS, O_RDONLY); +- if (fd != -1) { +- len = read(fd, buf, sizeof(buf)); +- close(fd); +- /* Assume FIPS in enabled if PROC_SYS_FIPS contains a non-0 value +- * similar to the is_fips_enabled() check in +- * ipaplatform/redhat/tasks.py */ +- if (!(len == 2 && buf[0] == '0' && buf[1] == '\n')) { +- return true; +- } +- } +- +- return false; +-} +- + static struct ipapwd_krbcfg *ipapwd_getConfig(void) + { + krb5_error_code krberr; +@@ -255,7 +233,7 @@ static struct ipapwd_krbcfg *ipapwd_getConfig(void) + + /* get the ipa etc/ipaConfig entry */ + config->allow_nt_hash = false; +- if (fips_enabled()) { ++ if (ipapwd_fips_enabled()) { + LOG("FIPS mode is enabled, NT hashes are not allowed.\n"); + } else { + ret = ipapwd_getEntry(ipa_etc_config_dn, &config_entry, NULL); +diff --git a/util/ipa_pwd.c b/util/ipa_pwd.c +index f6564c8021c656031d3f459dd50d830934c7143b..9890c980cacad08302fb5305c3aa9598a81ec681 100644 +--- a/util/ipa_pwd.c ++++ b/util/ipa_pwd.c +@@ -27,6 +27,8 @@ + #include <stdio.h> + #include <time.h> + #include <ctype.h> ++#include <fcntl.h> ++#include <unistd.h> + #include <nss.h> + #include <nssb64.h> + #include <hasht.h> +@@ -656,3 +658,26 @@ done: + free(hash); + return ret; + } ++ ++#define PROC_SYS_FIPS "/proc/sys/crypto/fips_enabled" ++ ++bool ipapwd_fips_enabled(void) ++{ ++ int fd; ++ ssize_t len; ++ char buf[8]; ++ ++ fd = open(PROC_SYS_FIPS, O_RDONLY); ++ if (fd != -1) { ++ len = read(fd, buf, sizeof(buf)); ++ close(fd); ++ /* Assume FIPS in enabled if PROC_SYS_FIPS contains a non-0 value ++ * similar to the is_fips_enabled() check in ++ * ipaplatform/redhat/tasks.py */ ++ if (!(len == 2 && buf[0] == '0' && buf[1] == '\n')) { ++ return true; ++ } ++ } ++ ++ return false; ++} +diff --git a/util/ipa_pwd.h b/util/ipa_pwd.h +index b3ee75063adc4baa93bbd4991161bebe1d233bb8..664c8b1827591e716095d9ef1727e422c7d82680 100644 +--- a/util/ipa_pwd.h ++++ b/util/ipa_pwd.h +@@ -77,3 +77,5 @@ int ipapwd_generate_new_history(char *password, + int *new_pwd_hlen); + + int encode_nt_key(char *newPasswd, uint8_t *nt_key); ++ ++bool ipapwd_fips_enabled(void); +-- +2.17.1 + diff --git a/SOURCES/0023-pep8-reduce-line-lengths-in-CAInstance.__enable_crl_.patch b/SOURCES/0023-pep8-reduce-line-lengths-in-CAInstance.__enable_crl_.patch deleted file mode 100644 index e0f1a0c..0000000 --- a/SOURCES/0023-pep8-reduce-line-lengths-in-CAInstance.__enable_crl_.patch +++ /dev/null @@ -1,113 +0,0 @@ -From a87278422807aa4004b63e8e46ad38dab5a911f3 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale <ftweedal@redhat.com> -Date: Thu, 30 Nov 2017 12:00:53 +1100 -Subject: [PATCH] pep8: reduce line lengths in CAInstance.__enable_crl_publish - -Part of: https://pagure.io/freeipa/issue/7288 - -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> ---- - ipaserver/install/cainstance.py | 71 ++++++++++++++++++++++++----------------- - 1 file changed, 41 insertions(+), 30 deletions(-) - -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index f45d2c8b89ba4b81be5acbbe85f256e85ef630fb..dd410d1c97cb4b27d35086bb2f511c42c02d022f 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -907,52 +907,63 @@ class CAInstance(DogtagInstance): - - https://access.redhat.com/knowledge/docs/en-US/Red_Hat_Certificate_System/8.0/html/Admin_Guide/Setting_up_Publishing.html - """ -- caconfig = paths.CA_CS_CFG_PATH - -- publishdir = self.prepare_crl_publish_dir() -+ def put(k, v): -+ installutils.set_directive( -+ paths.CA_CS_CFG_PATH, k, v, quotes=False, separator='=') - - # Enable file publishing, disable LDAP -- installutils.set_directive(caconfig, 'ca.publish.enable', 'true', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.ldappublish.enable', 'false', quotes=False, separator='=') -+ put('ca.publish.enable', 'true') -+ put('ca.publish.ldappublish.enable', 'false') - - # Create the file publisher, der only, not b64 -- installutils.set_directive(caconfig, 'ca.publish.publisher.impl.FileBasedPublisher.class','com.netscape.cms.publish.publishers.FileBasedPublisher', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.crlLinkExt', 'bin', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.directory', publishdir, quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.latestCrlLink', 'true', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.pluginName', 'FileBasedPublisher', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.timeStamp', 'LocalTime', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.zipCRLs', 'false', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.zipLevel', '9', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.Filename.b64', 'false', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.Filename.der', 'true', quotes=False, separator='=') -+ put('ca.publish.publisher.impl.FileBasedPublisher.class', -+ 'com.netscape.cms.publish.publishers.FileBasedPublisher') -+ put('ca.publish.publisher.instance.FileBaseCRLPublisher.crlLinkExt', -+ 'bin') -+ put('ca.publish.publisher.instance.FileBaseCRLPublisher.directory', -+ self.prepare_crl_publish_dir()) -+ put('ca.publish.publisher.instance.FileBaseCRLPublisher.latestCrlLink', -+ 'true') -+ put('ca.publish.publisher.instance.FileBaseCRLPublisher.pluginName', -+ 'FileBasedPublisher') -+ put('ca.publish.publisher.instance.FileBaseCRLPublisher.timeStamp', -+ 'LocalTime') -+ put('ca.publish.publisher.instance.FileBaseCRLPublisher.zipCRLs', -+ 'false') -+ put('ca.publish.publisher.instance.FileBaseCRLPublisher.zipLevel', '9') -+ put('ca.publish.publisher.instance.FileBaseCRLPublisher.Filename.b64', -+ 'false') -+ put('ca.publish.publisher.instance.FileBaseCRLPublisher.Filename.der', -+ 'true') - - # The publishing rule -- installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.enable', 'true', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.mapper', 'NoMap', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.pluginName', 'Rule', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.predicate', '', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.publisher', 'FileBaseCRLPublisher', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.type', 'crl', quotes=False, separator='=') -+ put('ca.publish.rule.instance.FileCrlRule.enable', 'true') -+ put('ca.publish.rule.instance.FileCrlRule.mapper', 'NoMap') -+ put('ca.publish.rule.instance.FileCrlRule.pluginName', 'Rule') -+ put('ca.publish.rule.instance.FileCrlRule.predicate', '') -+ put('ca.publish.rule.instance.FileCrlRule.publisher', -+ 'FileBaseCRLPublisher') -+ put('ca.publish.rule.instance.FileCrlRule.type', 'crl') - - # Now disable LDAP publishing -- installutils.set_directive(caconfig, 'ca.publish.rule.instance.LdapCaCertRule.enable', 'false', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.rule.instance.LdapCrlRule.enable', 'false', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.rule.instance.LdapUserCertRule.enable', 'false', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.publish.rule.instance.LdapXCertRule.enable', 'false', quotes=False, separator='=') -+ put('ca.publish.rule.instance.LdapCaCertRule.enable', 'false') -+ put('ca.publish.rule.instance.LdapCrlRule.enable', 'false') -+ put('ca.publish.rule.instance.LdapUserCertRule.enable', 'false') -+ put('ca.publish.rule.instance.LdapXCertRule.enable', 'false') - - # If we are the initial master then we are the CRL generator, otherwise - # we point to that master for CRLs. - if not self.clone: - # These next two are defaults, but I want to be explicit that the - # initial master is the CRL generator. -- installutils.set_directive(caconfig, 'ca.crl.MasterCRL.enableCRLCache', 'true', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.crl.MasterCRL.enableCRLUpdates', 'true', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.listenToCloneModifications', 'true', quotes=False, separator='=') -+ put('ca.crl.MasterCRL.enableCRLCache', 'true') -+ put('ca.crl.MasterCRL.enableCRLUpdates', 'true') -+ put('ca.listenToCloneModifications', 'true') - else: -- installutils.set_directive(caconfig, 'ca.crl.MasterCRL.enableCRLCache', 'false', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.crl.MasterCRL.enableCRLUpdates', 'false', quotes=False, separator='=') -- installutils.set_directive(caconfig, 'ca.listenToCloneModifications', 'false', quotes=False, separator='=') -+ put('ca.crl.MasterCRL.enableCRLCache', 'false') -+ put('ca.crl.MasterCRL.enableCRLUpdates', 'false') -+ put('ca.listenToCloneModifications', 'false') - - def uninstall(self): - # just eat state --- -2.13.6 - diff --git a/SOURCES/0024-installutils-refactor-set_directive.patch b/SOURCES/0024-installutils-refactor-set_directive.patch deleted file mode 100644 index 643edb9..0000000 --- a/SOURCES/0024-installutils-refactor-set_directive.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 25a6726a350fd4192b45a78b6312ab8345b02586 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale <ftweedal@redhat.com> -Date: Tue, 5 Dec 2017 13:43:04 +1100 -Subject: [PATCH] installutils: refactor set_directive - -To separate concerns and make it easier to test set_directive, -extract function ``set_directive_lines`` to do the line-wise -search/replace, leaving ``set_directive`` to deal with the file -handling. - -Part of: https://pagure.io/freeipa/issue/7288 - -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> ---- - ipaserver/install/installutils.py | 56 +++++++++++++++++++++++---------------- - 1 file changed, 33 insertions(+), 23 deletions(-) - -diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py -index 821609beb533fcc9064500a88ccd07b35142f1df..b56cf591496c679e5fcf3e94f458c286216eb1e4 100644 ---- a/ipaserver/install/installutils.py -+++ b/ipaserver/install/installutils.py -@@ -444,34 +444,44 @@ def set_directive(filename, directive, value, quotes=True, separator=' '): - :param separator: character serving as separator between directive and - value. Correct value required even when dropping a directive. - """ -+ st = os.stat(filename) -+ with open(filename, 'r') as f: -+ lines = list(f) # read the whole file -+ new_lines = set_directive_lines( -+ quotes, separator, directive, value, lines) -+ with open(filename, 'w') as f: -+ # don't construct the whole string; write line-wise -+ for line in new_lines: -+ f.write(line) -+ os.chown(filename, st.st_uid, st.st_gid) # reset perms - -- new_directive_value = "" -- if value is not None: -- value_to_set = quote_directive_value(value, '"') if quotes else value - -- new_directive_value = "".join( -- [directive, separator, value_to_set, '\n']) -+def set_directive_lines(quotes, separator, k, v, lines): -+ """Set a name/value pair in a configuration (iterable of lines). - -- valueset = False -- st = os.stat(filename) -- fd = open(filename) -- newfile = [] -- for line in fd: -- if re.match(r'\s*{}'.format(re.escape(directive + separator)), line): -- valueset = True -- if value is not None: -- newfile.append(new_directive_value) -+ Replaces the value of the key if found, otherwise adds it at -+ end. If value is ``None``, remove the key if found. -+ -+ Takes an iterable of lines (with trailing newline). -+ Yields lines (with trailing newline). -+ -+ """ -+ new_line = "" -+ if v is not None: -+ v_quoted = quote_directive_value(v, '"') if quotes else v -+ new_line = ''.join([k, separator, v_quoted, '\n']) -+ -+ found = False -+ for line in lines: -+ if re.match(r'\s*{}'.format(re.escape(k + separator)), line): -+ found = True -+ if v is not None: -+ yield new_line - else: -- newfile.append(line) -- fd.close() -- if not valueset: -- if value is not None: -- newfile.append(new_directive_value) -+ yield line - -- fd = open(filename, "w") -- fd.write("".join(newfile)) -- fd.close() -- os.chown(filename, st.st_uid, st.st_gid) # reset perms -+ if not found and v is not None: -+ yield new_line - - - def get_directive(filename, directive, separator=' '): --- -2.13.6 - diff --git a/SOURCES/0024-ipasam-do-not-use-RC4-in-FIPS-mode.patch b/SOURCES/0024-ipasam-do-not-use-RC4-in-FIPS-mode.patch new file mode 100644 index 0000000..041ca91 --- /dev/null +++ b/SOURCES/0024-ipasam-do-not-use-RC4-in-FIPS-mode.patch @@ -0,0 +1,96 @@ +From 1a7538f0d73b4b35769c4df5ba32ed836e26a648 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy <abokovoy@redhat.com> +Date: Wed, 8 Aug 2018 13:04:04 +0300 +Subject: [PATCH] ipasam: do not use RC4 in FIPS mode + +When creating Kerberos keys for trusted domain object account, ipasam +module requests to generate keys using a series of well-known encryption +types. In FIPS mode it is not possible to generate RC4-HMAC key: +MIT Kerberos is using openssl crypto backend and openssl does not allow +use of RC4 in FIPS mode. + +Thus, we have to filter out RC4-HMAC encryption type when running in +FIPS mode. A side-effect is that a trust to Active Directory running +with Windows Server 2003 will not be possible anymore in FIPS mode. + +Resolves: https://pagure.io/freeipa/issue/7659 +Reviewed-By: Robbie Harwood <rharwood@redhat.com> +--- + daemons/ipa-sam/ipa_sam.c | 23 +++++++++++++++++++---- + 1 file changed, 19 insertions(+), 4 deletions(-) + +diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c +index 0cd48d845b2edf9f328de0a949f80f98f9ef9025..675a511f0febf13cc5e00b547c18a050ac534f2e 100644 +--- a/daemons/ipa-sam/ipa_sam.c ++++ b/daemons/ipa-sam/ipa_sam.c +@@ -213,6 +213,7 @@ struct ipasam_private { + char *client_princ; + struct sss_idmap_ctx *idmap_ctx; + uint32_t supported_enctypes; ++ bool fips_enabled; + }; + + +@@ -1737,6 +1738,10 @@ static bool search_krb_princ(struct ipasam_private *ipasam_state, + return true; + } + ++/* Please keep ENCTYPE_ARCFOUR_HMAC the last in the list ++ * of the default encryption types so that we can exclude ++ * it when running in a FIPS mode where it is not allowed ++ */ + #define DEF_ENCTYPE_NUM 3 + long default_enctypes[DEF_ENCTYPE_NUM] = { + ENCTYPE_AES256_CTS_HMAC_SHA1_96, +@@ -1754,9 +1759,14 @@ static int set_cross_realm_pw(struct ipasam_private *ipasam_state, + struct berval reqdata = { 0 }; + struct berval *retdata = NULL; + char *retoid; ++ int enctypes_num = DEF_ENCTYPE_NUM; + ++ if (ipasam_state->fips_enabled) { ++ DEBUG(1, ("FIPS mode enabled: TDO account credentials will not have RC4-HMAC!\n")); ++ enctypes_num = DEF_ENCTYPE_NUM - 1; ++ } + ret = ipaasn1_enc_getkt(true, princ, pwd, +- default_enctypes, DEF_ENCTYPE_NUM, ++ default_enctypes, enctypes_num, + &buffer, &buflen); + if (!ret) goto done; + +@@ -3935,7 +3945,9 @@ static NTSTATUS ipasam_get_enctypes(struct ipasam_private *ipasam_state, + *enctypes |= KERB_ENCTYPE_DES_CBC_MD5; + break; + case ENCTYPE_ARCFOUR_HMAC: +- *enctypes |= KERB_ENCTYPE_RC4_HMAC_MD5; ++ if (!ipasam_state->fips_enabled) { ++ *enctypes |= KERB_ENCTYPE_RC4_HMAC_MD5; ++ } + break; + case ENCTYPE_AES128_CTS_HMAC_SHA1_96: + *enctypes |= KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96; +@@ -4563,6 +4575,7 @@ static NTSTATUS pdb_init_ipasam(struct pdb_methods **pdb_method, + return NT_STATUS_INVALID_PARAMETER; + } + ++ ipasam_state->fips_enabled = ipapwd_fips_enabled(); + ipasam_state->trust_dn = talloc_asprintf(ipasam_state, + "cn=ad,cn=trusts,%s", + ipasam_state->base_dn); +@@ -4684,9 +4697,11 @@ static NTSTATUS pdb_init_ipasam(struct pdb_methods **pdb_method, + &enctypes); + + if (!NT_STATUS_IS_OK(status)) { +- enctypes = KERB_ENCTYPE_RC4_HMAC_MD5 | +- KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96 | ++ enctypes = KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96 | + KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96; ++ if (!ipasam_state->fips_enabled) { ++ enctypes |= KERB_ENCTYPE_RC4_HMAC_MD5; ++ } + } + + ipasam_state->supported_enctypes = enctypes; +-- +2.17.1 + diff --git a/SOURCES/0025-Add-tests-for-installutils.set_directive.patch b/SOURCES/0025-Add-tests-for-installutils.set_directive.patch deleted file mode 100644 index da5f49a..0000000 --- a/SOURCES/0025-Add-tests-for-installutils.set_directive.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 8ffdc78b211c025c19636a5f5dcd12d12191aee4 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale <ftweedal@redhat.com> -Date: Tue, 5 Dec 2017 15:00:18 +1100 -Subject: [PATCH] Add tests for installutils.set_directive - -Part of: https://pagure.io/freeipa/issue/7288 - -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> ---- - .../test_install/test_installutils.py | 57 ++++++++++++++++++++++ - 1 file changed, 57 insertions(+) - create mode 100644 ipatests/test_ipaserver/test_install/test_installutils.py - -diff --git a/ipatests/test_ipaserver/test_install/test_installutils.py b/ipatests/test_ipaserver/test_install/test_installutils.py -new file mode 100644 -index 0000000000000000000000000000000000000000..cc8fd3cf3f82c2d9af48287f506a566ffbfc39f6 ---- /dev/null -+++ b/ipatests/test_ipaserver/test_install/test_installutils.py -@@ -0,0 +1,57 @@ -+# -+# Copyright (C) 2017 FreeIPA Contributors. See COPYING for license -+# -+ -+import os -+import tempfile -+ -+from ipaserver.install import installutils -+ -+EXAMPLE_CONFIG = [ -+ 'foo=1\n', -+ 'foobar=2\n', -+] -+ -+ -+class test_set_directive_lines(object): -+ def test_remove_directive(self): -+ lines = installutils.set_directive_lines( -+ False, '=', 'foo', None, EXAMPLE_CONFIG) -+ assert list(lines) == ['foobar=2\n'] -+ -+ def test_add_directive(self): -+ lines = installutils.set_directive_lines( -+ False, '=', 'baz', '4', EXAMPLE_CONFIG) -+ assert list(lines) == ['foo=1\n', 'foobar=2\n', 'baz=4\n'] -+ -+ def test_set_directive_does_not_clobber_suffix_key(self): -+ lines = installutils.set_directive_lines( -+ False, '=', 'foo', '3', EXAMPLE_CONFIG) -+ assert list(lines) == ['foo=3\n', 'foobar=2\n'] -+ -+ -+class test_set_directive(object): -+ def test_set_directive(self): -+ """Check that set_directive writes the new data and preserves mode.""" -+ fd, filename = tempfile.mkstemp() -+ try: -+ os.close(fd) -+ stat_pre = os.stat(filename) -+ -+ with open(filename, 'w') as f: -+ for line in EXAMPLE_CONFIG: -+ f.write(line) -+ -+ installutils.set_directive(filename, 'foo', '3', False, '=') -+ -+ stat_post = os.stat(filename) -+ with open(filename, 'r') as f: -+ lines = list(f) -+ -+ assert lines == ['foo=3\n', 'foobar=2\n'] -+ assert stat_pre.st_mode == stat_post.st_mode -+ assert stat_pre.st_uid == stat_post.st_uid -+ assert stat_pre.st_gid == stat_post.st_gid -+ -+ finally: -+ os.remove(filename) --- -2.13.6 - diff --git a/SOURCES/0025-Re-open-the-ldif-file-to-prevent-error-message.patch b/SOURCES/0025-Re-open-the-ldif-file-to-prevent-error-message.patch new file mode 100644 index 0000000..964792c --- /dev/null +++ b/SOURCES/0025-Re-open-the-ldif-file-to-prevent-error-message.patch @@ -0,0 +1,56 @@ +From fd54380d684494e13d8e797b17412a6713937b95 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Tibor=20Dudl=C3=A1k?= <tdudlak@redhat.com> +Date: Thu, 2 Aug 2018 18:05:51 +0200 +Subject: [PATCH] Re-open the ldif file to prevent error message + +There was an issue with ipa-server-upgrade and it was +showing an error while upgrading: +DN... does not exists or haven't been updated, caused +by not moving pointer to file begining when re-reading. + +Resolves: https://pagure.io/freeipa/issue/7644 +Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> +Reviewed-By: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +--- + ipaserver/install/upgradeinstance.py | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +diff --git a/ipaserver/install/upgradeinstance.py b/ipaserver/install/upgradeinstance.py +index 19a06a0a84536cb548822e47038142e97d8bee39..cb83d7bb1817d1fd9a36f2e97a5cc80bf806cabd 100644 +--- a/ipaserver/install/upgradeinstance.py ++++ b/ipaserver/install/upgradeinstance.py +@@ -237,17 +237,22 @@ class IPAUpgrade(service.Service): + + def __disable_schema_compat(self): + ldif_outfile = "%s.modified.out" % self.filename ++ ++ with open(self.filename, "r") as in_file: ++ parser = GetEntryFromLDIF(in_file, entries_dn=[COMPAT_DN]) ++ parser.parse() ++ ++ try: ++ compat_entry = parser.get_results()[COMPAT_DN] ++ except KeyError: ++ return ++ ++ if not compat_entry.get('nsslapd-pluginEnabled'): ++ return ++ + with open(ldif_outfile, "w") as out_file: + with open(self.filename, "r") as in_file: +- parser = GetEntryFromLDIF(in_file, entries_dn=[COMPAT_DN]) +- parser.parse() +- try: +- compat_entry = parser.get_results()[COMPAT_DN] +- except KeyError: +- return + parser = installutils.ModifyLDIF(in_file, out_file) +- if not compat_entry.get('nsslapd-pluginEnabled'): +- return + parser.remove_value(COMPAT_DN, "nsslapd-pluginEnabled") + parser.remove_value(COMPAT_DN, "nsslapd-pluginenabled") + parser.add_value(COMPAT_DN, "nsslapd-pluginEnabled", +-- +2.17.1 + diff --git a/SOURCES/0026-Add-safe-DirectiveSetter-context-manager.patch b/SOURCES/0026-Add-safe-DirectiveSetter-context-manager.patch deleted file mode 100644 index c142e7a..0000000 --- a/SOURCES/0026-Add-safe-DirectiveSetter-context-manager.patch +++ /dev/null @@ -1,365 +0,0 @@ -From dda1087a2e6e0f5fcb8623983f5296b8a426cfc5 Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Fri, 8 Dec 2017 12:38:41 +0100 -Subject: [PATCH] Add safe DirectiveSetter context manager - -installutils.set_directive() is both inefficient and potentially -dangerous. It does not ensure that the whole file is written and -properly synced to disk. In worst case it could lead to partially -written or destroyed config files. - -The new DirectiveSetter context manager wraps everything under an easy -to use interface. - -https://pagure.io/freeipa/issue/7312 - -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> ---- - ipaserver/install/cainstance.py | 109 ++++++++++----------- - ipaserver/install/installutils.py | 87 +++++++++++++++- - .../test_install/test_installutils.py | 67 +++++++++++++ - 3 files changed, 205 insertions(+), 58 deletions(-) - -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index dd410d1c97cb4b27d35086bb2f511c42c02d022f..20635eae22268ff72de73b8b9c430050114bb45b 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -908,62 +908,61 @@ class CAInstance(DogtagInstance): - https://access.redhat.com/knowledge/docs/en-US/Red_Hat_Certificate_System/8.0/html/Admin_Guide/Setting_up_Publishing.html - """ - -- def put(k, v): -- installutils.set_directive( -- paths.CA_CS_CFG_PATH, k, v, quotes=False, separator='=') -+ with installutils.DirectiveSetter(paths.CA_CS_CFG_PATH, -+ quotes=False, separator='=') as ds: - -- # Enable file publishing, disable LDAP -- put('ca.publish.enable', 'true') -- put('ca.publish.ldappublish.enable', 'false') -- -- # Create the file publisher, der only, not b64 -- put('ca.publish.publisher.impl.FileBasedPublisher.class', -- 'com.netscape.cms.publish.publishers.FileBasedPublisher') -- put('ca.publish.publisher.instance.FileBaseCRLPublisher.crlLinkExt', -- 'bin') -- put('ca.publish.publisher.instance.FileBaseCRLPublisher.directory', -- self.prepare_crl_publish_dir()) -- put('ca.publish.publisher.instance.FileBaseCRLPublisher.latestCrlLink', -- 'true') -- put('ca.publish.publisher.instance.FileBaseCRLPublisher.pluginName', -- 'FileBasedPublisher') -- put('ca.publish.publisher.instance.FileBaseCRLPublisher.timeStamp', -- 'LocalTime') -- put('ca.publish.publisher.instance.FileBaseCRLPublisher.zipCRLs', -- 'false') -- put('ca.publish.publisher.instance.FileBaseCRLPublisher.zipLevel', '9') -- put('ca.publish.publisher.instance.FileBaseCRLPublisher.Filename.b64', -- 'false') -- put('ca.publish.publisher.instance.FileBaseCRLPublisher.Filename.der', -- 'true') -- -- # The publishing rule -- put('ca.publish.rule.instance.FileCrlRule.enable', 'true') -- put('ca.publish.rule.instance.FileCrlRule.mapper', 'NoMap') -- put('ca.publish.rule.instance.FileCrlRule.pluginName', 'Rule') -- put('ca.publish.rule.instance.FileCrlRule.predicate', '') -- put('ca.publish.rule.instance.FileCrlRule.publisher', -- 'FileBaseCRLPublisher') -- put('ca.publish.rule.instance.FileCrlRule.type', 'crl') -- -- # Now disable LDAP publishing -- put('ca.publish.rule.instance.LdapCaCertRule.enable', 'false') -- put('ca.publish.rule.instance.LdapCrlRule.enable', 'false') -- put('ca.publish.rule.instance.LdapUserCertRule.enable', 'false') -- put('ca.publish.rule.instance.LdapXCertRule.enable', 'false') -- -- # If we are the initial master then we are the CRL generator, otherwise -- # we point to that master for CRLs. -- if not self.clone: -- # These next two are defaults, but I want to be explicit that the -- # initial master is the CRL generator. -- put('ca.crl.MasterCRL.enableCRLCache', 'true') -- put('ca.crl.MasterCRL.enableCRLUpdates', 'true') -- put('ca.listenToCloneModifications', 'true') -- else: -- put('ca.crl.MasterCRL.enableCRLCache', 'false') -- put('ca.crl.MasterCRL.enableCRLUpdates', 'false') -- put('ca.listenToCloneModifications', 'false') -+ # Enable file publishing, disable LDAP -+ ds.set('ca.publish.enable', 'true') -+ ds.set('ca.publish.ldappublish.enable', 'false') -+ -+ # Create the file publisher, der only, not b64 -+ ds.set( -+ 'ca.publish.publisher.impl.FileBasedPublisher.class', -+ 'com.netscape.cms.publish.publishers.FileBasedPublisher' -+ ) -+ prefix = 'ca.publish.publisher.instance.FileBaseCRLPublisher.' -+ ds.set(prefix + 'crlLinkExt', 'bin') -+ ds.set(prefix + 'directory', self.prepare_crl_publish_dir()) -+ ds.set(prefix + 'latestCrlLink', 'true') -+ ds.set(prefix + 'pluginName', 'FileBasedPublisher') -+ ds.set(prefix + 'timeStamp', 'LocalTime') -+ ds.set(prefix + 'zipCRLs', 'false') -+ ds.set(prefix + 'zipLevel', '9') -+ ds.set(prefix + 'Filename.b64', 'false') -+ ds.set(prefix + 'Filename.der', 'true') -+ -+ # The publishing rule -+ ds.set('ca.publish.rule.instance.FileCrlRule.enable', 'true') -+ ds.set('ca.publish.rule.instance.FileCrlRule.mapper', 'NoMap') -+ ds.set('ca.publish.rule.instance.FileCrlRule.pluginName', 'Rule') -+ ds.set('ca.publish.rule.instance.FileCrlRule.predicate', '') -+ ds.set( -+ 'ca.publish.rule.instance.FileCrlRule.publisher', -+ 'FileBaseCRLPublisher' -+ ) -+ ds.set('ca.publish.rule.instance.FileCrlRule.type', 'crl') -+ -+ # Now disable LDAP publishing -+ ds.set('ca.publish.rule.instance.LdapCaCertRule.enable', 'false') -+ ds.set('ca.publish.rule.instance.LdapCrlRule.enable', 'false') -+ ds.set( -+ 'ca.publish.rule.instance.LdapUserCertRule.enable', -+ 'false' -+ ) -+ ds.set('ca.publish.rule.instance.LdapXCertRule.enable', 'false') -+ -+ # If we are the initial master then we are the CRL generator, -+ # otherwise we point to that master for CRLs. -+ if not self.clone: -+ # These next two are defaults, but I want to be explicit -+ # that the initial master is the CRL generator. -+ ds.set('ca.crl.MasterCRL.enableCRLCache', 'true') -+ ds.set('ca.crl.MasterCRL.enableCRLUpdates', 'true') -+ ds.set('ca.listenToCloneModifications', 'true') -+ else: -+ ds.set('ca.crl.MasterCRL.enableCRLCache', 'false') -+ ds.set('ca.crl.MasterCRL.enableCRLUpdates', 'false') -+ ds.set('ca.listenToCloneModifications', 'false') - - def uninstall(self): - # just eat state -diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py -index b56cf591496c679e5fcf3e94f458c286216eb1e4..08e098f8656c8fe61a87fb046c01e1487c25da7f 100644 ---- a/ipaserver/install/installutils.py -+++ b/ipaserver/install/installutils.py -@@ -24,6 +24,7 @@ import errno - import socket - import getpass - import gssapi -+import io - import ldif - import os - import re -@@ -31,6 +32,7 @@ import fileinput - import sys - import tempfile - import shutil -+import stat # pylint: disable=bad-python3-import - import traceback - import textwrap - from contextlib import contextmanager -@@ -428,6 +430,82 @@ def unquote_directive_value(value, quote_char): - return unescaped_value - - -+_SENTINEL = object() -+ -+ -+class DirectiveSetter(object): -+ """Safe directive setter -+ -+ with DirectiveSetter('/path/to/conf') as ds: -+ ds.set(key, value) -+ """ -+ def __init__(self, filename, quotes=True, separator=' '): -+ self.filename = os.path.abspath(filename) -+ self.quotes = quotes -+ self.separator = separator -+ self.lines = None -+ self.stat = None -+ -+ def __enter__(self): -+ with io.open(self.filename) as f: -+ self.stat = os.fstat(f.fileno()) -+ self.lines = list(f) -+ return self -+ -+ def __exit__(self, exc_type, exc_val, exc_tb): -+ if exc_type is not None: -+ # something went wrong, reset -+ self.lines = None -+ self.stat = None -+ return -+ -+ directory, prefix = os.path.split(self.filename) -+ # use tempfile in same directory to have atomic rename -+ fd, name = tempfile.mkstemp(prefix=prefix, dir=directory, text=True) -+ with io.open(fd, mode='w', closefd=True) as f: -+ for line in self.lines: -+ if not isinstance(line, six.text_type): -+ line = line.decode('utf-8') -+ f.write(line) -+ self.lines = None -+ os.fchmod(f.fileno(), stat.S_IMODE(self.stat.st_mode)) -+ os.fchown(f.fileno(), self.stat.st_uid, self.stat.st_gid) -+ self.stat = None -+ # flush and sync tempfile inode -+ f.flush() -+ os.fsync(f.fileno()) -+ -+ # rename file and sync directory inode -+ os.rename(name, self.filename) -+ dirfd = os.open(directory, os.O_RDONLY | os.O_DIRECTORY) -+ try: -+ os.fsync(dirfd) -+ finally: -+ os.close(dirfd) -+ -+ def set(self, directive, value, quotes=_SENTINEL, separator=_SENTINEL): -+ """Set a single directive -+ """ -+ if quotes is _SENTINEL: -+ quotes = self.quotes -+ if separator is _SENTINEL: -+ separator = self.separator -+ # materialize lines -+ # set_directive_lines() modify item, shrink or enlage line count -+ self.lines = list(set_directive_lines( -+ quotes, separator, directive, value, self.lines -+ )) -+ -+ def setitems(self, items): -+ """Set multiple directives from a dict or list with key/value pairs -+ """ -+ if isinstance(items, dict): -+ # dict-like, use sorted for stable order -+ items = sorted(items.items()) -+ for k, v in items: -+ self.set(k, v) -+ -+ - def set_directive(filename, directive, value, quotes=True, separator=' '): - """Set a name/value pair directive in a configuration file. - -@@ -447,8 +525,10 @@ def set_directive(filename, directive, value, quotes=True, separator=' '): - st = os.stat(filename) - with open(filename, 'r') as f: - lines = list(f) # read the whole file -- new_lines = set_directive_lines( -- quotes, separator, directive, value, lines) -+ # materialize new list -+ new_lines = list(set_directive_lines( -+ quotes, separator, directive, value, lines -+ )) - with open(filename, 'w') as f: - # don't construct the whole string; write line-wise - for line in new_lines: -@@ -472,8 +552,9 @@ def set_directive_lines(quotes, separator, k, v, lines): - new_line = ''.join([k, separator, v_quoted, '\n']) - - found = False -+ matcher = re.compile(r'\s*{}'.format(re.escape(k + separator))) - for line in lines: -- if re.match(r'\s*{}'.format(re.escape(k + separator)), line): -+ if matcher.match(line): - found = True - if v is not None: - yield new_line -diff --git a/ipatests/test_ipaserver/test_install/test_installutils.py b/ipatests/test_ipaserver/test_install/test_installutils.py -index cc8fd3cf3f82c2d9af48287f506a566ffbfc39f6..3c992c9ab06ddc3af557329de81debe704b0fb16 100644 ---- a/ipatests/test_ipaserver/test_install/test_installutils.py -+++ b/ipatests/test_ipaserver/test_install/test_installutils.py -@@ -3,8 +3,11 @@ - # - - import os -+import shutil - import tempfile - -+import pytest -+ - from ipaserver.install import installutils - - EXAMPLE_CONFIG = [ -@@ -13,6 +16,17 @@ EXAMPLE_CONFIG = [ - ] - - -+@pytest.fixture -+def tempdir(request): -+ tempdir = tempfile.mkdtemp() -+ -+ def fin(): -+ shutil.rmtree(tempdir) -+ -+ request.addfinalizer(fin) -+ return tempdir -+ -+ - class test_set_directive_lines(object): - def test_remove_directive(self): - lines = installutils.set_directive_lines( -@@ -55,3 +69,56 @@ class test_set_directive(object): - - finally: - os.remove(filename) -+ -+ -+def test_directivesetter(tempdir): -+ filename = os.path.join(tempdir, 'example.conf') -+ with open(filename, 'w') as f: -+ for line in EXAMPLE_CONFIG: -+ f.write(line) -+ -+ ds = installutils.DirectiveSetter(filename) -+ assert ds.lines is None -+ with ds: -+ assert ds.lines == EXAMPLE_CONFIG -+ ds.set('foo', '3') # quoted, space separated, doesn't change 'foo=' -+ ds.set('foobar', None, separator='=') # remove -+ ds.set('baz', '4', False, '=') # add -+ ds.setitems([ -+ ('list1', 'value1'), -+ ('list2', 'value2'), -+ ]) -+ ds.setitems({ -+ 'dict1': 'value1', -+ 'dict2': 'value2', -+ }) -+ -+ with open(filename, 'r') as f: -+ lines = list(f) -+ -+ assert lines == [ -+ 'foo=1\n', -+ 'foo "3"\n', -+ 'baz=4\n', -+ 'list1 "value1"\n', -+ 'list2 "value2"\n', -+ 'dict1 "value1"\n', -+ 'dict2 "value2"\n', -+ ] -+ -+ with installutils.DirectiveSetter(filename, True, '=') as ds: -+ ds.set('foo', '4') # doesn't change 'foo ' -+ -+ with open(filename, 'r') as f: -+ lines = list(f) -+ -+ assert lines == [ -+ 'foo="4"\n', -+ 'foo "3"\n', -+ 'baz=4\n', -+ 'list1 "value1"\n', -+ 'list2 "value2"\n', -+ 'dict1 "value1"\n', -+ 'dict2 "value2"\n', -+ -+ ] --- -2.13.6 - diff --git a/SOURCES/0026-Catch-ACIError-instead-of-invalid-credentials.patch b/SOURCES/0026-Catch-ACIError-instead-of-invalid-credentials.patch new file mode 100644 index 0000000..9521355 --- /dev/null +++ b/SOURCES/0026-Catch-ACIError-instead-of-invalid-credentials.patch @@ -0,0 +1,36 @@ +From a24178a743e7a90ca80702207345a398bf8074ad Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Fri, 29 Jun 2018 11:08:45 +0200 +Subject: [PATCH] Catch ACIError instead of invalid credentials + +ipaldap's LDAPClient client turns INVALID_CREDENTIAL error into +ACIError. Catch the ACIError and wait until the user has been +replicated. + +Apparently no manual or automated test ran into the timeout during +testing. + +Fixes: Fixes: https://pagure.io/freeipa/issue/7593 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> +--- + ipaserver/install/dogtaginstance.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py +index 5b2c30f8a1b7e932ce1cca3ca38f5962a3d54266..437029315cb6774ce9057baafda27cdb68454b49 100644 +--- a/ipaserver/install/dogtaginstance.py ++++ b/ipaserver/install/dogtaginstance.py +@@ -471,7 +471,8 @@ class DogtagInstance(service.Service): + time.sleep(1) + try: + master_conn.simple_bind(self.admin_dn, self.admin_password) +- except ldap.INVALID_CREDENTIALS: ++ except errors.ACIError: ++ # user not replicated yet + pass + else: + logger.debug("Successfully logged in as %s", self.admin_dn) +-- +2.17.1 + diff --git a/SOURCES/0027-Auto-retry-failed-certmonger-requests.patch b/SOURCES/0027-Auto-retry-failed-certmonger-requests.patch new file mode 100644 index 0000000..54e1655 --- /dev/null +++ b/SOURCES/0027-Auto-retry-failed-certmonger-requests.patch @@ -0,0 +1,195 @@ +From 3e8427f3aa392f961923f5c9d509bab64ce3c9ab Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Sun, 8 Jul 2018 11:53:58 +0200 +Subject: [PATCH] Auto-retry failed certmonger requests + +During parallel replica installation, a request sometimes fails with +CA_REJECTED or CA_UNREACHABLE. The error occur when the master is +either busy or some information haven't been replicated yet. Even +a stuck request can be recovered, e.g. when permission and group +information have been replicated. + +A new function request_and_retry_cert() automatically resubmits failing +requests until it times out. + +Fixes: https://pagure.io/freeipa/issue/7623 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Stanislav Laznicka <slaznick@redhat.com> +--- + ipalib/install/certmonger.py | 64 ++++++++++++++++++++++++------- + ipaserver/install/cainstance.py | 4 +- + ipaserver/install/certs.py | 19 ++++++--- + ipaserver/install/dsinstance.py | 4 +- + ipaserver/install/httpinstance.py | 5 ++- + ipaserver/install/krbinstance.py | 4 +- + 6 files changed, 76 insertions(+), 24 deletions(-) + +diff --git a/ipalib/install/certmonger.py b/ipalib/install/certmonger.py +index c07242412affa29eca3312fd27985f65869d3f7a..3e1862192eb0d9245797ebbe8abf2ff69d7e7767 100644 +--- a/ipalib/install/certmonger.py ++++ b/ipalib/install/certmonger.py +@@ -305,20 +305,56 @@ def add_subject(request_id, subject): + def request_and_wait_for_cert( + certpath, subject, principal, nickname=None, passwd_fname=None, + dns=None, ca='IPA', profile=None, +- pre_command=None, post_command=None, storage='NSSDB', perms=None): +- """ +- Execute certmonger to request a server certificate. +- +- The method also waits for the certificate to be available. +- """ +- reqId = request_cert(certpath, subject, principal, nickname, +- passwd_fname, dns, ca, profile, +- pre_command, post_command, storage, perms) +- state = wait_for_request(reqId, api.env.startup_timeout) +- ca_error = get_request_value(reqId, 'ca-error') +- if state != 'MONITORING' or ca_error: +- raise RuntimeError("Certificate issuance failed ({})".format(state)) +- return reqId ++ pre_command=None, post_command=None, storage='NSSDB', perms=None, ++ resubmit_timeout=0): ++ """Request certificate, wait and possibly resubmit failing requests ++ ++ Submit a cert request to certmonger and wait until the request has ++ finished. ++ ++ With timeout, a failed request is resubmitted. During parallel replica ++ installation, a request sometimes fails with CA_REJECTED or ++ CA_UNREACHABLE. The error occurs when the master is either busy or some ++ information haven't been replicated yet. Even a stuck request can be ++ recovered, e.g. when permission and group information have been ++ replicated. ++ """ ++ req_id = request_cert( ++ certpath, subject, principal, nickname, passwd_fname, dns, ca, ++ profile, pre_command, post_command, storage, perms ++ ) ++ ++ deadline = time.time() + resubmit_timeout ++ while True: # until success, timeout, or error ++ state = wait_for_request(req_id, api.env.replication_wait_timeout) ++ ca_error = get_request_value(req_id, 'ca-error') ++ if state == 'MONITORING' and ca_error is None: ++ # we got a winner, exiting ++ logger.debug("Cert request %s was successful", req_id) ++ return req_id ++ ++ logger.debug( ++ "Cert request %s failed: %s (%s)", req_id, state, ca_error ++ ) ++ if state not in {'CA_REJECTED', 'CA_UNREACHABLE'}: ++ # probably unrecoverable error ++ logger.debug("Giving up on cert request %s", req_id) ++ break ++ elif not resubmit_timeout: ++ # no resubmit ++ break ++ elif time.time() > deadline: ++ logger.debug("Request %s reached resubmit dead line", req_id) ++ break ++ else: ++ # sleep and resubmit ++ logger.debug("Sleep and resubmit cert request %s", req_id) ++ time.sleep(10) ++ resubmit_request(req_id) ++ ++ raise RuntimeError( ++ "Certificate issuance failed ({}: {})".format(state, ca_error) ++ ) + + + def request_cert( +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index 8193f3da854b3a20d175de523fbc453f5c5104d8..6dbf69b3e5833f220a4d7d640b66a8fcf824f445 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -917,7 +917,9 @@ class CAInstance(DogtagInstance): + profile='caServerCert', + pre_command='renew_ra_cert_pre', + post_command='renew_ra_cert', +- storage="FILE") ++ storage="FILE", ++ resubmit_timeout=api.env.replication_wait_timeout ++ ) + self.__set_ra_cert_perms() + + self.requestId = str(reqId) +diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py +index 3f843399f4f964223f52242d610e842a5dc473e8..30b2aa0d3e7b2cafbcc17ad3d04764a342ae8002 100644 +--- a/ipaserver/install/certs.py ++++ b/ipaserver/install/certs.py +@@ -600,12 +600,19 @@ class CertDB(object): + def export_pem_cert(self, nickname, location): + return self.nssdb.export_pem_cert(nickname, location) + +- def request_service_cert(self, nickname, principal, host): +- certmonger.request_and_wait_for_cert(certpath=self.secdir, +- nickname=nickname, +- principal=principal, +- subject=host, +- passwd_fname=self.passwd_fname) ++ def request_service_cert(self, nickname, principal, host, ++ resubmit_timeout=None): ++ if resubmit_timeout is None: ++ resubmit_timeout = api.env.replication_wait_timeout ++ return certmonger.request_and_wait_for_cert( ++ certpath=self.secdir, ++ storage='NSSDB', ++ nickname=nickname, ++ principal=principal, ++ subject=host, ++ passwd_fname=self.passwd_fname, ++ resubmit_timeout=resubmit_timeout ++ ) + + def is_ipa_issued_cert(self, api, nickname): + """ +diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py +index eefbde3356e1077d490d09c4ea47d961ce3ce8e6..ac95f8c746477da375de518526dea0d02d51d984 100644 +--- a/ipaserver/install/dsinstance.py ++++ b/ipaserver/install/dsinstance.py +@@ -851,7 +851,9 @@ class DsInstance(service.Service): + ca='IPA', + profile=dogtag.DEFAULT_PROFILE, + dns=[self.fqdn], +- post_command=cmd) ++ post_command=cmd, ++ resubmit_timeout=api.env.replication_wait_timeout ++ ) + finally: + if prev_helper is not None: + certmonger.modify_ca_helper('IPA', prev_helper) +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index 0b7023c2f1b0feb996e0dd0adbefbd49c51da757..3f83248dd89118aeecfbf458c5079dde8b2cb93d 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -447,7 +447,10 @@ class HTTPInstance(service.Service): + ca='IPA', + profile=dogtag.DEFAULT_PROFILE, + dns=[self.fqdn], +- post_command='restart_httpd') ++ post_command='restart_httpd', ++ storage='NSSDB', ++ resubmit_timeout=api.env.replication_wait_timeout ++ ) + finally: + if prev_helper is not None: + certmonger.modify_ca_helper('IPA', prev_helper) +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index 33d66fb94b0a1f7571b22120e5159a0e0ad2e675..09cafb7b84623594fe88083f5b914cee0f050409 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -445,7 +445,9 @@ class KrbInstance(service.Service): + storage='FILE', + profile=KDC_PROFILE, + post_command='renew_kdc_cert', +- perms=(0o644, 0o600)) ++ perms=(0o644, 0o600), ++ resubmit_timeout=api.env.replication_wait_timeout ++ ) + except dbus.DBusException as e: + # if the certificate is already tracked, ignore the error + name = e.get_dbus_name() +-- +2.17.1 + diff --git a/SOURCES/0027-Old-pylint-doesn-t-support-bad-python3-option.patch b/SOURCES/0027-Old-pylint-doesn-t-support-bad-python3-option.patch deleted file mode 100644 index 820061b..0000000 --- a/SOURCES/0027-Old-pylint-doesn-t-support-bad-python3-option.patch +++ /dev/null @@ -1,27 +0,0 @@ -From cf61603340f05a78aff51bf7d2b17de559900636 Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Tue, 12 Dec 2017 15:03:01 +0100 -Subject: [PATCH] Old pylint doesn't support bad python3 option - -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> ---- - ipaserver/install/installutils.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py -index 08e098f8656c8fe61a87fb046c01e1487c25da7f..40ae9e19f42170a0552a07c9ec73f60b34bcb84d 100644 ---- a/ipaserver/install/installutils.py -+++ b/ipaserver/install/installutils.py -@@ -32,7 +32,7 @@ import fileinput - import sys - import tempfile - import shutil --import stat # pylint: disable=bad-python3-import -+import stat - import traceback - import textwrap - from contextlib import contextmanager --- -2.13.6 - diff --git a/SOURCES/0028-Wait-for-client-certificates.patch b/SOURCES/0028-Wait-for-client-certificates.patch new file mode 100644 index 0000000..e2f204a --- /dev/null +++ b/SOURCES/0028-Wait-for-client-certificates.patch @@ -0,0 +1,66 @@ +From fb346fab2495a9343ed68131c0ebf071e3e9654f Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Mon, 9 Jul 2018 13:53:44 +0200 +Subject: [PATCH] Wait for client certificates + +ipa-client-install --request-cert now waits until certmonger has +provided a host certificate. In case of an error, ipa-client-install no +longer pretents to success but fails with an error code. + +The --request-cert option also ensures that certmonger is enabled and +running. + +See: Fixes: https://pagure.io/freeipa/issue/7623 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Stanislav Laznicka <slaznick@redhat.com> +--- + ipaclient/install/client.py | 25 ++++++++++++++++++------- + 1 file changed, 18 insertions(+), 7 deletions(-) + +diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py +index 5173d90bfeb61acab6032f2972dcc4a0d1344094..0fbe31b762561b3e2ee2f35a666a93de8857bced 100644 +--- a/ipaclient/install/client.py ++++ b/ipaclient/install/client.py +@@ -775,6 +775,7 @@ def configure_certmonger( + cmonger = services.knownservices.certmonger + try: + cmonger.enable() ++ cmonger.start() + except Exception as e: + logger.error( + "Failed to configure automatic startup of the %s daemon: %s", +@@ -786,14 +787,24 @@ def configure_certmonger( + subject = str(DN(('CN', hostname), subject_base)) + passwd_fname = os.path.join(paths.IPA_NSSDB_DIR, 'pwdfile.txt') + try: +- certmonger.request_cert( ++ certmonger.request_and_wait_for_cert( + certpath=paths.IPA_NSSDB_DIR, +- nickname='Local IPA host', subject=subject, dns=[hostname], +- principal=principal, passwd_fname=passwd_fname) +- except Exception as ex: +- logger.error( +- "%s request for host certificate failed: %s", +- cmonger.service_name, ex) ++ storage='NSSDB', ++ nickname='Local IPA host', ++ subject=subject, ++ dns=[hostname], ++ principal=principal, ++ passwd_fname=passwd_fname, ++ resubmit_timeout=120, ++ ) ++ except Exception as e: ++ logger.exception("certmonger request failed") ++ raise ScriptError( ++ "{} request for host certificate failed: {}".format( ++ cmonger.service_name, e ++ ), ++ rval=CLIENT_INSTALL_ERROR ++ ) + + + def configure_sssd_conf( +-- +2.17.1 + diff --git a/SOURCES/0028-WebUI-make-keytab-tables-on-service-and-host-pages-w.patch b/SOURCES/0028-WebUI-make-keytab-tables-on-service-and-host-pages-w.patch deleted file mode 100644 index 45cf8f9..0000000 --- a/SOURCES/0028-WebUI-make-keytab-tables-on-service-and-host-pages-w.patch +++ /dev/null @@ -1,158 +0,0 @@ -From 8c4561a1ea598f645c33a8ed2f0c841326b2373d Mon Sep 17 00:00:00 2001 -From: Pavel Vomacka <pvomacka@redhat.com> -Date: Thu, 14 Dec 2017 15:14:03 +0100 -Subject: [PATCH] WebUI: make keytab tables on service and host pages writable - -There is no object class before adding the first item into tables, -therefore there are no ACI and WebUI is not able to figure out -whether table is writable or not. Adding flag 'w_if_no_aci' -tells "make it writable even if we have not ACIs and try to do -the API call. - -https://pagure.io/freeipa/issue/7111 - -Reviewed-By: Felipe Volpone <fbarreto@redhat.com> ---- - install/ui/src/freeipa/host.js | 8 ++++++++ - install/ui/src/freeipa/service.js | 8 ++++++++ - 2 files changed, 16 insertions(+) - -diff --git a/install/ui/src/freeipa/host.js b/install/ui/src/freeipa/host.js -index ac434d8455384ded2cbebc28445deaecbafc46b5..acecff1e5b99c541b216a3e6789efb77eb262fef 100644 ---- a/install/ui/src/freeipa/host.js -+++ b/install/ui/src/freeipa/host.js -@@ -198,6 +198,7 @@ return { - $type: 'association_table', - id: 'host_ipaallowedtoperform_read_keys_user', - name: 'ipaallowedtoperform_read_keys_user', -+ flags: ['w_if_no_aci'], - add_method: 'allow_retrieve_keytab', - remove_method: 'disallow_retrieve_keytab', - add_title: '@i18n:keytab.add_retrive', -@@ -214,6 +215,7 @@ return { - $type: 'association_table', - id: 'host_ipaallowedtoperform_read_keys_group', - name: 'ipaallowedtoperform_read_keys_group', -+ flags: ['w_if_no_aci'], - add_method: 'allow_retrieve_keytab', - remove_method: 'disallow_retrieve_keytab', - add_title: '@i18n:keytab.add_retrive', -@@ -230,6 +232,7 @@ return { - $type: 'association_table', - id: 'service_ipaallowedtoperform_read_keys_host', - name: 'ipaallowedtoperform_read_keys_host', -+ flags: ['w_if_no_aci'], - add_method: 'allow_retrieve_keytab', - remove_method: 'disallow_retrieve_keytab', - add_title: '@i18n:keytab.add_retrive', -@@ -246,6 +249,7 @@ return { - $type: 'association_table', - id: 'service_ipaallowedtoperform_read_keys_hostgroup', - name: 'ipaallowedtoperform_read_keys_hostgroup', -+ flags: ['w_if_no_aci'], - add_method: 'allow_retrieve_keytab', - remove_method: 'disallow_retrieve_keytab', - add_title: '@i18n:keytab.add_retrive', -@@ -269,6 +273,7 @@ return { - $type: 'association_table', - id: 'host_ipaallowedtoperform_write_keys_user', - name: 'ipaallowedtoperform_write_keys_user', -+ flags: ['w_if_no_aci'], - add_method: 'allow_create_keytab', - remove_method: 'disallow_create_keytab', - add_title: '@i18n:keytab.add_create', -@@ -285,6 +290,7 @@ return { - $type: 'association_table', - id: 'host_ipaallowedtoperform_write_keys_group', - name: 'ipaallowedtoperform_write_keys_group', -+ flags: ['w_if_no_aci'], - add_method: 'allow_create_keytab', - remove_method: 'disallow_create_keytab', - add_title: '@i18n:keytab.add_create', -@@ -301,6 +307,7 @@ return { - $type: 'association_table', - id: 'service_ipaallowedtoperform_write_keys_host', - name: 'ipaallowedtoperform_write_keys_host', -+ flags: ['w_if_no_aci'], - add_method: 'allow_create_keytab', - remove_method: 'disallow_create_keytab', - add_title: '@i18n:keytab.add_create', -@@ -317,6 +324,7 @@ return { - $type: 'association_table', - id: 'service_ipaallowedtoperform_write_keys_hostgroup', - name: 'ipaallowedtoperform_write_keys_hostgroup', -+ flags: ['w_if_no_aci'], - add_method: 'allow_create_keytab', - remove_method: 'disallow_create_keytab', - add_title: '@i18n:keytab.add_create', -diff --git a/install/ui/src/freeipa/service.js b/install/ui/src/freeipa/service.js -index 752ff98e3e5290442ce5f011a4de53ccc0db8f8f..c798d2999fc909fdbc26b016e4752a3edf1f702e 100644 ---- a/install/ui/src/freeipa/service.js -+++ b/install/ui/src/freeipa/service.js -@@ -201,6 +201,7 @@ return { - $type: 'association_table', - id: 'service_ipaallowedtoperform_read_keys_user', - name: 'ipaallowedtoperform_read_keys_user', -+ flags: ['w_if_no_aci'], - add_method: 'allow_retrieve_keytab', - remove_method: 'disallow_retrieve_keytab', - add_title: '@i18n:keytab.add_retrive', -@@ -217,6 +218,7 @@ return { - $type: 'association_table', - id: 'service_ipaallowedtoperform_read_keys_group', - name: 'ipaallowedtoperform_read_keys_group', -+ flags: ['w_if_no_aci'], - add_method: 'allow_retrieve_keytab', - remove_method: 'disallow_retrieve_keytab', - add_title: '@i18n:keytab.add_retrive', -@@ -233,6 +235,7 @@ return { - $type: 'association_table', - id: 'service_ipaallowedtoperform_read_keys_host', - name: 'ipaallowedtoperform_read_keys_host', -+ flags: ['w_if_no_aci'], - add_method: 'allow_retrieve_keytab', - remove_method: 'disallow_retrieve_keytab', - add_title: '@i18n:keytab.add_retrive', -@@ -249,6 +252,7 @@ return { - $type: 'association_table', - id: 'service_ipaallowedtoperform_read_keys_hostgroup', - name: 'ipaallowedtoperform_read_keys_hostgroup', -+ flags: ['w_if_no_aci'], - add_method: 'allow_retrieve_keytab', - remove_method: 'disallow_retrieve_keytab', - add_title: '@i18n:keytab.add_retrive', -@@ -272,6 +276,7 @@ return { - $type: 'association_table', - id: 'service_ipaallowedtoperform_write_keys_user', - name: 'ipaallowedtoperform_write_keys_user', -+ flags: ['w_if_no_aci'], - add_method: 'allow_create_keytab', - remove_method: 'disallow_create_keytab', - add_title: '@i18n:keytab.add_create', -@@ -288,6 +293,7 @@ return { - $type: 'association_table', - id: 'service_ipaallowedtoperform_write_keys_group', - name: 'ipaallowedtoperform_write_keys_group', -+ flags: ['w_if_no_aci'], - add_method: 'allow_create_keytab', - remove_method: 'disallow_create_keytab', - add_title: '@i18n:keytab.add_create', -@@ -304,6 +310,7 @@ return { - $type: 'association_table', - id: 'service_ipaallowedtoperform_write_keys_host', - name: 'ipaallowedtoperform_write_keys_host', -+ flags: ['w_if_no_aci'], - add_method: 'allow_create_keytab', - remove_method: 'disallow_create_keytab', - add_title: '@i18n:keytab.add_create', -@@ -320,6 +327,7 @@ return { - $type: 'association_table', - id: 'service_ipaallowedtoperform_write_keys_hostgroup', - name: 'ipaallowedtoperform_write_keys_hostgroup', -+ flags: ['w_if_no_aci'], - add_method: 'allow_create_keytab', - remove_method: 'disallow_create_keytab', - add_title: '@i18n:keytab.add_create', --- -2.13.6 - diff --git a/SOURCES/0029-Fix-KRA-replica-installation-from-CA-master.patch b/SOURCES/0029-Fix-KRA-replica-installation-from-CA-master.patch new file mode 100644 index 0000000..689560f --- /dev/null +++ b/SOURCES/0029-Fix-KRA-replica-installation-from-CA-master.patch @@ -0,0 +1,46 @@ +From 609ccb601843b97b25f2fde3c4981839822af503 Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Tue, 17 Jul 2018 08:53:39 +0200 +Subject: [PATCH] Fix KRA replica installation from CA master + +ipa-replica-install --kra-install can fail when the topology already has +a KRA, but replica is installed from a master with just CA. In that +case, Custodia may pick a machine that doesn't have the KRA auditing and +signing certs in its NSSDB. + +Example: + * master with CA + * replica1 with CA and KRA + * new replica gets installed from master + +The replica installer now always picks a KRA peer. + +The change fixes test scenario TestInstallWithCA1::()::test_replica2_ipa_dns_install + +Fixes: https://pagure.io/freeipa/issue/7518 +See: https://pagure.io/freeipa/issue/7008 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +--- + ipaserver/install/server/replicainstall.py | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 8826da232a90380084b0e4f3dca783125a5500da..e78a2b992fbd44b8ee3ccd8183ebd6e13dfd1749 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -1486,7 +1486,10 @@ def install(installer): + otpd.create_instance('OTPD', config.host_name, + ipautil.realm_to_suffix(config.realm_name)) + +- if ca_enabled: ++ if kra_enabled: ++ # A KRA peer always provides a CA, too. ++ mode = custodiainstance.CustodiaModes.KRA_PEER ++ elif ca_enabled: + mode = custodiainstance.CustodiaModes.CA_PEER + else: + mode = custodiainstance.CustodiaModes.MASTER_PEER +-- +2.17.1 + diff --git a/SOURCES/0029-Idviews-fix-objectclass-violation-on-idview-add.patch b/SOURCES/0029-Idviews-fix-objectclass-violation-on-idview-add.patch deleted file mode 100644 index 583ad41..0000000 --- a/SOURCES/0029-Idviews-fix-objectclass-violation-on-idview-add.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 6d4676c4e3403df547ef03a2e716d6254c3c512e Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud <flo@redhat.com> -Date: Fri, 5 Jan 2018 09:50:26 +0100 -Subject: [PATCH] Idviews: fix objectclass violation on idview-add - -When the option --domain-resolution-order is used with the command -ipa idview-add, the resulting LDAP object stores the value in -ipadomainresolutionorder attribute. -The issue is that the add command does not add the needed object -class (ipaNameResolutionData) because it is part of -possible_objectclasses but not of object_class. - -The fix makes sure to add the objectclass when the option ---domain-resolution-order is used, and adds a non-regression test. - -Note that idview-mod does not have any issue as it correctly handles -the addition of missing possible objectclasses. - -Fixes: -https://pagure.io/freeipa/issue/7350 - -Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> -Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> ---- - ipaserver/plugins/idviews.py | 15 +++++++++---- - ipatests/test_xmlrpc/test_idviews_plugin.py | 35 +++++++++++++++++++++++++++++ - 2 files changed, 46 insertions(+), 4 deletions(-) - -diff --git a/ipaserver/plugins/idviews.py b/ipaserver/plugins/idviews.py -index a55c20bbf2466d9cb3a317d49a8bba3c9379f572..2b06cc54e4b04aac004efbf02a446464b8c89777 100644 ---- a/ipaserver/plugins/idviews.py -+++ b/ipaserver/plugins/idviews.py -@@ -22,10 +22,11 @@ import re - import six - - from .baseldap import (LDAPQuery, LDAPObject, LDAPCreate, -- LDAPDelete, LDAPUpdate, LDAPSearch, -- LDAPAddAttributeViaOption, -- LDAPRemoveAttributeViaOption, -- LDAPRetrieve, global_output_params) -+ LDAPDelete, LDAPUpdate, LDAPSearch, -+ LDAPAddAttributeViaOption, -+ LDAPRemoveAttributeViaOption, -+ LDAPRetrieve, global_output_params, -+ add_missing_object_class) - from .hostgroup import get_complete_hostgroup_member_list - from .service import validate_certificate - from ipalib import api, Str, Int, Bytes, Flag, _, ngettext, errors, output -@@ -169,6 +170,12 @@ class idview_add(LDAPCreate): - def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): - self.api.Object.config.validate_domain_resolution_order(entry_attrs) - -+ # The objectclass ipaNameResolutionData may not be present on -+ # the id view. We need to add it if we define a new -+ # value for ipaDomainResolutionOrder -+ if 'ipadomainresolutionorder' in entry_attrs: -+ add_missing_object_class(ldap, u'ipanameresolutiondata', dn, -+ entry_attrs, update=False) - return dn - - -diff --git a/ipatests/test_xmlrpc/test_idviews_plugin.py b/ipatests/test_xmlrpc/test_idviews_plugin.py -index 35d31b37d8fb87384d9ae550182e353c1d6383cc..3d4cce5ea0505ef8b0cd8253fd74b037890ce18b 100644 ---- a/ipatests/test_xmlrpc/test_idviews_plugin.py -+++ b/ipatests/test_xmlrpc/test_idviews_plugin.py -@@ -1704,4 +1704,39 @@ class test_idviews(Declarative): - ), - ), - -+ # Delete the ID View -+ -+ dict( -+ desc='Delete ID View "%s"' % idview1, -+ command=('idview_del', [idview1], {}), -+ expected=dict( -+ result=dict(failed=[]), -+ summary=u'Deleted ID View "%s"' % idview1, -+ value=[idview1], -+ ), -+ ), -+ -+ # Test the creation of ID view with domain resolution order -+ # Non-regression test for issue 7350 -+ -+ dict( -+ desc='Create ID View "%s"' % idview1, -+ command=( -+ 'idview_add', -+ [idview1], -+ dict(ipadomainresolutionorder=u'%s' % api.env.domain) -+ ), -+ expected=dict( -+ value=idview1, -+ summary=u'Added ID View "%s"' % idview1, -+ result=dict( -+ dn=get_idview_dn(idview1), -+ objectclass=objectclasses.idview + -+ [u'ipanameresolutiondata'], -+ cn=[idview1], -+ ipadomainresolutionorder=[api.env.domain] -+ ) -+ ), -+ ), -+ - ] --- -2.13.6 - diff --git a/SOURCES/0030-Fixing-the-cert-request-comparing-whole-email-addres.patch b/SOURCES/0030-Fixing-the-cert-request-comparing-whole-email-addres.patch deleted file mode 100644 index 8b381a7..0000000 --- a/SOURCES/0030-Fixing-the-cert-request-comparing-whole-email-addres.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 7d28e12612ec08e80cf1351ea523bf4a9adfc255 Mon Sep 17 00:00:00 2001 -From: Felipe Volpone <felipevolpone@gmail.com> -Date: Thu, 11 May 2017 10:20:02 -0300 -Subject: [PATCH] Fixing the cert-request comparing whole email address - case-sensitively. - -Now, the cert-request command compares the domain part of the -email case-insensitively. - -https://pagure.io/freeipa/issue/5919 - -Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> -Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> ---- - ipaserver/plugins/cert.py | 27 ++++++++++++++++++++++++--- - ipatests/test_xmlrpc/test_cert_plugin.py | 23 +++++++++++++++++++++++ - 2 files changed, 47 insertions(+), 3 deletions(-) - -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index c1d389217265f44e646ac27d9adc8d5524c74ce7..501fc9015468c864215cfb604de37cdf6d805e52 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -710,7 +710,9 @@ class cert_request(Create, BaseCertMethod, VirtualCommand): - # fail if any email addr from DN does not appear in ldap entry - email_addrs = csr_obj.subject.get_attributes_for_oid( - cryptography.x509.oid.NameOID.EMAIL_ADDRESS) -- if len(set(email_addrs) - set(principal_obj.get('mail', []))) > 0: -+ csr_emails = [attr.value for attr in email_addrs] -+ if not _emails_are_valid(csr_emails, -+ principal_obj.get('mail', [])): - raise errors.ValidationError( - name='csr', - error=_( -@@ -796,8 +798,8 @@ class cert_request(Create, BaseCertMethod, VirtualCommand): - "match requested principal") % gn.name) - elif isinstance(gn, cryptography.x509.general_name.RFC822Name): - if principal_type == USER: -- if principal_obj and gn.value not in principal_obj.get( -- 'mail', []): -+ if not _emails_are_valid([gn.value], -+ principal_obj.get('mail', [])): - raise errors.ValidationError( - name='csr', - error=_( -@@ -865,6 +867,25 @@ class cert_request(Create, BaseCertMethod, VirtualCommand): - ) - - -+def _emails_are_valid(csr_emails, principal_emails): -+ """ -+ Checks if any email address from certificate request does not -+ appear in ldap entry, comparing the domain part case-insensitively. -+ """ -+ -+ def lower_domain(email): -+ email_splitted = email.split('@', 1) -+ if len(email_splitted) > 1: -+ email_splitted[1] = email_splitted[1].lower() -+ -+ return '@'.join(email_splitted) -+ -+ principal_emails_lower = set(map(lower_domain, principal_emails)) -+ csr_emails_lower = set(map(lower_domain, csr_emails)) -+ -+ return csr_emails_lower.issubset(principal_emails_lower) -+ -+ - def principal_to_principal_type(principal): - if principal.is_user: - return USER -diff --git a/ipatests/test_xmlrpc/test_cert_plugin.py b/ipatests/test_xmlrpc/test_cert_plugin.py -index 0b8277b8a6d67777db2eb328116ed0a761914663..dc9e8cba7b40e7b655ea7c0e3bed7706ac78ed1a 100644 ---- a/ipatests/test_xmlrpc/test_cert_plugin.py -+++ b/ipatests/test_xmlrpc/test_cert_plugin.py -@@ -253,6 +253,29 @@ class test_cert(BaseCert): - res = api.Command['service_find'](self.service_princ) - assert res['count'] == 0 - -+ def test_00011_emails_are_valid(self): -+ """ -+ Verify the different scenarios when checking if any email addr -+ from DN or SAN extension does not appear in ldap entry. -+ """ -+ -+ from ipaserver.plugins.cert import _emails_are_valid -+ email_addrs = [u'any@EmAiL.CoM'] -+ result = _emails_are_valid(email_addrs, [u'any@email.com']) -+ assert True == result, result -+ -+ email_addrs = [u'any@EmAiL.CoM'] -+ result = _emails_are_valid(email_addrs, [u'any@email.com', -+ u'another@email.com']) -+ assert True == result, result -+ -+ result = _emails_are_valid([], [u'any@email.com']) -+ assert True == result, result -+ -+ email_addrs = [u'invalidEmailAddress'] -+ result = _emails_are_valid(email_addrs, []) -+ assert False == result, result -+ - - @pytest.mark.tier1 - class test_cert_find(XMLRPC_test): --- -2.13.6 - diff --git a/SOURCES/0030-ipaserver-plugins-cert.py-Added-reason-to-raise-of-e.patch b/SOURCES/0030-ipaserver-plugins-cert.py-Added-reason-to-raise-of-e.patch new file mode 100644 index 0000000..e744031 --- /dev/null +++ b/SOURCES/0030-ipaserver-plugins-cert.py-Added-reason-to-raise-of-e.patch @@ -0,0 +1,33 @@ +From f49068ecd3484b4898517854b9886bd3b0691691 Mon Sep 17 00:00:00 2001 +From: Thomas Woerner <twoerner@redhat.com> +Date: Fri, 27 Jul 2018 12:15:17 +0200 +Subject: [PATCH] ipaserver/plugins/cert.py: Added reason to raise of + errors.NotFound + +In the case that enabledService is not found ipaConfigString kdc entry, a +NotFound error was raised without setting the reason. This resulted in a +traceback. + +Fixes: https://pagure.io/freeipa/issue/7652 +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +--- + ipaserver/plugins/cert.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py +index db624357af189753980927655215b17c06291a15..0663272c9b4fd73225f63fe52d8d31157d5cc690 100644 +--- a/ipaserver/plugins/cert.py ++++ b/ipaserver/plugins/cert.py +@@ -301,7 +301,8 @@ def ca_kdc_check(api_instance, hostname): + ipaconfigstring = {val.lower() for val in kdc_entry['ipaConfigString']} + + if 'enabledservice' not in ipaconfigstring: +- raise errors.NotFound() ++ raise errors.NotFound( ++ reason=_("enabledService not in ipaConfigString kdc entry")) + + except errors.NotFound: + raise errors.ACIError( +-- +2.17.1 + diff --git a/SOURCES/0031-Add-force-join-into-ipa-replica-install-manpage.patch b/SOURCES/0031-Add-force-join-into-ipa-replica-install-manpage.patch deleted file mode 100644 index 75c9b16..0000000 --- a/SOURCES/0031-Add-force-join-into-ipa-replica-install-manpage.patch +++ /dev/null @@ -1,29 +0,0 @@ -From c5b8c6256e65e5bb735bd89ab132c28c5a03dd64 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Tibor=20Dudl=C3=A1k?= <tdudlak@redhat.com> -Date: Tue, 13 Jun 2017 12:27:01 +0200 -Subject: [PATCH] Add --force-join into ipa-replica-install manpage - -Resolves: https://pagure.io/freeipa/issue/7011 -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> -Reviewed-By: Stanislav Laznicka <slaznick@redhat.com> ---- - install/tools/man/ipa-replica-install.1 | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1 -index 7d241324818dd3a5294da5e84b67a19d0d9a31b6..a1284135ac67de2b67b322aec3f6bbfb05f1a8ec 100644 ---- a/install/tools/man/ipa-replica-install.1 -+++ b/install/tools/man/ipa-replica-install.1 -@@ -62,6 +62,9 @@ The Kerberos realm of an existing IPA deployment. - .TP - \fB\-\-hostname\fR - The hostname of this machine (FQDN). If specified, the hostname will be set and the system configuration will be updated to persist over reboot. -+.TP -+\fB\-\-force\-join\fR -+Join the host even if it is already enrolled. - - .SS "DOMAIN LEVEL 0 OPTIONS" - .TP --- -2.13.6 - diff --git a/SOURCES/0031-ipa-commands-print-IPA-is-not-configured-when-ipa-is.patch b/SOURCES/0031-ipa-commands-print-IPA-is-not-configured-when-ipa-is.patch new file mode 100644 index 0000000..b2c1b19 --- /dev/null +++ b/SOURCES/0031-ipa-commands-print-IPA-is-not-configured-when-ipa-is.patch @@ -0,0 +1,135 @@ +From 040df002df8c58c84a94d2fb3dec717beb6e5f0a Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud <flo@redhat.com> +Date: Wed, 22 Aug 2018 18:29:07 +0200 +Subject: [PATCH] ipa commands: print 'IPA is not configured' when ipa is not + setup + +Some commands print tracebacks or unclear error message when +they are called on a machine where ipa packages are installed but +IPA is not configured. +Consistently report 'IPA is not configured on this system' in this +case. + +Related to https://pagure.io/freeipa/issue/6261 + +Reviewed-By: Christian Heimes <cheimes@redhat.com> +--- + install/tools/ipa-compat-manage | 2 ++ + install/tools/ipa-csreplica-manage | 4 +++- + ipaserver/advise/base.py | 2 ++ + ipaserver/install/ipa_pkinit_manage.py | 2 ++ + ipaserver/install/ipa_server_upgrade.py | 2 ++ + ipaserver/install/ipa_winsync_migrate.py | 2 +- + 6 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/install/tools/ipa-compat-manage b/install/tools/ipa-compat-manage +index 6dd259d2aad870e575093d6732157de743502ac2..ce61b702689448dcfbddbf0dad6c2adde861e6e9 100755 +--- a/install/tools/ipa-compat-manage ++++ b/install/tools/ipa-compat-manage +@@ -82,6 +82,8 @@ def main(): + retval = 0 + files = [paths.SCHEMA_COMPAT_ULDIF] + ++ installutils.check_server_configuration() ++ + options, args = parse_options() + + if len(args) != 1: +diff --git a/install/tools/ipa-csreplica-manage b/install/tools/ipa-csreplica-manage +index 87f034d1205938c4551f939b0e8c0da292e90bc1..c7b62b293d68c95912ab641294180eeb74a98573 100755 +--- a/install/tools/ipa-csreplica-manage ++++ b/install/tools/ipa-csreplica-manage +@@ -32,6 +32,7 @@ from ipaserver.install import (replication, installutils, bindinstance, + from ipalib import api, errors + from ipalib.util import has_managed_topology + from ipapython import ipautil, ipaldap, version ++from ipapython.admintool import ScriptError + from ipapython.dn import DN + + logger = logging.getLogger(os.path.basename(__file__)) +@@ -408,6 +409,7 @@ def exit_on_managed_topology(what, hint="topologysegment"): + + + def main(): ++ installutils.check_server_configuration() + options, args = parse_options() + + # Just initialize the environment. This is so the installer can have +@@ -496,7 +498,7 @@ try: + main() + except KeyboardInterrupt: + sys.exit(1) +-except SystemExit as e: ++except (SystemExit, ScriptError) as e: + sys.exit(e) + except Exception as e: + sys.exit("unexpected error: %s" % e) +diff --git a/ipaserver/advise/base.py b/ipaserver/advise/base.py +index 40f2e65dc8f74a833ef6fe107eabf96ac6a3c12b..07b1431e84c31cb7ba2ecc58a9d152e596dd8b00 100644 +--- a/ipaserver/advise/base.py ++++ b/ipaserver/advise/base.py +@@ -30,6 +30,7 @@ from ipalib.errors import ValidationError + from ipaplatform.paths import paths + from ipapython import admintool + from ipapython.ipa_log_manager import Filter ++from ipaserver.install import installutils + + + """ +@@ -418,6 +419,7 @@ class IpaAdvise(admintool.AdminTool): + + def validate_options(self): + super(IpaAdvise, self).validate_options(needs_root=False) ++ installutils.check_server_configuration() + + if len(self.args) > 1: + raise self.option_parser.error("You can only provide one " +diff --git a/ipaserver/install/ipa_pkinit_manage.py b/ipaserver/install/ipa_pkinit_manage.py +index c54bb14f58b9bfd19ae860270a1c1955b4de1732..4a79bba5d1b636827a7a031965b49cf7b34c6330 100644 +--- a/ipaserver/install/ipa_pkinit_manage.py ++++ b/ipaserver/install/ipa_pkinit_manage.py +@@ -9,6 +9,7 @@ import logging + from ipalib import api + from ipaplatform.paths import paths + from ipapython.admintool import AdminTool ++from ipaserver.install import installutils + from ipaserver.install.krbinstance import KrbInstance, is_pkinit_enabled + + logger = logging.getLogger(__name__) +@@ -21,6 +22,7 @@ class PKINITManage(AdminTool): + + def validate_options(self): + super(PKINITManage, self).validate_options(needs_root=True) ++ installutils.check_server_configuration() + + option_parser = self.option_parser + +diff --git a/ipaserver/install/ipa_server_upgrade.py b/ipaserver/install/ipa_server_upgrade.py +index 1e52bca9765671c0b63bf08b0ad47d40477037ee..7643b97f22fbf6c6861317a171c6e2da377365cd 100644 +--- a/ipaserver/install/ipa_server_upgrade.py ++++ b/ipaserver/install/ipa_server_upgrade.py +@@ -35,6 +35,8 @@ class ServerUpgrade(admintool.AdminTool): + def validate_options(self): + super(ServerUpgrade, self).validate_options(needs_root=True) + ++ installutils.check_server_configuration() ++ + if self.options.force: + self.options.skip_version_check = True + +diff --git a/ipaserver/install/ipa_winsync_migrate.py b/ipaserver/install/ipa_winsync_migrate.py +index 0399b9b7b683cd92692094b53208dcc0f40fd392..43330ad502e736816a1af8e8c2a444e1eae05baa 100644 +--- a/ipaserver/install/ipa_winsync_migrate.py ++++ b/ipaserver/install/ipa_winsync_migrate.py +@@ -350,7 +350,7 @@ class WinsyncMigrate(admintool.AdminTool): + # Check if the IPA server is configured before attempting to migrate + try: + installutils.check_server_configuration() +- except RuntimeError as e: ++ except admintool.ScriptError as e: + sys.exit(e) + + # Finalize API +-- +2.17.1 + diff --git a/SOURCES/0032-Changed-ownership-of-ldiffile-to-DS_USER.patch b/SOURCES/0032-Changed-ownership-of-ldiffile-to-DS_USER.patch deleted file mode 100644 index d2e1476..0000000 --- a/SOURCES/0032-Changed-ownership-of-ldiffile-to-DS_USER.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 780dc73f513cc312e87948b51e90ae885f29a8fb Mon Sep 17 00:00:00 2001 -From: Thorsten Scherf <tscherf@redhat.com> -Date: Thu, 1 Jun 2017 22:02:57 +0200 -Subject: [PATCH] Changed ownership of ldiffile to DS_USER - -Resolves: -https://pagure.io/freeipa/issue/7010 - -Reviewed-By: Martin Basti <mbasti@redhat.com> -Reviewed-By: Stanislav Laznicka <slaznick@redhat.com> ---- - ipaserver/install/ipa_restore.py | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index 923b1d6696d33c0bb07ca018b53dd3dabcc191aa..a3824df230857b02b47c12645fadee1200afdf66 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -540,6 +540,10 @@ class Restore(admintool.AdminTool): - ldif_parser = RemoveRUVParser(in_file, ldif_writer, self.log) - ldif_parser.parse() - -+ # Make sure the modified ldiffile is owned by DS_USER -+ pent = pwd.getpwnam(constants.DS_USER) -+ os.chown(ldiffile, pent.pw_uid, pent.pw_gid) -+ - if online: - conn = self.get_connection() - ent = conn.make_entry( --- -2.13.6 - diff --git a/SOURCES/0032-DS-replication-settings-fix-regression-with-3.3-mast.patch b/SOURCES/0032-DS-replication-settings-fix-regression-with-3.3-mast.patch new file mode 100644 index 0000000..3b21d3c --- /dev/null +++ b/SOURCES/0032-DS-replication-settings-fix-regression-with-3.3-mast.patch @@ -0,0 +1,57 @@ +From e561f8bb163e68766b61bca72619a54cc5e8bc2d Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud <flo@redhat.com> +Date: Tue, 21 Aug 2018 11:37:17 +0200 +Subject: [PATCH] DS replication settings: fix regression with <3.3 master + +Commit 811b0fdb4620938963f1a29d3fdd22257327562c introduced a regression +when configuring replication with a master < 3.3 +Even if 389-ds schema is extended with nsds5ReplicaReleaseTimeout, +nsds5ReplicaBackoffMax and nsDS5ReplicaBindDnGroupCheckInterval +attributes, it will return UNWILLING_TO_PERFORM when a mod +operation is performed on the cn=replica entry. + +This patch ignores the error and logs a debug msg. + +See: https://pagure.io/freeipa/issue/7617 +Reviewed-By: Christian Heimes <cheimes@redhat.com> +--- + ipaserver/install/replication.py | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py +index 78c4a43cc9b8d9a6740d26209f347f64b879743e..92a99cd9482f86d6820230479bf94c871669572e 100644 +--- a/ipaserver/install/replication.py ++++ b/ipaserver/install/replication.py +@@ -22,6 +22,7 @@ from __future__ import print_function, absolute_import + import logging + import itertools + ++import re + import six + import time + import datetime +@@ -600,7 +601,20 @@ class ReplicationManager(object): + r_conn.simple_bind(r_binddn, r_bindpw) + else: + r_conn.gssapi_bind() +- self._finalize_replica_settings(r_conn) ++ # If the remote server has 389-ds < 1.3, it does not ++ # support the attributes we are trying to set. ++ # Find which 389-ds is installed ++ rootdse = r_conn.get_entry(DN(''), ['vendorVersion']) ++ version = rootdse.single_value.get('vendorVersion') ++ mo = re.search(r'(\d+)\.(\d+)\.(\d+)[\.\d]*', version) ++ vendor_version = tuple(int(v) for v in mo.groups()) ++ if vendor_version >= (1, 3, 0): ++ # 389-ds understands the replication attributes, ++ # we can safely modify them ++ self._finalize_replica_settings(r_conn) ++ else: ++ logger.debug("replication attributes not supported " ++ "on remote master, skipping update.") + r_conn.close() + + def setup_chaining_backend(self, conn): +-- +2.17.1 + diff --git a/SOURCES/0033-Checks-if-Dir-Server-is-installed-and-running-before.patch b/SOURCES/0033-Checks-if-Dir-Server-is-installed-and-running-before.patch deleted file mode 100644 index c6a3dba..0000000 --- a/SOURCES/0033-Checks-if-Dir-Server-is-installed-and-running-before.patch +++ /dev/null @@ -1,57 +0,0 @@ -From a81a4a502b020e0b0d91e6018914ea18b4e3e47e Mon Sep 17 00:00:00 2001 -From: Felipe Barreto <fbarreto@redhat.com> -Date: Wed, 20 Sep 2017 09:51:44 -0300 -Subject: [PATCH] Checks if Dir Server is installed and running before IPA - installation - -In cases when IPA is installed in two steps (external CA), it's -necessary to check (in the second step) if Dir. Server is -running before continue with the installation. If it's not, -start Directory Server. - -https://pagure.io/freeipa/issue/6611 - -Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> -Reviewed-By: Christian Heimes <cheimes@redhat.com> ---- - ipaplatform/redhat/services.py | 4 ++++ - ipaserver/install/server/install.py | 8 ++++++++ - 2 files changed, 12 insertions(+) - -diff --git a/ipaplatform/redhat/services.py b/ipaplatform/redhat/services.py -index 8fae1f3cc5b12dba0fa0192f21bc6d2d369941eb..57aa15ad9a4d83366ff02e5a5ca6e4574561e1fa 100644 ---- a/ipaplatform/redhat/services.py -+++ b/ipaplatform/redhat/services.py -@@ -119,6 +119,10 @@ class RedHatDirectoryService(RedHatService): - - return True - -+ def is_installed(self, instance_name): -+ file_path = "{}/{}-{}".format(paths.ETC_DIRSRV, "slapd", instance_name) -+ return os.path.exists(file_path) -+ - def restart(self, instance_name="", capture_output=True, wait=True, - ldapi=False): - # We need to explicitly enable instances to install proper symlinks as -diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py -index 97cbc6d8c84ee8fc21b6f8983c7897dc5d30c42d..422474fa915b4876530f304ef9424f6b31cf26cc 100644 ---- a/ipaserver/install/server/install.py -+++ b/ipaserver/install/server/install.py -@@ -616,6 +616,14 @@ def install_check(installer): - # check addresses here, dns module is doing own check - no_matching_interface_for_ip_address_warning(ip_addresses) - -+ instance_name = "-".join(realm_name.split(".")) -+ dirsrv = services.knownservices.dirsrv -+ if (options.external_cert_files -+ and dirsrv.is_installed(instance_name) -+ and not dirsrv.is_running(instance_name)): -+ root_logger.debug('Starting Directory Server') -+ services.knownservices.dirsrv.start(instance_name) -+ - if options.setup_adtrust: - adtrust.install_check(False, options, api) - --- -2.13.6 - diff --git a/SOURCES/0033-Disable-message-about-log-in-ipa-backup-if-IPA-is-no.patch b/SOURCES/0033-Disable-message-about-log-in-ipa-backup-if-IPA-is-no.patch new file mode 100644 index 0000000..6d0a2af --- /dev/null +++ b/SOURCES/0033-Disable-message-about-log-in-ipa-backup-if-IPA-is-no.patch @@ -0,0 +1,92 @@ +From 840e6144cd1ad75a7cf6ba5a8c936c6aa9bfc58d Mon Sep 17 00:00:00 2001 +From: Rob Crittenden <rcritten@redhat.com> +Date: Tue, 1 May 2018 11:15:18 -0400 +Subject: [PATCH] Disable message about log in ipa-backup if IPA is not + configured + +Introduce server installation constants similar to the client +but only tie in SERVER_NOT_CONFIGURED right now. + +For the case of not configured don't spit out the "See <some log> +for more information" because no logging was actually done. + +In the case of ipa-backup this could also be confusing if the +--log-file option was also passed in because it would not be +used. + +https://pagure.io/freeipa/issue/6843 + +Signed-off-by: Rob Crittenden <rcritten@redhat.com> +Reviewed-By: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Christian Heimes <cheimes@redhat.com> +--- + install/tools/man/ipa-backup.1 | 2 ++ + ipapython/admintool.py | 8 +++++++- + ipaserver/install/installutils.py | 5 +++-- + 3 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/install/tools/man/ipa-backup.1 b/install/tools/man/ipa-backup.1 +index ff9759ec77d54f32532c4ececfa5081daab9ec15..9e2900f770880d3a554df5cd5d0430716e3bf70e 100644 +--- a/install/tools/man/ipa-backup.1 ++++ b/install/tools/man/ipa-backup.1 +@@ -69,6 +69,8 @@ Log to the given file + 0 if the command was successful + + 1 if an error occurred ++ ++2 if IPA is not configured + .SH "FILES" + .PP + \fI/var/lib/ipa/backup\fR +diff --git a/ipapython/admintool.py b/ipapython/admintool.py +index 329e20f3744e304626bebcadfbb187782451dd4f..5a5d3eb421b204944123e19a2d7303d7237492cb 100644 +--- a/ipapython/admintool.py ++++ b/ipapython/admintool.py +@@ -32,6 +32,10 @@ from ipapython import version + from ipapython import config + from ipapython.ipa_log_manager import standard_logging_setup + ++SUCCESS = 0 ++SERVER_INSTALL_ERROR = 1 ++SERVER_NOT_CONFIGURED = 2 ++ + logger = logging.getLogger(__name__) + + +@@ -301,7 +305,9 @@ class AdminTool(object): + if error_message: + logger.error('%s', error_message) + message = "The %s command failed." % self.command_name +- if self.log_file_name: ++ if self.log_file_name and return_value != 2: ++ # magic value because this is common between server and client ++ # but imports are not straigthforward + message += " See %s for more information" % self.log_file_name + logger.error('%s', message) + +diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py +index 22889ed1b305b8df91eda0831c56c4b187cf6f86..6614da69a0a046cdfa1b309f77972ead9de1279f 100644 +--- a/ipaserver/install/installutils.py ++++ b/ipaserver/install/installutils.py +@@ -56,7 +56,7 @@ from ipalib.install import sysrestore + from ipalib.install.kinit import kinit_password + import ipaplatform + from ipapython import ipautil, admintool, version +-from ipapython.admintool import ScriptError ++from ipapython.admintool import ScriptError, SERVER_NOT_CONFIGURED # noqa: E402 + from ipapython.certdb import EXTERNAL_CA_TRUST_FLAGS + from ipapython.ipaldap import DIRMAN_DN, LDAPClient + from ipalib.util import validate_hostname +@@ -934,7 +934,8 @@ def check_server_configuration(): + """ + server_fstore = sysrestore.FileStore(paths.SYSRESTORE) + if not server_fstore.has_files(): +- raise RuntimeError("IPA is not configured on this system.") ++ raise ScriptError("IPA is not configured on this system.", ++ rval=SERVER_NOT_CONFIGURED) + + + def remove_file(filename): +-- +2.17.1 + diff --git a/SOURCES/0034-WebUI-Add-positive-number-validator.patch b/SOURCES/0034-WebUI-Add-positive-number-validator.patch deleted file mode 100644 index f4089e9..0000000 --- a/SOURCES/0034-WebUI-Add-positive-number-validator.patch +++ /dev/null @@ -1,96 +0,0 @@ -From a919a3ad3463eedee55b4aa2ae680c34241412b0 Mon Sep 17 00:00:00 2001 -From: Pavel Vomacka <pvomacka@redhat.com> -Date: Tue, 11 Jul 2017 10:46:36 +0200 -Subject: [PATCH] WebUI: Add positive number validator - -Add new validator which inherits from integer validator -and checks whether the integer is positive. - -https://pagure.io/freeipa/issue/6980 - -Reviewed-By: Felipe Volpone <felipevolpone@gmail.com> -Reviewed-By: Felipe Barreto <fbarreto@redhat.com> ---- - install/ui/src/freeipa/field.js | 43 +++++++++++++++++++++++++++++++++++++++++ - ipaserver/plugins/internal.py | 1 + - 2 files changed, 44 insertions(+) - -diff --git a/install/ui/src/freeipa/field.js b/install/ui/src/freeipa/field.js -index 76ce2533af5388ff5e1a2cfe8e35286f4e55b378..f998b578c38d91819fea418ea50e03589a691cbf 100644 ---- a/install/ui/src/freeipa/field.js -+++ b/install/ui/src/freeipa/field.js -@@ -1049,9 +1049,51 @@ field.validator = IPA.validator = function(spec) { - return that.true_result(); - }; - -+ that.integer_validate = that.validate; -+ - return that; - }; - -+ -+/** -+ * Javascript positive integer validator -+ * -+ * It allows to insert only positive integer. -+ * -+ * @class -+ * @alternateClassName IPA.positive_integer_validator -+ * @extends IPA.validator -+ */ -+ field.positive_integer_validator = IPA.positive_integer_validator = function(spec) { -+ -+ var that = IPA.integer_validator(spec); -+ -+ /** -+ * @inheritDoc -+ */ -+ -+ that.validate = function(value) { -+ -+ var integer_check = that.integer_validate(value); -+ -+ if (!integer_check.valid) { -+ return integer_check; -+ } -+ -+ var num = parseInt(value); -+ -+ if (num <= 0) { -+ return that.false_result( -+ text.get('@i18n:widget.validation.positive_number')); -+ } -+ -+ return that.true_result(); -+ }; -+ -+ return that; -+ }; -+ -+ - /** - * Metadata validator - * -@@ -1871,6 +1913,7 @@ field.register = function() { - v.register('unsupported', field.unsupported_validator); - v.register('same_password', field.same_password_validator); - v.register('integer', field.integer_validator); -+ v.register('positive_integer', field.positive_integer_validator); - - l.register('adapter', field.Adapter); - l.register('object_adapter', field.ObjectAdapter); -diff --git a/ipaserver/plugins/internal.py b/ipaserver/plugins/internal.py -index ff239db07ec1235c4174c6f9451c71195ab5a60a..c293e0b5e06677f09daa4b820ffd06a2671cd6e1 100644 ---- a/ipaserver/plugins/internal.py -+++ b/ipaserver/plugins/internal.py -@@ -982,6 +982,7 @@ class i18n_messages(Command): - "min_value": _("Minimum value is ${value}"), - "net_address": _("Not a valid network address (examples: 2001:db8::/64, 192.0.2.0/24)"), - "parse": _("Parse error"), -+ "positive_number": _("Must be a positive number"), - "port": _("'${port}' is not a valid port"), - "required": _("Required field"), - "unsupported": _("Unsupported value"), --- -2.13.6 - diff --git a/SOURCES/0034-uninstall-v-remove-Tracebacks.patch b/SOURCES/0034-uninstall-v-remove-Tracebacks.patch new file mode 100644 index 0000000..d498c81 --- /dev/null +++ b/SOURCES/0034-uninstall-v-remove-Tracebacks.patch @@ -0,0 +1,58 @@ +From da98cbda7b61792d956b21f0a9999d91894ae194 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud <flo@redhat.com> +Date: Tue, 21 Aug 2018 17:55:45 +0200 +Subject: [PATCH] uninstall -v: remove Tracebacks + +ipa-server-install --uninstall -v -U prints Traceback in its log file. +This issue happens because it calls subprocess.Popen with close_fds=True +(which closes all file descriptors in the child process) +but it is trying to use the file logger in the child process +(preexec_fn is called in the child just before the child is executed). +The fix is using the logger only in the parent process. + +Fixes: https://pagure.io/freeipa/issue/7681 +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +--- + ipapython/ipautil.py | 23 ++++++++++++----------- + 1 file changed, 12 insertions(+), 11 deletions(-) + +diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py +index 0de5fe86374429bfb9666a0d257e079883a1c56b..42329ad7c1677ad16c8d3275d79666005571cbc7 100644 +--- a/ipapython/ipautil.py ++++ b/ipapython/ipautil.py +@@ -481,20 +481,21 @@ def run(args, stdin=None, raiseonerr=True, nolog=(), env=None, + logger.debug('Starting external process') + logger.debug('args=%s', arg_string) + +- def preexec_fn(): +- if runas is not None: +- pent = pwd.getpwnam(runas) ++ if runas is not None: ++ pent = pwd.getpwnam(runas) + +- suplementary_gids = [ +- grp.getgrnam(sgroup).gr_gid for sgroup in suplementary_groups +- ] ++ suplementary_gids = [ ++ grp.getgrnam(sgroup).gr_gid for sgroup in suplementary_groups ++ ] + +- logger.debug('runas=%s (UID %d, GID %s)', runas, +- pent.pw_uid, pent.pw_gid) +- if suplementary_groups: +- for group, gid in zip(suplementary_groups, suplementary_gids): +- logger.debug('suplementary_group=%s (GID %d)', group, gid) ++ logger.debug('runas=%s (UID %d, GID %s)', runas, ++ pent.pw_uid, pent.pw_gid) ++ if suplementary_groups: ++ for group, gid in zip(suplementary_groups, suplementary_gids): ++ logger.debug('suplementary_group=%s (GID %d)', group, gid) + ++ def preexec_fn(): ++ if runas is not None: + os.setgroups(suplementary_gids) + os.setregid(pent.pw_gid, pent.pw_gid) + os.setreuid(pent.pw_uid, pent.pw_uid) +-- +2.17.1 + diff --git a/SOURCES/0035-Do-not-set-ca_host-when-setup-ca-is-used.patch b/SOURCES/0035-Do-not-set-ca_host-when-setup-ca-is-used.patch new file mode 100644 index 0000000..27b11e1 --- /dev/null +++ b/SOURCES/0035-Do-not-set-ca_host-when-setup-ca-is-used.patch @@ -0,0 +1,86 @@ +From 06654aba40bd79eff8bd44ac629bb5bb9b8f9c26 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Tibor=20Dudl=C3=A1k?= <tdudlak@redhat.com> +Date: Thu, 26 Jul 2018 11:46:55 +0200 +Subject: [PATCH] Do not set ca_host when --setup-ca is used + +Setting ca_host caused replication failures on DL0 +because it was trying to connect to wrong CA host. +Trying to avoid corner-case in ipaserver/plugins/dogtag.py +when api.env.host nor api.env.ca_host had not CA configured +and there was ca_host set to api.env.ca_host variable. + +See: https://pagure.io/freeipa/issue/7566 +Resolves: https://pagure.io/freeipa/issue/7629 +Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> +Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> +Reviewed-By: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +--- + ipaserver/install/cainstance.py | 24 ++++++++++++++++++++++ + ipaserver/install/server/replicainstall.py | 7 +++++-- + 2 files changed, 29 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index 6dbf69b3e5833f220a4d7d640b66a8fcf824f445..ffcebd719a16ebc5a991b35507b96411ad31eb10 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -451,6 +451,11 @@ class CAInstance(DogtagInstance): + self.step("updating IPA configuration", update_ipa_conf) + self.step("enabling CA instance", self.__enable_instance) + if not promote: ++ if self.clone: ++ # DL0 workaround; see docstring of __expose_ca_in_ldap ++ self.step("exposing CA instance on LDAP", ++ self.__expose_ca_in_ldap) ++ + self.step("migrating certificate profiles to LDAP", + migrate_profiles_to_ldap) + self.step("importing IPA certificate profiles", +@@ -1268,6 +1273,25 @@ class CAInstance(DogtagInstance): + config = [] + self.ldap_configure('CA', self.fqdn, None, basedn, config) + ++ def __expose_ca_in_ldap(self): ++ """ ++ In a case when replica is created on DL0 we need to make ++ sure that query for CA service record of this replica in ++ ldap will succeed in time of installation. ++ This method is needed for sucessfull replica installation ++ on DL0 and should be removed alongside with code for DL0. ++ ++ To suppress deprecation warning message this method is ++ not invoking ldap_enable() but _ldap_enable() method. ++ """ ++ ++ basedn = ipautil.realm_to_suffix(self.realm) ++ if not self.clone: ++ config = ['caRenewalMaster'] ++ else: ++ config = [] ++ self._ldap_enable(u'enabledService', "CA", self.fqdn, basedn, config) ++ + def setup_lightweight_ca_key_retrieval(self): + if sysupgrade.get_upgrade_state('dogtag', 'setup_lwca_key_retrieval'): + return +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index e78a2b992fbd44b8ee3ccd8183ebd6e13dfd1749..42c723b57699340d7dfa67f581ab7d4d4fdcf551 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -241,9 +241,12 @@ def create_ipa_conf(fstore, config, ca_enabled, master=None): + gopts.extend([ + ipaconf.setOption('enable_ra', 'True'), + ipaconf.setOption('ra_plugin', 'dogtag'), +- ipaconf.setOption('dogtag_version', '10'), +- ipaconf.setOption('ca_host', config.ca_host_name) ++ ipaconf.setOption('dogtag_version', '10') + ]) ++ ++ if not config.setup_ca: ++ gopts.append(ipaconf.setOption('ca_host', config.ca_host_name)) ++ + else: + gopts.extend([ + ipaconf.setOption('enable_ra', 'False'), +-- +2.17.1 + diff --git a/SOURCES/0035-WebUI-change-validator-of-page-size-settings.patch b/SOURCES/0035-WebUI-change-validator-of-page-size-settings.patch deleted file mode 100644 index 5f15079..0000000 --- a/SOURCES/0035-WebUI-change-validator-of-page-size-settings.patch +++ /dev/null @@ -1,34 +0,0 @@ -From e37b90a39420cd3e4f5b6e48d83aa331cd52c9da Mon Sep 17 00:00:00 2001 -From: Pavel Vomacka <pvomacka@redhat.com> -Date: Tue, 11 Jul 2017 10:49:46 +0200 -Subject: [PATCH] WebUI: change validator of page size settings - -Previously, this configuration field was validated by integer_validator -which only checks that the input is number. -Now new positive_integer_validator can also check that -the inputed number positive. - -https://pagure.io/freeipa/issue/6980 - -Reviewed-By: Felipe Volpone <felipevolpone@gmail.com> -Reviewed-By: Felipe Barreto <fbarreto@redhat.com> ---- - install/ui/src/freeipa/Application_controller.js | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/install/ui/src/freeipa/Application_controller.js b/install/ui/src/freeipa/Application_controller.js -index 5eb4e7a5104b780761b9a5179dbfd1501a8d1478..51f579e3cce2c28e8f1d2d231fa10711d0b2498d 100644 ---- a/install/ui/src/freeipa/Application_controller.js -+++ b/install/ui/src/freeipa/Application_controller.js -@@ -312,7 +312,7 @@ define([ - $type: 'text', - name: 'pagination_size', - label: '@i18n:customization.table_pagination', -- validators: ['integer'] -+ validators: ['positive_integer'] - } - ] - }); --- -2.13.6 - diff --git a/SOURCES/0036-Fix-ipa-replica-install-when-key-not-protected-by-PI.patch b/SOURCES/0036-Fix-ipa-replica-install-when-key-not-protected-by-PI.patch new file mode 100644 index 0000000..8e96414 --- /dev/null +++ b/SOURCES/0036-Fix-ipa-replica-install-when-key-not-protected-by-PI.patch @@ -0,0 +1,59 @@ +From 42bb4ee747a2f22db756bd037b2b0044853bb41d Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud <flo@redhat.com> +Date: Tue, 21 Nov 2017 14:49:46 +0100 +Subject: [PATCH] Fix ipa-replica-install when key not protected by PIN + +When ipa-replica-install is called in a CA-less environment, the certs, +keys and pins need to be provided with --{http|dirsrv|pkinit}-cert-file and +--{http|dirsrv|pkinit}-pin. If the pin is not provided in the CLI options, +and in interactive mode, the installer prompts for the PIN. +The issue happens when the keys are not protected by any PIN, the installer +does not accept an empty string and keeps on asking for a PIN. + +The fix makes sure that the installer accepts an empty PIN. A similar fix +was done for ipa-server-install in +https://pagure.io/freeipa/c/4ee426a68ec60370eee6f5aec917ecce444840c7 + +Fixes: +https://pagure.io/freeipa/issue/7274 + +Reviewed-By: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Christian Heimes <cheimes@redhat.com> +--- + ipaserver/install/server/replicainstall.py | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 42c723b57699340d7dfa67f581ab7d4d4fdcf551..396d6089449225cc83aa28552a2009b9057e65ab 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -1057,7 +1057,7 @@ def promote_check(installer): + if options.http_pin is None: + options.http_pin = installutils.read_password( + "Enter Apache Server private key unlock", +- confirm=False, validate=False) ++ confirm=False, validate=False, retry=False) + if options.http_pin is None: + raise ScriptError( + "Apache Server private key unlock password required") +@@ -1073,7 +1073,7 @@ def promote_check(installer): + if options.dirsrv_pin is None: + options.dirsrv_pin = installutils.read_password( + "Enter Directory Server private key unlock", +- confirm=False, validate=False) ++ confirm=False, validate=False, retry=False) + if options.dirsrv_pin is None: + raise ScriptError( + "Directory Server private key unlock password required") +@@ -1089,7 +1089,7 @@ def promote_check(installer): + if options.pkinit_pin is None: + options.pkinit_pin = installutils.read_password( + "Enter Kerberos KDC private key unlock", +- confirm=False, validate=False) ++ confirm=False, validate=False, retry=False) + if options.pkinit_pin is None: + raise ScriptError( + "Kerberos KDC private key unlock password required") +-- +2.17.1 + diff --git a/SOURCES/0036-WebUI-fix-jslint-error.patch b/SOURCES/0036-WebUI-fix-jslint-error.patch deleted file mode 100644 index 93224f9..0000000 --- a/SOURCES/0036-WebUI-fix-jslint-error.patch +++ /dev/null @@ -1,30 +0,0 @@ -From ae6a8489b65fb28a3381267bcfacf4a1d42047c9 Mon Sep 17 00:00:00 2001 -From: Pavel Vomacka <pvomacka@redhat.com> -Date: Fri, 21 Jul 2017 18:49:01 +0200 -Subject: [PATCH] WebUI: fix jslint error - -jslint warned about parsing string to integer without explicit radix. -This error was introduced in commit 3cac851 . - -Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> -Reviewed-By: Felipe Barreto <fbarreto@redhat.com> ---- - install/ui/src/freeipa/field.js | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/install/ui/src/freeipa/field.js b/install/ui/src/freeipa/field.js -index f998b578c38d91819fea418ea50e03589a691cbf..6c99ddbe2e08522c14980e42ad63e28e5b739794 100644 ---- a/install/ui/src/freeipa/field.js -+++ b/install/ui/src/freeipa/field.js -@@ -1080,7 +1080,7 @@ field.validator = IPA.validator = function(spec) { - return integer_check; - } - -- var num = parseInt(value); -+ var num = parseInt(value, 10); - - if (num <= 0) { - return that.false_result( --- -2.13.6 - diff --git a/SOURCES/0037-Clear-next-field-when-returnining-list-elements-in-q.patch b/SOURCES/0037-Clear-next-field-when-returnining-list-elements-in-q.patch new file mode 100644 index 0000000..73bbaf0 --- /dev/null +++ b/SOURCES/0037-Clear-next-field-when-returnining-list-elements-in-q.patch @@ -0,0 +1,64 @@ +From a099794ab890979dbd9fb567c44fcb105da229ff Mon Sep 17 00:00:00 2001 +From: Robbie Harwood <rharwood@redhat.com> +Date: Wed, 22 Aug 2018 15:32:16 -0400 +Subject: [PATCH] Clear next field when returnining list elements in queue.c + +The ipa-otpd code occasionally removes elements from one queue, +inspects and modifies them, and then inserts them into +another (possibly identical, possibly different) queue. When the next +pointer isn't cleared, this can result in element membership in both +queues, leading to double frees, or even self-referential elements, +causing infinite loops at traversal time. + +Rather than eliminating the pattern, make it safe by clearing the next +field any time an element enters or exits a queue. + +Related https://pagure.io/freeipa/issue/7262 + +Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> +--- + daemons/ipa-otpd/queue.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/daemons/ipa-otpd/queue.c b/daemons/ipa-otpd/queue.c +index 9e29fb238d5c7a7395bcf3860ce7445c27ca98ac..2944b7ea0db6f49d0a3230b5f33c7a89281fd8c6 100644 +--- a/daemons/ipa-otpd/queue.c ++++ b/daemons/ipa-otpd/queue.c +@@ -111,6 +111,8 @@ void otpd_queue_push(struct otpd_queue *q, struct otpd_queue_item *item) + q->head = q->tail = item; + else + q->tail = q->tail->next = item; ++ ++ item->next = NULL; + } + + void otpd_queue_push_head(struct otpd_queue *q, struct otpd_queue_item *item) +@@ -118,6 +120,8 @@ void otpd_queue_push_head(struct otpd_queue *q, struct otpd_queue_item *item) + if (item == NULL) + return; + ++ item->next = NULL; ++ + if (q->head == NULL) + q->tail = q->head = item; + else { +@@ -145,6 +149,8 @@ struct otpd_queue_item *otpd_queue_pop(struct otpd_queue *q) + if (q->head == NULL) + q->tail = NULL; + ++ if (item != NULL) ++ item->next = NULL; + return item; + } + +@@ -160,6 +166,7 @@ struct otpd_queue_item *otpd_queue_pop_msgid(struct otpd_queue *q, int msgid) + *prev = item->next; + if (q->head == NULL) + q->tail = NULL; ++ item->next = NULL; + return item; + } + } +-- +2.17.1 + diff --git a/SOURCES/0037-ipa-advise-for-smartcards-updated.patch b/SOURCES/0037-ipa-advise-for-smartcards-updated.patch deleted file mode 100644 index d3a9781..0000000 --- a/SOURCES/0037-ipa-advise-for-smartcards-updated.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 1c18017e2fc7dc4e4d943611115e94dc0bc70263 Mon Sep 17 00:00:00 2001 -From: amitkuma <amitkuma@redhat.com> -Date: Tue, 16 Jan 2018 15:56:25 +0530 -Subject: [PATCH] ipa-advise for smartcards updated - -...... -authconfig --enablesmartcard --smartcardmodule=sssd --updateall - -Advise is updated to: -authconfig --enablesssd --enablesssdauth --enablesmartcard --smartcardmodule=sssd ---smartcardaction=1 --updateall - -Resolves: https://pagure.io/freeipa/issue/7358 -Reviewed-By: Christian Heimes <cheimes@redhat.com> ---- - ipaserver/advise/plugins/smart_card_auth.py | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/advise/plugins/smart_card_auth.py b/ipaserver/advise/plugins/smart_card_auth.py -index fb328f29ca5051ad52c9c5e0000021ad5e8b94e8..109e9ba3815301a556a38f5185918992c4622148 100644 ---- a/ipaserver/advise/plugins/smart_card_auth.py -+++ b/ipaserver/advise/plugins/smart_card_auth.py -@@ -315,7 +315,8 @@ class config_client_for_smart_card_auth(common_smart_card_auth_config): - - def run_authconfig_to_configure_smart_card_auth(self): - self.log.exit_on_failed_command( -- 'authconfig --enablesmartcard --smartcardmodule=sssd --updateall', -+ 'authconfig --enablesssd --enablesssdauth --enablesmartcard ' -+ '--smartcardmodule=sssd --smartcardaction=1 --updateall', - [ - 'Failed to configure Smart Card authentication in SSSD' - ] --- -2.13.6 - diff --git a/SOURCES/0038-Add-a-notice-to-restart-ipa-services-after-certs-are.patch b/SOURCES/0038-Add-a-notice-to-restart-ipa-services-after-certs-are.patch deleted file mode 100644 index e94b45c..0000000 --- a/SOURCES/0038-Add-a-notice-to-restart-ipa-services-after-certs-are.patch +++ /dev/null @@ -1,59 +0,0 @@ -From accc490a5f1db734c94e739d9b9638d44d60d21c Mon Sep 17 00:00:00 2001 -From: Aleksei Slaikovskii <aslaikov@redhat.com> -Date: Mon, 23 Oct 2017 11:17:32 +0200 -Subject: [PATCH] Add a notice to restart ipa services after certs are - installed - -Adding notice for user to restart services after -ipa-server-certinstall. - -https://pagure.io/freeipa/issue/7016 - -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> -Reviewed-By: Rob Crittenden <rcritten@redhat.com> -Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> ---- - install/tools/man/ipa-server-certinstall.1 | 3 ++- - ipaserver/install/ipa_server_certinstall.py | 5 +++++ - 2 files changed, 7 insertions(+), 1 deletion(-) - -diff --git a/install/tools/man/ipa-server-certinstall.1 b/install/tools/man/ipa-server-certinstall.1 -index 35cd8c6c711119d7c782c6a89ac78b4894cec073..00fd03b6bc2184ec2bbc099fd9799551c07d2390 100644 ---- a/install/tools/man/ipa-server-certinstall.1 -+++ b/install/tools/man/ipa-server-certinstall.1 -@@ -28,7 +28,8 @@ PKCS#12 is a file format used to safely transport SSL certificates and public/pr - - They may be generated and managed using the NSS pk12util command or the OpenSSL pkcs12 command. - --The service(s) are not automatically restarted. In order to use the newly installed certificate(s) you will need to manually restart the Directory and/or Apache servers. -+The service(s) are not automatically restarted. In order to use the newly installed certificate(s) you will need to manually restart the Directory, Apache and/or Krb5kdc servers. -+ - .SH "OPTIONS" - .TP - \fB\-d\fR, \fB\-\-dirsrv\fR -diff --git a/ipaserver/install/ipa_server_certinstall.py b/ipaserver/install/ipa_server_certinstall.py -index 9c8f6e81a802e1a87bab1fd15f729e10676fe3a3..ec283705a4038239ddf0c6bacaac200936ed04e8 100644 ---- a/ipaserver/install/ipa_server_certinstall.py -+++ b/ipaserver/install/ipa_server_certinstall.py -@@ -17,6 +17,7 @@ - # You should have received a copy of the GNU General Public License - # along with this program. If not, see <http://www.gnu.org/licenses/>. - # -+from __future__ import print_function - - import os - import os.path -@@ -121,6 +122,10 @@ class ServerCertInstall(admintool.AdminTool): - if self.options.kdc: - self.install_kdc_cert() - -+ print( -+ "Please restart ipa services after installing certificate " -+ "(ipactl restart)") -+ - api.Backend.ldap2.disconnect() - - def install_dirsrv_cert(self): --- -2.14.3 - diff --git a/SOURCES/0038-Add-cmocka-unit-tests-for-ipa-otpd-queue-code.patch b/SOURCES/0038-Add-cmocka-unit-tests-for-ipa-otpd-queue-code.patch new file mode 100644 index 0000000..a1380c7 --- /dev/null +++ b/SOURCES/0038-Add-cmocka-unit-tests-for-ipa-otpd-queue-code.patch @@ -0,0 +1,253 @@ +From efd0a988a7431e3f31f5dde78f66eaec8c7f7f37 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood <rharwood@redhat.com> +Date: Thu, 30 Aug 2018 15:34:31 -0400 +Subject: [PATCH] Add cmocka unit tests for ipa otpd queue code + +Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> +--- + daemons/ipa-otpd/Makefile.am | 12 + + .../ipa-otpd/ipa_otpd_queue_cmocka_tests.c | 212 ++++++++++++++++++ + 2 files changed, 224 insertions(+) + create mode 100644 daemons/ipa-otpd/ipa_otpd_queue_cmocka_tests.c + +diff --git a/daemons/ipa-otpd/Makefile.am b/daemons/ipa-otpd/Makefile.am +index 923e16ebe127a36cea372d656dd913c4ffa09313..c1d6c2053354a59b1fd897f9a67cc7507eed5294 100644 +--- a/daemons/ipa-otpd/Makefile.am ++++ b/daemons/ipa-otpd/Makefile.am +@@ -21,3 +21,15 @@ ipa_otpd_SOURCES = bind.c forward.c main.c parse.c query.c queue.c stdio.c + $< > $@ + + CLEANFILES = $(systemdsystemunit_DATA) ++ ++TESTS = ++check_PROGRAMS = ++ ++if HAVE_CMOCKA ++TESTS += queue_tests ++check_PROGRAMS += queue_tests ++endif ++ ++queue_tests_SOURCES = ipa_otpd_queue_cmocka_tests.c queue.c ++queue_tests_CFLAGS = $(CMOCKA_CFLAGS) ++queue_tests_LDADD = $(CMOCKA_LIBS) +diff --git a/daemons/ipa-otpd/ipa_otpd_queue_cmocka_tests.c b/daemons/ipa-otpd/ipa_otpd_queue_cmocka_tests.c +new file mode 100644 +index 0000000000000000000000000000000000000000..068431e6475bb74b01acbcab22115915dec1a278 +--- /dev/null ++++ b/daemons/ipa-otpd/ipa_otpd_queue_cmocka_tests.c +@@ -0,0 +1,212 @@ ++/* ++ * FreeIPA 2FA companion daemon - internal queue tests ++ * ++ * Author: Robbie Harwood <rharwood@redhat.com> ++ * ++ * Copyright (C) 2018 Robbie Harwood, Red Hat ++ * see file 'COPYING' for use and warranty information ++ * ++ * This program is free software you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the Free ++ * Software Foundation, either version 3 of the License, or (at your option) ++ * any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <setjmp.h> ++#include <stdarg.h> ++#include <stddef.h> ++ ++#include <cmocka.h> ++ ++#include "internal.h" ++ ++/* Bypass otpd queue allocation/freeing to avoid calling into LDAP and ++ * krad. No effort is made to make the types match. */ ++static struct otpd_queue_item *new_elt(int id) ++{ ++ krb5_error_code ret; ++ struct otpd_queue_item *e = NULL; ++ ++ ret = otpd_queue_item_new(NULL, &e); ++ assert_int_equal(ret, 0); ++ assert_ptr_not_equal(e, NULL); ++ ++ e->msgid = id; ++ return e; ++} ++static void free_elt(struct otpd_queue_item **e) ++{ ++ assert_ptr_not_equal(e, NULL); ++ free(*e); ++ *e = NULL; ++} ++static void free_elts(struct otpd_queue *q) ++{ ++ assert_ptr_not_equal(q, NULL); ++ for (struct otpd_queue_item *e = otpd_queue_pop(q); e != NULL; ++ e = otpd_queue_pop(q)) ++ free_elt(&e); ++} ++#define otpd_queue_item_new new_elt ++#define otpd_queue_item_free free_elt ++#define otpd_queue_free_items free_elts ++ ++static void assert_elt_equal(struct otpd_queue_item *e1, ++ struct otpd_queue_item *e2) ++{ ++ if (e1 == NULL && e2 == NULL) ++ return; ++ assert_ptr_not_equal(e1, NULL); ++ assert_ptr_not_equal(e2, NULL); ++ assert_int_equal(e1->msgid, e2->msgid); ++} ++ ++static void test_single_insert() ++{ ++ struct otpd_queue q = { NULL }; ++ struct otpd_queue_item *ein, *eout; ++ ++ ein = new_elt(0); ++ otpd_queue_push(&q, ein); ++ ++ eout = otpd_queue_peek(&q); ++ assert_elt_equal(ein, eout); ++ ++ eout = otpd_queue_pop(&q); ++ assert_elt_equal(ein, eout); ++ free_elt(&eout); ++ ++ eout = otpd_queue_pop(&q); ++ assert_ptr_equal(eout, NULL); ++ ++ free_elts(&q); ++} ++ ++static void test_jump_insert() ++{ ++ struct otpd_queue q = { NULL }; ++ struct otpd_queue_item *echeck; ++ ++ for (int i = 0; i < 3; i++) { ++ struct otpd_queue_item *e = new_elt(i); ++ otpd_queue_push_head(&q, e); ++ ++ echeck = otpd_queue_peek(&q); ++ assert_elt_equal(e, echeck); ++ } ++ ++ free_elts(&q); ++} ++ ++static void test_garbage_insert() ++{ ++ struct otpd_queue q = { NULL }; ++ struct otpd_queue_item *e, *g; ++ ++ g = new_elt(0); ++ g->next = g; ++ otpd_queue_push(&q, g); ++ ++ e = otpd_queue_peek(&q); ++ assert_ptr_equal(e->next, NULL); ++ ++ free_elts(&q); ++} ++ ++static void test_removal() ++{ ++ struct otpd_queue q = { NULL }; ++ ++ for (int i = 0; i < 3; i++) { ++ struct otpd_queue_item *e = new_elt(i); ++ otpd_queue_push(&q, e); ++ } ++ for (int i = 0; i < 3; i++) { ++ struct otpd_queue_item *e = otpd_queue_pop(&q); ++ assert_ptr_not_equal(e, NULL); ++ assert_ptr_equal(e->next, NULL); ++ assert_int_equal(e->msgid, i); ++ free_elt(&e); ++ } ++} ++ ++static void pick_id(struct otpd_queue *q, int msgid) ++{ ++ struct otpd_queue_item *e; ++ ++ e = otpd_queue_pop_msgid(q, msgid); ++ assert_int_equal(e->msgid, msgid); ++ assert_ptr_equal(e->next, NULL); ++ free_elt(&e); ++ e = otpd_queue_pop_msgid(q, msgid); ++ assert_ptr_equal(e, NULL); ++} ++static void test_pick_removal() ++{ ++ struct otpd_queue q = { NULL }; ++ ++ for (int i = 0; i < 4; i++) { ++ struct otpd_queue_item *e = new_elt(i); ++ otpd_queue_push(&q, e); ++ } ++ ++ pick_id(&q, 0); /* first */ ++ pick_id(&q, 2); /* middle */ ++ pick_id(&q, 3); /* last */ ++ pick_id(&q, 1); /* singleton */ ++ ++ free_elts(&q); ++} ++ ++static void test_iter() ++{ ++ krb5_error_code ret; ++ struct otpd_queue q = { NULL }; ++ const struct otpd_queue *queues[3]; ++ struct otpd_queue_iter *iter = NULL; ++ const krad_packet *p = NULL; ++ ++ for (ptrdiff_t i = 1; i <= 3; i++) { ++ struct otpd_queue_item *e = new_elt(i); ++ e->req = (void *)i; ++ otpd_queue_push(&q, e); ++ } ++ ++ queues[0] = &q; ++ queues[1] = &q; ++ queues[2] = NULL; ++ ret = otpd_queue_iter_new(queues, &iter); ++ assert_int_equal(ret, 0); ++ assert_ptr_not_equal(iter, NULL); ++ ++ for (ptrdiff_t i = 0; i < 6; i++) { ++ p = otpd_queue_iter_func(iter, FALSE); ++ assert_ptr_equal(p, (void *) (i % 3 + 1)); ++ } ++ p = otpd_queue_iter_func(iter, FALSE); ++ assert_ptr_equal(p, NULL); ++ ++ free_elts(&q); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ const struct CMUnitTest tests[] = { ++ cmocka_unit_test(test_single_insert), ++ cmocka_unit_test(test_jump_insert), ++ cmocka_unit_test(test_garbage_insert), ++ cmocka_unit_test(test_removal), ++ cmocka_unit_test(test_pick_removal), ++ cmocka_unit_test(test_iter), ++ }; ++ ++ return cmocka_run_group_tests(tests, NULL, NULL); ++} +-- +2.17.1 + diff --git a/SOURCES/0039-Fix-OTP-validation-in-FIPS-mode.patch b/SOURCES/0039-Fix-OTP-validation-in-FIPS-mode.patch deleted file mode 100644 index 0c0e1b7..0000000 --- a/SOURCES/0039-Fix-OTP-validation-in-FIPS-mode.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 20ab0c731eea95327c8c2dc296461b612c6e98ae Mon Sep 17 00:00:00 2001 -From: Nathaniel McCallum <npmccallum@redhat.com> -Date: Wed, 21 Feb 2018 23:39:55 -0500 -Subject: [PATCH] Fix OTP validation in FIPS mode - -NSS doesn't allow keys to be loaded directly in FIPS mode. To work around -this, we encrypt the input key using an ephemeral key and then unwrap the -encrypted key. - -https://pagure.io/freeipa/issue/7168 - -Reviewed-By: Rob Crittenden <rcritten@redhat.com> -Reviewed-By: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Rob Crittenden <rcritten@redhat.com> ---- - daemons/ipa-slapi-plugins/libotp/hotp.c | 47 +++++++++++++++++++++++++++++++-- - 1 file changed, 45 insertions(+), 2 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/libotp/hotp.c b/daemons/ipa-slapi-plugins/libotp/hotp.c -index 619bc63ab1bee99d71c2f0fb887809762107c94c..0c9de96d37183e597867b736d6324db60fa1b3bb 100644 ---- a/daemons/ipa-slapi-plugins/libotp/hotp.c -+++ b/daemons/ipa-slapi-plugins/libotp/hotp.c -@@ -46,6 +46,7 @@ - #include <time.h> - - #include <nss.h> -+#include <blapit.h> - #include <pk11pub.h> - #include <hasht.h> - #include <prnetdb.h> -@@ -66,6 +67,49 @@ static const struct { - { } - }; - -+static PK11SymKey * -+import_key(PK11SlotInfo *slot, CK_MECHANISM_TYPE mech, SECItem *key) -+{ -+ uint8_t ct[(key->len / AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE]; -+ uint8_t iv[AES_BLOCK_SIZE] = {}; -+ SECItem ivitem = { .data = iv, .len = sizeof(iv), .type = siBuffer }; -+ SECItem ctitem = { .data = ct, .len = sizeof(ct), .type = siBuffer }; -+ PK11SymKey *ekey = NULL; -+ PK11SymKey *skey = NULL; -+ -+ /* Try to import the key directly. */ -+ skey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, -+ CKA_SIGN, key, NULL); -+ if (skey) -+ return skey; -+ -+ /* If we get here, we are probably in FIPS mode. Let's encrypt the key so -+ * that we can unseal it instead of loading it directly. */ -+ -+ /* Generate an ephemeral key. */ -+ ekey = PK11_TokenKeyGenWithFlags(slot, CKM_AES_CBC_PAD, NULL, -+ AES_128_KEY_LENGTH, NULL, -+ CKF_ENCRYPT | CKF_UNWRAP, -+ PK11_ATTR_SESSION | -+ PK11_ATTR_PRIVATE | -+ PK11_ATTR_SENSITIVE, NULL); -+ if (!ekey) -+ goto egress; -+ -+ /* Encrypt the input key. */ -+ if (PK11_Encrypt(ekey, CKM_AES_CBC_PAD, &ivitem, ctitem.data, &ctitem.len, -+ ctitem.len, key->data, key->len) != SECSuccess) -+ goto egress; -+ -+ /* Unwrap the input key. */ -+ skey = PK11_UnwrapSymKey(ekey, CKM_AES_CBC_PAD, &ivitem, -+ &ctitem, mech, CKA_SIGN, key->len); -+ -+egress: -+ PK11_FreeSymKey(ekey); -+ return skey; -+} -+ - /* - * This code is mostly cargo-cult taken from here: - * http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn5.html -@@ -90,8 +134,7 @@ static bool hmac(SECItem *key, CK_MECHANISM_TYPE mech, const SECItem *in, - } - } - -- symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, -- CKA_SIGN, key, NULL); -+ symkey = import_key(slot, mech, key); - if (symkey == NULL) - goto done; - --- -2.14.3 - diff --git a/SOURCES/0039-ipa-server-install-do-not-perform-forwarder-validati.patch b/SOURCES/0039-ipa-server-install-do-not-perform-forwarder-validati.patch new file mode 100644 index 0000000..37eef97 --- /dev/null +++ b/SOURCES/0039-ipa-server-install-do-not-perform-forwarder-validati.patch @@ -0,0 +1,34 @@ +From f387cbe6f9d1e21cb46c7b9752735bf6ded176b7 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud <flo@redhat.com> +Date: Fri, 31 Aug 2018 10:09:15 +0200 +Subject: [PATCH] ipa-server-install: do not perform forwarder validation with + --no-dnssec-validation + +ipa-server-install is checking if the forwarder(s) specified with +--forwarder argument support DNSSEC. When the --no-dnssec-validation +option is added, the installer should not perform the check. + +Fixes: https://pagure.io/freeipa/issue/7666 +Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> +--- + ipaserver/install/dns.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py +index cac7a9213796d6618854b12da6c2a7fe60afdbf9..e4f73ac025dfe8aa19ef99c8d0ab9379caa32610 100644 +--- a/ipaserver/install/dns.py ++++ b/ipaserver/install/dns.py +@@ -293,8 +293,8 @@ def install_check(standalone, api, replica, options, hostname): + + # test DNSSEC forwarders + if options.forwarders: +- if (not bindinstance.check_forwarders(options.forwarders) +- and not options.no_dnssec_validation): ++ if not options.no_dnssec_validation \ ++ and not bindinstance.check_forwarders(options.forwarders): + options.no_dnssec_validation = True + print("WARNING: DNSSEC validation will be disabled") + +-- +2.17.1 + diff --git a/SOURCES/0040-Increase-the-default-token-key-size.patch b/SOURCES/0040-Increase-the-default-token-key-size.patch deleted file mode 100644 index 77a44f8..0000000 --- a/SOURCES/0040-Increase-the-default-token-key-size.patch +++ /dev/null @@ -1,34 +0,0 @@ -From ab2eaf607dd3746dd239595315dbaaebade06320 Mon Sep 17 00:00:00 2001 -From: Nathaniel McCallum <npmccallum@redhat.com> -Date: Thu, 22 Feb 2018 14:04:10 -0500 -Subject: [PATCH] Increase the default token key size - -The previous default token key size would fail in FIPS mode for the sha384 -and sha512 algorithms. With the updated key size, the default will work in -all cases. - -https://pagure.io/freeipa/issue/7168 - -Reviewed-By: Rob Crittenden <rcritten@redhat.com> -Reviewed-By: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Rob Crittenden <rcritten@redhat.com> ---- - ipaserver/plugins/otptoken.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaserver/plugins/otptoken.py b/ipaserver/plugins/otptoken.py -index c66f0980f0fc2ed49b4224be40a18ce528a6da7b..a6e423f949659d8157c8471d0fbc3ee8a299ac98 100644 ---- a/ipaserver/plugins/otptoken.py -+++ b/ipaserver/plugins/otptoken.py -@@ -72,7 +72,7 @@ TOKEN_TYPES = { - } - - # NOTE: For maximum compatibility, KEY_LENGTH % 5 == 0 --KEY_LENGTH = 20 -+KEY_LENGTH = 35 - - class OTPTokenKey(Bytes): - """A binary password type specified in base32.""" --- -2.14.3 - diff --git a/SOURCES/0040-ipa-replica-install-fix-pkinit-setup.patch b/SOURCES/0040-ipa-replica-install-fix-pkinit-setup.patch new file mode 100644 index 0000000..8ef6481 --- /dev/null +++ b/SOURCES/0040-ipa-replica-install-fix-pkinit-setup.patch @@ -0,0 +1,46 @@ +From 7fe3cba3d4cbe62c23e0e74f6bf3c44c50feb985 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud <flo@redhat.com> +Date: Tue, 4 Sep 2018 14:15:50 +0200 +Subject: [PATCH] ipa-replica-install: fix pkinit setup + +commit 7284097 (Delay enabling services until end of installer) +introduced a regression in replica installation. +When the replica requests a cert for PKINIT, a check is done +to ensure that the hostname corresponds to a machine with a +KDC service enabled (ipaconfigstring attribute of +cn=KDC,cn=<hostname>,cn=masters,cn=ipa,cn=etc,$BASEDN must contain +'enabledService'). +With the commit mentioned above, the service is set to enabled only +at the end of the installation. + +The fix makes a less strict check, ensuring that 'enabledService' +or 'configuredService' is in ipaconfigstring. + +Fixes: https://pagure.io/freeipa/issue/7566 +Reviewed-By: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Christian Heimes <cheimes@redhat.com> +--- + ipaserver/plugins/cert.py | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py +index 0663272c9b4fd73225f63fe52d8d31157d5cc690..ed78388c8b8b4688873a5b047fb1b67e417a8a6d 100644 +--- a/ipaserver/plugins/cert.py ++++ b/ipaserver/plugins/cert.py +@@ -300,9 +300,11 @@ def ca_kdc_check(api_instance, hostname): + + ipaconfigstring = {val.lower() for val in kdc_entry['ipaConfigString']} + +- if 'enabledservice' not in ipaconfigstring: ++ if 'enabledservice' not in ipaconfigstring \ ++ and 'configuredservice' not in ipaconfigstring: + raise errors.NotFound( +- reason=_("enabledService not in ipaConfigString kdc entry")) ++ reason=_("enabledService/configuredService not in " ++ "ipaConfigString kdc entry")) + + except errors.NotFound: + raise errors.ACIError( +-- +2.17.1 + diff --git a/SOURCES/0041-Revert-Don-t-allow-OTP-or-RADIUS-in-FIPS-mode.patch b/SOURCES/0041-Revert-Don-t-allow-OTP-or-RADIUS-in-FIPS-mode.patch deleted file mode 100644 index a8818c2..0000000 --- a/SOURCES/0041-Revert-Don-t-allow-OTP-or-RADIUS-in-FIPS-mode.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 6d813f6b03811a285c3c6dae85942c0086b619a6 Mon Sep 17 00:00:00 2001 -From: Nathaniel McCallum <npmccallum@redhat.com> -Date: Mon, 26 Feb 2018 09:48:22 -0500 -Subject: [PATCH] Revert "Don't allow OTP or RADIUS in FIPS mode" - -This reverts commit 16a952a0a44a0ebee97029ea1d2f6b7593dd2622. - -OTP now works in FIPS mode. RADIUS can be made to be compliant by wrapping -traffic in a VPN. - -https://pagure.io/freeipa/issue/7168 -https://pagure.io/freeipa/issue/7243 - -Reviewed-By: Rob Crittenden <rcritten@redhat.com> -Reviewed-By: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Rob Crittenden <rcritten@redhat.com> ---- - ipaserver/plugins/baseuser.py | 3 --- - ipaserver/plugins/config.py | 16 ---------------- - 2 files changed, 19 deletions(-) - -diff --git a/ipaserver/plugins/baseuser.py b/ipaserver/plugins/baseuser.py -index bb8a73ded0fed135d5829ec0b0829a936f2196fb..bf24dbf542d3b481671dfe4e8cee14a2edcc26e0 100644 ---- a/ipaserver/plugins/baseuser.py -+++ b/ipaserver/plugins/baseuser.py -@@ -32,7 +32,6 @@ from .baseldap import ( - add_missing_object_class) - from ipaserver.plugins.service import ( - validate_certificate, validate_realm, normalize_principal) --from ipaserver.plugins.config import check_fips_auth_opts - from ipalib.request import context - from ipalib import _ - from ipalib.constants import PATTERN_GROUPUSER_NAME -@@ -478,7 +477,6 @@ class baseuser_add(LDAPCreate): - **options): - assert isinstance(dn, DN) - set_krbcanonicalname(entry_attrs) -- check_fips_auth_opts(fips_mode=self.api.env.fips_mode, **options) - self.obj.convert_usercertificate_pre(entry_attrs) - - def post_common_callback(self, ldap, dn, entry_attrs, *keys, **options): -@@ -602,7 +600,6 @@ class baseuser_mod(LDAPUpdate): - assert isinstance(dn, DN) - add_sshpubkey_to_attrs_pre(self.context, attrs_list) - -- check_fips_auth_opts(fips_mode=self.api.env.fips_mode, **options) - self.check_namelength(ldap, **options) - - self.check_mail(entry_attrs) -diff --git a/ipaserver/plugins/config.py b/ipaserver/plugins/config.py -index c9033fa8e7a2a0bfe77464fa4f9c62278bd814f6..ce15e6096f5b84dc45ee21d5aecc73ecf86eba07 100644 ---- a/ipaserver/plugins/config.py -+++ b/ipaserver/plugins/config.py -@@ -85,20 +85,6 @@ EXAMPLES: - - register = Registry() - -- --def check_fips_auth_opts(fips_mode, **options): -- """ -- OTP and RADIUS are not allowed in FIPS mode since they use MD5 -- checksums (OTP uses our RADIUS responder daemon ipa-otpd). -- """ -- if 'ipauserauthtype' in options and fips_mode: -- if ('otp' in options['ipauserauthtype'] or -- 'radius' in options['ipauserauthtype']): -- raise errors.InvocationError( -- 'OTP and RADIUS authentication in FIPS is ' -- 'not yet supported') -- -- - @register() - class config(LDAPObject): - """ -@@ -412,8 +398,6 @@ class config_mod(LDAPUpdate): - - def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): - assert isinstance(dn, DN) -- check_fips_auth_opts(fips_mode=self.api.env.fips_mode, **options) -- - if 'ipadefaultprimarygroup' in entry_attrs: - group=entry_attrs['ipadefaultprimarygroup'] - try: --- -2.14.3 - diff --git a/SOURCES/0041-ipa-replica-install-properly-use-the-file-store.patch b/SOURCES/0041-ipa-replica-install-properly-use-the-file-store.patch new file mode 100644 index 0000000..b1e37b0 --- /dev/null +++ b/SOURCES/0041-ipa-replica-install-properly-use-the-file-store.patch @@ -0,0 +1,141 @@ +From d169b6fc759a7586c6b3372db7e81c7862b2f96e Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud <flo@redhat.com> +Date: Wed, 5 Sep 2018 17:36:16 +0200 +Subject: [PATCH] ipa-replica-install: properly use the file store + +In ipa-replica-install, many components use their own instance +of the FileStore to backup configuration files to the pre-install +state. This causes issues when the calls are mixed, like for +instance: +ds.do_task1_that_backups_file (using ds.filestore) +http.do_task2_that_backups_file (using http.filestore) +ds.do_task3_that_backups_file (using ds.filestore) + +because the list of files managed by ds.filestore does not include +the files managed by http.filestore, and the 3rd call would remove +any file added on 2nd call. + +The symptom of this bug is that ipa-replica-install does not save +/etc/httpd/conf.d/ssl.conf and subsequent uninstallation does not +restore the file, leading to a line referring to ipa-rewrite.conf +that prevents httpd startup. + +The installer should consistently use the same filestore. + +Fixes https://pagure.io/freeipa/issue/7684 + +Reviewed-By: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Christian Heimes <cheimes@redhat.com> +--- + ipaserver/install/server/replicainstall.py | 31 +++++++++++++--------- + 1 file changed, 18 insertions(+), 13 deletions(-) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 396d6089449225cc83aa28552a2009b9057e65ab..525a62c474c7429b7efee4853eb71e487e656bba 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -79,7 +79,7 @@ def make_pkcs12_info(directory, cert_name, password_name): + + + def install_replica_ds(config, options, ca_is_configured, remote_api, +- ca_file, promote=False, pkcs12_info=None): ++ ca_file, promote=False, pkcs12_info=None, fstore=None): + dsinstance.check_ports() + + # if we have a pkcs12 file, create the cert db from +@@ -95,7 +95,8 @@ def install_replica_ds(config, options, ca_is_configured, remote_api, + ca_subject = installutils.default_ca_subject_dn(config.subject_base) + + ds = dsinstance.DsInstance( +- config_ldif=options.dirsrv_config_file) ++ config_ldif=options.dirsrv_config_file, ++ fstore=fstore) + ds.create_replica( + realm_name=config.realm_name, + master_fqdn=config.master_host_name, +@@ -115,8 +116,9 @@ def install_replica_ds(config, options, ca_is_configured, remote_api, + return ds + + +-def install_krb(config, setup_pkinit=False, pkcs12_info=None, promote=False): +- krb = krbinstance.KrbInstance() ++def install_krb(config, setup_pkinit=False, pkcs12_info=None, promote=False, ++ fstore=None): ++ krb = krbinstance.KrbInstance(fstore=fstore) + + # pkinit files + if pkcs12_info is None: +@@ -153,7 +155,8 @@ def install_ca_cert(ldap, base_dn, realm, cafile, destfile=paths.IPA_CA_CRT): + + def install_http(config, auto_redirect, ca_is_configured, ca_file, + promote=False, +- pkcs12_info=None): ++ pkcs12_info=None, ++ fstore=None): + # if we have a pkcs12 file, create the cert db from + # that. Otherwise the ds setup will create the CA + # cert +@@ -161,8 +164,7 @@ def install_http(config, auto_redirect, ca_is_configured, ca_file, + pkcs12_info = make_pkcs12_info(config.dir, "httpcert.p12", + "http_pin.txt") + +- +- http = httpinstance.HTTPInstance() ++ http = httpinstance.HTTPInstance(fstore=fstore) + http.create_instance( + config.realm_name, config.host_name, config.domain_name, + config.dirman_password, pkcs12_info, +@@ -173,14 +175,14 @@ def install_http(config, auto_redirect, ca_is_configured, ca_file, + return http + + +-def install_dns_records(config, options, remote_api): ++def install_dns_records(config, options, remote_api, fstore=None): + + if not bindinstance.dns_container_exists( + ipautil.realm_to_suffix(config.realm_name)): + return + + try: +- bind = bindinstance.BindInstance(api=remote_api) ++ bind = bindinstance.BindInstance(api=remote_api, fstore=fstore) + for ip in config.ips: + reverse_zone = bindinstance.find_reverse_zone(ip, remote_api) + +@@ -1425,10 +1427,11 @@ def install(installer): + remote_api, + ca_file=cafile, + promote=promote, +- pkcs12_info=dirsrv_pkcs12_info) ++ pkcs12_info=dirsrv_pkcs12_info, ++ fstore=fstore) + + # Always try to install DNS records +- install_dns_records(config, options, remote_api) ++ install_dns_records(config, options, remote_api, fstore=fstore) + + ntpinstance.ntp_ldap_enable(config.host_name, ds.suffix, + remote_api.env.realm) +@@ -1449,7 +1452,8 @@ def install(installer): + config, + setup_pkinit=not options.no_pkinit, + pkcs12_info=pkinit_pkcs12_info, +- promote=promote) ++ promote=promote, ++ fstore=fstore) + + if promote: + # We need to point to the master when certmonger asks for +@@ -1479,7 +1483,8 @@ def install(installer): + promote=promote, + pkcs12_info=http_pkcs12_info, + ca_is_configured=ca_enabled, +- ca_file=cafile) ++ ca_file=cafile, ++ fstore=fstore) + + if promote: + # Need to point back to ourself after the cert for HTTP is obtained +-- +2.17.1 + diff --git a/SOURCES/0042-Ensure-that-public-cert-and-CA-bundle-are-readable.patch b/SOURCES/0042-Ensure-that-public-cert-and-CA-bundle-are-readable.patch new file mode 100644 index 0000000..ce6f140 --- /dev/null +++ b/SOURCES/0042-Ensure-that-public-cert-and-CA-bundle-are-readable.patch @@ -0,0 +1,175 @@ +From e4084fc1608cd13e73ce201471ff518105f4b9f5 Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Fri, 22 Jun 2018 12:17:23 +0200 +Subject: [PATCH] Ensure that public cert and CA bundle are readable + +In CIS hardened mode, the process umask is 027. This results in some +files not being world readable. Ensure that write_certificate_list() +calls in client installer, server installer, and upgrader create cert +bundles with permission bits 0644. + +Fixes: https://pagure.io/freeipa/issue/7594 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +--- + ipaclient/install/client.py | 10 +++++++--- + ipaclient/install/ipa_certupdate.py | 4 ++-- + ipalib/x509.py | 5 ++++- + ipaserver/install/cainstance.py | 2 +- + ipaserver/install/httpinstance.py | 2 +- + ipaserver/install/installutils.py | 6 +++++- + ipaserver/install/krbinstance.py | 2 +- + ipaserver/install/server/replicainstall.py | 2 +- + 8 files changed, 22 insertions(+), 11 deletions(-) + +diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py +index 0fbe31b762561b3e2ee2f35a666a93de8857bced..a1c74b41f790917a302ab32f6be7a4d23a989708 100644 +--- a/ipaclient/install/client.py ++++ b/ipaclient/install/client.py +@@ -1837,7 +1837,7 @@ def get_ca_certs(fstore, options, server, basedn, realm): + + if ca_certs is not None: + try: +- x509.write_certificate_list(ca_certs, ca_file) ++ x509.write_certificate_list(ca_certs, ca_file, mode=0o644) + except Exception as e: + if os.path.exists(ca_file): + try: +@@ -2775,10 +2775,14 @@ def _install(options): + + x509.write_certificate_list( + [c for c, n, t, u in ca_certs if t is not False], +- paths.KDC_CA_BUNDLE_PEM) ++ paths.KDC_CA_BUNDLE_PEM, ++ mode=0o644 ++ ) + x509.write_certificate_list( + [c for c, n, t, u in ca_certs if t is not False], +- paths.CA_BUNDLE_PEM) ++ paths.CA_BUNDLE_PEM, ++ mode=0o644 ++ ) + + # Add the CA certificates to the IPA NSS database + logger.debug("Adding CA certificates to the IPA NSS database.") +diff --git a/ipaclient/install/ipa_certupdate.py b/ipaclient/install/ipa_certupdate.py +index 875cd7000c09aee044c5141a889617c9195182b1..878af250428fbf122c048d612fefc17e4ea674ff 100644 +--- a/ipaclient/install/ipa_certupdate.py ++++ b/ipaclient/install/ipa_certupdate.py +@@ -187,10 +187,10 @@ def update_server(certs): + update_file(paths.CACERT_PEM, certs) + + +-def update_file(filename, certs, mode=0o444): ++def update_file(filename, certs, mode=0o644): + certs = (c[0] for c in certs if c[2] is not False) + try: +- x509.write_certificate_list(certs, filename) ++ x509.write_certificate_list(certs, filename, mode=mode) + except Exception as e: + logger.error("failed to update %s: %s", filename, e) + +diff --git a/ipalib/x509.py b/ipalib/x509.py +index 67a9af4c5d3456f8cdd6d966373be75d7036f1b7..cfacfa6fc784a4bc1559d68da0cc505874346e22 100644 +--- a/ipalib/x509.py ++++ b/ipalib/x509.py +@@ -36,6 +36,7 @@ import datetime + import ipaddress + import ssl + import base64 ++import os + import re + + from cryptography import x509 as crypto_x509 +@@ -519,7 +520,7 @@ def write_certificate(cert, filename): + raise errors.FileError(reason=str(e)) + + +-def write_certificate_list(certs, filename): ++def write_certificate_list(certs, filename, mode=None): + """ + Write a list of certificates to a file in PEM format. + +@@ -529,6 +530,8 @@ def write_certificate_list(certs, filename): + + try: + with open(filename, 'wb') as f: ++ if mode is not None: ++ os.fchmod(f.fileno(), mode) + for cert in certs: + f.write(cert.public_bytes(Encoding.PEM)) + except (IOError, OSError) as e: +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index ffcebd719a16ebc5a991b35507b96411ad31eb10..d6e467097808594756d947fa721b8cf10fe7d043 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -848,7 +848,7 @@ class CAInstance(DogtagInstance): + for path in [paths.IPA_CA_CRT, + paths.KDC_CA_BUNDLE_PEM, + paths.CA_BUNDLE_PEM]: +- x509.write_certificate_list(certlist, path) ++ x509.write_certificate_list(certlist, path, mode=0o644) + + def __request_ra_certificate(self): + """ +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index 3f83248dd89118aeecfbf458c5079dde8b2cb93d..05b88998353597aebc39b6dad5e1a688dca84f49 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -481,7 +481,7 @@ class HTTPInstance(service.Service): + raise RuntimeError("HTTPD cert was issued by an unknown CA.") + # at this time we can assume any CA cert will be valid since this is + # only run during installation +- x509.write_certificate_list(certlist, paths.CA_CRT) ++ x509.write_certificate_list(certlist, paths.CA_CRT, mode=0o644) + + def is_kdcproxy_configured(self): + """Check if KDC proxy has already been configured in the past""" +diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py +index 6614da69a0a046cdfa1b309f77972ead9de1279f..64beeffaebc4bcfe2b11dbf1109e54d7a9479d67 100644 +--- a/ipaserver/install/installutils.py ++++ b/ipaserver/install/installutils.py +@@ -1314,7 +1314,11 @@ def load_external_cert(files, ca_subject): + cert_file.flush() + + ca_file = tempfile.NamedTemporaryFile() +- x509.write_certificate_list(ca_cert_chain[1:], ca_file.name) ++ x509.write_certificate_list( ++ ca_cert_chain[1:], ++ ca_file.name, ++ mode=0o644 ++ ) + ca_file.flush() + + return cert_file, ca_file +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index 09cafb7b84623594fe88083f5b914cee0f050409..a3079bd6304a41116f9aa5e78b6c6c71d72d7aa6 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -495,7 +495,7 @@ class KrbInstance(service.Service): + self.api.env.realm, + False) + ca_certs = [c for c, _n, t, _u in ca_certs if t is not False] +- x509.write_certificate_list(ca_certs, paths.CACERT_PEM) ++ x509.write_certificate_list(ca_certs, paths.CACERT_PEM, mode=0o644) + + def issue_selfsigned_pkinit_certs(self): + self._call_certmonger(certmonger_ca="SelfSign") +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 525a62c474c7429b7efee4853eb71e487e656bba..eb354f81ba6e4cbc3848f9c24338fb85cc7639ae 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -147,7 +147,7 @@ def install_ca_cert(ldap, base_dn, realm, cafile, destfile=paths.IPA_CA_CRT): + pass + else: + certs = [c[0] for c in certs if c[2] is not False] +- x509.write_certificate_list(certs, destfile) ++ x509.write_certificate_list(certs, destfile, mode=0o644) + except Exception as e: + raise ScriptError("error copying files: " + str(e)) + return destfile +-- +2.17.1 + diff --git a/SOURCES/0042-Log-errors-from-NSS-during-FIPS-OTP-key-import.patch b/SOURCES/0042-Log-errors-from-NSS-during-FIPS-OTP-key-import.patch deleted file mode 100644 index 4ee49e1..0000000 --- a/SOURCES/0042-Log-errors-from-NSS-during-FIPS-OTP-key-import.patch +++ /dev/null @@ -1,59 +0,0 @@ -From b9194a0292ce57418b3c9f5faf2ee5509f0fb749 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood <rharwood@redhat.com> -Date: Thu, 1 Mar 2018 14:25:55 -0500 -Subject: [PATCH] Log errors from NSS during FIPS OTP key import - -Signed-off-by: Robbie Harwood <rharwood@redhat.com> -Reviewed-By: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Petr Vobornik <pvoborni@redhat.com> ---- - daemons/ipa-slapi-plugins/libotp/hotp.c | 16 ++++++++++++++-- - 1 file changed, 14 insertions(+), 2 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/libotp/hotp.c b/daemons/ipa-slapi-plugins/libotp/hotp.c -index 0c9de96d37183e597867b736d6324db60fa1b3bb..1b9110ebf89a705c9c670d4d33fc7ed615ad25f3 100644 ---- a/daemons/ipa-slapi-plugins/libotp/hotp.c -+++ b/daemons/ipa-slapi-plugins/libotp/hotp.c -@@ -49,7 +49,9 @@ - #include <blapit.h> - #include <pk11pub.h> - #include <hasht.h> -+#include <prerror.h> - #include <prnetdb.h> -+#include <syslog.h> - - struct digest_buffer { - uint8_t buf[SHA512_LENGTH]; -@@ -93,17 +95,27 @@ import_key(PK11SlotInfo *slot, CK_MECHANISM_TYPE mech, SECItem *key) - PK11_ATTR_SESSION | - PK11_ATTR_PRIVATE | - PK11_ATTR_SENSITIVE, NULL); -- if (!ekey) -+ if (!ekey) { -+ syslog(LOG_ERR, "libotp: in FIPS, PK11_TokenKeyGenWithFlags failed: %d", -+ PR_GetError()); - goto egress; -+ } - - /* Encrypt the input key. */ - if (PK11_Encrypt(ekey, CKM_AES_CBC_PAD, &ivitem, ctitem.data, &ctitem.len, -- ctitem.len, key->data, key->len) != SECSuccess) -+ ctitem.len, key->data, key->len) != SECSuccess) { -+ syslog(LOG_ERR, "libotp: in FIPS, PK11_Encrypt failed: %d", -+ PR_GetError()); - goto egress; -+ } - - /* Unwrap the input key. */ - skey = PK11_UnwrapSymKey(ekey, CKM_AES_CBC_PAD, &ivitem, - &ctitem, mech, CKA_SIGN, key->len); -+ if (!skey) { -+ syslog(LOG_ERR, "libotp: in FIPS, PK11_UnwrapSymKey failed: %d", -+ PR_GetError()); -+ } - - egress: - PK11_FreeSymKey(ekey); --- -2.14.3 - diff --git a/SOURCES/0043-Always-make-ipa.p11-kit-world-readable.patch b/SOURCES/0043-Always-make-ipa.p11-kit-world-readable.patch new file mode 100644 index 0000000..48c83c6 --- /dev/null +++ b/SOURCES/0043-Always-make-ipa.p11-kit-world-readable.patch @@ -0,0 +1,31 @@ +From 8ba1a1e89b34e587a9898a85f1c545dbd1c7765a Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Fri, 22 Jun 2018 12:22:06 +0200 +Subject: [PATCH] Always make ipa.p11-kit world-readable + +Ensure that ipa.p11-kit is always world-readable. + +Fixes: https://pagure.io/freeipa/issue/7594 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +--- + ipaplatform/redhat/tasks.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/ipaplatform/redhat/tasks.py b/ipaplatform/redhat/tasks.py +index 6a4270defc9f444f76677bdf08d2a680649664bb..8fc8b54c146d540c988d97b7fb0927fced7c3e29 100644 +--- a/ipaplatform/redhat/tasks.py ++++ b/ipaplatform/redhat/tasks.py +@@ -269,6 +269,7 @@ class RedHatTaskNamespace(BaseTaskNamespace): + + try: + f = open(new_cacert_path, 'w') ++ os.fchmod(f.fileno(), 0o644) + except IOError as e: + logger.info("Failed to open %s: %s", new_cacert_path, e) + return False +-- +2.17.1 + diff --git a/SOURCES/0043-ipa-replica-install-make-sure-that-certmonger-picks-.patch b/SOURCES/0043-ipa-replica-install-make-sure-that-certmonger-picks-.patch deleted file mode 100644 index 0a475e2..0000000 --- a/SOURCES/0043-ipa-replica-install-make-sure-that-certmonger-picks-.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 13d111faedfd5cbd0a7382e566edda7bd9ffc7ad Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud <flo@redhat.com> -Date: Wed, 14 Mar 2018 16:13:17 +0100 -Subject: [PATCH] ipa-replica-install: make sure that certmonger picks the - right master - -During ipa-replica-install, http installation first creates a service -principal for http/hostname (locally on the soon-to-be-replica), then -waits for this entry to be replicated on the master picked for the -install. -In a later step, the installer requests a certificate for HTTPd. The local -certmonger first tries the master defined in xmlrpc_uri (which is -pointing to the soon-to-be-replica), but fails because the service is not -up yet. Then certmonger tries to find a master by using the DNS and looking -for a ldap service. This step can pick a different master, where the -principal entry has not always be replicated yet. -As the certificate request adds the principal if it does not exist, we can -end by re-creating the principal and have a replication conflict. - -The replication conflict later causes kerberos issues, preventing -from installing a new replica. - -The proposed fix forces xmlrpc_uri to point to the same master as the one -picked for the installation, in order to make sure that the master already -contains the principal entry. - -https://pagure.io/freeipa/issue/7041 - -Reviewed-By: Rob Crittenden <rcritten@redhat.com> -Reviewed-By: Rob Crittenden <rcritten@redhat.com> ---- - ipaserver/install/server/replicainstall.py | 42 +++++++++++++++++++++++++++--- - 1 file changed, 39 insertions(+), 3 deletions(-) - -diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index 6aa1157133423e854514de61a69810433e436d2f..5a37aea0ac913d5c9cb88346345ba5760a9e923d 100644 ---- a/ipaserver/install/server/replicainstall.py -+++ b/ipaserver/install/server/replicainstall.py -@@ -194,7 +194,16 @@ def install_dns_records(config, options, remote_api): - 'on master: %s', str(e)) - - --def create_ipa_conf(fstore, config, ca_enabled): -+def create_ipa_conf(fstore, config, ca_enabled, master=None): -+ """ -+ Create /etc/ipa/default.conf master configuration -+ :param fstore: sysrestore file store used for backup and restore of -+ the server configuration -+ :param config: replica config -+ :param ca_enabled: True if the topology includes a CA -+ :param master: if set, the xmlrpc_uri parameter will use the provided -+ master instead of this host -+ """ - # Save client file on Domain Level 1 - target_fname = paths.IPA_DEFAULT_CONF - fstore.backup_file(target_fname) -@@ -203,8 +212,12 @@ def create_ipa_conf(fstore, config, ca_enabled): - ipaconf.setOptionAssignment(" = ") - ipaconf.setSectionNameDelimiters(("[", "]")) - -- xmlrpc_uri = 'https://{0}/ipa/xml'.format( -- ipautil.format_netloc(config.host_name)) -+ if master: -+ xmlrpc_uri = 'https://{0}/ipa/xml'.format( -+ ipautil.format_netloc(master)) -+ else: -+ xmlrpc_uri = 'https://{0}/ipa/xml'.format( -+ ipautil.format_netloc(config.host_name)) - ldapi_uri = 'ldapi://%2fvar%2frun%2fslapd-{0}.socket\n'.format( - installutils.realm_to_serverid(config.realm_name)) - -@@ -1431,6 +1444,25 @@ def install(installer): - # we now need to enable ssl on the ds - ds.enable_ssl() - -+ if promote: -+ # We need to point to the master when certmonger asks for -+ # HTTP certificate. -+ # During http installation, the HTTP/hostname principal is created -+ # locally then the installer waits for the entry to appear on the -+ # master selected for the installation. -+ # In a later step, the installer requests a SSL certificate through -+ # Certmonger (and the op adds the principal if it does not exist yet). -+ # If xmlrpc_uri points to the soon-to-be replica, -+ # the httpd service is not ready yet to handle certmonger requests -+ # and certmonger tries to find another master. The master can be -+ # different from the one selected for the installation, and it is -+ # possible that the principal has not been replicated yet. This -+ # may lead to a replication conflict. -+ # This is why we need to force the use of the same master by -+ # setting xmlrpc_uri -+ create_ipa_conf(fstore, config, ca_enabled, -+ master=config.master_host_name) -+ - install_http( - config, - auto_redirect=not options.no_ui_redirect, -@@ -1439,6 +1471,10 @@ def install(installer): - ca_is_configured=ca_enabled, - ca_file=cafile) - -+ if promote: -+ # Need to point back to ourself after the cert for HTTP is obtained -+ create_ipa_conf(fstore, config, ca_enabled) -+ - otpd = otpdinstance.OtpdInstance() - otpd.create_instance('OTPD', config.host_name, - ipautil.realm_to_suffix(config.realm_name)) --- -2.14.3 - diff --git a/SOURCES/0044-Make-etc-httpd-alias-world-readable-executable.patch b/SOURCES/0044-Make-etc-httpd-alias-world-readable-executable.patch new file mode 100644 index 0000000..f7b0c12 --- /dev/null +++ b/SOURCES/0044-Make-etc-httpd-alias-world-readable-executable.patch @@ -0,0 +1,37 @@ +From 9bb9255161eef8da54842c0a6aeb1ddb0b20c0df Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Fri, 22 Jun 2018 12:25:33 +0200 +Subject: [PATCH] Make /etc/httpd/alias world readable & executable + +The directory /etc/httpd/alias contains public key material. It must be +world readable and executable, so any client can read public certs. + +Note: executable for a directory means, that a process is allowed to +traverse into the directory. + +Fixes: https://pagure.io/freeipa/issue/7594 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +--- + ipaserver/install/httpinstance.py | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index 05b88998353597aebc39b6dad5e1a688dca84f49..3f8b18c4e8412c1767b6ad541da18d8b30ad59f7 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -217,6 +217,9 @@ class HTTPInstance(service.Service): + self.update_httpd_service_ipa_conf() + self.update_httpd_wsgi_conf() + ++ # Must be world-readable / executable ++ os.chmod(paths.HTTPD_ALIAS_DIR, 0o755) ++ + target_fname = paths.HTTPD_IPA_CONF + http_txt = ipautil.template_file( + os.path.join(paths.USR_SHARE_IPA_DIR, "ipa.conf"), self.sub_dict) +-- +2.17.1 + diff --git a/SOURCES/0044-replica-install-pass-ip-address-to-client-install.patch b/SOURCES/0044-replica-install-pass-ip-address-to-client-install.patch deleted file mode 100644 index cdb3af3..0000000 --- a/SOURCES/0044-replica-install-pass-ip-address-to-client-install.patch +++ /dev/null @@ -1,38 +0,0 @@ -From d1506d6a44b4c4b85772cd0764113f2b20a147fe Mon Sep 17 00:00:00 2001 -From: Stanislav Laznicka <slaznick@redhat.com> -Date: Fri, 6 Apr 2018 09:10:20 +0200 -Subject: [PATCH] replica-install: pass --ip-address to client install - -In replica DL1 installation, the --ip-address option was not passed -down to the ipa-client-install script (when not promoting client). -This resulted in creating DNS records for all of the host's interface -IP adresses instead of just those specified. - -This patch passes all the --ip-address options down to the client -installation script. - -https://pagure.io/freeipa/issue/7405 - -Reviewed-By: Stanislav Laznicka <slaznick@redhat.com> ---- - ipaserver/install/server/replicainstall.py | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index 5a37aea0ac913d5c9cb88346345ba5760a9e923d..42e4615ad2dc1f604f5d8d14f8e57e3e4674bcb9 100644 ---- a/ipaserver/install/server/replicainstall.py -+++ b/ipaserver/install/server/replicainstall.py -@@ -942,6 +942,10 @@ def ensure_enrolled(installer): - args.append("--mkhomedir") - if installer.force_join: - args.append("--force-join") -+ if installer.ip_addresses: -+ for ip in installer.ip_addresses: -+ # installer.ip_addresses is of type [CheckedIPAddress] -+ args.extend(("--ip-address", str(ip))) - - try: - # Call client install script --- -2.14.3 - diff --git a/SOURCES/0045-Add-nsds5ReplicaReleaseTimeout-to-replica-config.patch b/SOURCES/0045-Add-nsds5ReplicaReleaseTimeout-to-replica-config.patch deleted file mode 100644 index 7dea73f..0000000 --- a/SOURCES/0045-Add-nsds5ReplicaReleaseTimeout-to-replica-config.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 7076fd22e744fd51dbcc0c4e4a4089884a3dae48 Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Wed, 11 Apr 2018 13:34:41 +0200 -Subject: [PATCH] Add nsds5ReplicaReleaseTimeout to replica config - -The nsds5ReplicaReleaseTimeout setting prevents the monopolization of -replicas during initial or busy master-master replication. 389-DS -documentation suggets a timeout of 60 seconds to improve convergence of -replicas. - -See: http://directory.fedoraproject.org/docs/389ds/design/repl-conv-design.html -Fixes: https://pagure.io/freeipa/issue/7488 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> -Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> ---- - ipaserver/install/replication.py | 21 ++++++++++++++++----- - ipaserver/install/server/upgrade.py | 17 +++++++++++++++++ - 2 files changed, 33 insertions(+), 5 deletions(-) - -diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py -index 3cd871e5df44398fd994504a3807a5648af5e048..e0055b792ce5b51fd411a7ea1f4316bb017984ba 100644 ---- a/ipaserver/install/replication.py -+++ b/ipaserver/install/replication.py -@@ -468,20 +468,30 @@ class ReplicationManager(object): - - try: - entry = conn.get_entry(dn) -+ except errors.NotFound: -+ pass -+ else: - managers = {DN(m) for m in entry.get('nsDS5ReplicaBindDN', [])} - -+ mods = [] - if replica_binddn not in managers: - # Add the new replication manager -- mod = [(ldap.MOD_ADD, 'nsDS5ReplicaBindDN', -- replica_binddn)] -- conn.modify_s(dn, mod) -+ mods.append( -+ (ldap.MOD_ADD, 'nsDS5ReplicaBindDN', replica_binddn) -+ ) -+ if 'nsds5replicareleasetimeout' not in entry: -+ # See https://pagure.io/freeipa/issue/7488 -+ mods.append( -+ (ldap.MOD_ADD, 'nsds5replicareleasetimeout', ['60']) -+ ) -+ -+ if mods: -+ conn.modify_s(dn, mods) - - self.set_replica_binddngroup(conn, entry) - - # replication is already configured - return -- except errors.NotFound: -- pass - - replica_type = self.get_replica_type() - -@@ -496,6 +506,7 @@ class ReplicationManager(object): - nsds5replicabinddn=[replica_binddn], - nsds5replicabinddngroup=[self.repl_man_group_dn], - nsds5replicabinddngroupcheckinterval=["60"], -+ nsds5replicareleasetimeout=["60"], - nsds5replicalegacyconsumer=["off"], - ) - conn.add_entry(entry) -diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py -index 62665d56ca0fb2c632f8ba135f8b6191a18b6aa1..62a75510ad331923f468c28908ea407789ec380c 100644 ---- a/ipaserver/install/server/upgrade.py -+++ b/ipaserver/install/server/upgrade.py -@@ -1565,6 +1565,19 @@ def disable_httpd_system_trust(http): - db.add_cert(cert, nickname, trust_flags) - - -+def update_replica_config(db_suffix): -+ dn = DN( -+ ('cn', 'replica'), ('cn', db_suffix), ('cn', 'mapping tree'), -+ ('cn', 'config') -+ ) -+ entry = api.Backend.ldap2.get_entry(dn) -+ if 'nsds5replicareleasetimeout' not in entry: -+ # See https://pagure.io/freeipa/issue/7488 -+ root_logger.info("Adding nsds5replicaReleaseTimeout=60 to %s", dn) -+ entry['nsds5replicareleasetimeout'] = '60' -+ api.Backend.ldap2.update_entry(entry) -+ -+ - def upgrade_configuration(): - """ - Execute configuration upgrade of the IPA services -@@ -1681,6 +1694,10 @@ def upgrade_configuration(): - - ds.configure_dirsrv_ccache() - -+ update_replica_config(ipautil.realm_to_suffix(api.env.realm)) -+ if ca.is_configured(): -+ update_replica_config(DN(('o', 'ipaca'))) -+ - ntpinstance.ntp_ldap_enable(api.env.host, api.env.basedn, api.env.realm) - - ds.stop(ds_serverid) --- -2.14.3 - diff --git a/SOURCES/0045-Fix-permission-of-public-files-in-upgrader.patch b/SOURCES/0045-Fix-permission-of-public-files-in-upgrader.patch new file mode 100644 index 0000000..0b81a5c --- /dev/null +++ b/SOURCES/0045-Fix-permission-of-public-files-in-upgrader.patch @@ -0,0 +1,82 @@ +From 19bfd7c36d6d087f0cd7def5eb4d8850c395fb4b Mon Sep 17 00:00:00 2001 +From: Christian Heimes <cheimes@redhat.com> +Date: Fri, 22 Jun 2018 12:53:19 +0200 +Subject: [PATCH] Fix permission of public files in upgrader + +Make CA bundles, certs, and cert directories world-accessible in +upgrader. + +Fixes: https://pagure.io/freeipa/issue/7594 +Signed-off-by: Christian Heimes <cheimes@redhat.com> +Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +Reviewed-By: Rob Crittenden <rcritten@redhat.com> +--- + ipaserver/install/server/upgrade.py | 31 +++++++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 4e5096e598cd10e3bd98f91946b4d26377d0de6e..7faaacd5d2f0c39bcf744c288b283009ccb3ead5 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -4,12 +4,14 @@ + + from __future__ import print_function, absolute_import + ++import errno + import logging + import re + import os + import shutil + import pwd + import fileinput ++import stat + import sys + import tempfile + from contextlib import contextmanager +@@ -1656,6 +1658,34 @@ def update_replica_config(db_suffix): + logger.info("Updated entry %s", dn) + + ++def fix_permissions(): ++ """Fix permission of public accessible files and directories ++ ++ In case IPA was installed with restricted umask, some public files and ++ directories may not be readable and accessible. ++ ++ See https://pagure.io/freeipa/issue/7594 ++ """ ++ candidates = [ ++ paths.HTTPD_ALIAS_DIR, ++ paths.CA_BUNDLE_PEM, ++ paths.KDC_CA_BUNDLE_PEM, ++ paths.IPA_CA_CRT, ++ paths.IPA_P11_KIT, ++ ] ++ for filename in candidates: ++ try: ++ s = os.stat(filename) ++ except OSError as e: ++ if e.errno != errno.ENOENT: ++ raise ++ continue ++ mode = 0o755 if stat.S_ISDIR(s.st_mode) else 0o644 ++ if mode != stat.S_IMODE(s.st_mode): ++ logger.debug("Fix permission of %s to %o", filename, mode) ++ os.chmod(filename, mode) ++ ++ + def upgrade_configuration(): + """ + Execute configuration upgrade of the IPA services +@@ -1677,6 +1707,7 @@ def upgrade_configuration(): + ds.start(ds_serverid) + + check_certs() ++ fix_permissions() + + auto_redirect = find_autoredirect(fqdn) + sub_dict = dict( +-- +2.17.1 + diff --git a/SOURCES/0046-Fix-upgrade-update_replica_config-in-single-master-m.patch b/SOURCES/0046-Fix-upgrade-update_replica_config-in-single-master-m.patch deleted file mode 100644 index 78b5617..0000000 --- a/SOURCES/0046-Fix-upgrade-update_replica_config-in-single-master-m.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 6d868b2dd17ada072553c8d7440ee6fbd95a052a Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale <ftweedal@redhat.com> -Date: Mon, 16 Apr 2018 16:02:03 +1000 -Subject: [PATCH] Fix upgrade (update_replica_config) in single master mode - -Commit afc0d4b62d043cd568ce87400f60e8fa8273495f added an upgrade -step that add an attribute to a replica config entry. The entry -only exists after a replica has been added, so upgrade was broken -for standalone server. Catch and suppress the NotFound error. - -Related to: https://pagure.io/freeipa/issue/7488 - -Reviewed-By: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> ---- - ipaserver/install/server/upgrade.py | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py -index 62a75510ad331923f468c28908ea407789ec380c..c55242a4af990c3218d8451fac7b082066a23be3 100644 ---- a/ipaserver/install/server/upgrade.py -+++ b/ipaserver/install/server/upgrade.py -@@ -1570,7 +1570,11 @@ def update_replica_config(db_suffix): - ('cn', 'replica'), ('cn', db_suffix), ('cn', 'mapping tree'), - ('cn', 'config') - ) -- entry = api.Backend.ldap2.get_entry(dn) -+ try: -+ entry = api.Backend.ldap2.get_entry(dn) -+ except ipalib.errors.NotFound: -+ return # entry does not exist until a replica is installed -+ - if 'nsds5replicareleasetimeout' not in entry: - # See https://pagure.io/freeipa/issue/7488 - root_logger.info("Adding nsds5replicaReleaseTimeout=60 to %s", dn) --- -2.14.3 - diff --git a/SOURCES/0047-Use-single-Custodia-instance-in-installers.patch b/SOURCES/0047-Use-single-Custodia-instance-in-installers.patch deleted file mode 100644 index 6ff3f36..0000000 --- a/SOURCES/0047-Use-single-Custodia-instance-in-installers.patch +++ /dev/null @@ -1,620 +0,0 @@ -From 11e597217fe6f1dcee3a918eef0bc3a0d2928e6d Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Thu, 26 Apr 2018 12:06:36 +0200 -Subject: [PATCH] Use single Custodia instance in installers - -Installers now pass a single CustodiaInstance object around, instead of -creating new instances on demand. In case of replica promotion with CA, -the instance gets all secrets from a master with CA present. Before, an -installer created multiple instances and may have requested CA key -material from a different machine than DM password hash. - -In case of Domain Level 1 and replica promotion, the CustodiaInstance no -longer adds the keys to the local instance and waits for replication to -other replica. Instead the installer directly uploads the new public -keys to the remote 389-DS instance. - -Without promotion, new Custodia public keys are still added to local -389-DS over LDAPI. - -Fixes: https://pagure.io/freeipa/issue/7518 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Simo Sorce <ssorce@redhat.com> -Reviewed-By: Simo Sorce <ssorce@redhat.com> ---- - install/tools/ipa-ca-install | 13 ++- - ipaserver/install/ca.py | 26 +++-- - ipaserver/install/cainstance.py | 9 +- - ipaserver/install/custodiainstance.py | 150 ++++++++++++++++++++++------- - ipaserver/install/ipa_kra_install.py | 10 +- - ipaserver/install/kra.py | 6 +- - ipaserver/install/server/install.py | 14 +-- - ipaserver/install/server/replicainstall.py | 15 +-- - 8 files changed, 165 insertions(+), 78 deletions(-) - -diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install -index f84b4749a3e2a80aca002a2aa057b200e6187f18..a3694007e5815d1c44f642057c749879d336dfc5 100755 ---- a/install/tools/ipa-ca-install -+++ b/install/tools/ipa-ca-install -@@ -31,6 +31,7 @@ from ipaserver.install.installutils import create_replica_config - from ipaserver.install.installutils import check_creds, ReplicaConfig - from ipaserver.install import dsinstance, ca - from ipaserver.install import cainstance, service -+from ipaserver.install import custodiainstance - from ipapython import version - from ipalib import api - from ipalib.constants import DOMAIN_LEVEL_0 -@@ -193,13 +194,17 @@ def install_replica(safe_options, options, filename): - options.domain_name = config.domain_name - options.dm_password = config.dirman_password - options.host_name = config.host_name -+ options.ca_host_name = config.ca_host_name - if os.path.exists(cafile): - options.ca_cert_file = cafile - else: - options.ca_cert_file = None - - ca.install_check(True, config, options) -- ca.install(True, config, options) -+ -+ custodia = custodiainstance.get_custodia_instance( -+ options, custodiainstance.CustodiaModes.CA_PEER) -+ ca.install(True, config, options, custodia=custodia) - - - def install_master(safe_options, options): -@@ -228,7 +233,11 @@ def install_master(safe_options, options): - sys.exit("CA subject: {}".format(e.message)) - - ca.install_check(True, None, options) -- ca.install(True, None, options) -+ -+ # No CA peer available yet. -+ custodia = custodiainstance.get_custodia_instance( -+ options, custodiainstance.CustodiaModes.STANDALONE) -+ ca.install(True, None, options, custodia=custodia) - - - def install(safe_options, options, filename): -diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py -index 52cb20f1cb3612394544a6a41f10e9e939bc0657..2ac4382ccd24d217832950b94baddd113f7a8930 100644 ---- a/ipaserver/install/ca.py -+++ b/ipaserver/install/ca.py -@@ -19,10 +19,7 @@ from ipalib.install.service import enroll_only, master_install_only, replica_ins - from ipaserver.install import sysupgrade - from ipapython.install import typing - from ipapython.install.core import group, knob, extend_knob --from ipaserver.install import (cainstance, -- custodiainstance, -- dsinstance, -- bindinstance) -+from ipaserver.install import cainstance, bindinstance, dsinstance - from ipapython import ipautil, certdb - from ipapython.admintool import ScriptError - from ipaplatform import services -@@ -201,12 +198,12 @@ def install_check(standalone, replica_config, options): - "cannot continue." % (subject, db.secdir)) - - --def install(standalone, replica_config, options): -- install_step_0(standalone, replica_config, options) -- install_step_1(standalone, replica_config, options) -+def install(standalone, replica_config, options, custodia): -+ install_step_0(standalone, replica_config, options, custodia=custodia) -+ install_step_1(standalone, replica_config, options, custodia=custodia) - - --def install_step_0(standalone, replica_config, options): -+def install_step_0(standalone, replica_config, options, custodia): - realm_name = options.realm_name - dm_password = options.dm_password - host_name = options.host_name -@@ -237,9 +234,6 @@ def install_step_0(standalone, replica_config, options): - else: - cafile = os.path.join(replica_config.dir, 'cacert.p12') - if options.promote: -- custodia = custodiainstance.CustodiaInstance( -- replica_config.host_name, -- replica_config.realm_name) - custodia.get_ca_keys( - replica_config.ca_host_name, - cafile, -@@ -266,7 +260,9 @@ def install_step_0(standalone, replica_config, options): - 'certmap.conf', 'subject_base', str(subject_base)) - dsinstance.write_certmap_conf(realm_name, ca_subject) - -- ca = cainstance.CAInstance(realm_name, host_name=host_name) -+ ca = cainstance.CAInstance( -+ realm=realm_name, host_name=host_name, custodia=custodia -+ ) - ca.configure_instance(host_name, dm_password, dm_password, - subject_base=subject_base, - ca_subject=ca_subject, -@@ -284,7 +280,7 @@ def install_step_0(standalone, replica_config, options): - use_ldaps=standalone) - - --def install_step_1(standalone, replica_config, options): -+def install_step_1(standalone, replica_config, options, custodia): - if replica_config is not None and not replica_config.setup_ca: - return - -@@ -293,7 +289,9 @@ def install_step_1(standalone, replica_config, options): - subject_base = options._subject_base - basedn = ipautil.realm_to_suffix(realm_name) - -- ca = cainstance.CAInstance(realm_name, host_name=host_name) -+ ca = cainstance.CAInstance( -+ realm=realm_name, host_name=host_name, custodia=custodia -+ ) - - ca.stop('pki-tomcat') - -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index 20635eae22268ff72de73b8b9c430050114bb45b..eefc30b6e01dcf744703b8607cbe169fbec5d859 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -59,7 +59,6 @@ from ipapython.ipa_log_manager import log_mgr,\ - from ipaserver.secrets.kem import IPAKEMKeys - - from ipaserver.install import certs --from ipaserver.install import custodiainstance - from ipaserver.install import dsinstance - from ipaserver.install import installutils - from ipaserver.install import ldapupdate -@@ -285,7 +284,7 @@ class CAInstance(DogtagInstance): - 'caSigningCert cert-pki-ca') - server_cert_name = 'Server-Cert cert-pki-ca' - -- def __init__(self, realm=None, host_name=None): -+ def __init__(self, realm=None, host_name=None, custodia=None): - super(CAInstance, self).__init__( - realm=realm, - subsystem="CA", -@@ -310,6 +309,8 @@ class CAInstance(DogtagInstance): - self.no_db_setup = False - self.keytab = os.path.join( - paths.PKI_TOMCAT, self.service_prefix + '.keytab') -+ # Custodia instance for RA key retrieval -+ self._custodia = custodia - - def configure_instance(self, host_name, dm_password, admin_password, - pkcs12_info=None, master_host=None, csr_file=None, -@@ -711,9 +712,7 @@ class CAInstance(DogtagInstance): - self.configure_agent_renewal() - - def __import_ra_key(self): -- custodia = custodiainstance.CustodiaInstance(host_name=self.fqdn, -- realm=self.realm) -- custodia.import_ra_key(self.master_host) -+ self._custodia.import_ra_key(self.master_host) - self.__set_ra_cert_perms() - - self.configure_agent_renewal() -diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py -index 0a90bb3954486b9773e3553e9981d2a8d0d4e44a..262ae5857c64719ff5cebde31b4b107e1245d458 100644 ---- a/ipaserver/install/custodiainstance.py -+++ b/ipaserver/install/custodiainstance.py -@@ -1,5 +1,9 @@ - # Copyright (C) 2015 FreeIPa Project Contributors, see 'COPYING' for license. - -+from __future__ import print_function, absolute_import -+ -+import enum -+ - from ipaserver.secrets.kem import IPAKEMKeys, KEMLdap - from ipaserver.secrets.client import CustodiaClient - from ipaplatform.paths import paths -@@ -21,12 +25,84 @@ import time - import pwd - - -+class CustodiaModes(enum.Enum): -+ # peer must have a CA -+ CA_PEER = 'Custodia CA peer' -+ # peer must have a CA, KRA preferred -+ KRA_PEER = 'Custodia KRA peer' -+ # any master will do -+ MASTER_PEER = 'Custodia master peer' -+ # standalone / local instance -+ STANDALONE = 'Custodia standalone' -+ -+ -+def get_custodia_instance(config, mode): -+ """Create Custodia instance -+ -+ :param config: configuration/installer object -+ :param mode: CustodiaModes member -+ :return: CustodiaInstance object -+ -+ The config object must have the following attribute -+ -+ *host_name* -+ FQDN of the new replica/master -+ *realm_name* -+ Kerberos realm -+ *promote* -+ True, when instance will be promoted from client to replica -+ *master_host_name* (for *CustodiaModes.MASTER_PEER*) -+ hostname of a master (may not have a CA) -+ *ca_host_name* (for *CustodiaModes.CA_PEER*) -+ hostname of a master with CA -+ *kra_host_name* (for *CustodiaModes.KRA_PEER*) -+ hostname of a master with KRA or CA -+ -+ For promotion, the instance will upload new keys and retrieve secrets -+ from the same host. Therefore it uses *ca_host_name* instead of -+ *master_host_name* to create a replica with CA. -+ """ -+ assert isinstance(mode, CustodiaModes) -+ root_logger.info( -+ "Custodia client for '%r' with promotion %s.", -+ mode, 'yes' if config.promote else 'no' -+ ) -+ if config.promote: -+ if mode == CustodiaModes.CA_PEER: -+ # In case we install replica with CA, prefer CA host as source for -+ # all Custodia secret material. -+ custodia_master = config.ca_host_name -+ elif mode == CustodiaModes.KRA_PEER: -+ custodia_master = config.kra_host_name -+ elif mode == CustodiaModes.MASTER_PEER: -+ custodia_master = config.master_host_name -+ elif mode == CustodiaModes.STANDALONE: -+ custodia_master = None -+ else: -+ custodia_master = None -+ -+ if custodia_master is None: -+ # use ldapi with local dirsrv instance -+ root_logger.info("Custodia uses LDAPI.") -+ ldap_uri = None -+ else: -+ root_logger.info("Custodia uses '%s' as master peer.", -+ custodia_master) -+ ldap_uri = 'ldap://{}'.format(custodia_master) -+ -+ return CustodiaInstance( -+ host_name=config.host_name, -+ realm=config.realm_name, -+ ldap_uri=ldap_uri -+ ) -+ -+ - class CustodiaInstance(SimpleServiceInstance): -- def __init__(self, host_name=None, realm=None): -+ def __init__(self, host_name=None, realm=None, ldap_uri=None): - super(CustodiaInstance, self).__init__("ipa-custodia") - self.config_file = paths.IPA_CUSTODIA_CONF - self.server_keys = paths.IPA_CUSTODIA_KEYS -- self.ldap_uri = None -+ self.ldap_uri = ldap_uri - self.fqdn = host_name - self.realm = realm - -@@ -49,14 +125,19 @@ class CustodiaInstance(SimpleServiceInstance): - ipautil.flush_sync(f) - - def create_instance(self): -- suffix = ipautil.realm_to_suffix(self.realm) -+ if self.ldap_uri is None or self.ldap_uri.startswith('ldapi://'): -+ # local case, ensure container exists -+ self.step("Making sure custodia container exists", -+ self.__create_container) -+ - self.step("Generating ipa-custodia config file", self.__config_file) -- self.step("Making sure custodia container exists", self.__create_container) - self.step("Generating ipa-custodia keys", self.__gen_keys) -- super(CustodiaInstance, self).create_instance(gensvc_name='KEYS', -- fqdn=self.fqdn, -- ldap_suffix=suffix, -- realm=self.realm) -+ super(CustodiaInstance, self).create_instance( -+ gensvc_name='KEYS', -+ fqdn=self.fqdn, -+ ldap_suffix=ipautil.realm_to_suffix(self.realm), -+ realm=self.realm -+ ) - sysupgrade.set_upgrade_state('custodia', 'installed', True) - - def __gen_keys(self): -@@ -81,18 +162,6 @@ class CustodiaInstance(SimpleServiceInstance): - root_logger.info("Secure server.keys mode") - os.chmod(self.server_keys, 0o600) - -- def create_replica(self, master_host_name): -- suffix = ipautil.realm_to_suffix(self.realm) -- self.ldap_uri = 'ldap://%s' % master_host_name -- self.master_host_name = master_host_name -- -- self.step("Generating ipa-custodia config file", self.__config_file) -- self.step("Generating ipa-custodia keys", self.__gen_keys) -- super(CustodiaInstance, self).create_instance(gensvc_name='KEYS', -- fqdn=self.fqdn, -- ldap_suffix=suffix, -- realm=self.realm) -- - def __create_container(self): - """ - Runs the custodia update file to ensure custodia container is present. -@@ -106,7 +175,7 @@ class CustodiaInstance(SimpleServiceInstance): - updater.update([os.path.join(paths.UPDATES_DIR, '73-custodia.update')]) - - def import_ra_key(self, master_host_name): -- cli = self.__CustodiaClient(server=master_host_name) -+ cli = self._get_custodia_client(server=master_host_name) - # please note that ipaCert part has to stay here for historical - # reasons (old servers expect you to ask for ra/ipaCert during - # replication as they store the RA agent cert in an NSS database -@@ -114,14 +183,14 @@ class CustodiaInstance(SimpleServiceInstance): - cli.fetch_key('ra/ipaCert') - - def import_dm_password(self, master_host_name): -- cli = self.__CustodiaClient(server=master_host_name) -+ cli = self._get_custodia_client(server=master_host_name) - cli.fetch_key('dm/DMHash') - -- def __wait_keys(self, host, timeout=300): -+ def _wait_keys(self, host, timeout=300): - ldap_uri = 'ldap://%s' % host - deadline = int(time.time()) + timeout -- root_logger.info("Waiting up to {} seconds to see our keys " -- "appear on host: {}".format(timeout, host)) -+ root_logger.info("Waiting up to %s seconds to see our keys " -+ "appear on host: %s", timeout, host) - - konn = KEMLdap(ldap_uri) - saved_e = None -@@ -129,6 +198,12 @@ class CustodiaInstance(SimpleServiceInstance): - try: - return konn.check_host_keys(self.fqdn) - except Exception as e: -+ # Print message to console only once for first error. -+ if saved_e is None: -+ # FIXME: Change once there's better way to show this -+ # message in installer output, -+ print(" Waiting for keys to appear on host: {}, please " -+ "wait until this has completed.".format(host)) - # log only once for the same error - if not isinstance(e, type(saved_e)): - root_logger.debug( -@@ -138,22 +213,23 @@ class CustodiaInstance(SimpleServiceInstance): - raise RuntimeError("Timed out trying to obtain keys.") - time.sleep(1) - -- def __CustodiaClient(self, server): -+ def _get_custodia_client(self, server): - # Before we attempt to fetch keys from this host, make sure our public - # keys have been replicated there. -- self.__wait_keys(server) -- -- return CustodiaClient('host@%s' % self.fqdn, self.server_keys, -- paths.KRB5_KEYTAB, server, realm=self.realm) -+ self._wait_keys(server) - -- def __get_keys(self, ca_host, cacerts_file, cacerts_pwd, data): -- # Fecth all needed certs one by one, then combine them in a single -- # p12 file -+ return CustodiaClient( -+ client_service='host@{}'.format(self.fqdn), -+ keyfile=self.server_keys, keytab=paths.KRB5_KEYTAB, -+ server=server, realm=self.realm -+ ) - -+ def _get_keys(self, ca_host, cacerts_file, cacerts_pwd, data): -+ # Fetch all needed certs one by one, then combine them in a single -+ # PKCS12 file - prefix = data['prefix'] - certlist = data['list'] -- -- cli = self.__CustodiaClient(server=ca_host) -+ cli = self._get_custodia_client(server=ca_host) - - # Temporary nssdb - tmpnssdir = tempfile.mkdtemp(dir=paths.TMP) -@@ -203,7 +279,7 @@ class CustodiaInstance(SimpleServiceInstance): - 'subsystemCert cert-pki-ca'] - data = {'prefix': 'ca', - 'list': certlist} -- self.__get_keys(ca_host, cacerts_file, cacerts_pwd, data) -+ self._get_keys(ca_host, cacerts_file, cacerts_pwd, data) - - def get_kra_keys(self, ca_host, cacerts_file, cacerts_pwd): - certlist = ['auditSigningCert cert-pki-kra', -@@ -212,7 +288,7 @@ class CustodiaInstance(SimpleServiceInstance): - 'transportCert cert-pki-kra'] - data = {'prefix': 'ca', - 'list': certlist} -- self.__get_keys(ca_host, cacerts_file, cacerts_pwd, data) -+ self._get_keys(ca_host, cacerts_file, cacerts_pwd, data) - - def __start(self): - super(CustodiaInstance, self).__start() -diff --git a/ipaserver/install/ipa_kra_install.py b/ipaserver/install/ipa_kra_install.py -index 3e08f4da94651b49876e1427daddbd957f0027ae..9ebabe057513141ee76d238a3f20e76a27dd932e 100644 ---- a/ipaserver/install/ipa_kra_install.py -+++ b/ipaserver/install/ipa_kra_install.py -@@ -32,6 +32,7 @@ from ipapython import admintool - from ipapython import ipautil - from ipaserver.install import service - from ipaserver.install import cainstance -+from ipaserver.install import custodiainstance - from ipaserver.install import krainstance - from ipaserver.install import dsinstance - from ipaserver.install import installutils -@@ -176,7 +177,6 @@ class KRAInstaller(KRAInstall): - - api.Backend.ldap2.connect() - -- config = None - if self.installing_replica: - if self.options.promote: - config = ReplicaConfig() -@@ -196,6 +196,7 @@ class KRAInstaller(KRAInstall): - config.kra_host_name = config.master_host_name - - config.setup_kra = True -+ config.promote = self.options.promote - - if config.subject_base is None: - attrs = api.Backend.ldap2.get_ipa_config() -@@ -204,6 +205,11 @@ class KRAInstaller(KRAInstall): - if config.kra_host_name is None: - config.kra_host_name = service.find_providing_server( - 'KRA', api.Backend.ldap2, api.env.ca_host) -+ custodia = custodiainstance.get_custodia_instance( -+ config, custodiainstance.CustodiaModes.KRA_PEER) -+ else: -+ config = None -+ custodia = None - - try: - kra.install_check(api, config, self.options) -@@ -213,7 +219,7 @@ class KRAInstaller(KRAInstall): - print(dedent(self.INSTALLER_START_MESSAGE)) - - try: -- kra.install(api, config, self.options) -+ kra.install(api, config, self.options, custodia=custodia) - except: - self.log.error(dedent(self.FAIL_MESSAGE)) - raise -diff --git a/ipaserver/install/kra.py b/ipaserver/install/kra.py -index 3545b301a977f4b7e7801ca1ef87d594bb3ba54f..3333970e8af9e36d6b7614286cc1e774f6eb9b25 100644 ---- a/ipaserver/install/kra.py -+++ b/ipaserver/install/kra.py -@@ -16,7 +16,6 @@ from ipaplatform.paths import paths - from ipapython import certdb - from ipapython import ipautil - from ipapython.install.core import group --from ipaserver.install import custodiainstance - from ipaserver.install import cainstance - from ipaserver.install import krainstance - from ipaserver.install import dsinstance -@@ -68,7 +67,7 @@ def install_check(api, replica_config, options): - "new replica file.") - - --def install(api, replica_config, options): -+def install(api, replica_config, options, custodia): - if replica_config is None: - if not options.setup_kra: - return -@@ -91,9 +90,6 @@ def install(api, replica_config, options): - 'host/{env.host}@{env.realm}'.format(env=api.env), - paths.KRB5_KEYTAB, - ccache) -- custodia = custodiainstance.CustodiaInstance( -- replica_config.host_name, -- replica_config.realm_name) - custodia.get_kra_keys( - replica_config.kra_host_name, - krafile, -diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py -index 422474fa915b4876530f304ef9424f6b31cf26cc..f4338ed0428f7f44decd004f6a183258bef7f795 100644 ---- a/ipaserver/install/server/install.py -+++ b/ipaserver/install/server/install.py -@@ -709,6 +709,7 @@ def install(installer): - host_name = options.host_name - ip_addresses = options.ip_addresses - setup_ca = options.setup_ca -+ options.promote = False # first master, no promotion - - # Installation has started. No IPA sysrestore items are restored in case of - # failure to enable root cause investigation -@@ -789,6 +790,10 @@ def install(installer): - setup_pkinit=not options.no_pkinit, - subject_base=options.subject_base) - -+ custodia = custodiainstance.get_custodia_instance( -+ options, custodiainstance.CustodiaModes.MASTER_PEER) -+ custodia.create_instance() -+ - if setup_ca: - if not options.external_cert_files and options.external_ca: - # stage 1 of external CA installation -@@ -803,7 +808,7 @@ def install(installer): - if n in options.__dict__} - write_cache(cache_vars) - -- ca.install_step_0(False, None, options) -+ ca.install_step_0(False, None, options, custodia=custodia) - else: - # Put the CA cert where other instances expect it - x509.write_certificate(http_ca_cert, paths.IPA_CA_CRT) -@@ -823,15 +828,12 @@ def install(installer): - ds.enable_ssl() - - if setup_ca: -- ca.install_step_1(False, None, options) -+ ca.install_step_1(False, None, options, custodia=custodia) - - otpd = otpdinstance.OtpdInstance() - otpd.create_instance('OTPD', host_name, - ipautil.realm_to_suffix(realm_name)) - -- custodia = custodiainstance.CustodiaInstance(host_name, realm_name) -- custodia.create_instance() -- - # Create a HTTP instance - http = httpinstance.HTTPInstance(fstore) - if options.http_cert_files: -@@ -863,7 +865,7 @@ def install(installer): - krb.restart() - - if options.setup_kra: -- kra.install(api, None, options) -+ kra.install(api, None, options, custodia=custodia) - - if options.setup_dns: - dns.install(False, False, options) -diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index 42e4615ad2dc1f604f5d8d14f8e57e3e4674bcb9..2ecc0abe0c5918cf5aefccc1bd6f09e70503baab 100644 ---- a/ipaserver/install/server/replicainstall.py -+++ b/ipaserver/install/server/replicainstall.py -@@ -1357,6 +1357,7 @@ def install(installer): - fstore = installer._fstore - sstore = installer._sstore - config = installer._config -+ config.promote = installer.promote - promote = installer.promote - cafile = installer._ca_file - dirsrv_pkcs12_info = installer._dirsrv_pkcs12_info -@@ -1483,19 +1484,19 @@ def install(installer): - otpd.create_instance('OTPD', config.host_name, - ipautil.realm_to_suffix(config.realm_name)) - -- custodia = custodiainstance.CustodiaInstance(config.host_name, -- config.realm_name) -- if promote: -- custodia.create_replica(config.master_host_name) -+ if ca_enabled: -+ mode = custodiainstance.CustodiaModes.CA_PEER - else: -- custodia.create_instance() -+ mode = custodiainstance.CustodiaModes.MASTER_PEER -+ custodia = custodiainstance.get_custodia_instance(config, mode) -+ custodia.create_instance() - - 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 -- ca.install(False, config, options) -+ ca.install(False, config, options, custodia=custodia) - - # configure PKINIT now that all required services are in place - krb.enable_ssl() -@@ -1505,7 +1506,7 @@ def install(installer): - ds.apply_updates() - - if kra_enabled: -- kra.install(api, config, options) -+ kra.install(api, config, options, custodia=custodia) - - service.print_msg("Restarting the KDC") - krb.restart() --- -2.14.3 - diff --git a/SOURCES/0048-Don-t-try-to-backup-CS.cfg-during-upgrade-if-CA-is-n.patch b/SOURCES/0048-Don-t-try-to-backup-CS.cfg-during-upgrade-if-CA-is-n.patch deleted file mode 100644 index cd44943..0000000 --- a/SOURCES/0048-Don-t-try-to-backup-CS.cfg-during-upgrade-if-CA-is-n.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 56326828c7ccf75bd867330606c83a621affab9a Mon Sep 17 00:00:00 2001 -From: Rob Crittenden <rcritten@redhat.com> -Date: Mon, 26 Feb 2018 16:13:58 -0500 -Subject: [PATCH] Don't try to backup CS.cfg during upgrade if CA is not - configured - -https://pagure.io/freeipa/issue/7409 - -Signed-off-by: Rob Crittenden <rcritten@redhat.com> -Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> -Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> -Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> ---- - ipaserver/install/server/upgrade.py | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py -index c55242a4af990c3218d8451fac7b082066a23be3..bf603acb5f931a4194320795874859f5bdc94647 100644 ---- a/ipaserver/install/server/upgrade.py -+++ b/ipaserver/install/server/upgrade.py -@@ -1630,7 +1630,8 @@ def upgrade_configuration(): - - with installutils.stopped_service('pki-tomcatd', 'pki-tomcat'): - # Dogtag must be stopped to be able to backup CS.cfg config -- ca.backup_config() -+ if ca.is_configured(): -+ ca.backup_config() - - # migrate CRL publish dir before the location in ipa.conf is updated - ca_restart = migrate_crl_publish_dir(ca) --- -2.14.3 - diff --git a/SOURCES/0049-Use-one-Custodia-peer-to-retrieve-all-secrets.patch b/SOURCES/0049-Use-one-Custodia-peer-to-retrieve-all-secrets.patch deleted file mode 100644 index 44a243a..0000000 --- a/SOURCES/0049-Use-one-Custodia-peer-to-retrieve-all-secrets.patch +++ /dev/null @@ -1,270 +0,0 @@ -From d3c09a6de06d8ae19d05c0b96cb9c2a5b789b472 Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Thu, 7 Jun 2018 18:17:20 +0200 -Subject: [PATCH] Use one Custodia peer to retrieve all secrets - -Fix 994f71ac8a1bb7ba6bc9caf0f6e4f59af44ad9c4 was incomplete. Under some -circumstancs the DM hash and CA keys were still retrieved from two different -machines. - -Custodia client now uses a single remote to upload keys and download all -secrets. - -Fixes: https://pagure.io/freeipa/issue/7518 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Simo Sorce <ssorce@redhat.com> ---- - ipaserver/install/ca.py | 1 - - ipaserver/install/cainstance.py | 2 +- - ipaserver/install/custodiainstance.py | 74 +++++++++++++++++------------- - ipaserver/install/kra.py | 1 - - ipaserver/install/server/install.py | 4 +- - ipaserver/install/server/replicainstall.py | 2 +- - 6 files changed, 46 insertions(+), 38 deletions(-) - -diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py -index 2ac4382..1c7d375 100644 ---- a/ipaserver/install/ca.py -+++ b/ipaserver/install/ca.py -@@ -235,7 +235,6 @@ def install_step_0(standalone, replica_config, options, custodia): - cafile = os.path.join(replica_config.dir, 'cacert.p12') - if options.promote: - custodia.get_ca_keys( -- replica_config.ca_host_name, - cafile, - replica_config.dirman_password) - -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index eefc30b..cc0dbf3 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -712,7 +712,7 @@ class CAInstance(DogtagInstance): - self.configure_agent_renewal() - - def __import_ra_key(self): -- self._custodia.import_ra_key(self.master_host) -+ self._custodia.import_ra_key() - self.__set_ra_cert_perms() - - self.configure_agent_renewal() -diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py -index 262ae58..ada8d03 100644 ---- a/ipaserver/install/custodiainstance.py -+++ b/ipaserver/install/custodiainstance.py -@@ -71,41 +71,45 @@ def get_custodia_instance(config, mode): - if mode == CustodiaModes.CA_PEER: - # In case we install replica with CA, prefer CA host as source for - # all Custodia secret material. -- custodia_master = config.ca_host_name -+ custodia_peer = config.ca_host_name - elif mode == CustodiaModes.KRA_PEER: -- custodia_master = config.kra_host_name -+ custodia_peer = config.kra_host_name - elif mode == CustodiaModes.MASTER_PEER: -- custodia_master = config.master_host_name -+ custodia_peer = config.master_host_name - elif mode == CustodiaModes.STANDALONE: -- custodia_master = None -+ custodia_peer = None - else: -- custodia_master = None -+ custodia_peer = None - -- if custodia_master is None: -+ if custodia_peer is None: - # use ldapi with local dirsrv instance - root_logger.info("Custodia uses LDAPI.") -- ldap_uri = None - else: -- root_logger.info("Custodia uses '%s' as master peer.", -- custodia_master) -- ldap_uri = 'ldap://{}'.format(custodia_master) -+ root_logger.info("Custodia uses '%s' as master peer.", custodia_peer) - - return CustodiaInstance( - host_name=config.host_name, - realm=config.realm_name, -- ldap_uri=ldap_uri -+ custodia_peer=custodia_peer - ) - - - class CustodiaInstance(SimpleServiceInstance): -- def __init__(self, host_name=None, realm=None, ldap_uri=None): -+ def __init__(self, host_name=None, realm=None, custodia_peer=None): - super(CustodiaInstance, self).__init__("ipa-custodia") - self.config_file = paths.IPA_CUSTODIA_CONF - self.server_keys = paths.IPA_CUSTODIA_KEYS -- self.ldap_uri = ldap_uri -+ self.custodia_peer = custodia_peer - self.fqdn = host_name - self.realm = realm - -+ @property -+ def ldap_uri(self): -+ if self.custodia_peer is None: -+ return installutils.realm_to_ldapi_uri(self.realm) -+ else: -+ return "ldap://{}".format(self.custodia_peer) -+ - def __config_file(self): - template_file = os.path.basename(self.config_file) + '.template' - template = os.path.join(paths.USR_SHARE_IPA_DIR, template_file) -@@ -125,7 +129,7 @@ class CustodiaInstance(SimpleServiceInstance): - ipautil.flush_sync(f) - - def create_instance(self): -- if self.ldap_uri is None or self.ldap_uri.startswith('ldapi://'): -+ if self.ldap_uri.startswith('ldapi://'): - # local case, ensure container exists - self.step("Making sure custodia container exists", - self.__create_container) -@@ -174,25 +178,24 @@ class CustodiaInstance(SimpleServiceInstance): - updater = ldapupdate.LDAPUpdate(sub_dict=sub_dict) - updater.update([os.path.join(paths.UPDATES_DIR, '73-custodia.update')]) - -- def import_ra_key(self, master_host_name): -- cli = self._get_custodia_client(server=master_host_name) -+ def import_ra_key(self): -+ cli = self._get_custodia_client() - # please note that ipaCert part has to stay here for historical - # reasons (old servers expect you to ask for ra/ipaCert during - # replication as they store the RA agent cert in an NSS database - # with this nickname) - cli.fetch_key('ra/ipaCert') - -- def import_dm_password(self, master_host_name): -- cli = self._get_custodia_client(server=master_host_name) -+ def import_dm_password(self): -+ cli = self._get_custodia_client() - cli.fetch_key('dm/DMHash') - -- def _wait_keys(self, host, timeout=300): -- ldap_uri = 'ldap://%s' % host -+ def _wait_keys(self, timeout=300): - deadline = int(time.time()) + timeout - root_logger.info("Waiting up to %s seconds to see our keys " -- "appear on host: %s", timeout, host) -+ "appear on host %s", timeout, self.ldap_uri) - -- konn = KEMLdap(ldap_uri) -+ konn = KEMLdap(self.ldap_uri) - saved_e = None - while True: - try: -@@ -202,8 +205,11 @@ class CustodiaInstance(SimpleServiceInstance): - if saved_e is None: - # FIXME: Change once there's better way to show this - # message in installer output, -- print(" Waiting for keys to appear on host: {}, please " -- "wait until this has completed.".format(host)) -+ print( -+ " Waiting for keys to appear on host: {}, please " -+ "wait until this has completed.".format( -+ self.ldap_uri) -+ ) - # log only once for the same error - if not isinstance(e, type(saved_e)): - root_logger.debug( -@@ -213,23 +219,25 @@ class CustodiaInstance(SimpleServiceInstance): - raise RuntimeError("Timed out trying to obtain keys.") - time.sleep(1) - -- def _get_custodia_client(self, server): -+ def _get_custodia_client(self): -+ if self.custodia_peer is None: -+ raise ValueError("Can't replicate secrets without Custodia peer") - # Before we attempt to fetch keys from this host, make sure our public - # keys have been replicated there. -- self._wait_keys(server) -+ self._wait_keys() - - return CustodiaClient( - client_service='host@{}'.format(self.fqdn), - keyfile=self.server_keys, keytab=paths.KRB5_KEYTAB, -- server=server, realm=self.realm -+ server=self.custodia_peer, realm=self.realm - ) - -- def _get_keys(self, ca_host, cacerts_file, cacerts_pwd, data): -+ def _get_keys(self, cacerts_file, cacerts_pwd, data): - # Fetch all needed certs one by one, then combine them in a single - # PKCS12 file - prefix = data['prefix'] - certlist = data['list'] -- cli = self._get_custodia_client(server=ca_host) -+ cli = self._get_custodia_client() - - # Temporary nssdb - tmpnssdir = tempfile.mkdtemp(dir=paths.TMP) -@@ -272,23 +280,23 @@ class CustodiaInstance(SimpleServiceInstance): - finally: - shutil.rmtree(tmpnssdir) - -- def get_ca_keys(self, ca_host, cacerts_file, cacerts_pwd): -+ def get_ca_keys(self, cacerts_file, cacerts_pwd): - certlist = ['caSigningCert cert-pki-ca', - 'ocspSigningCert cert-pki-ca', - 'auditSigningCert cert-pki-ca', - 'subsystemCert cert-pki-ca'] - data = {'prefix': 'ca', - 'list': certlist} -- self._get_keys(ca_host, cacerts_file, cacerts_pwd, data) -+ self._get_keys(cacerts_file, cacerts_pwd, data) - -- def get_kra_keys(self, ca_host, cacerts_file, cacerts_pwd): -+ def get_kra_keys(self, cacerts_file, cacerts_pwd): - certlist = ['auditSigningCert cert-pki-kra', - 'storageCert cert-pki-kra', - 'subsystemCert cert-pki-ca', - 'transportCert cert-pki-kra'] - data = {'prefix': 'ca', - 'list': certlist} -- self._get_keys(ca_host, cacerts_file, cacerts_pwd, data) -+ self._get_keys(cacerts_file, cacerts_pwd, data) - - def __start(self): - super(CustodiaInstance, self).__start() -diff --git a/ipaserver/install/kra.py b/ipaserver/install/kra.py -index 3333970..d8773b9 100644 ---- a/ipaserver/install/kra.py -+++ b/ipaserver/install/kra.py -@@ -91,7 +91,6 @@ def install(api, replica_config, options, custodia): - paths.KRB5_KEYTAB, - ccache) - custodia.get_kra_keys( -- replica_config.kra_host_name, - krafile, - replica_config.dirman_password) - else: -diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py -index f4338ed..3651cde 100644 ---- a/ipaserver/install/server/install.py -+++ b/ipaserver/install/server/install.py -@@ -1085,7 +1085,9 @@ def uninstall(installer): - dsinstance.DsInstance(fstore=fstore).uninstall() - if _server_trust_ad_installed: - adtrustinstance.ADTRUSTInstance(fstore).uninstall() -- custodiainstance.CustodiaInstance().uninstall() -+ # realm isn't used, but IPAKEMKeys parses /etc/ipa/default.conf -+ # otherwise, see https://pagure.io/freeipa/issue/7474 . -+ custodiainstance.CustodiaInstance(realm='REALM.INVALID').uninstall() - otpdinstance.OtpdInstance().uninstall() - tasks.restore_hostname(fstore, sstore) - fstore.restore_all_files() -diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index ef61590..b9cd518 100644 ---- a/ipaserver/install/server/replicainstall.py -+++ b/ipaserver/install/server/replicainstall.py -@@ -1512,7 +1512,7 @@ def install(installer): - krb.restart() - - if promote: -- custodia.import_dm_password(config.master_host_name) -+ custodia.import_dm_password() - promote_sssd(config.host_name) - promote_openldap_conf(config.host_name, config.master_host_name) - --- -2.9.3 - diff --git a/SOURCES/0050-Fix-elements-not-being-removed-in-otpd_queue_pop_msg.patch b/SOURCES/0050-Fix-elements-not-being-removed-in-otpd_queue_pop_msg.patch deleted file mode 100644 index d0e2f25..0000000 --- a/SOURCES/0050-Fix-elements-not-being-removed-in-otpd_queue_pop_msg.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 006986b0f004b4cdbc3620b417d5a7f62931ecb6 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood <rharwood@redhat.com> -Date: Wed, 30 May 2018 14:54:54 -0400 -Subject: [PATCH] Fix elements not being removed in otpd_queue_pop_msgid() - -If the element being removed were not the queue head, -otpd_queue_pop_msgid() would not actually remove the element, leading -to potential double frees and request replays. - -Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> -Reviewed-By: Stanislav Laznicka <slaznick@redhat.com> ---- - daemons/ipa-otpd/queue.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/daemons/ipa-otpd/queue.c b/daemons/ipa-otpd/queue.c -index 730bbc40b864b9dc65a69049c0a0e516e3daac0e..9e29fb238d5c7a7395bcf3860ce7445c27ca98ac 100644 ---- a/daemons/ipa-otpd/queue.c -+++ b/daemons/ipa-otpd/queue.c -@@ -155,7 +155,7 @@ struct otpd_queue_item *otpd_queue_pop_msgid(struct otpd_queue *q, int msgid) - - for (item = q->head, prev = &q->head; - item != NULL; -- item = item->next, prev = &item->next) { -+ prev = &item->next, item = item->next) { - if (item->msgid == msgid) { - *prev = item->next; - if (q->head == NULL) --- -2.17.1 - diff --git a/SOURCES/0051-Tune-DS-replication-settings.patch b/SOURCES/0051-Tune-DS-replication-settings.patch deleted file mode 100644 index 6776b5b..0000000 --- a/SOURCES/0051-Tune-DS-replication-settings.patch +++ /dev/null @@ -1,434 +0,0 @@ -From f86e77a8e6fd9e57472e6d1b63246254143f706d Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Tue, 3 Jul 2018 19:40:05 +0200 -Subject: [PATCH] Tune DS replication settings - -Tune 389-DS replication settings to improve performance and avoid -timeouts. During installation of a replica, the value of -nsDS5ReplicaBindDnGroupCheckInterval is reduced to 2 seconds. At the end -of the installation, the value is increased sensible production -settings. This avoids long delays during replication. - -See: https://pagure.io/freeipa/issue/7617 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> ---- - ipaserver/install/cainstance.py | 14 ++- - ipaserver/install/dsinstance.py | 48 +++++--- - ipaserver/install/replication.py | 92 +++++++++++---- - ipaserver/install/server/replicainstall.py | 2 + - ipaserver/install/server/upgrade.py | 12 +- - ipatests/test_integration/test_external_ca.py | 109 ++++++------------ - 6 files changed, 157 insertions(+), 120 deletions(-) - -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index eefc30b6e01dcf744703b8607cbe169fbec5d859..e72e706ffd2d9163a283f6bb09815e5aa60c889c 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -388,8 +388,13 @@ class CAInstance(DogtagInstance): - self.step("set up CRL publishing", self.__enable_crl_publish) - self.step("enable PKIX certificate path discovery and validation", self.enable_pkix) - if promote: -- self.step("destroying installation admin user", self.teardown_admin) -- self.step("starting certificate server instance", self.start_instance) -+ self.step("destroying installation admin user", -+ self.teardown_admin) -+ self.step("starting certificate server instance", -+ self.start_instance) -+ if promote: -+ self.step("Finalize replication settings", -+ self.finalize_replica_config) - # Step 1 of external is getting a CSR so we don't need to do these - # steps until we get a cert back from the external CA. - if self.external != 1: -@@ -1196,13 +1201,16 @@ class CAInstance(DogtagInstance): - api.Backend.ldap2.add_entry(entry) - - def __setup_replication(self): -- - repl = replication.CAReplicationManager(self.realm, self.fqdn) - repl.setup_cs_replication(self.master_host) - - # Activate Topology for o=ipaca segments - self.__update_topology() - -+ def finalize_replica_config(self): -+ repl = replication.CAReplicationManager(self.realm, self.fqdn) -+ repl.finalize_replica_config(self.master_host) -+ - def __enable_instance(self): - basedn = ipautil.realm_to_suffix(self.realm) - if not self.clone: -diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py -index 923f483340a26a614001701ce6c235dd73501501..7adaabd3c1280709150329003130f70233de37f4 100644 ---- a/ipaserver/install/dsinstance.py -+++ b/ipaserver/install/dsinstance.py -@@ -417,6 +417,20 @@ class DsInstance(service.Service): - - self.start_creation(runtime=30) - -+ def _get_replication_manager(self): -+ # Always connect to self over ldapi -+ ldap_uri = ipaldap.get_ldap_uri(protocol='ldapi', realm=self.realm) -+ conn = ipaldap.LDAPClient(ldap_uri) -+ conn.external_bind() -+ repl = replication.ReplicationManager( -+ self.realm, self.fqdn, self.dm_password, conn=conn -+ ) -+ if self.dm_password is not None and not self.promote: -+ bind_dn = DN(('cn', 'Directory Manager')) -+ bind_pw = self.dm_password -+ else: -+ bind_dn = bind_pw = None -+ return repl, bind_dn, bind_pw - - def __setup_replica(self): - """ -@@ -433,26 +447,24 @@ class DsInstance(service.Service): - self.realm, - self.dm_password) - -- # Always connect to self over ldapi -- ldap_uri = ipaldap.get_ldap_uri(protocol='ldapi', realm=self.realm) -- conn = ipaldap.LDAPClient(ldap_uri) -- conn.external_bind() -- repl = replication.ReplicationManager(self.realm, -- self.fqdn, -- self.dm_password, conn=conn) -- -- if self.dm_password is not None and not self.promote: -- bind_dn = DN(('cn', 'Directory Manager')) -- bind_pw = self.dm_password -- else: -- bind_dn = bind_pw = None -- -- repl.setup_promote_replication(self.master_fqdn, -- r_binddn=bind_dn, -- r_bindpw=bind_pw, -- cacert=self.ca_file) -+ repl, bind_dn, bind_pw = self._get_replication_manager() -+ repl.setup_promote_replication( -+ self.master_fqdn, -+ r_binddn=bind_dn, -+ r_bindpw=bind_pw, -+ cacert=self.ca_file -+ ) - self.run_init_memberof = repl.needs_memberof_fixup() - -+ def finalize_replica_config(self): -+ repl, bind_dn, bind_pw = self._get_replication_manager() -+ repl.finalize_replica_config( -+ self.master_fqdn, -+ r_binddn=bind_dn, -+ r_bindpw=bind_pw, -+ cacert=self.ca_file -+ ) -+ - def __configure_sasl_mappings(self): - # we need to remove any existing SASL mappings in the directory as otherwise they - # they may conflict. -diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py -index e0055b792ce5b51fd411a7ea1f4316bb017984ba..3a76b70038bf6f739fe63aeac0233ccbfda2f016 100644 ---- a/ipaserver/install/replication.py -+++ b/ipaserver/install/replication.py -@@ -69,6 +69,20 @@ STRIP_ATTRS = ('modifiersName', - 'internalModifiersName', - 'internalModifyTimestamp') - -+# settings for cn=replica,cn=$DB,cn=mapping tree,cn=config -+# during replica installation -+REPLICA_CREATION_SETTINGS = { -+ "nsds5ReplicaReleaseTimeout": ["20"], -+ "nsds5ReplicaBackoffMax": ["3"], -+ "nsDS5ReplicaBindDnGroupCheckInterval": ["2"] -+} -+# after replica installation -+REPLICA_FINAL_SETTINGS = { -+ "nsds5ReplicaReleaseTimeout": ["60"], -+ "nsds5ReplicaBackoffMax": ["300"], # default -+ "nsDS5ReplicaBindDnGroupCheckInterval": ["60"] -+} -+ - - def replica_conn_check(master_host, host_name, realm, check_ca, - dogtag_master_ds_port, admin_password=None, -@@ -192,9 +206,13 @@ def wait_for_entry(connection, dn, timeout=7200, attr='', quiet=True): - - - class ReplicationManager(object): -- """Manage replication agreements between DS servers, and sync -- agreements with Windows servers""" -- def __init__(self, realm, hostname, dirman_passwd, port=PORT, starttls=False, conn=None): -+ """Manage replication agreements -+ -+ between DS servers, and sync agreements with Windows servers -+ """ -+ -+ def __init__(self, realm, hostname, dirman_passwd=None, port=PORT, -+ starttls=False, conn=None): - self.hostname = hostname - self.port = port - self.dirman_passwd = dirman_passwd -@@ -471,22 +489,16 @@ class ReplicationManager(object): - except errors.NotFound: - pass - else: -- managers = {DN(m) for m in entry.get('nsDS5ReplicaBindDN', [])} -- -- mods = [] -- if replica_binddn not in managers: -+ binddns = entry.setdefault('nsDS5ReplicaBindDN', []) -+ if replica_binddn not in {DN(m) for m in binddns}: - # Add the new replication manager -- mods.append( -- (ldap.MOD_ADD, 'nsDS5ReplicaBindDN', replica_binddn) -- ) -- if 'nsds5replicareleasetimeout' not in entry: -- # See https://pagure.io/freeipa/issue/7488 -- mods.append( -- (ldap.MOD_ADD, 'nsds5replicareleasetimeout', ['60']) -- ) -- -- if mods: -- conn.modify_s(dn, mods) -+ binddns.append(replica_binddn) -+ for key, value in REPLICA_CREATION_SETTINGS.items(): -+ entry[key] = value -+ try: -+ conn.update_entry(entry) -+ except errors.EmptyModlist: -+ pass - - self.set_replica_binddngroup(conn, entry) - -@@ -505,9 +517,8 @@ class ReplicationManager(object): - nsds5flags=["1"], - nsds5replicabinddn=[replica_binddn], - nsds5replicabinddngroup=[self.repl_man_group_dn], -- nsds5replicabinddngroupcheckinterval=["60"], -- nsds5replicareleasetimeout=["60"], - nsds5replicalegacyconsumer=["off"], -+ **REPLICA_CREATION_SETTINGS - ) - conn.add_entry(entry) - -@@ -533,6 +544,47 @@ class ReplicationManager(object): - except errors.DuplicateEntry: - return - -+ def _finalize_replica_settings(self, conn): -+ """Change replica settings to final values -+ -+ During replica installation, some settings are configured for faster -+ replication. -+ """ -+ dn = self.replica_dn() -+ entry = conn.get_entry(dn) -+ for key, value in REPLICA_FINAL_SETTINGS.items(): -+ entry[key] = value -+ try: -+ conn.update_entry(entry) -+ except errors.EmptyModlist: -+ pass -+ -+ def finalize_replica_config(self, r_hostname, r_binddn=None, -+ r_bindpw=None, cacert=paths.IPA_CA_CRT): -+ """Apply final cn=replica settings -+ -+ replica_config() sets several attribute to fast cache invalidation -+ and fast reconnects to optimize replicat installation. For -+ production, longer timeouts and less aggressive cache invalidation -+ is sufficient. finalize_replica_config() sets the values on new -+ replica and the master. -+ -+ When installing multiple replicas in parallel, one replica may -+ finalize the values while another is still installing. -+ -+ See https://pagure.io/freeipa/issue/7617 -+ """ -+ self._finalize_replica_settings(self.conn) -+ -+ ldap_uri = ipaldap.get_ldap_uri(r_hostname) -+ r_conn = ipaldap.LDAPClient(ldap_uri, cacert=cacert) -+ if r_bindpw: -+ r_conn.simple_bind(r_binddn, r_bindpw) -+ else: -+ r_conn.gssapi_bind() -+ self._finalize_replica_settings(r_conn) -+ r_conn.close() -+ - def setup_chaining_backend(self, conn): - chaindn = DN(('cn', 'chaining database'), ('cn', 'plugins'), ('cn', 'config')) - benamebase = "chaindb" -diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index 2ecc0abe0c5918cf5aefccc1bd6f09e70503baab..27e5e9cde7788b8c9b78b27ed47f5748f34c90ff 100644 ---- a/ipaserver/install/server/replicainstall.py -+++ b/ipaserver/install/server/replicainstall.py -@@ -1504,6 +1504,8 @@ def install(installer): - # Apply any LDAP updates. Needs to be done after the replica is synced-up - service.print_msg("Applying LDAP updates") - ds.apply_updates() -+ service.print_msg("Finalize replication settings") -+ ds.finalize_replica_config() - - if kra_enabled: - kra.install(api, config, options, custodia=custodia) -diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py -index bf603acb5f931a4194320795874859f5bdc94647..793092be86da687fd21cf2c0ef3608f32fcf9f16 100644 ---- a/ipaserver/install/server/upgrade.py -+++ b/ipaserver/install/server/upgrade.py -@@ -50,6 +50,7 @@ from ipaserver.install import dnskeysyncinstance - from ipaserver.install import dogtaginstance - from ipaserver.install import krbinstance - from ipaserver.install import adtrustinstance -+from ipaserver.install import replication - from ipaserver.install.upgradeinstance import IPAUpgrade - from ipaserver.install.ldapupdate import BadSyntax - -@@ -1575,11 +1576,14 @@ def update_replica_config(db_suffix): - except ipalib.errors.NotFound: - return # entry does not exist until a replica is installed - -- if 'nsds5replicareleasetimeout' not in entry: -- # See https://pagure.io/freeipa/issue/7488 -- root_logger.info("Adding nsds5replicaReleaseTimeout=60 to %s", dn) -- entry['nsds5replicareleasetimeout'] = '60' -+ for key, value in replication.REPLICA_FINAL_SETTINGS.items(): -+ entry[key] = value -+ try: - api.Backend.ldap2.update_entry(entry) -+ except ipalib.errors.EmptyModlist: -+ pass -+ else: -+ root_logger.info("Updated entry %s", dn) - - - def upgrade_configuration(): -diff --git a/ipatests/test_integration/test_external_ca.py b/ipatests/test_integration/test_external_ca.py -index 7fc89cc949ca6a7ccddde17aca434cf55f2918ed..b22fa05206204e3dc382dc2b02c23a73e5c1b80b 100644 ---- a/ipatests/test_integration/test_external_ca.py -+++ b/ipatests/test_integration/test_external_ca.py -@@ -31,86 +31,45 @@ class TestExternalCA(IntegrationTest): - """ - Test of FreeIPA server installation with exernal CA - """ -- def test_external_ca(self): -- # Step 1 of ipa-server-install -- self.master.run_command([ -- 'ipa-server-install', '-U', -- '-a', self.master.config.admin_password, -- '-p', self.master.config.dirman_password, -- '--setup-dns', '--no-forwarders', -- '-n', self.master.domain.name, -- '-r', self.master.domain.realm, -- '--domain-level=%i' % self.master.config.domain_level, -- '--external-ca' -- ]) -- -- nss_db = os.path.join(self.master.config.test_dir, 'testdb') -- external_cert_file = os.path.join(nss_db, 'ipa.crt') -- external_ca_file = os.path.join(nss_db, 'ca.crt') -- noisefile = os.path.join(self.master.config.test_dir, 'noise.txt') -- pwdfile = os.path.join(self.master.config.test_dir, 'pwdfile.txt') -- -- # Create noise and password files for NSS database -- self.master.run_command('date | sha256sum > %s' % noisefile) -- self.master.run_command('echo %s > %s' % -- (self.master.config.admin_password, pwdfile)) -- -- # Create NSS database -- self.master.run_command(['mkdir', nss_db]) -- self.master.run_command([ -- 'certutil', '-N', -- '-d', nss_db, -- '-f', pwdfile -- ]) -- -- # Create external CA -- self.master.run_command([ -- 'certutil', '-S', -- '-d', nss_db, -- '-f', pwdfile, -- '-n', 'external', -- '-s', 'CN=External CA, O=%s' % self.master.domain.name, -- '-x', -- '-t', 'CTu,CTu,CTu', -- '-g', '2048', -- '-m', '0', -- '-v', '60', -- '-z', noisefile, -- '-2', '-1', '-5', '--extSKID' -- ], stdin_text='5\n9\nn\ny\n10\ny\n{}\nn\n5\n6\n7\n9\nn\n' -- ''.format(EXTERNAL_CA_KEY_ID)) -+ num_replicas = 1 - -- # Sign IPA cert request using the external CA -- self.master.run_command([ -- 'certutil', '-C', -- '-d', nss_db, -- '-f', pwdfile, -- '-c', 'external', -- '-m', '1', -- '-v', '60', -- '-2', '-1', '-3', '--extSKID', -- '-i', '/root/ipa.csr', -- '-o', external_cert_file, -- '-a' -- ], stdin_text='0\n1\n5\n9\ny\ny\n\ny\ny\n{}\n-1\n\nn\n{}\nn\n' -- ''.format(EXTERNAL_CA_KEY_ID, IPA_CA_KEY_ID)) -+ @tasks.collect_logs -+ def test_external_ca(self): -+ # Step 1 of ipa-server-install. -+ result = install_server_external_ca_step1(self.master) -+ assert result.returncode == 0 - -- # Export external CA file -- self.master.run_command( -- 'certutil -L -d %s -n "external" -a > %s' % -- (nss_db, external_ca_file) -- ) -+ # Sign CA, transport it to the host and get ipa a root ca paths. -+ root_ca_fname, ipa_ca_fname = tasks.sign_ca_and_transport( -+ self.master, paths.ROOT_IPA_CSR, ROOT_CA, IPA_CA) - -- # Step 2 of ipa-server-install -- self.master.run_command([ -- 'ipa-server-install', -- '-a', self.master.config.admin_password, -- '-p', self.master.config.dirman_password, -- '--external-cert-file', external_cert_file, -- '--external-cert-file', external_ca_file -- ]) -+ # Step 2 of ipa-server-install. -+ result = install_server_external_ca_step2( -+ self.master, ipa_ca_fname, root_ca_fname) -+ assert result.returncode == 0 - - # Make sure IPA server is working properly - tasks.kinit_admin(self.master) - result = self.master.run_command(['ipa', 'user-show', 'admin']) - assert 'User login: admin' in result.stdout_text -+ -+ # check that we can also install replica -+ tasks.install_replica(self.master, self.replicas[0]) -+ -+ # check that nsds5ReplicaReleaseTimeout option was set -+ result = self.master.run_command([ -+ 'ldapsearch', -+ '-x', -+ '-D', -+ 'cn=directory manager', -+ '-w', self.master.config.dirman_password, -+ '-b', 'cn=mapping tree,cn=config', -+ '(cn=replica)', -+ '-LLL', -+ '-o', -+ 'ldif-wrap=no']) -+ # case insensitive match -+ text = result.stdout_text.lower() -+ # see ipaserver.install.replication.REPLICA_FINAL_SETTINGS -+ assert 'nsds5ReplicaReleaseTimeout: 60'.lower() in text -+ assert 'nsDS5ReplicaBindDnGroupCheckInterval: 60'.lower() in text --- -2.17.1 - diff --git a/SOURCES/0052-In-IPA-4.4-when-updating-userpassword-with-ldapmodif.patch b/SOURCES/0052-In-IPA-4.4-when-updating-userpassword-with-ldapmodif.patch deleted file mode 100644 index 69de466..0000000 --- a/SOURCES/0052-In-IPA-4.4-when-updating-userpassword-with-ldapmodif.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0335e799ce5f73a1a1e9901fb5e9c85aaa718ecd Mon Sep 17 00:00:00 2001 -From: Thierry Bordaz <tbordaz@redhat.com> -Date: Tue, 24 Jul 2018 12:16:35 +0200 -Subject: [PATCH] In IPA 4.4 when updating userpassword with ldapmodify does - not update krbPasswordExpiration nor krbLastPwdChange - -When making ipa-pwd-extop TXN aware, some callbacks are call twice. -Particularily - ipapwd_pre_add is called during PRE_ADD and TXN_PRE_ADD - ipapwd_pre_mod is called during PRE_MOD and TXN_PRE_MOD - ipapwd_post_modadd is called during POST_ADD and TXN_POST_ADD - ipapwd_post_modadd is called during POST_MOD and TXN_POST_MOD -It is not the expected behavior and it results on some skipped updates krbPasswordExpiration -and krbLastPwdChange - -https://pagure.io/freeipa/issue/7601 - -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> ---- - daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c | 4 ---- - 1 file changed, 4 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c -index c62eae33418f8368c831a91f611915addf7d423b..209d596255d05bfd03de432b7930e6406cc025dc 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c -@@ -1488,8 +1488,6 @@ int ipapwd_pre_init(Slapi_PBlock *pb) - ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01); - if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc); - if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_BIND_FN, (void *)ipapwd_pre_bind); -- if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_ADD_FN, (void *)ipapwd_pre_add); -- if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODIFY_FN, (void *)ipapwd_pre_mod); - - return ret; - } -@@ -1513,9 +1511,7 @@ int ipapwd_post_init(Slapi_PBlock *pb) - - ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01); - if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc); -- if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN, (void *)ipapwd_post_modadd); - if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN, (void *)ipapwd_post_updatecfg); -- if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN, (void *)ipapwd_post_modadd); - if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN, (void *)ipapwd_post_updatecfg); - - return ret; --- -2.17.1 - diff --git a/SOURCES/0053-Tests-add-integration-test-for-password-changes-by-d.patch b/SOURCES/0053-Tests-add-integration-test-for-password-changes-by-d.patch deleted file mode 100644 index 4580cb4..0000000 --- a/SOURCES/0053-Tests-add-integration-test-for-password-changes-by-d.patch +++ /dev/null @@ -1,157 +0,0 @@ -From 97e0d55745a125a933a8d4f9dddd31a752977948 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud <flo@redhat.com> -Date: Mon, 6 Aug 2018 18:25:16 +0200 -Subject: [PATCH] Tests: add integration test for password changes by dir mgr - -Add a test for issue 7601: -- add a user, perform kinit user to modify the password, read krblastpwdchange -and krbpasswordexpiration. -- perform a ldapmodify on the password as dir mgr -- make sure that krblastpwdchange and krbpasswordexpiration have been modified -- perform the same check with ldappasswd - -Related to: -https://pagure.io/freeipa/issue/7601 - -Reviewed-By: Thierry Bordaz <tbordaz@redhat.com> ---- - ipatests/test_integration/test_commands.py | 127 +++++++++++++++++++++ - 1 file changed, 127 insertions(+) - create mode 100644 ipatests/test_integration/test_commands.py - -diff --git a/ipatests/test_integration/test_commands.py b/ipatests/test_integration/test_commands.py -new file mode 100644 -index 0000000000000000000000000000000000000000..e277e4a2fe4089392b08719d46b011e6444e8094 ---- /dev/null -+++ b/ipatests/test_integration/test_commands.py -@@ -0,0 +1,127 @@ -+# -+# Copyright (C) 2018 FreeIPA Contributors see COPYING for license -+# -+"""Misc test for 'ipa' CLI regressions -+""" -+from __future__ import print_function -+ -+import re -+from tempfile import NamedTemporaryFile -+import textwrap -+import time -+ -+from ipaplatform.paths import paths -+ -+from ipatests.test_integration.base import IntegrationTest -+from ipatests.pytest_plugins.integration import tasks -+ -+ -+class TestIPACommand(IntegrationTest): -+ """ -+ A lot of commands can be executed against a single IPA installation -+ so provide a generic class to execute one-off commands that need to be -+ tested without having to fire up a full server to run one command. -+ """ -+ topology = 'line' -+ -+ def test_ldapmodify_password_issue7601(self): -+ user = 'ipauser' -+ original_passwd = 'Secret123' -+ new_passwd = 'userPasswd123' -+ new_passwd2 = 'mynewPwd123' -+ master = self.master -+ base_dn = str(master.domain.basedn) # pylint: disable=no-member -+ -+ # Create a user with a password -+ tasks.kinit_admin(master) -+ add_password_stdin_text = "{pwd}\n{pwd}".format(pwd=original_passwd) -+ master.run_command(['ipa', 'user-add', user, -+ '--first', user, -+ '--last', user, -+ '--password'], -+ stdin_text=add_password_stdin_text) -+ # kinit as that user in order to modify the pwd -+ user_kinit_stdin_text = "{old}\n%{new}\n%{new}\n".format( -+ old=original_passwd, -+ new=original_passwd) -+ master.run_command(['kinit', user], stdin_text=user_kinit_stdin_text) -+ # Retrieve krblastpwdchange and krbpasswordexpiration -+ search_cmd = [ -+ 'ldapsearch', '-x', -+ '-D', 'cn=directory manager', -+ '-w', master.config.dirman_password, -+ '-s', 'base', -+ '-b', 'uid={user},cn=users,cn=accounts,{base_dn}'.format( -+ user=user, base_dn=base_dn), -+ '-o', 'ldif-wrap=no', -+ '-LLL', -+ 'krblastpwdchange', -+ 'krbpasswordexpiration'] -+ output = master.run_command(search_cmd).stdout_text.lower() -+ -+ # extract krblastpwdchange and krbpasswordexpiration -+ krbchg_pattern = 'krblastpwdchange: (.+)\n' -+ krbexp_pattern = 'krbpasswordexpiration: (.+)\n' -+ krblastpwdchange = re.findall(krbchg_pattern, output)[0] -+ krbexp = re.findall(krbexp_pattern, output)[0] -+ -+ # sleep 1 sec (krblastpwdchange and krbpasswordexpiration have at most -+ # a 1s precision) -+ time.sleep(1) -+ # perform ldapmodify on userpassword as dir mgr -+ mod = NamedTemporaryFile() -+ ldif_file = mod.name -+ entry_ldif = textwrap.dedent(""" -+ dn: uid={user},cn=users,cn=accounts,{base_dn} -+ changetype: modify -+ replace: userpassword -+ userpassword: {new_passwd} -+ """).format( -+ user=user, -+ base_dn=base_dn, -+ new_passwd=new_passwd) -+ master.put_file_contents(ldif_file, entry_ldif) -+ arg = ['ldapmodify', -+ '-h', master.hostname, -+ '-p', '389', '-D', -+ str(master.config.dirman_dn), # pylint: disable=no-member -+ '-w', master.config.dirman_password, -+ '-f', ldif_file] -+ master.run_command(arg) -+ -+ # Test new password with kinit -+ master.run_command(['kinit', user], stdin_text=new_passwd) -+ # Retrieve krblastpwdchange and krbpasswordexpiration -+ output = master.run_command(search_cmd).stdout_text.lower() -+ # extract krblastpwdchange and krbpasswordexpiration -+ newkrblastpwdchange = re.findall(krbchg_pattern, output)[0] -+ newkrbexp = re.findall(krbexp_pattern, output)[0] -+ -+ # both should have changed -+ assert newkrblastpwdchange != krblastpwdchange -+ assert newkrbexp != krbexp -+ -+ # Now test passwd modif with ldappasswd -+ time.sleep(1) -+ master.run_command([ -+ paths.LDAPPASSWD, -+ '-D', str(master.config.dirman_dn), # pylint: disable=no-member -+ '-w', master.config.dirman_password, -+ '-a', new_passwd, -+ '-s', new_passwd2, -+ '-x', '-ZZ', -+ '-H', 'ldap://{hostname}'.format(hostname=master.hostname), -+ 'uid={user},cn=users,cn=accounts,{base_dn}'.format( -+ user=user, base_dn=base_dn)] -+ ) -+ # Test new password with kinit -+ master.run_command(['kinit', user], stdin_text=new_passwd2) -+ # Retrieve krblastpwdchange and krbpasswordexpiration -+ output = master.run_command(search_cmd).stdout_text.lower() -+ # extract krblastpwdchange and krbpasswordexpiration -+ newkrblastpwdchange2 = re.findall(krbchg_pattern, output)[0] -+ newkrbexp2 = re.findall(krbexp_pattern, output)[0] -+ -+ # both should have changed -+ assert newkrblastpwdchange != newkrblastpwdchange2 -+ assert newkrbexp != newkrbexp2 --- -2.17.1 - diff --git a/SOURCES/0054-Check-if-replication-agreement-exist-before-enable-d.patch b/SOURCES/0054-Check-if-replication-agreement-exist-before-enable-d.patch deleted file mode 100644 index 82ede2d..0000000 --- a/SOURCES/0054-Check-if-replication-agreement-exist-before-enable-d.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 6db737931822c188833dee8cd086f91c640710fd Mon Sep 17 00:00:00 2001 -From: Felipe Barreto <fbarreto@redhat.com> -Date: Mon, 15 Jan 2018 17:12:15 -0200 -Subject: [PATCH] Check if replication agreement exist before enable/disable it - -If the replication agreement does not exist, a custom exception is -raised explaining the problem. - -https://pagure.io/freeipa/issue/7201 - -Reviewed-By: Rob Crittenden <rcritten@redhat.com> -Reviewed-By: Christian Heimes <cheimes@redhat.com> ---- - install/tools/ipa-replica-manage | 7 +++++-- - ipaserver/install/replication.py | 11 +++++++++++ - 2 files changed, 16 insertions(+), 2 deletions(-) - -diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage -index c00d8ca3a0fa8228c5aa782a270991f14ee16974..019826f822b23e4e55dedb794ff6c1459a3d93c8 100755 ---- a/install/tools/ipa-replica-manage -+++ b/install/tools/ipa-replica-manage -@@ -1200,8 +1200,11 @@ def re_initialize(realm, thishost, fromhost, dirman_passwd, nolookup=False): - repl = replication.ReplicationManager(realm, fromhost, dirman_passwd) - agreement = repl.get_replication_agreement(thishost) - -- thisrepl.enable_agreement(fromhost) -- repl.enable_agreement(thishost) -+ try: -+ thisrepl.enable_agreement(fromhost) -+ repl.enable_agreement(thishost) -+ except errors.NotFound as e: -+ sys.exit(e) - - repl.force_sync(repl.conn, thishost) - -diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py -index 3a76b70038bf6f739fe63aeac0233ccbfda2f016..d4b41caa45409fa1537ae10f182599307f3e0439 100644 ---- a/ipaserver/install/replication.py -+++ b/ipaserver/install/replication.py -@@ -31,6 +31,7 @@ import ldap - from ipalib import api, errors - from ipalib.cli import textui - from ipapython.ipa_log_manager import root_logger -+from ipalib.text import _ - from ipapython import ipautil, ipaldap, kerberos - from ipapython.admintool import ScriptError - from ipapython.dn import DN -@@ -1599,6 +1600,11 @@ class ReplicationManager(object): - Disable the replication agreement to hostname. - """ - entry = self.get_replication_agreement(hostname) -+ if not entry: -+ raise errors.NotFound(reason=_( -+ "Replication agreement for %(hostname)s not found") % { -+ 'hostname': hostname -+ }) - entry['nsds5ReplicaEnabled'] = 'off' - - try: -@@ -1613,6 +1619,11 @@ class ReplicationManager(object): - Note: for replication to work it needs to be enabled both ways. - """ - entry = self.get_replication_agreement(hostname) -+ if not entry: -+ raise errors.NotFound(reason=_( -+ "Replication agreement for %(hostname)s not found") % { -+ 'hostname': hostname -+ }) - entry['nsds5ReplicaEnabled'] = 'on' - - try: --- -2.17.1 - diff --git a/SOURCES/0055-Fix-ipa-restore-create-var-run-ipa-files.patch b/SOURCES/0055-Fix-ipa-restore-create-var-run-ipa-files.patch deleted file mode 100644 index c47f4b9..0000000 --- a/SOURCES/0055-Fix-ipa-restore-create-var-run-ipa-files.patch +++ /dev/null @@ -1,47 +0,0 @@ -From be17d3c929027a5ef9f5024aa1bb4112006bb6f6 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud <flo@redhat.com> -Date: Mon, 6 Aug 2018 16:57:48 +0200 -Subject: [PATCH] Fix ipa-restore: create /var/run/ipa files - -In ipa 4.5.4, ipa-restore fails because the file /etc/tmpfiles.d/ipa.conf -is not restored => /var/run/ipa and /var/run/ipa/ccaches directories -are not created. - -The fix creates these directories in ipa-restore and creates ipa.conf. -With this approach, the fix allows to restore a backup done with 4.5.4 -prior to the fix. - -Note: the fix is specific to ipa-4-5, in ipa-4-6 and above version the file -/etc/tmpfiles.d/ipa.conf is created at package install time and not at -ipa server install time. - -Fixes: https://pagure.io/freeipa/issue/7571 -Reviewed-By: Christian Heimes <cheimes@redhat.com> ---- - ipaserver/install/ipa_restore.py | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index a3824df230857b02b47c12645fadee1200afdf66..e069b8ba9b7a01e7602e66d4404063bbc2a1e795 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -32,6 +32,7 @@ from six.moves.configparser import SafeConfigParser - from ipaclient.install.client import update_ipa_nssdb - from ipalib import api, errors - from ipalib.constants import FQDN -+from ipalib.constants import IPAAPI_USER - from ipapython import version, ipautil - from ipapython.ipautil import run, user_input - from ipapython import admintool -@@ -377,6 +378,8 @@ class Restore(admintool.AdminTool): - if restore_type == 'FULL': - self.remove_old_files() - self.cert_restore_prepare() -+ tasks.create_tmpfiles_dirs(IPAAPI_USER) -+ tasks.configure_tmpfiles() - self.file_restore(options.no_logs) - self.cert_restore() - if 'CA' in self.backup_services: --- -2.17.1 - diff --git a/SOURCES/0056-Sort-and-shuffle-SRV-record-by-priority-and-weight.patch b/SOURCES/0056-Sort-and-shuffle-SRV-record-by-priority-and-weight.patch deleted file mode 100644 index fcb6006..0000000 --- a/SOURCES/0056-Sort-and-shuffle-SRV-record-by-priority-and-weight.patch +++ /dev/null @@ -1,427 +0,0 @@ -From 9e2b0c4b026f281507d1879da8398841270bc20f Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Fri, 15 Jun 2018 17:03:29 +0200 -Subject: [PATCH] Sort and shuffle SRV record by priority and weight - -On multiple occasions, SRV query answers were not properly sorted by -priority. Records with same priority weren't randomized and shuffled. -This caused FreeIPA to contact the same remote peer instead of -distributing the load across all available servers. - -Two new helper functions now take care of SRV queries. sort_prio_weight() -sorts SRV and URI records. query_srv() combines SRV lookup with -sort_prio_weight(). - -Fixes: https://pagure.io/freeipa/issue/7475 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Rob Crittenden <rcritten@redhat.com> ---- - ipaclient/install/ipadiscovery.py | 3 +- - ipalib/rpc.py | 21 ++--- - ipalib/util.py | 11 ++- - ipapython/config.py | 8 +- - ipapython/dnsutil.py | 92 +++++++++++++++++++- - ipaserver/dcerpc.py | 4 +- - ipatests/test_ipapython/test_dnsutil.py | 106 ++++++++++++++++++++++++ - 7 files changed, 217 insertions(+), 28 deletions(-) - create mode 100644 ipatests/test_ipapython/test_dnsutil.py - -diff --git a/ipaclient/install/ipadiscovery.py b/ipaclient/install/ipadiscovery.py -index 46e05c971647b4f0fb4e6044ef74aff3e7919632..34142179a9f4957e842769d9d4036d2024130793 100644 ---- a/ipaclient/install/ipadiscovery.py -+++ b/ipaclient/install/ipadiscovery.py -@@ -25,6 +25,7 @@ from ipapython.ipa_log_manager import root_logger - from dns import resolver, rdatatype - from dns.exception import DNSException - from ipalib import errors -+from ipapython.dnsutil import query_srv - from ipapython import ipaldap - from ipaplatform.paths import paths - from ipapython.ipautil import valid_ip, realm_to_suffix -@@ -492,7 +493,7 @@ class IPADiscovery(object): - root_logger.debug("Search DNS for SRV record of %s", qname) - - try: -- answers = resolver.query(qname, rdatatype.SRV) -+ answers = query_srv(qname) - except DNSException as e: - root_logger.debug("DNS record not found: %s", e.__class__.__name__) - answers = [] -diff --git a/ipalib/rpc.py b/ipalib/rpc.py -index e3b8d67d69c084ad1a43390b5f93061826a27e1d..e74807d57955cd36aa8622b4441e08ee89cd313e 100644 ---- a/ipalib/rpc.py -+++ b/ipalib/rpc.py -@@ -43,7 +43,6 @@ import socket - import gzip - - import gssapi --from dns import resolver, rdatatype - from dns.exception import DNSException - from ssl import SSLError - import six -@@ -59,7 +58,7 @@ from ipapython.ipa_log_manager import root_logger - from ipapython import ipautil - from ipapython import session_storage - from ipapython.cookie import Cookie --from ipapython.dnsutil import DNSName -+from ipapython.dnsutil import DNSName, query_srv - from ipalib.text import _ - from ipalib.util import create_https_connection - from ipalib.krb_utils import KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN, KRB5KRB_AP_ERR_TKT_EXPIRED, \ -@@ -853,7 +852,7 @@ class RPCClient(Connectible): - name = '_ldap._tcp.%s.' % self.env.domain - - try: -- answers = resolver.query(name, rdatatype.SRV) -+ answers = query_srv(name) - except DNSException: - answers = [] - -@@ -861,17 +860,11 @@ class RPCClient(Connectible): - server = str(answer.target).rstrip(".") - servers.append('https://%s%s' % (ipautil.format_netloc(server), path)) - -- servers = list(set(servers)) -- # the list/set conversion won't preserve order so stick in the -- # local config file version here. -- cfg_server = rpc_uri -- if cfg_server in servers: -- # make sure the configured master server is there just once and -- # it is the first one -- servers.remove(cfg_server) -- servers.insert(0, cfg_server) -- else: -- servers.insert(0, cfg_server) -+ # make sure the configured master server is there just once and -+ # it is the first one. -+ if rpc_uri in servers: -+ servers.remove(rpc_uri) -+ servers.insert(0, rpc_uri) - - return servers - -diff --git a/ipalib/util.py b/ipalib/util.py -index 6ee65498b4de674fe4b2ee361541d3bfe648bba0..56db48638e8319859850fba449ed7c23b6e909ab 100644 ---- a/ipalib/util.py -+++ b/ipalib/util.py -@@ -934,14 +934,13 @@ def detect_dns_zone_realm_type(api, domain): - - try: - # The presence of this record is enough, return foreign in such case -- result = resolver.query(ad_specific_record_name, rdatatype.SRV) -- return 'foreign' -- -+ resolver.query(ad_specific_record_name, rdatatype.SRV) - except DNSException: -- pass -+ # If we could not detect type with certainty, return unknown -+ return 'unknown' -+ else: -+ return 'foreign' - -- # If we could not detect type with certainity, return unknown -- return 'unknown' - - def has_managed_topology(api): - domainlevel = api.Command['domainlevel_get']().get('result', DOMAIN_LEVEL_0) -diff --git a/ipapython/config.py b/ipapython/config.py -index 19abfc51ee354d2971be836fa6bad70eea3a6720..44c823b6b946c28a510e5f156061eba0b05aa059 100644 ---- a/ipapython/config.py -+++ b/ipapython/config.py -@@ -24,7 +24,6 @@ from optparse import ( - from copy import copy - import socket - --from dns import resolver, rdatatype - from dns.exception import DNSException - import dns.name - # pylint: disable=import-error -@@ -33,6 +32,7 @@ from six.moves.urllib.parse import urlsplit - # pylint: enable=import-error - - from ipapython.dn import DN -+from ipapython.dnsutil import query_srv - - try: - # pylint: disable=ipa-forbidden-import -@@ -195,7 +195,7 @@ def __discover_config(discover_server = True): - name = "_ldap._tcp." + domain - - try: -- servers = resolver.query(name, rdatatype.SRV) -+ servers = query_srv(name) - except DNSException: - # try cycling on domain components of FQDN - try: -@@ -210,7 +210,7 @@ def __discover_config(discover_server = True): - return False - name = "_ldap._tcp.%s" % domain - try: -- servers = resolver.query(name, rdatatype.SRV) -+ servers = query_srv(name) - break - except DNSException: - pass -@@ -221,7 +221,7 @@ def __discover_config(discover_server = True): - if not servers: - name = "_ldap._tcp.%s." % config.default_domain - try: -- servers = resolver.query(name, rdatatype.SRV) -+ servers = query_srv(name) - except DNSException: - pass - -diff --git a/ipapython/dnsutil.py b/ipapython/dnsutil.py -index 011b722dac3e181ac52f7d92d9f44d31c5e2e6bb..25435ba51e6e7c2c6581b60eb077dd133dd29724 100644 ---- a/ipapython/dnsutil.py -+++ b/ipapython/dnsutil.py -@@ -17,10 +17,15 @@ - # along with this program. If not, see <http://www.gnu.org/licenses/>. - # - -+import copy -+import operator -+import random -+ - import dns.name - import dns.exception - import dns.resolver --import copy -+import dns.rdataclass -+import dns.rdatatype - - import six - -@@ -369,3 +374,88 @@ def check_zone_overlap(zone, raise_on_error=True): - if ns: - msg += u" and is handled by server(s): {0}".format(', '.join(ns)) - raise ValueError(msg) -+ -+ -+def _mix_weight(records): -+ """Weighted population sorting for records with same priority -+ """ -+ # trivial case -+ if len(records) <= 1: -+ return records -+ -+ # Optimization for common case: If all weights are the same (e.g. 0), -+ # just shuffle the records, which is about four times faster. -+ if all(rr.weight == records[0].weight for rr in records): -+ random.shuffle(records) -+ return records -+ -+ noweight = 0.01 # give records with 0 weight a small chance -+ result = [] -+ records = set(records) -+ while len(records) > 1: -+ # Compute the sum of the weights of those RRs. Then choose a -+ # uniform random number between 0 and the sum computed (inclusive). -+ urn = random.uniform(0, sum(rr.weight or noweight for rr in records)) -+ # Select the RR whose running sum value is the first in the selected -+ # order which is greater than or equal to the random number selected. -+ acc = 0. -+ for rr in records.copy(): -+ acc += rr.weight or noweight -+ if acc >= urn: -+ records.remove(rr) -+ result.append(rr) -+ if records: -+ result.append(records.pop()) -+ return result -+ -+ -+def sort_prio_weight(records): -+ """RFC 2782 sorting algorithm for SRV and URI records -+ -+ RFC 2782 defines a sorting algorithms for SRV records, that is also used -+ for sorting URI records. Records are sorted by priority and than randomly -+ shuffled according to weight. -+ -+ This implementation also removes duplicate entries. -+ """ -+ # order records by priority -+ records = sorted(records, key=operator.attrgetter("priority")) -+ -+ # remove duplicate entries -+ uniquerecords = [] -+ seen = set() -+ for rr in records: -+ # A SRV record has target and port, URI just has target. -+ target = (rr.target, getattr(rr, "port", None)) -+ if target not in seen: -+ uniquerecords.append(rr) -+ seen.add(target) -+ -+ # weighted randomization of entries with same priority -+ result = [] -+ sameprio = [] -+ for rr in uniquerecords: -+ # add all items with same priority in a bucket -+ if not sameprio or sameprio[0].priority == rr.priority: -+ sameprio.append(rr) -+ else: -+ # got different priority, shuffle bucket -+ result.extend(_mix_weight(sameprio)) -+ # start a new priority list -+ sameprio = [rr] -+ # add last batch of records with same priority -+ if sameprio: -+ result.extend(_mix_weight(sameprio)) -+ return result -+ -+ -+def query_srv(qname, resolver=None, **kwargs): -+ """Query SRV records and sort reply according to RFC 2782 -+ -+ :param qname: query name, _service._proto.domain. -+ :return: list of dns.rdtypes.IN.SRV.SRV instances -+ """ -+ if resolver is None: -+ resolver = dns.resolver -+ answer = resolver.query(qname, rdtype=dns.rdatatype.SRV, **kwargs) -+ return sort_prio_weight(answer) -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index ac1b2a34784df491a3851aa21bbadbec2297241c..4e957b19292f51a7f6e3540dc38590737c7ae5e4 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -30,6 +30,7 @@ from ipalib import errors - from ipapython import ipautil - from ipapython.ipa_log_manager import root_logger - from ipapython.dn import DN -+from ipapython.dnsutil import query_srv - from ipaserver.install import installutils - from ipaserver.dcerpc_common import (TRUST_BIDIRECTIONAL, - TRUST_JOIN_EXTERNAL, -@@ -55,7 +56,6 @@ import samba - import ldap as _ldap - from ipapython import ipaldap - from ipapython.dnsutil import DNSName --from dns import resolver, rdatatype - from dns.exception import DNSException - import pysss_nss_idmap - import pysss -@@ -795,7 +795,7 @@ class DomainValidator(object): - gc_name = '_gc._tcp.%s.' % info['dns_domain'] - - try: -- answers = resolver.query(gc_name, rdatatype.SRV) -+ answers = query_srv(gc_name) - except DNSException as e: - answers = [] - -diff --git a/ipatests/test_ipapython/test_dnsutil.py b/ipatests/test_ipapython/test_dnsutil.py -new file mode 100644 -index 0000000000000000000000000000000000000000..36adb077cf38f6d036aa1048b201dee7d08eb310 ---- /dev/null -+++ b/ipatests/test_ipapython/test_dnsutil.py -@@ -0,0 +1,106 @@ -+# -+# Copyright (C) 2018 FreeIPA Contributors. See COPYING for license -+# -+import dns.name -+import dns.rdataclass -+import dns.rdatatype -+from dns.rdtypes.IN.SRV import SRV -+from dns.rdtypes.ANY.URI import URI -+ -+from ipapython import dnsutil -+ -+import pytest -+ -+ -+def mksrv(priority, weight, port, target): -+ return SRV( -+ rdclass=dns.rdataclass.IN, -+ rdtype=dns.rdatatype.SRV, -+ priority=priority, -+ weight=weight, -+ port=port, -+ target=dns.name.from_text(target) -+ ) -+ -+ -+def mkuri(priority, weight, target): -+ return URI( -+ rdclass=dns.rdataclass.IN, -+ rdtype=dns.rdatatype.URI, -+ priority=priority, -+ weight=weight, -+ target=target -+ ) -+ -+ -+class TestSortSRV(object): -+ def test_empty(self): -+ assert dnsutil.sort_prio_weight([]) == [] -+ -+ def test_one(self): -+ h1 = mksrv(1, 0, 443, u"host1") -+ assert dnsutil.sort_prio_weight([h1]) == [h1] -+ -+ h2 = mksrv(10, 5, 443, u"host2") -+ assert dnsutil.sort_prio_weight([h2]) == [h2] -+ -+ def test_prio(self): -+ h1 = mksrv(1, 0, 443, u"host1") -+ h2 = mksrv(2, 0, 443, u"host2") -+ h3 = mksrv(3, 0, 443, u"host3") -+ 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] -+ -+ h380 = mksrv(4, 0, 80, u"host3") -+ assert dnsutil.sort_prio_weight([h1, h3, h380]) == [h1, h3, h380] -+ -+ hs = mksrv(-1, 0, 443, u"special") -+ assert dnsutil.sort_prio_weight([h1, h2, hs]) == [hs, h1, h2] -+ -+ def assert_permutations(self, answers, permutations): -+ seen = set() -+ for _unused in range(1000): -+ result = tuple(dnsutil.sort_prio_weight(answers)) -+ assert result in permutations -+ seen.add(result) -+ if seen == permutations: -+ break -+ else: -+ pytest.fail("sorting didn't exhaust all permutations.") -+ -+ def test_sameprio(self): -+ h1 = mksrv(1, 0, 443, u"host1") -+ h2 = mksrv(1, 0, 443, u"host2") -+ permutations = { -+ (h1, h2), -+ (h2, h1), -+ } -+ self.assert_permutations([h1, h2], permutations) -+ -+ def test_weight(self): -+ h1 = mksrv(1, 0, 443, u"host1") -+ h2_w15 = mksrv(2, 15, 443, u"host2") -+ h3_w10 = mksrv(2, 10, 443, u"host3") -+ -+ permutations = { -+ (h1, h2_w15, h3_w10), -+ (h1, h3_w10, h2_w15), -+ } -+ self.assert_permutations([h1, h2_w15, h3_w10], permutations) -+ -+ def test_large(self): -+ records = tuple( -+ mksrv(1, i, 443, "host{}".format(i)) for i in range(1000) -+ ) -+ assert len(dnsutil.sort_prio_weight(records)) == len(records) -+ -+ -+class TestSortURI(object): -+ def test_prio(self): -+ h1 = mkuri(1, 0, u"https://host1/api") -+ h2 = mkuri(2, 0, u"https://host2/api") -+ h3 = mkuri(3, 0, u"https://host3/api") -+ 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] --- -2.17.1 - diff --git a/SOURCES/0057-Always-set-ca_host-when-installing-replica.patch b/SOURCES/0057-Always-set-ca_host-when-installing-replica.patch deleted file mode 100644 index bb73ba1..0000000 --- a/SOURCES/0057-Always-set-ca_host-when-installing-replica.patch +++ /dev/null @@ -1,43 +0,0 @@ -From f084ab0a6828efd8d76b4495e800f7cc7158d909 Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Tue, 19 Jun 2018 19:10:27 +0200 -Subject: [PATCH] Always set ca_host when installing replica - -ipa-replica-install only set ca_host in its temporary -/etc/ipa/default.conf, when it wasn't installing a replica with CA. As a -consequence, the replica installer was picking a random CA server from -LDAP. - -Always set the replication peer as ca_host. This will ensure that the -installer uses the same replication peer for CA. In case the replication -peer is not a CA master, the installer will automatically pick another -host later. - -See: https://pagure.io/freeipa/issue/7566 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> ---- - ipaserver/install/server/replicainstall.py | 6 ++---- - 1 file changed, 2 insertions(+), 4 deletions(-) - -diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index 8668859ba5da427ea6e752ed52af057635061f23..b10f761e3f643f9fa868451192fa4550b24b6b16 100644 ---- a/ipaserver/install/server/replicainstall.py -+++ b/ipaserver/install/server/replicainstall.py -@@ -236,11 +236,9 @@ def create_ipa_conf(fstore, config, ca_enabled, master=None): - gopts.extend([ - ipaconf.setOption('enable_ra', 'True'), - ipaconf.setOption('ra_plugin', 'dogtag'), -- ipaconf.setOption('dogtag_version', '10') -+ ipaconf.setOption('dogtag_version', '10'), -+ ipaconf.setOption('ca_host', config.ca_host_name) - ]) -- -- if not config.setup_ca: -- gopts.append(ipaconf.setOption('ca_host', config.ca_host_name)) - else: - gopts.extend([ - ipaconf.setOption('enable_ra', 'False'), --- -2.17.1 - diff --git a/SOURCES/0058-Improve-and-fix-timeout-bug-in-wait_for_entry.patch b/SOURCES/0058-Improve-and-fix-timeout-bug-in-wait_for_entry.patch deleted file mode 100644 index 78bf47d..0000000 --- a/SOURCES/0058-Improve-and-fix-timeout-bug-in-wait_for_entry.patch +++ /dev/null @@ -1,110 +0,0 @@ -From f52d626c166ad0f94f9d3752a4d8978dd3d9ccfc Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Fri, 22 Jun 2018 09:39:26 +0200 -Subject: [PATCH] Improve and fix timeout bug in wait_for_entry() - -replication.wait_for_entry() now can wait for an attribute value to -appear on a replica. - -Fixed timeout handling caused by bad rounding and comparison. For small -timeouts, the actual time was rounded down. For example for 60 seconds -timeout and fast replica, the query accumulated to about 0.45 seconds -plus 60 seconds sleep. 60.45 is large enough to terminate the loop -"while int(time.time()) < timeout", but not large enough to trigger the -exception in "if int(time.time()) > timeout", because int(60.65) == 60. - -See: https://pagure.io/freeipa/issue/7593 -Fixes: https://pagure.io/freeipa/issue/7595 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> ---- - ipaserver/install/replication.py | 57 +++++++++++++++++--------------- - 1 file changed, 31 insertions(+), 26 deletions(-) - -diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py -index d4b41caa45409fa1537ae10f182599307f3e0439..5a491f248236c8d2166484d0db2acccb28ccf178 100644 ---- a/ipaserver/install/replication.py -+++ b/ipaserver/install/replication.py -@@ -17,7 +17,9 @@ - # along with this program. If not, see <http://www.gnu.org/licenses/>. - # - --from __future__ import print_function -+from __future__ import print_function, absolute_import -+ -+import itertools - - import six - import time -@@ -170,40 +172,43 @@ def wait_for_task(conn, dn): - return exit_code - - --def wait_for_entry(connection, dn, timeout=7200, attr='', quiet=True): -- """Wait for entry and/or attr to show up""" -- -- filter = "(objectclass=*)" -+def wait_for_entry(connection, dn, timeout=7200, attr=None, attrvalue='*', -+ quiet=True): -+ """Wait for entry and/or attr to show up -+ """ -+ log = root_logger.debug if quiet else root_logger.info - attrlist = [] -- if attr: -- filter = "(%s=*)" % attr -+ if attr is not None: -+ filterstr = ipaldap.LDAPClient.make_filter_from_attr(attr, attrvalue) - attrlist.append(attr) -- timeout += int(time.time()) -- -- if not quiet: -- sys.stdout.write("Waiting for %s %s:%s " % (connection, dn, attr)) -- sys.stdout.flush() -- entry = None -- while not entry and int(time.time()) < timeout: -+ else: -+ filterstr = "(objectclass=*)" -+ log("Waiting for replication (%s) %s %s", connection, dn, filterstr) -+ entry = [] -+ deadline = time.time() + timeout -+ for i in itertools.count(start=1): - try: -- [entry] = connection.get_entries( -- dn, ldap.SCOPE_BASE, filter, attrlist) -+ entry = connection.get_entries( -+ dn, ldap.SCOPE_BASE, filterstr, attrlist) - except errors.NotFound: - pass # no entry yet - except Exception as e: # badness - root_logger.error("Error reading entry %s: %s", dn, e) - raise -- if not entry: -- if not quiet: -- sys.stdout.write(".") -- sys.stdout.flush() -- time.sleep(1) - -- if not entry and int(time.time()) > timeout: -- raise errors.NotFound( -- reason="wait_for_entry timeout for %s for %s" % (connection, dn)) -- elif entry and not quiet: -- root_logger.error("The waited for entry is: %s", entry) -+ if entry: -+ log("Entry found %r", entry) -+ return -+ elif time.time() > deadline: -+ raise errors.NotFound( -+ reason="wait_for_entry timeout on {} for {}".format( -+ connection, dn -+ ) -+ ) -+ else: -+ if i % 10 == 0: -+ root_logger.debug("Still waiting for replication of %s", dn) -+ time.sleep(1) - - - class ReplicationManager(object): --- -2.17.1 - diff --git a/SOURCES/0059-Use-common-replication-wait-timeout-of-5min.patch b/SOURCES/0059-Use-common-replication-wait-timeout-of-5min.patch deleted file mode 100644 index d752feb..0000000 --- a/SOURCES/0059-Use-common-replication-wait-timeout-of-5min.patch +++ /dev/null @@ -1,123 +0,0 @@ -From 3bf0ee3a4128dc538183ee8e45bc22a3966cfd4b Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Fri, 22 Jun 2018 10:00:24 +0200 -Subject: [PATCH] Use common replication wait timeout of 5min - -Instead of multiple timeout values all over the code base, all -replication waits now use a common timeout value from api.env of 5 -minutes. Waiting for HTTP/replica principal takes 90 to 120 seconds, so -5 minutes seem like a sufficient value for slow setups. - -Fixes: https://pagure.io/freeipa/issue/7595 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> ---- - ipalib/constants.py | 2 ++ - ipaserver/install/custodiainstance.py | 4 +++- - ipaserver/install/httpinstance.py | 6 +++++- - ipaserver/install/krbinstance.py | 13 ++++++++----- - ipaserver/install/replication.py | 6 ++++-- - 5 files changed, 22 insertions(+), 9 deletions(-) - -diff --git a/ipalib/constants.py b/ipalib/constants.py -index ab466bab7fc17a563a849e2cd9bb89515caff77b..b6a79ce716b3ee0f832390f5bc895c3bb9d37e33 100644 ---- a/ipalib/constants.py -+++ b/ipalib/constants.py -@@ -142,6 +142,8 @@ DEFAULT_CONFIG = ( - ('startup_timeout', 300), - # How long http connection should wait for reply [seconds]. - ('http_timeout', 30), -+ # How long to wait for an entry to appear on a replica -+ ('replication_wait_timeout', 300), - - # Web Application mount points - ('mount_ipa', '/ipa/'), -diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py -index ada8d03a6914e19c186264f68178cce2442945ca..b37032974e4825a3f3043929171533e4d94730e9 100644 ---- a/ipaserver/install/custodiainstance.py -+++ b/ipaserver/install/custodiainstance.py -@@ -4,6 +4,7 @@ from __future__ import print_function, absolute_import - - import enum - -+from ipalib import api - from ipaserver.secrets.kem import IPAKEMKeys, KEMLdap - from ipaserver.secrets.client import CustodiaClient - from ipaplatform.paths import paths -@@ -190,7 +191,8 @@ class CustodiaInstance(SimpleServiceInstance): - cli = self._get_custodia_client() - cli.fetch_key('dm/DMHash') - -- def _wait_keys(self, timeout=300): -+ def _wait_keys(self): -+ timeout = api.env.replication_wait_timeout - deadline = int(time.time()) + timeout - root_logger.info("Waiting up to %s seconds to see our keys " - "appear on host %s", timeout, self.ldap_uri) -diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py -index 434c2549dd868554735f4bcedc4cdceb23eeccdd..e68bfc09b34e087dfb4872b6565b06c6c2188384 100644 ---- a/ipaserver/install/httpinstance.py -+++ b/ipaserver/install/httpinstance.py -@@ -617,4 +617,8 @@ class HTTPInstance(service.Service): - else: - remote_ldap.simple_bind(ipaldap.DIRMAN_DN, - self.dm_password) -- replication.wait_for_entry(remote_ldap, service_dn, timeout=60) -+ replication.wait_for_entry( -+ remote_ldap, -+ service_dn, -+ timeout=api.env.replication_wait_timeout -+ ) -diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py -index 34fe46aa8ef297bf69eb74953c956ad9c3d30def..5971a30fc566f6e96ce0b08632772d33da5602d2 100644 ---- a/ipaserver/install/krbinstance.py -+++ b/ipaserver/install/krbinstance.py -@@ -390,13 +390,16 @@ class KrbInstance(service.Service): - def _wait_for_replica_kdc_entry(self): - master_dn = self.api.Object.server.get_dn(self.fqdn) - kdc_dn = DN(('cn', 'KDC'), master_dn) -- -- ldap_uri = 'ldap://{}'.format(self.master_fqdn) -- -+ ldap_uri = ipaldap.get_ldap_uri(self.master_fqdn) - with ipaldap.LDAPClient( -- ldap_uri, cacert=paths.IPA_CA_CRT) as remote_ldap: -+ ldap_uri, cacert=paths.IPA_CA_CRT, start_tls=True -+ ) as remote_ldap: - remote_ldap.gssapi_bind() -- replication.wait_for_entry(remote_ldap, kdc_dn, timeout=60) -+ replication.wait_for_entry( -+ remote_ldap, -+ kdc_dn, -+ timeout=api.env.replication_wait_timeout -+ ) - - def _call_certmonger(self, certmonger_ca='IPA'): - subject = str(DN(('cn', self.fqdn), self.subject_base)) -diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py -index 5a491f248236c8d2166484d0db2acccb28ccf178..c017764468674830670a817b3d815c5e2d78728e 100644 ---- a/ipaserver/install/replication.py -+++ b/ipaserver/install/replication.py -@@ -172,7 +172,7 @@ def wait_for_task(conn, dn): - return exit_code - - --def wait_for_entry(connection, dn, timeout=7200, attr=None, attrvalue='*', -+def wait_for_entry(connection, dn, timeout, attr=None, attrvalue='*', - quiet=True): - """Wait for entry and/or attr to show up - """ -@@ -799,7 +799,9 @@ class ReplicationManager(object): - # that we will have to set the memberof fixup task - self.need_memberof_fixup = True - -- wait_for_entry(a_conn, entry.dn) -+ wait_for_entry( -+ a_conn, entry.dn, timeout=api.env.replication_wait_timeout -+ ) - - def needs_memberof_fixup(self): - return self.need_memberof_fixup --- -2.17.1 - diff --git a/SOURCES/0060-Fix-replication-races-in-Dogtag-admin-code.patch b/SOURCES/0060-Fix-replication-races-in-Dogtag-admin-code.patch deleted file mode 100644 index b4eae37..0000000 --- a/SOURCES/0060-Fix-replication-races-in-Dogtag-admin-code.patch +++ /dev/null @@ -1,209 +0,0 @@ -From 9a576f7303fd1b7faae3a419f6d54720f234585b Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Fri, 22 Jun 2018 10:04:38 +0200 -Subject: [PATCH] Fix replication races in Dogtag admin code - -DogtagInstance.setup_admin and related methods have multiple LDAP -replication race conditions. The bugs can cause parallel -ipa-replica-install to fail. - -The code from __add_admin_to_group() has been changed to use MOD_ADD -ather than search + MOD_REPLACE. The MOD_REPLACE approach can lead to -data loss, when more than one writer changes a group. - -setup_admin() now waits until both admin user and group membership have -been replicated to the master peer. The method also adds a new ACI to -allow querying group member in the replication check. - -Fixes: https://pagure.io/freeipa/issue/7593 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> ---- - ipaserver/install/cainstance.py | 1 + - ipaserver/install/dogtaginstance.py | 101 ++++++++++++++++++++++------ - ipaserver/install/krainstance.py | 1 + - 3 files changed, 82 insertions(+), 21 deletions(-) - -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index 3a3558a5ded6de3e578574d08a5cdb59338e99c4..0c4d9bf9ad8ae11ac88523857845e16eb62651b9 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -377,6 +377,7 @@ class CAInstance(DogtagInstance): - # Setup Database - self.step("creating certificate server db", self.__create_ds_db) - self.step("setting up initial replication", self.__setup_replication) -+ self.step("creating ACIs for admin", self.add_ipaca_aci) - self.step("creating installation admin user", self.setup_admin) - self.step("configuring certificate server instance", - self.__spawn_instance) -diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py -index 9470e1a13608a8a84aab8a36c269a708e3f3e9f4..960b8cc7ce495bf5ca359f72b46aa0d43ccec5c3 100644 ---- a/ipaserver/install/dogtaginstance.py -+++ b/ipaserver/install/dogtaginstance.py -@@ -18,6 +18,8 @@ - # - - import base64 -+import time -+ - import ldap - import os - import shutil -@@ -84,6 +86,16 @@ class DogtagInstance(service.Service): - tracking_reqs = None - server_cert_name = None - -+ ipaca_groups = DN(('ou', 'groups'), ('o', 'ipaca')) -+ ipaca_people = DN(('ou', 'people'), ('o', 'ipaca')) -+ groups_aci = ( -+ b'(targetfilter="(objectClass=groupOfUniqueNames)")' -+ b'(targetattr="cn || description || objectclass || uniquemember")' -+ b'(version 3.0; acl "Allow users from o=ipaca to read groups"; ' -+ b'allow (read, search, compare) ' -+ b'userdn="ldap:///uid=*,ou=people,o=ipaca";)' -+ ) -+ - def __init__(self, realm, subsystem, service_desc, host_name=None, - nss_db=paths.PKI_TOMCAT_ALIAS_DIR, service_prefix=None): - """Initializer""" -@@ -101,10 +113,11 @@ class DogtagInstance(service.Service): - self.pkcs12_info = None - self.clone = False - -- self.basedn = DN(('o', 'ipa%s' % subsystem.lower())) -+ self.basedn = DN(('o', 'ipaca')) - self.admin_user = "admin" -- self.admin_dn = DN(('uid', self.admin_user), -- ('ou', 'people'), ('o', 'ipaca')) -+ self.admin_dn = DN( -+ ('uid', self.admin_user), self.ipaca_people -+ ) - self.admin_groups = None - self.tmp_agent_db = None - self.subsystem = subsystem -@@ -385,27 +398,33 @@ class DogtagInstance(service.Service): - - raise RuntimeError("%s configuration failed." % self.subsystem) - -- def __add_admin_to_group(self, group): -- dn = DN(('cn', group), ('ou', 'groups'), ('o', 'ipaca')) -- entry = api.Backend.ldap2.get_entry(dn) -- members = entry.get('uniqueMember', []) -- members.append(self.admin_dn) -- mod = [(ldap.MOD_REPLACE, 'uniqueMember', members)] -+ def add_ipaca_aci(self): -+ """Add ACI to allow ipaca users to read their own group information -+ -+ Dogtag users aren't allowed to enumerate their own groups. The -+ setup_admin() method needs the permission to wait, until all group -+ information has been replicated. -+ """ -+ dn = self.ipaca_groups -+ mod = [(ldap.MOD_ADD, 'aci', [self.groups_aci])] - try: - api.Backend.ldap2.modify_s(dn, mod) - except ldap.TYPE_OR_VALUE_EXISTS: -- # already there -- pass -+ self.log.debug( -+ "%s already has ACI to read group information", dn -+ ) -+ else: -+ self.log.debug("Added ACI to read groups to %s", dn) - - def setup_admin(self): - self.admin_user = "admin-%s" % self.fqdn - self.admin_password = ipautil.ipa_generate_password() -- self.admin_dn = DN(('uid', self.admin_user), -- ('ou', 'people'), ('o', 'ipaca')) -- -+ self.admin_dn = DN( -+ ('uid', self.admin_user), self.ipaca_people -+ ) - # remove user if left-over exists - try: -- entry = api.Backend.ldap2.delete_entry(self.admin_dn) -+ api.Backend.ldap2.delete_entry(self.admin_dn) - except errors.NotFound: - pass - -@@ -424,18 +443,58 @@ class DogtagInstance(service.Service): - ) - api.Backend.ldap2.add_entry(entry) - -+ wait_groups = [] - for group in self.admin_groups: -- self.__add_admin_to_group(group) -+ group_dn = DN(('cn', group), self.ipaca_groups) -+ mod = [(ldap.MOD_ADD, 'uniqueMember', [self.admin_dn])] -+ try: -+ api.Backend.ldap2.modify_s(group_dn, mod) -+ except ldap.TYPE_OR_VALUE_EXISTS: -+ # already there -+ return None -+ else: -+ wait_groups.append(group_dn) - - # Now wait until the other server gets replicated this data - ldap_uri = ipaldap.get_ldap_uri(self.master_host) -- master_conn = ipaldap.LDAPClient(ldap_uri) -- master_conn.gssapi_bind() -- replication.wait_for_entry(master_conn, entry.dn) -- del master_conn -+ master_conn = ipaldap.LDAPClient( -+ ldap_uri, start_tls=True, cacert=paths.IPA_CA_CRT -+ ) -+ self.log.debug( -+ "Waiting for %s to appear on %s", self.admin_dn, master_conn -+ ) -+ deadline = time.time() + api.env.replication_wait_timeout -+ while time.time() < deadline: -+ time.sleep(1) -+ try: -+ master_conn.simple_bind(self.admin_dn, self.admin_password) -+ except ldap.INVALID_CREDENTIALS: -+ pass -+ else: -+ self.log.debug("Successfully logged in as %s", self.admin_dn) -+ break -+ else: -+ self.log.error( -+ "Unable to log in as %s on %s", self.admin_dn, master_conn -+ ) -+ raise errors.NotFound( -+ reason="{} did not replicate to {}".format( -+ self.admin_dn, master_conn -+ ) -+ ) -+ -+ # wait for group membership -+ for group_dn in wait_groups: -+ replication.wait_for_entry( -+ master_conn, -+ group_dn, -+ timeout=api.env.replication_wait_timeout, -+ attr='uniqueMember', -+ attrvalue=self.admin_dn -+ ) - - def __remove_admin_from_group(self, group): -- dn = DN(('cn', group), ('ou', 'groups'), ('o', 'ipaca')) -+ dn = DN(('cn', group), self.ipaca_groups) - mod = [(ldap.MOD_DELETE, 'uniqueMember', self.admin_dn)] - try: - api.Backend.ldap2.modify_s(dn, mod) -diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py -index 990bb87ca2f0029d2450cbef47958399f534f2a6..915d3c3c6e038eeb6a8f94f1ed7f7008c0ef4ead 100644 ---- a/ipaserver/install/krainstance.py -+++ b/ipaserver/install/krainstance.py -@@ -111,6 +111,7 @@ class KRAInstance(DogtagInstance): - "A Dogtag CA must be installed first") - - if promote: -+ self.step("creating ACIs for admin", self.add_ipaca_aci) - self.step("creating installation admin user", self.setup_admin) - self.step("configuring KRA instance", self.__spawn_instance) - if not self.clone: --- -2.17.1 - diff --git a/SOURCES/0061-Increase-WSGI-process-count-to-5-on-64bit.patch b/SOURCES/0061-Increase-WSGI-process-count-to-5-on-64bit.patch deleted file mode 100644 index ff15210..0000000 --- a/SOURCES/0061-Increase-WSGI-process-count-to-5-on-64bit.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 6110a949aee9c98ab077c9cd907881ad82be5f45 Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Thu, 14 Jun 2018 17:04:13 +0200 -Subject: [PATCH] Increase WSGI process count to 5 on 64bit - -Increase the WSGI daemon worker process count from 2 processes to 5 -processes. This allows IPA RPC to handle more parallel requests. The -additional processes increase memory consumption by approximante 250 MB -in total. - -Since memory is scarce on 32bit platforms, only 64bit platforms are -bumped to 5 workers. - -Fixes: https://pagure.io/freeipa/issue/7587 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> ---- - install/conf/ipa.conf | 2 +- - ipaplatform/base/constants.py | 5 +++++ - ipaserver/install/httpinstance.py | 1 + - ipaserver/install/server/upgrade.py | 3 ++- - 4 files changed, 9 insertions(+), 2 deletions(-) - -diff --git a/install/conf/ipa.conf b/install/conf/ipa.conf -index 01bf9a4f97fc0cf197c0ad12743affa597b54911..34ced2ab9d91ae174a42a580e1c4f9436c1a8c3b 100644 ---- a/install/conf/ipa.conf -+++ b/install/conf/ipa.conf -@@ -51,7 +51,7 @@ WSGISocketPrefix /run/httpd/wsgi - - - # Configure mod_wsgi handler for /ipa --WSGIDaemonProcess ipa processes=2 threads=1 maximum-requests=500 \ -+WSGIDaemonProcess ipa processes=$WSGI_PROCESSES threads=1 maximum-requests=500 \ - user=ipaapi group=ipaapi display-name=%{GROUP} socket-timeout=2147483647 - WSGIImportScript /usr/share/ipa/wsgi.py process-group=ipa application-group=ipa - WSGIScriptAlias /ipa /usr/share/ipa/wsgi.py -diff --git a/ipaplatform/base/constants.py b/ipaplatform/base/constants.py -index dccb0e7191cb0d9644eb286b9ec061599afa3980..db250d9a40466e852453e7309c704a6897c6bcf8 100644 ---- a/ipaplatform/base/constants.py -+++ b/ipaplatform/base/constants.py -@@ -5,9 +5,11 @@ - ''' - This base platform module exports platform dependant constants. - ''' -+import sys - - - class BaseConstantsNamespace(object): -+ IS_64BITS = sys.maxsize > 2 ** 32 - DS_USER = 'dirsrv' - DS_GROUP = 'dirsrv' - HTTPD_USER = "apache" -@@ -28,3 +30,6 @@ class BaseConstantsNamespace(object): - # nfsd init variable used to enable kerberized NFS - SECURE_NFS_VAR = "SECURE_NFS" - SSSD_USER = "sssd" -+ # WSGIDaemonProcess process count. On 64bit platforms, each process -+ # consumes about 110 MB RSS, from which are about 35 MB shared. -+ WSGI_PROCESSES = 5 if IS_64BITS else 2 -diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py -index e68bfc09b34e087dfb4872b6565b06c6c2188384..7081c7418e76afbd1b4ae28deafefb6b264c62f0 100644 ---- a/ipaserver/install/httpinstance.py -+++ b/ipaserver/install/httpinstance.py -@@ -152,6 +152,7 @@ class HTTPInstance(service.Service): - DOMAIN=self.domain, - AUTOREDIR='' if auto_redirect else '#', - CRL_PUBLISH_PATH=paths.PKI_CA_PUBLISH_DIR, -+ WSGI_PROCESSES=constants.WSGI_PROCESSES, - ) - self.ca_file = ca_file - if ca_is_configured is not None: -diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py -index 793092be86da687fd21cf2c0ef3608f32fcf9f16..667b9d214ce76031b5d0f205e03ddb46178e9b2f 100644 ---- a/ipaserver/install/server/upgrade.py -+++ b/ipaserver/install/server/upgrade.py -@@ -1615,7 +1615,8 @@ def upgrade_configuration(): - AUTOREDIR='' if auto_redirect else '#', - CRL_PUBLISH_PATH=paths.PKI_CA_PUBLISH_DIR, - DOGTAG_PORT=8009, -- CLONE='#' -+ CLONE='#', -+ WSGI_PROCESSES=constants.WSGI_PROCESSES, - ) - - subject_base = find_subject_base() --- -2.17.1 - diff --git a/SOURCES/0062-Use-4-WSGI-workers-on-64bit-systems.patch b/SOURCES/0062-Use-4-WSGI-workers-on-64bit-systems.patch deleted file mode 100644 index eee7d99..0000000 --- a/SOURCES/0062-Use-4-WSGI-workers-on-64bit-systems.patch +++ /dev/null @@ -1,28 +0,0 @@ -From e9c4bf911675d88c300458faacdc32d2b80a189e Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Mon, 25 Jun 2018 10:59:18 +0200 -Subject: [PATCH] Use 4 WSGI workers on 64bit systems - -Commit f1d5ab3a03191dbb02e5f95308cf8c4f1971cdcf increases WSGI worker -count to five. This turned out to be a bit much for our test systems. -Four workers are good enough and still double the old amount. - -See: https://pagure.io/freeipa/issue/7587 -Signed-off-by: Christian Heimes <cheimes@redhat.com> ---- - ipaplatform/base/constants.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaplatform/base/constants.py b/ipaplatform/base/constants.py -index db250d9a40466e852453e7309c704a6897c6bcf8..8cfd46290d6e0021238c2f8d96a795928b2913df 100644 ---- a/ipaplatform/base/constants.py -+++ b/ipaplatform/base/constants.py -@@ -32,4 +32,4 @@ class BaseConstantsNamespace(object): - SSSD_USER = "sssd" - # WSGIDaemonProcess process count. On 64bit platforms, each process - # consumes about 110 MB RSS, from which are about 35 MB shared. -- WSGI_PROCESSES = 5 if IS_64BITS else 2 -+ WSGI_PROCESSES = 4 if IS_64BITS else 2 --- -2.17.1 - diff --git a/SOURCES/0063-Catch-ACIError-instead-of-invalid-credentials.patch b/SOURCES/0063-Catch-ACIError-instead-of-invalid-credentials.patch deleted file mode 100644 index ac76cb3..0000000 --- a/SOURCES/0063-Catch-ACIError-instead-of-invalid-credentials.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 699104cf8b8d0ec2570b3801e86c6a358343527a Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Fri, 29 Jun 2018 11:08:45 +0200 -Subject: [PATCH] Catch ACIError instead of invalid credentials - -ipaldap's LDAPClient client turns INVALID_CREDENTIAL error into -ACIError. Catch the ACIError and wait until the user has been -replicated. - -Apparently no manual or automated test ran into the timeout during -testing. - -Fixes: Fixes: https://pagure.io/freeipa/issue/7593 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> ---- - ipaserver/install/dogtaginstance.py | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py -index 960b8cc7ce495bf5ca359f72b46aa0d43ccec5c3..1f9742b287f58ed117aba627ad85ac3ced4b2645 100644 ---- a/ipaserver/install/dogtaginstance.py -+++ b/ipaserver/install/dogtaginstance.py -@@ -468,7 +468,8 @@ class DogtagInstance(service.Service): - time.sleep(1) - try: - master_conn.simple_bind(self.admin_dn, self.admin_password) -- except ldap.INVALID_CREDENTIALS: -+ except errors.ACIError: -+ # user not replicated yet - pass - else: - self.log.debug("Successfully logged in as %s", self.admin_dn) --- -2.17.1 - diff --git a/SOURCES/0064-Query-for-server-role-IPA-master.patch b/SOURCES/0064-Query-for-server-role-IPA-master.patch deleted file mode 100644 index 1d184fb..0000000 --- a/SOURCES/0064-Query-for-server-role-IPA-master.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 500be304c4b218b40acfa31cf987e541958b8985 Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Thu, 5 Jul 2018 23:50:37 +0200 -Subject: [PATCH] Query for server role IPA master - -server_find and server_role plugin were hiding IPA master role -information. It's now possible to fetch IPA master role information and -to filter by IPA master role, e.g. to ignore servers that have some -services configured but not (yet) enabled. - -See: https://pagure.io/freeipa/issue/7566 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> -Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> ---- - API.txt | 3 ++- - ipaserver/plugins/server.py | 9 +++++++-- - ipaserver/plugins/serverrole.py | 18 +++++++++++++++--- - 3 files changed, 24 insertions(+), 6 deletions(-) - -diff --git a/API.txt b/API.txt -index 5feed54947e044a0a2c908e70b44fe59a86972ff..7262a4122be06ab3ca2296897de84bea458fcf0a 100644 ---- a/API.txt -+++ b/API.txt -@@ -4421,9 +4421,10 @@ output: Entry('result') - output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) - output: PrimaryKey('value') - command: server_role_find/1 --args: 1,8,4 -+args: 1,9,4 - arg: Str('criteria?') - option: Flag('all', autofill=True, cli_name='all', default=False) -+option: Flag('include_master', autofill=True, default=False) - option: Flag('raw', autofill=True, cli_name='raw', default=False) - option: Str('role_servrole?', autofill=False, cli_name='role') - option: Str('server_server?', autofill=False, cli_name='server') -diff --git a/ipaserver/plugins/server.py b/ipaserver/plugins/server.py -index e0dc953a1ef870c95fdcdb629fb6ab3103e8f999..eb776aa8cf676c26d80c22ec87f8b5a310d0c6dc 100644 ---- a/ipaserver/plugins/server.py -+++ b/ipaserver/plugins/server.py -@@ -199,7 +199,10 @@ class server(LDAPObject): - return - - enabled_roles = self.api.Command.server_role_find( -- server_server=entry_attrs['cn'][0], status=ENABLED)['result'] -+ server_server=entry_attrs['cn'][0], -+ status=ENABLED, -+ include_master=True, -+ )['result'] - - enabled_role_names = [r[u'role_servrole'] for r in enabled_roles] - -@@ -333,7 +336,9 @@ class server_find(LDAPSearch): - role_status = self.api.Command.server_role_find( - server_server=None, - role_servrole=role, -- status=ENABLED)['result'] -+ status=ENABLED, -+ include_master=True, -+ )['result'] - - return set( - r[u'server_server'] for r in role_status) -diff --git a/ipaserver/plugins/serverrole.py b/ipaserver/plugins/serverrole.py -index b5781b0dff4c5d6f433e6a5531fc3e830ffcd972..db88b3885c538c2800f6e4a1d649083859d43641 100644 ---- a/ipaserver/plugins/serverrole.py -+++ b/ipaserver/plugins/serverrole.py -@@ -5,7 +5,7 @@ - from ipalib.crud import Retrieve, Search - from ipalib.errors import NotFound - from ipalib.frontend import Object --from ipalib.parameters import Int, Str, StrEnum -+from ipalib.parameters import Flag, Int, Str, StrEnum - from ipalib.plugable import Registry - from ipalib import _, ngettext - -@@ -129,6 +129,10 @@ class server_role_find(Search): - minvalue=0, - autofill=False, - ), -+ Flag( -+ 'include_master', -+ doc=_('Include IPA master entries'), -+ ) - ) - - def execute(self, *keys, **options): -@@ -151,8 +155,16 @@ class server_role_find(Search): - role_servrole=role_name, - status=status) - -- result = [ -- r for r in role_status if r[u'role_servrole'] != "IPA master"] -+ # Don't display "IPA master" information unless the role is -+ # requested explicitly. All servers are considered IPA masters, -+ # except for replicas during installation. -+ if options.get('include_master') or role_name == "IPA master": -+ result = role_status -+ else: -+ result = [ -+ r for r in role_status -+ if r[u'role_servrole'] != "IPA master" -+ ] - return dict( - result=result, - count=len(result), --- -2.17.1 - diff --git a/SOURCES/0065-Only-create-DNS-SRV-records-for-ready-server.patch b/SOURCES/0065-Only-create-DNS-SRV-records-for-ready-server.patch deleted file mode 100644 index 61ef03b..0000000 --- a/SOURCES/0065-Only-create-DNS-SRV-records-for-ready-server.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 0f6afe8ffa39804d7bb5e86e4aa447f4d56a4dfa Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Thu, 5 Jul 2018 23:59:06 +0200 -Subject: [PATCH] Only create DNS SRV records for ready server - -When installing multiple replicas in parallel, one replica may create -SRV entries for other replicas, although the replicas aren't fully -installed yet. This may cause some services to connect to a server, that -isn't ready to serve requests. - -The DNS IPASystemRecords framework now skips all servers that aren't -ready IPA masters. - -See: https://pagure.io/freeipa/issue/7566 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> -Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> ---- - ipaserver/dns_data_management.py | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/dns_data_management.py b/ipaserver/dns_data_management.py -index 2008ba6e7d387046b74e3de0af644d97b145ccb7..6016d8a0044d487c3118f43f199b2a433facfa9a 100644 ---- a/ipaserver/dns_data_management.py -+++ b/ipaserver/dns_data_management.py -@@ -93,7 +93,9 @@ class IPASystemRecords(object): - self.servers_data = {} - - servers_result = self.api_instance.Command.server_find( -- no_members=False)['result'] -+ no_members=False, -+ servrole=u"IPA master", # only active, fully installed masters -+ )['result'] - for s in servers_result: - weight, location, roles = self.__get_server_attrs(s) - self.servers_data[s['cn'][0]] = { -@@ -345,7 +347,9 @@ class IPASystemRecords(object): - zone_obj = zone.Zone(self.domain_abs, relativize=False) - if servers is None: - servers_result = self.api_instance.Command.server_find( -- pkey_only=True)['result'] -+ pkey_only=True, -+ servrole=u"IPA master", # only fully installed masters -+ )['result'] - servers = [s['cn'][0] for s in servers_result] - - locations_result = self.api_instance.Command.location_find()['result'] --- -2.17.1 - diff --git a/SOURCES/0066-Delay-enabling-services-until-end-of-installer.patch b/SOURCES/0066-Delay-enabling-services-until-end-of-installer.patch deleted file mode 100644 index 9395c45..0000000 --- a/SOURCES/0066-Delay-enabling-services-until-end-of-installer.patch +++ /dev/null @@ -1,602 +0,0 @@ -From f0d829754e2e35225f0dfba980c9f4bae011407e Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Fri, 6 Jul 2018 00:04:39 +0200 -Subject: [PATCH] Delay enabling services until end of installer - -Service entries in cn=FQDN,cn=masters,cn=ipa,cn=etc are no longer -created as enabled. Instead they are flagged as configuredService. At -the very end of the installer, the service entries are switched from -configured to enabled service. - -- SRV records are created at the very end of the installer. -- Dogtag installer only picks fully installed servers -- Certmonger ignores all configured but not yet enabled servers. - -Fixes: https://pagure.io/freeipa/issue/7566 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> -Reviewed-By: Fraser Tweedale <ftweedal@redhat.com> ---- - install/tools/ipa-adtrust-install | 6 +- - install/tools/ipa-ca-install | 12 ++- - install/tools/ipa-dns-install | 4 + - ipaserver/dns_data_management.py | 18 +++-- - ipaserver/install/adtrustinstance.py | 6 +- - ipaserver/install/bindinstance.py | 6 +- - ipaserver/install/cainstance.py | 2 +- - ipaserver/install/dnskeysyncinstance.py | 4 +- - ipaserver/install/httpinstance.py | 4 +- - ipaserver/install/ipa_kra_install.py | 7 ++ - ipaserver/install/krainstance.py | 2 +- - ipaserver/install/krbinstance.py | 4 +- - ipaserver/install/odsexporterinstance.py | 4 +- - ipaserver/install/opendnssecinstance.py | 6 +- - ipaserver/install/server/install.py | 18 +++-- - ipaserver/install/server/replicainstall.py | 9 ++- - ipaserver/install/service.py | 90 ++++++++++++++++++++-- - ipaserver/plugins/serverrole.py | 7 +- - 18 files changed, 161 insertions(+), 48 deletions(-) - -diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install -index 1484598adba5b1237f00cc55e95167d45a6b40d7..4258f489873b4095a6672e20f2ac5f2858b71982 100755 ---- a/install/tools/ipa-adtrust-install -+++ b/install/tools/ipa-adtrust-install -@@ -31,7 +31,7 @@ import six - from optparse import SUPPRESS_HELP # pylint: disable=deprecated-module - - from ipalib.install import sysrestore --from ipaserver.install import adtrust -+from ipaserver.install import adtrust, service - from ipaserver.install.installutils import ( - read_password, - check_server_configuration, -@@ -210,6 +210,10 @@ def main(): - adtrust.install_check(True, options, api) - adtrust.install(True, options, fstore, api) - -+ # Enable configured services and update DNS SRV records -+ service.enable_services(api.env.host) -+ api.Command.dns_update_system_records() -+ - print(""" - ============================================================================= - Setup complete -diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install -index a3694007e5815d1c44f642057c749879d336dfc5..215a60ae744577de73a7260bbf3dea5a09a4d118 100755 ---- a/install/tools/ipa-ca-install -+++ b/install/tools/ipa-ca-install -@@ -303,18 +303,26 @@ def main(): - ) - api.finalize() - api.Backend.ldap2.connect() -- - domain_level = dsinstance.get_domain_level(api) -+ - if domain_level > DOMAIN_LEVEL_0: - promote(safe_options, options, filename) - else: - install(safe_options, options, filename) - -+ # pki-spawn restarts 389-DS, reconnect -+ api.Backend.ldap2.close() -+ api.Backend.ldap2.connect() -+ -+ # Enable configured services and update DNS SRV records -+ service.enable_services(api.env.host) -+ api.Command.dns_update_system_records() -+ api.Backend.ldap2.disconnect() -+ - # execute ipactl to refresh services status - ipautil.run(['ipactl', 'start', '--ignore-service-failures'], - raiseonerr=False) - -- api.Backend.ldap2.disconnect() - - fail_message = ''' - Your system may be partly configured. -diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install -index cb6c5d887f101135ca593ea6d4ed0caf51478a4c..04d1b140d2c79a0fa72d7df47d556643751bddb7 100755 ---- a/install/tools/ipa-dns-install -+++ b/install/tools/ipa-dns-install -@@ -36,6 +36,7 @@ from ipapython.config import IPAOptionParser - from ipapython.ipa_log_manager import standard_logging_setup, root_logger - - from ipaserver.install import dns as dns_installer -+from ipaserver.install import service - - log_file_name = paths.IPASERVER_INSTALL_LOG - -@@ -145,6 +146,9 @@ def main(): - - dns_installer.install_check(True, api, False, options, hostname=api.env.host) - dns_installer.install(True, False, options) -+ # Enable configured services and update DNS SRV records -+ service.enable_services(api.env.host) -+ api.Command.dns_update_system_records() - - # execute ipactl to refresh services status - ipautil.run(['ipactl', 'start', '--ignore-service-failures'], -diff --git a/ipaserver/dns_data_management.py b/ipaserver/dns_data_management.py -index 6016d8a0044d487c3118f43f199b2a433facfa9a..e5987b4bd7b43d3920e9da917258153e448206b7 100644 ---- a/ipaserver/dns_data_management.py -+++ b/ipaserver/dns_data_management.py -@@ -65,11 +65,11 @@ class IPASystemRecords(object): - PRIORITY_HIGH = 0 - PRIORITY_LOW = 50 - -- def __init__(self, api_instance): -+ def __init__(self, api_instance, all_servers=False): - self.api_instance = api_instance - self.domain_abs = DNSName(self.api_instance.env.domain).make_absolute() - self.servers_data = {} -- self.__init_data() -+ self.__init_data(all_servers=all_servers) - - def reload_data(self): - """ -@@ -89,14 +89,16 @@ class IPASystemRecords(object): - def __get_location_suffix(self, location): - return location + DNSName('_locations') + self.domain_abs - -- def __init_data(self): -+ def __init_data(self, all_servers=False): - self.servers_data = {} - -- servers_result = self.api_instance.Command.server_find( -- no_members=False, -- servrole=u"IPA master", # only active, fully installed masters -- )['result'] -- for s in servers_result: -+ kwargs = dict(no_members=False) -+ if not all_servers: -+ # only active, fully installed masters] -+ kwargs["servrole"] = u"IPA master" -+ servers = self.api_instance.Command.server_find(**kwargs) -+ -+ for s in servers['result']: - weight, location, roles = self.__get_server_attrs(s) - self.servers_data[s['cn'][0]] = { - 'weight': weight, -diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py -index b4db055045823ce8ae7e3b264e1442a085f81b2d..a7261b92ac227228b5b6af41db621ed2e5e96668 100644 ---- a/ipaserver/install/adtrustinstance.py -+++ b/ipaserver/install/adtrustinstance.py -@@ -581,7 +581,7 @@ class ADTRUSTInstance(service.Service): - self.print_msg(err_msg) - self.print_msg("Add the following service records to your DNS " \ - "server for DNS zone %s: " % zone) -- system_records = IPASystemRecords(api) -+ system_records = IPASystemRecords(api, all_servers=True) - adtrust_records = system_records.get_base_records( - [self.fqdn], ["AD trust controller"], - include_master_role=False, include_kerberos_realm=False) -@@ -734,12 +734,12 @@ class ADTRUSTInstance(service.Service): - # Note that self.dm_password is None for ADTrustInstance because - # we ensure to be called as root and using ldapi to use autobind - try: -- self.ldap_enable('ADTRUST', self.fqdn, None, self.suffix) -+ self.ldap_configure('ADTRUST', self.fqdn, None, self.suffix) - except (ldap.ALREADY_EXISTS, errors.DuplicateEntry): - root_logger.info("ADTRUST Service startup entry already exists.") - - try: -- self.ldap_enable('EXTID', self.fqdn, None, self.suffix) -+ self.ldap_configure('EXTID', self.fqdn, None, self.suffix) - except (ldap.ALREADY_EXISTS, errors.DuplicateEntry): - root_logger.info("EXTID Service startup entry already exists.") - -diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py -index 03dce56aa0610b3dc530e6b2a185515be7956e8b..771c6b0483d07b20fbc8470397eed306651f4a8f 100644 ---- a/ipaserver/install/bindinstance.py -+++ b/ipaserver/install/bindinstance.py -@@ -664,7 +664,7 @@ class BindInstance(service.Service): - return normalize_zone(self.host_domain) == normalize_zone(self.domain) - - def create_file_with_system_records(self): -- system_records = IPASystemRecords(self.api) -+ system_records = IPASystemRecords(self.api, all_servers=True) - text = u'\n'.join( - IPASystemRecords.records_list_from_zone( - system_records.get_base_records() -@@ -741,7 +741,7 @@ class BindInstance(service.Service): - # Instead we reply on the IPA init script to start only enabled - # components as found in our LDAP configuration tree - try: -- self.ldap_enable('DNS', self.fqdn, None, self.suffix) -+ self.ldap_configure('DNS', self.fqdn, None, self.suffix) - except errors.DuplicateEntry: - # service already exists (forced DNS reinstall) - # don't crash, just report error -@@ -1175,7 +1175,7 @@ class BindInstance(service.Service): - except ValueError as error: - root_logger.debug(error) - -- # disabled by default, by ldap_enable() -+ # disabled by default, by ldap_configure() - if enabled: - self.enable() - -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index 0c4d9bf9ad8ae11ac88523857845e16eb62651b9..62e9ad7de6f00eabb48f726a3931eb8acf0ba22b 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -1218,7 +1218,7 @@ class CAInstance(DogtagInstance): - config = ['caRenewalMaster'] - else: - config = [] -- self.ldap_enable('CA', self.fqdn, None, basedn, config) -+ self.ldap_configure('CA', self.fqdn, None, basedn, config) - - def setup_lightweight_ca_key_retrieval(self): - if sysupgrade.get_upgrade_state('dogtag', 'setup_lwca_key_retrieval'): -diff --git a/ipaserver/install/dnskeysyncinstance.py b/ipaserver/install/dnskeysyncinstance.py -index 3849626e5a253667271913337d1a5aa4a72755bb..28468826d7194e7103e61c0ef3957b849e1be896 100644 ---- a/ipaserver/install/dnskeysyncinstance.py -+++ b/ipaserver/install/dnskeysyncinstance.py -@@ -384,8 +384,8 @@ class DNSKeySyncInstance(service.Service): - - def __enable(self): - try: -- self.ldap_enable('DNSKeySync', self.fqdn, None, -- self.suffix, self.extra_config) -+ self.ldap_configure('DNSKeySync', self.fqdn, None, -+ self.suffix, self.extra_config) - except errors.DuplicateEntry: - self.logger.error("DNSKeySync service already exists") - -diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py -index 7081c7418e76afbd1b4ae28deafefb6b264c62f0..2df51eaa77d3ee3246027a6bcbc4023dbad61160 100644 ---- a/ipaserver/install/httpinstance.py -+++ b/ipaserver/install/httpinstance.py -@@ -200,7 +200,7 @@ class HTTPInstance(service.Service): - # We do not let the system start IPA components on its own, - # Instead we reply on the IPA init script to start only enabled - # components as found in our LDAP configuration tree -- self.ldap_enable('HTTP', self.fqdn, None, self.suffix) -+ self.ldap_configure('HTTP', self.fqdn, None, self.suffix) - - def configure_selinux_for_httpd(self): - try: -@@ -583,7 +583,7 @@ class HTTPInstance(service.Service): - if running: - self.restart() - -- # disabled by default, by ldap_enable() -+ # disabled by default, by ldap_configure() - if enabled: - self.enable() - -diff --git a/ipaserver/install/ipa_kra_install.py b/ipaserver/install/ipa_kra_install.py -index 9ebabe057513141ee76d238a3f20e76a27dd932e..3a639ac20f101293edd7449f8846a451469e2297 100644 ---- a/ipaserver/install/ipa_kra_install.py -+++ b/ipaserver/install/ipa_kra_install.py -@@ -224,4 +224,11 @@ class KRAInstaller(KRAInstall): - self.log.error(dedent(self.FAIL_MESSAGE)) - raise - -+ # pki-spawn restarts 389-DS, reconnect -+ api.Backend.ldap2.close() -+ api.Backend.ldap2.connect() -+ -+ # Enable configured services and update DNS SRV records -+ service.enable_services(api.env.host) -+ api.Command.dns_update_system_records() - api.Backend.ldap2.disconnect() -diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py -index 915d3c3c6e038eeb6a8f94f1ed7f7008c0ef4ead..a23de3960f0789761b4b86227508236c80e97c2f 100644 ---- a/ipaserver/install/krainstance.py -+++ b/ipaserver/install/krainstance.py -@@ -376,4 +376,4 @@ class KRAInstance(DogtagInstance): - directives[nickname], cert, paths.KRA_CS_CFG_PATH) - - def __enable_instance(self): -- self.ldap_enable('KRA', self.fqdn, None, self.suffix) -+ self.ldap_configure('KRA', self.fqdn, None, self.suffix) -diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py -index 5971a30fc566f6e96ce0b08632772d33da5602d2..4041d1b5fb3c3cf3db78b6cb282ce5f17793a0e3 100644 ---- a/ipaserver/install/krbinstance.py -+++ b/ipaserver/install/krbinstance.py -@@ -240,7 +240,7 @@ class KrbInstance(service.Service): - # We do not let the system start IPA components on its own, - # Instead we reply on the IPA init script to start only enabled - # components as found in our LDAP configuration tree -- self.ldap_enable('KDC', self.fqdn, None, self.suffix) -+ self.ldap_configure('KDC', self.fqdn, None, self.suffix) - - def __start_instance(self): - try: -@@ -598,7 +598,7 @@ class KrbInstance(service.Service): - except ValueError as error: - root_logger.debug(error) - -- # disabled by default, by ldap_enable() -+ # disabled by default, by ldap_configure() - if enabled: - self.enable() - -diff --git a/ipaserver/install/odsexporterinstance.py b/ipaserver/install/odsexporterinstance.py -index 59f27f578dab5663b1a7b734dff3699a6996084d..1694704f967b0b2a5debe76252ae859ae8a47f2b 100644 ---- a/ipaserver/install/odsexporterinstance.py -+++ b/ipaserver/install/odsexporterinstance.py -@@ -69,8 +69,8 @@ class ODSExporterInstance(service.Service): - def __enable(self): - - try: -- self.ldap_enable('DNSKeyExporter', self.fqdn, None, -- self.suffix) -+ self.ldap_configure('DNSKeyExporter', self.fqdn, None, -+ self.suffix) - except errors.DuplicateEntry: - root_logger.error("DNSKeyExporter service already exists") - -diff --git a/ipaserver/install/opendnssecinstance.py b/ipaserver/install/opendnssecinstance.py -index bc2974a2cf56e4ade1b778303c14f9ce05a8bf0f..92a46a9f6e318454084398ed625cf27a8250c2af 100644 ---- a/ipaserver/install/opendnssecinstance.py -+++ b/ipaserver/install/opendnssecinstance.py -@@ -136,8 +136,8 @@ class OpenDNSSECInstance(service.Service): - - def __enable(self): - try: -- self.ldap_enable('DNSSEC', self.fqdn, None, -- self.suffix, self.extra_config) -+ self.ldap_configure('DNSSEC', self.fqdn, None, -+ self.suffix, self.extra_config) - except errors.DuplicateEntry: - root_logger.error("DNSSEC service already exists") - -@@ -368,7 +368,7 @@ class OpenDNSSECInstance(service.Service): - - self.restore_state("kasp_db_configured") # just eat state - -- # disabled by default, by ldap_enable() -+ # disabled by default, by ldap_configure() - if enabled: - self.enable() - -diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py -index 3651cde827ecf299e5570feed4936311f91749fb..dcdd9aabb746c4973b3f73934d94225503728f0b 100644 ---- a/ipaserver/install/server/install.py -+++ b/ipaserver/install/server/install.py -@@ -869,14 +869,6 @@ def install(installer): - - if options.setup_dns: - dns.install(False, False, options) -- else: -- # Create a BIND instance -- bind = bindinstance.BindInstance(fstore) -- bind.setup(host_name, ip_addresses, realm_name, -- domain_name, (), 'first', (), -- zonemgr=options.zonemgr, -- no_dnssec_validation=options.no_dnssec_validation) -- bind.create_file_with_system_records() - - if options.setup_adtrust: - adtrust.install(False, options, fstore, api) -@@ -908,6 +900,16 @@ def install(installer): - # Make sure the files we crated in /var/run are recreated at startup - tasks.configure_tmpfiles() - -+ # Enable configured services and update DNS SRV records -+ service.enable_services(host_name) -+ api.Command.dns_update_system_records() -+ -+ if not options.setup_dns: -+ # After DNS and AD trust are configured and services are -+ # enabled, create a dummy instance to dump DNS configuration. -+ bind = bindinstance.BindInstance(fstore) -+ bind.create_file_with_system_records() -+ - # Everything installed properly, activate ipa service. - services.knownservices.ipa.enable() - -diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index b10f761e3f643f9fa868451192fa4550b24b6b16..59fec452c674b9941ce731748dd63985a08fefc0 100644 ---- a/ipaserver/install/server/replicainstall.py -+++ b/ipaserver/install/server/replicainstall.py -@@ -1518,14 +1518,10 @@ def install(installer): - - if options.setup_dns: - dns.install(False, True, options, api) -- else: -- api.Command.dns_update_system_records() - - if options.setup_adtrust: - adtrust.install(False, options, fstore, api) - -- api.Backend.ldap2.disconnect() -- - if not promote: - # Call client install script - service.print_msg("Configuring client side components") -@@ -1556,6 +1552,11 @@ def install(installer): - # Make sure the files we crated in /var/run are recreated at startup - tasks.configure_tmpfiles() - -+ # Enable configured services and update DNS SRV records -+ service.enable_services(config.host_name) -+ api.Command.dns_update_system_records() -+ api.Backend.ldap2.disconnect() -+ - # Everything installed properly, activate ipa service. - services.knownservices.ipa.enable() - -diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py -index 0523e914aa7debf6aaa82ddcce9b7b26c1833cd3..4271ebe06be03199165894f7a884e17f311896cb 100644 ---- a/ipaserver/install/service.py -+++ b/ipaserver/install/service.py -@@ -24,6 +24,7 @@ import socket - import datetime - import traceback - import tempfile -+import warnings - - import six - -@@ -59,6 +60,10 @@ SERVICE_LIST = { - 'DNSKeySync': ('ipa-dnskeysyncd', 110), - } - -+CONFIGURED_SERVICE = u'configuredService' -+ENABLED_SERVICE = 'enabledService' -+ -+ - def print_msg(message, output_fd=sys.stdout): - root_logger.debug(message) - output_fd.write(message) -@@ -120,7 +125,7 @@ def find_providing_server(svcname, conn, host_name=None, api=api): - """ - dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) - query_filter = conn.make_filter({'objectClass': 'ipaConfigObject', -- 'ipaConfigString': 'enabledService', -+ 'ipaConfigString': ENABLED_SERVICE, - 'cn': svcname}, rules='&') - try: - entries, _trunc = conn.find_entries(filter=query_filter, base_dn=dn) -@@ -217,6 +222,53 @@ def set_service_entry_config(name, fqdn, config_values, - raise e - - -+def enable_services(fqdn): -+ """Change all configured services to enabled -+ -+ Server.ldap_configure() only marks a service as configured. Services -+ are enabled at the very end of installation. -+ -+ Note: DNS records must be updated with dns_update_system_records, too. -+ -+ :param fqdn: hostname of server -+ """ -+ ldap2 = api.Backend.ldap2 -+ search_base = DN(('cn', fqdn), api.env.container_masters, api.env.basedn) -+ search_filter = ldap2.make_filter( -+ { -+ 'objectClass': 'ipaConfigObject', -+ 'ipaConfigString': CONFIGURED_SERVICE -+ }, -+ rules='&' -+ ) -+ entries = ldap2.get_entries( -+ search_base, -+ filter=search_filter, -+ scope=api.Backend.ldap2.SCOPE_ONELEVEL, -+ attrs_list=['cn', 'ipaConfigString'] -+ ) -+ for entry in entries: -+ name = entry['cn'] -+ cfgstrings = entry.setdefault('ipaConfigString', []) -+ for value in list(cfgstrings): -+ if value.lower() == CONFIGURED_SERVICE.lower(): -+ cfgstrings.remove(value) -+ if not case_insensitive_attr_has_value(cfgstrings, ENABLED_SERVICE): -+ cfgstrings.append(ENABLED_SERVICE) -+ -+ try: -+ ldap2.update_entry(entry) -+ except errors.EmptyModlist: -+ root_logger.debug("Nothing to do for service %s", name) -+ except Exception: -+ root_logger.exception( -+ "failed to set service %s config values", name -+ ) -+ raise -+ else: -+ root_logger.debug("Enabled service %s for %s", name, fqdn) -+ -+ - class Service(object): - def __init__(self, service_name, service_desc=None, sstore=None, - fstore=None, api=api, realm_name=None, -@@ -522,7 +574,35 @@ class Service(object): - self.steps = [] - - def ldap_enable(self, name, fqdn, dm_password=None, ldap_suffix='', -- config=[]): -+ config=()): -+ """Legacy function, all services should use ldap_configure() -+ """ -+ warnings.warn( -+ "ldap_enable is deprecated, use ldap_configure instead.", -+ DeprecationWarning, -+ stacklevel=2 -+ ) -+ self._ldap_enable(ENABLED_SERVICE, name, fqdn, ldap_suffix, config) -+ -+ def ldap_configure(self, name, fqdn, dm_password=None, ldap_suffix='', -+ config=()): -+ """Create or modify service entry in cn=masters,cn=ipa,cn=etc -+ -+ Contrary to ldap_enable(), the method only sets -+ ipaConfigString=configuredService. ipaConfigString=enabledService -+ is set at the very end of the installation process, to ensure that -+ other machines see this master/replica after it is fully installed. -+ -+ To switch all configured services to enabled, use:: -+ -+ ipaserver.install.service.enable_services(api.env.host) -+ api.Command.dns_update_system_records() -+ """ -+ self._ldap_enable( -+ CONFIGURED_SERVICE, name, fqdn, ldap_suffix, config -+ ) -+ -+ def _ldap_enable(self, value, name, fqdn, ldap_suffix, config): - extra_config_opts = [ - ' '.join([u'startOrder', unicode(SERVICE_LIST[name][1])]) - ] -@@ -533,7 +613,7 @@ class Service(object): - set_service_entry_config( - name, - fqdn, -- [u'enabledService'], -+ [value], - ldap_suffix=ldap_suffix, - post_add_config=extra_config_opts) - -@@ -559,7 +639,7 @@ class Service(object): - - # case insensitive - for value in entry.get('ipaConfigString', []): -- if value.lower() == u'enabledservice': -+ if value.lower() == ENABLED_SERVICE: - entry['ipaConfigString'].remove(value) - break - -@@ -672,7 +752,7 @@ class SimpleServiceInstance(Service): - if self.gensvc_name == None: - self.enable() - else: -- self.ldap_enable(self.gensvc_name, self.fqdn, None, self.suffix) -+ self.ldap_configure(self.gensvc_name, self.fqdn, None, self.suffix) - - def is_installed(self): - return self.service.is_installed() -diff --git a/ipaserver/plugins/serverrole.py b/ipaserver/plugins/serverrole.py -index db88b3885c538c2800f6e4a1d649083859d43641..35b199387b4d3512d39f197d125c20571e23ad7a 100644 ---- a/ipaserver/plugins/serverrole.py -+++ b/ipaserver/plugins/serverrole.py -@@ -15,16 +15,21 @@ IPA server roles - """) + _(""" - Get status of roles (DNS server, CA, etc.) provided by IPA masters. - """) + _(""" -+The status of a role is either enabled, configured, or absent. -+""") + _(""" - EXAMPLES: - """) + _(""" - Show status of 'DNS server' role on a server: - ipa server-role-show ipa.example.com "DNS server" - """) + _(""" - Show status of all roles containing 'AD' on a server: -- ipa server-role-find --server ipa.example.com --role='AD' -+ ipa server-role-find --server ipa.example.com --role="AD trust controller" - """) + _(""" - Show status of all configured roles on a server: - ipa server-role-find ipa.example.com -+""") + _(""" -+ Show implicit IPA master role: -+ ipa server-role-find --include-master - """) - - --- -2.17.1 - diff --git a/SOURCES/0067-replicainstall-DS-SSL-replica-install-pick-right-cer.patch b/SOURCES/0067-replicainstall-DS-SSL-replica-install-pick-right-cer.patch deleted file mode 100644 index f4c2388..0000000 --- a/SOURCES/0067-replicainstall-DS-SSL-replica-install-pick-right-cer.patch +++ /dev/null @@ -1,55 +0,0 @@ -From ab325034a6d837cc51db2aa029498fa222e9d4e7 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden <rcritten@redhat.com> -Date: Fri, 6 Jul 2018 09:26:19 -0400 -Subject: [PATCH] replicainstall: DS SSL replica install pick right certmonger - host - -Extend fix 0f31564b35aac250456233f98730811560eda664 to also move -the DS SSL setup so that the xmlrpc_uri is configured to point -to the remote master we are configuring against. - -https://pagure.io/freeipa/issue/7566 - -Signed-off-by: Rob Crittenden <rcritten@redhat.com> -Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> ---- - ipaserver/install/server/replicainstall.py | 14 +++++++------- - 1 file changed, 7 insertions(+), 7 deletions(-) - -diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index 59fec452c674b9941ce731748dd63985a08fefc0..a47412e39b9e2c603206c56a935de17321c71e91 100644 ---- a/ipaserver/install/server/replicainstall.py -+++ b/ipaserver/install/server/replicainstall.py -@@ -1444,15 +1444,12 @@ def install(installer): - pkcs12_info=pkinit_pkcs12_info, - promote=promote) - -- # we now need to enable ssl on the ds -- ds.enable_ssl() -- - if promote: - # We need to point to the master when certmonger asks for -- # HTTP certificate. -- # During http installation, the HTTP/hostname principal is created -- # locally then the installer waits for the entry to appear on the -- # master selected for the installation. -+ # a DS or HTTP certificate. -+ # During http installation, the <service>/hostname principal is -+ # created locally then the installer waits for the entry to appear -+ # on the master selected for the installation. - # In a later step, the installer requests a SSL certificate through - # Certmonger (and the op adds the principal if it does not exist yet). - # If xmlrpc_uri points to the soon-to-be replica, -@@ -1466,6 +1463,9 @@ def install(installer): - create_ipa_conf(fstore, config, ca_enabled, - master=config.master_host_name) - -+ # we now need to enable ssl on the ds -+ ds.enable_ssl() -+ - install_http( - config, - auto_redirect=not options.no_ui_redirect, --- -2.17.1 - diff --git a/SOURCES/0068-Fix-race-condition-in-get_locations_records.patch b/SOURCES/0068-Fix-race-condition-in-get_locations_records.patch deleted file mode 100644 index 50317ad..0000000 --- a/SOURCES/0068-Fix-race-condition-in-get_locations_records.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 2347e7d3b9979533f471874919e1a39747bf4597 Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Fri, 6 Jul 2018 21:47:32 +0200 -Subject: [PATCH] Fix race condition in get_locations_records() - -The method IPASystemRecords.get_locations_records() has a race condition. -The IPASystemRecords object creates a mapping of server names to server -data. get_locations_records() uses server_find() again to get a list of -servers, but then operates on the cached dict of server names. - -In parallel replication case, the second server_find() call in -get_locations_records() can return additional servers. Since the rest of -the code operates on the cached data, the method then fails with a KeyError. - -server_data is now an OrderedDict to keep same sorting as with -server_find(). - -Fixes: https://pagure.io/freeipa/issue/7566 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> ---- - ipaserver/dns_data_management.py | 14 +++++--------- - 1 file changed, 5 insertions(+), 9 deletions(-) - -diff --git a/ipaserver/dns_data_management.py b/ipaserver/dns_data_management.py -index e5987b4bd7b43d3920e9da917258153e448206b7..c4f204c4941984d74e442c51ea206f11c05db2b9 100644 ---- a/ipaserver/dns_data_management.py -+++ b/ipaserver/dns_data_management.py -@@ -6,7 +6,7 @@ from __future__ import absolute_import - - import six - --from collections import defaultdict -+from collections import defaultdict, OrderedDict - from dns import ( - rdata, - rdataclass, -@@ -68,7 +68,7 @@ class IPASystemRecords(object): - def __init__(self, api_instance, all_servers=False): - self.api_instance = api_instance - self.domain_abs = DNSName(self.api_instance.env.domain).make_absolute() -- self.servers_data = {} -+ self.servers_data = OrderedDict() - self.__init_data(all_servers=all_servers) - - def reload_data(self): -@@ -90,7 +90,7 @@ class IPASystemRecords(object): - return location + DNSName('_locations') + self.domain_abs - - def __init_data(self, all_servers=False): -- self.servers_data = {} -+ self.servers_data.clear() - - kwargs = dict(no_members=False) - if not all_servers: -@@ -325,7 +325,7 @@ class IPASystemRecords(object): - - zone_obj = zone.Zone(self.domain_abs, relativize=False) - if servers is None: -- servers = self.servers_data.keys() -+ servers = list(self.servers_data) - - for server in servers: - self._add_base_dns_records_for_server(zone_obj, server, -@@ -348,11 +348,7 @@ class IPASystemRecords(object): - """ - zone_obj = zone.Zone(self.domain_abs, relativize=False) - if servers is None: -- servers_result = self.api_instance.Command.server_find( -- pkey_only=True, -- servrole=u"IPA master", # only fully installed masters -- )['result'] -- servers = [s['cn'][0] for s in servers_result] -+ servers = list(self.servers_data) - - locations_result = self.api_instance.Command.location_find()['result'] - locations = [l['idnsname'][0] for l in locations_result] --- -2.17.1 - diff --git a/SOURCES/0069-Auto-retry-failed-certmonger-requests.patch b/SOURCES/0069-Auto-retry-failed-certmonger-requests.patch deleted file mode 100644 index f92e7f5..0000000 --- a/SOURCES/0069-Auto-retry-failed-certmonger-requests.patch +++ /dev/null @@ -1,195 +0,0 @@ -From 83445df2894426cdaf2f09f8bf2ac4c829922620 Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Sun, 8 Jul 2018 11:53:58 +0200 -Subject: [PATCH] Auto-retry failed certmonger requests - -During parallel replica installation, a request sometimes fails with -CA_REJECTED or CA_UNREACHABLE. The error occur when the master is -either busy or some information haven't been replicated yet. Even -a stuck request can be recovered, e.g. when permission and group -information have been replicated. - -A new function request_and_retry_cert() automatically resubmits failing -requests until it times out. - -Fixes: https://pagure.io/freeipa/issue/7623 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> ---- - ipalib/install/certmonger.py | 64 ++++++++++++++++++++++++------- - ipaserver/install/cainstance.py | 4 +- - ipaserver/install/certs.py | 19 ++++++--- - ipaserver/install/dsinstance.py | 4 +- - ipaserver/install/httpinstance.py | 5 ++- - ipaserver/install/krbinstance.py | 4 +- - 6 files changed, 76 insertions(+), 24 deletions(-) - -diff --git a/ipalib/install/certmonger.py b/ipalib/install/certmonger.py -index d2b782ddb0c746a3dfd96d0222bb31c6a960fdff..d915cbf7638c68f3ad5170b2878a706ad39def62 100644 ---- a/ipalib/install/certmonger.py -+++ b/ipalib/install/certmonger.py -@@ -302,20 +302,56 @@ def add_subject(request_id, subject): - def request_and_wait_for_cert( - certpath, subject, principal, nickname=None, passwd_fname=None, - dns=None, ca='IPA', profile=None, -- pre_command=None, post_command=None, storage='NSSDB', perms=None): -- """ -- Execute certmonger to request a server certificate. -- -- The method also waits for the certificate to be available. -- """ -- reqId = request_cert(certpath, subject, principal, nickname, -- passwd_fname, dns, ca, profile, -- pre_command, post_command, storage, perms) -- state = wait_for_request(reqId, api.env.startup_timeout) -- ca_error = get_request_value(reqId, 'ca-error') -- if state != 'MONITORING' or ca_error: -- raise RuntimeError("Certificate issuance failed ({})".format(state)) -- return reqId -+ pre_command=None, post_command=None, storage='NSSDB', perms=None, -+ resubmit_timeout=0): -+ """Request certificate, wait and possibly resubmit failing requests -+ -+ Submit a cert request to certmonger and wait until the request has -+ finished. -+ -+ With timeout, a failed request is resubmitted. During parallel replica -+ installation, a request sometimes fails with CA_REJECTED or -+ CA_UNREACHABLE. The error occurs when the master is either busy or some -+ information haven't been replicated yet. Even a stuck request can be -+ recovered, e.g. when permission and group information have been -+ replicated. -+ """ -+ req_id = request_cert( -+ certpath, subject, principal, nickname, passwd_fname, dns, ca, -+ profile, pre_command, post_command, storage, perms -+ ) -+ -+ deadline = time.time() + resubmit_timeout -+ while True: # until success, timeout, or error -+ state = wait_for_request(req_id, api.env.replication_wait_timeout) -+ ca_error = get_request_value(req_id, 'ca-error') -+ if state == 'MONITORING' and ca_error is None: -+ # we got a winner, exiting -+ root_logger.debug("Cert request %s was successful", req_id) -+ return req_id -+ -+ root_logger.debug( -+ "Cert request %s failed: %s (%s)", req_id, state, ca_error -+ ) -+ if state not in {'CA_REJECTED', 'CA_UNREACHABLE'}: -+ # probably unrecoverable error -+ root_logger.debug("Giving up on cert request %s", req_id) -+ break -+ elif not resubmit_timeout: -+ # no resubmit -+ break -+ elif time.time() > deadline: -+ root_logger.debug("Request %s reached resubmit dead line", req_id) -+ break -+ else: -+ # sleep and resubmit -+ root_logger.debug("Sleep and resubmit cert request %s", req_id) -+ time.sleep(10) -+ resubmit_request(req_id) -+ -+ raise RuntimeError( -+ "Certificate issuance failed ({}: {})".format(state, ca_error) -+ ) - - - def request_cert( -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index 62e9ad7de6f00eabb48f726a3931eb8acf0ba22b..e207911814e3553c5aa5310694170d3575337c55 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -863,7 +863,9 @@ class CAInstance(DogtagInstance): - profile='caServerCert', - pre_command='renew_ra_cert_pre', - post_command='renew_ra_cert', -- storage="FILE") -+ storage="FILE", -+ resubmit_timeout=api.env.replication_wait_timeout -+ ) - self.__set_ra_cert_perms() - - self.requestId = str(reqId) -diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py -index de96318db51b03f2515814d574cfebf1b242b6a6..5670d468bb1b168af7ada7b2d8924b8ec9f5d9c1 100644 ---- a/ipaserver/install/certs.py -+++ b/ipaserver/install/certs.py -@@ -663,12 +663,19 @@ class CertDB(object): - def export_pem_cert(self, nickname, location): - return self.nssdb.export_pem_cert(nickname, location) - -- def request_service_cert(self, nickname, principal, host): -- certmonger.request_and_wait_for_cert(certpath=self.secdir, -- nickname=nickname, -- principal=principal, -- subject=host, -- passwd_fname=self.passwd_fname) -+ def request_service_cert(self, nickname, principal, host, -+ resubmit_timeout=None): -+ if resubmit_timeout is None: -+ resubmit_timeout = api.env.replication_wait_timeout -+ return certmonger.request_and_wait_for_cert( -+ certpath=self.secdir, -+ storage='NSSDB', -+ nickname=nickname, -+ principal=principal, -+ subject=host, -+ passwd_fname=self.passwd_fname, -+ resubmit_timeout=resubmit_timeout -+ ) - - def is_ipa_issued_cert(self, api, nickname): - """ -diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py -index 7adaabd3c1280709150329003130f70233de37f4..8ec5cdd7a4a324a1a40dbe968defcc797db8f054 100644 ---- a/ipaserver/install/dsinstance.py -+++ b/ipaserver/install/dsinstance.py -@@ -847,7 +847,9 @@ class DsInstance(service.Service): - ca='IPA', - profile=dogtag.DEFAULT_PROFILE, - dns=[self.fqdn], -- post_command=cmd) -+ post_command=cmd, -+ resubmit_timeout=api.env.replication_wait_timeout -+ ) - finally: - if prev_helper is not None: - certmonger.modify_ca_helper('IPA', prev_helper) -diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py -index 2df51eaa77d3ee3246027a6bcbc4023dbad61160..2366698bb0d6a7c9cd481ba9d5568d320742f6bb 100644 ---- a/ipaserver/install/httpinstance.py -+++ b/ipaserver/install/httpinstance.py -@@ -450,7 +450,10 @@ class HTTPInstance(service.Service): - ca='IPA', - profile=dogtag.DEFAULT_PROFILE, - dns=[self.fqdn], -- post_command='restart_httpd') -+ post_command='restart_httpd', -+ storage='NSSDB', -+ resubmit_timeout=api.env.replication_wait_timeout -+ ) - finally: - if prev_helper is not None: - certmonger.modify_ca_helper('IPA', prev_helper) -diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py -index 4041d1b5fb3c3cf3db78b6cb282ce5f17793a0e3..62de118b7104fe7d72d2c1fd5577e9a76000c663 100644 ---- a/ipaserver/install/krbinstance.py -+++ b/ipaserver/install/krbinstance.py -@@ -436,7 +436,9 @@ class KrbInstance(service.Service): - storage='FILE', - profile=KDC_PROFILE, - post_command='renew_kdc_cert', -- perms=(0o644, 0o600)) -+ perms=(0o644, 0o600), -+ resubmit_timeout=api.env.replication_wait_timeout -+ ) - except dbus.DBusException as e: - # if the certificate is already tracked, ignore the error - name = e.get_dbus_name() --- -2.17.1 - diff --git a/SOURCES/0070-Wait-for-client-certificates.patch b/SOURCES/0070-Wait-for-client-certificates.patch deleted file mode 100644 index ebdea06..0000000 --- a/SOURCES/0070-Wait-for-client-certificates.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 30b4300eb27ddeca50096687a9a4122e59d9b66d Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Mon, 9 Jul 2018 13:53:44 +0200 -Subject: [PATCH] Wait for client certificates - -ipa-client-install --request-cert now waits until certmonger has -provided a host certificate. In case of an error, ipa-client-install no -longer pretents to success but fails with an error code. - -The --request-cert option also ensures that certmonger is enabled and -running. - -See: Fixes: https://pagure.io/freeipa/issue/7623 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> ---- - ipaclient/install/client.py | 25 ++++++++++++++++++------- - 1 file changed, 18 insertions(+), 7 deletions(-) - -diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py -index c88061320c29faba25374ba71c53407de8e71db2..dbada726280d9a90293842370f303de6a77ceb01 100644 ---- a/ipaclient/install/client.py -+++ b/ipaclient/install/client.py -@@ -771,6 +771,7 @@ def configure_certmonger( - cmonger = services.knownservices.certmonger - try: - cmonger.enable() -+ cmonger.start() - except Exception as e: - root_logger.error( - "Failed to configure automatic startup of the %s daemon: %s", -@@ -782,14 +783,24 @@ def configure_certmonger( - subject = str(DN(('CN', hostname), subject_base)) - passwd_fname = os.path.join(paths.IPA_NSSDB_DIR, 'pwdfile.txt') - try: -- certmonger.request_cert( -+ certmonger.request_and_wait_for_cert( - certpath=paths.IPA_NSSDB_DIR, -- nickname='Local IPA host', subject=subject, dns=[hostname], -- principal=principal, passwd_fname=passwd_fname) -- except Exception as ex: -- root_logger.error( -- "%s request for host certificate failed: %s", -- cmonger.service_name, ex) -+ storage='NSSDB', -+ nickname='Local IPA host', -+ subject=subject, -+ dns=[hostname], -+ principal=principal, -+ passwd_fname=passwd_fname, -+ resubmit_timeout=120, -+ ) -+ except Exception as e: -+ root_logger.exception("certmonger request failed") -+ raise ScriptError( -+ "{} request for host certificate failed: {}".format( -+ cmonger.service_name, e -+ ), -+ rval=CLIENT_INSTALL_ERROR -+ ) - - - def configure_sssd_conf( --- -2.17.1 - diff --git a/SOURCES/0071-Fix-DNSSEC-install-regression.patch b/SOURCES/0071-Fix-DNSSEC-install-regression.patch deleted file mode 100644 index 6c438f5..0000000 --- a/SOURCES/0071-Fix-DNSSEC-install-regression.patch +++ /dev/null @@ -1,68 +0,0 @@ -From bd769b979c26c0c1ff723faca167cd83a27420d5 Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Tue, 10 Jul 2018 12:51:36 +0200 -Subject: [PATCH] Fix DNSSEC install regression - -7284097eedef70dd556270732e6ab8e23501ce09 introduced a regression in -DNSSEC master installation. For standalone and replica installation, -services have to be enabled before checking bind config. - -Fixes: https://pagure.io/freeipa/issue/7635 -See: https://pagure.io/freeipa/issue/7566 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> -Reviewed-By: Tibor Dudlak <tdudlak@redhat.com> ---- - install/tools/ipa-dns-install | 5 +---- - ipaserver/install/dns.py | 5 +++++ - 2 files changed, 6 insertions(+), 4 deletions(-) - -diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install -index 04d1b140d2c79a0fa72d7df47d556643751bddb7..e7b6ea3a00468190b8dafe7c696f3bf212f81b9c 100755 ---- a/install/tools/ipa-dns-install -+++ b/install/tools/ipa-dns-install -@@ -36,7 +36,6 @@ from ipapython.config import IPAOptionParser - from ipapython.ipa_log_manager import standard_logging_setup, root_logger - - from ipaserver.install import dns as dns_installer --from ipaserver.install import service - - log_file_name = paths.IPASERVER_INSTALL_LOG - -@@ -146,9 +145,7 @@ def main(): - - dns_installer.install_check(True, api, False, options, hostname=api.env.host) - dns_installer.install(True, False, options) -- # Enable configured services and update DNS SRV records -- service.enable_services(api.env.host) -- api.Command.dns_update_system_records() -+ # Services are enabled in dns_installer.install() - - # execute ipactl to refresh services status - ipautil.run(['ipactl', 'start', '--ignore-service-failures'], -diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py -index 1c1aac06a18fe3c1f63b5881c7887f6a4cfc9ac2..0046b78066cbb8e4f43e04af86da74118a5aa8c6 100644 ---- a/ipaserver/install/dns.py -+++ b/ipaserver/install/dns.py -@@ -43,6 +43,7 @@ from ipaserver.install import bindinstance - from ipaserver.install import dnskeysyncinstance - from ipaserver.install import odsexporterinstance - from ipaserver.install import opendnssecinstance -+from ipaserver.install import service - - if six.PY3: - unicode = str -@@ -355,6 +356,10 @@ def install(standalone, replica, options, api=api): - dnskeysyncd.start_dnskeysyncd() - bind.start_named() - -+ # Enable configured services for standalone check_global_configuration() -+ if standalone: -+ service.enable_services(api.env.host) -+ - # this must be done when bind is started and operational - bind.update_system_records() - --- -2.17.1 - diff --git a/SOURCES/0072-Handle-races-in-replica-config.patch b/SOURCES/0072-Handle-races-in-replica-config.patch deleted file mode 100644 index 4deee3a..0000000 --- a/SOURCES/0072-Handle-races-in-replica-config.patch +++ /dev/null @@ -1,270 +0,0 @@ -From 33f562bba3729bc596e07dc2805d78b80de55784 Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Tue, 10 Jul 2018 14:03:28 +0200 -Subject: [PATCH] Handle races in replica config - -When multiple replicas are installed in parallel, two replicas may try -to create the cn=replica entry at the same time. This leads to a -conflict on one of the replicas. replica_config() and -ensure_replication_managers() now handle conflicts. - -ipaldap now maps TYPE_OR_VALUE_EXISTS to DuplicateEntry(). The type or -value exists exception is raised, when an attribute value or type is -already set. - -Fixes: https://pagure.io/freeipa/issue/7566 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Thierry Bordaz <tbordaz@redhat.com> -Reviewed-By: Thierry Bordaz <tbordaz@redhat.com> ---- - ipapython/ipaldap.py | 5 ++ - ipaserver/install/replication.py | 125 ++++++++++++++++++------------- - ipaserver/plugins/ldap2.py | 3 +- - 3 files changed, 81 insertions(+), 52 deletions(-) - -diff --git a/ipapython/ipaldap.py b/ipapython/ipaldap.py -index 1b0aaddd63d92776448d1a7ae6c1bd26a02d5dcc..e2ff0626986aa20f3a2bc42721fba9fad3156498 100644 ---- a/ipapython/ipaldap.py -+++ b/ipapython/ipaldap.py -@@ -965,7 +965,12 @@ class LDAPClient(object): - except ldap.NO_SUCH_OBJECT: - raise errors.NotFound(reason=arg_desc or 'no such entry') - except ldap.ALREADY_EXISTS: -+ # entry already exists - raise errors.DuplicateEntry() -+ except ldap.TYPE_OR_VALUE_EXISTS: -+ # attribute type or attribute value already exists, usually only -+ # occurs, when two machines try to write at the same time. -+ raise errors.DuplicateEntry(message=unicode(desc)) - except ldap.CONSTRAINT_VIOLATION: - # This error gets thrown by the uniqueness plugin - _msg = 'Another entry with the same attribute value already exists' -diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py -index c017764468674830670a817b3d815c5e2d78728e..ffda9a182f840317d96f1b3b914b38233022fb5b 100644 ---- a/ipaserver/install/replication.py -+++ b/ipaserver/install/replication.py -@@ -34,7 +34,7 @@ from ipalib import api, errors - from ipalib.cli import textui - from ipapython.ipa_log_manager import root_logger - from ipalib.text import _ --from ipapython import ipautil, ipaldap, kerberos -+from ipapython import ipautil, ipaldap - from ipapython.admintool import ScriptError - from ipapython.dn import DN - from ipaplatform.paths import paths -@@ -457,7 +457,7 @@ class ReplicationManager(object): - return DN(('cn', 'replica'), ('cn', self.db_suffix), - ('cn', 'mapping tree'), ('cn', 'config')) - -- def set_replica_binddngroup(self, r_conn, entry): -+ def _set_replica_binddngroup(self, r_conn, entry): - """ - Set nsds5replicabinddngroup attribute on remote master's replica entry. - Older masters (ipa < 3.3) may not support setting this attribute. In -@@ -472,11 +472,6 @@ class ReplicationManager(object): - mod.append((ldap.MOD_ADD, 'nsds5replicabinddngroup', - self.repl_man_group_dn)) - -- if 'nsds5replicabinddngroupcheckinterval' not in entry: -- mod.append( -- (ldap.MOD_ADD, -- 'nsds5replicabinddngroupcheckinterval', -- '60')) - if mod: - try: - r_conn.modify_s(entry.dn, mod) -@@ -484,49 +479,64 @@ class ReplicationManager(object): - root_logger.debug( - "nsds5replicabinddngroup attribute not supported on " - "remote master.") -+ except (ldap.ALREADY_EXISTS, ldap.CONSTRAINT_VIOLATION): -+ root_logger.debug("No update to %s necessary", entry.dn) - - def replica_config(self, conn, replica_id, replica_binddn): - assert isinstance(replica_binddn, DN) - dn = self.replica_dn() - assert isinstance(dn, DN) - -+ root_logger.debug("Add or update replica config %s", dn) - try: - entry = conn.get_entry(dn) - except errors.NotFound: -- pass -- else: -- binddns = entry.setdefault('nsDS5ReplicaBindDN', []) -- if replica_binddn not in {DN(m) for m in binddns}: -- # Add the new replication manager -- binddns.append(replica_binddn) -- for key, value in REPLICA_CREATION_SETTINGS.items(): -- entry[key] = value -+ # no entry, create new one -+ entry = conn.make_entry( -+ dn, -+ objectclass=["top", "nsds5replica", "extensibleobject"], -+ cn=["replica"], -+ nsds5replicaroot=[str(self.db_suffix)], -+ nsds5replicaid=[str(replica_id)], -+ nsds5replicatype=[self.get_replica_type()], -+ nsds5flags=["1"], -+ nsds5replicabinddn=[replica_binddn], -+ nsds5replicabinddngroup=[self.repl_man_group_dn], -+ nsds5replicalegacyconsumer=["off"], -+ **REPLICA_CREATION_SETTINGS -+ ) - try: -- conn.update_entry(entry) -- except errors.EmptyModlist: -- pass -+ conn.add_entry(entry) -+ except errors.DuplicateEntry: -+ root_logger.debug( -+ "Lost race against another replica, updating" -+ ) -+ # fetch entry that have been added by another replica -+ entry = conn.get_entry(dn) -+ else: -+ root_logger.debug("Added replica config %s", dn) -+ # added entry successfully -+ return entry - -- self.set_replica_binddngroup(conn, entry) -+ # either existing entry or lost race -+ binddns = entry.setdefault('nsDS5ReplicaBindDN', []) -+ if replica_binddn not in {DN(m) for m in binddns}: -+ # Add the new replication manager -+ binddns.append(replica_binddn) - -- # replication is already configured -- return -+ for key, value in REPLICA_CREATION_SETTINGS.items(): -+ entry[key] = value - -- replica_type = self.get_replica_type() -+ try: -+ conn.update_entry(entry) -+ except errors.EmptyModlist: -+ root_logger.debug("No update to %s necessary", entry.dn) -+ else: -+ root_logger.debug("Update replica config %s", entry.dn) - -- entry = conn.make_entry( -- dn, -- objectclass=["top", "nsds5replica", "extensibleobject"], -- cn=["replica"], -- nsds5replicaroot=[str(self.db_suffix)], -- nsds5replicaid=[str(replica_id)], -- nsds5replicatype=[replica_type], -- nsds5flags=["1"], -- nsds5replicabinddn=[replica_binddn], -- nsds5replicabinddngroup=[self.repl_man_group_dn], -- nsds5replicalegacyconsumer=["off"], -- **REPLICA_CREATION_SETTINGS -- ) -- conn.add_entry(entry) -+ self._set_replica_binddngroup(conn, entry) -+ -+ return entry - - def setup_changelog(self, conn): - ent = conn.get_entry( -@@ -686,7 +696,10 @@ class ReplicationManager(object): - uid=["passsync"], - userPassword=[password], - ) -- conn.add_entry(entry) -+ try: -+ conn.add_entry(entry) -+ except errors.DuplicateEntry: -+ pass - - # Add the user to the list of users allowed to bypass password policy - extop_dn = DN(('cn', 'ipa_pwd_extop'), ('cn', 'plugins'), ('cn', 'config')) -@@ -1644,7 +1657,10 @@ class ReplicationManager(object): - objectclass=['top', 'groupofnames'], - cn=['replication managers'] - ) -- conn.add_entry(entry) -+ try: -+ conn.add_entry(entry) -+ except errors.DuplicateEntry: -+ pass - - def ensure_replication_managers(self, conn, r_hostname): - """ -@@ -1654,23 +1670,24 @@ class ReplicationManager(object): - On FreeIPA 3.x masters lacking support for nsds5ReplicaBinddnGroup - attribute, add replica bind DN directly into the replica entry. - """ -- my_princ = kerberos.Principal((u'ldap', unicode(self.hostname)), -- realm=self.realm) -- remote_princ = kerberos.Principal((u'ldap', unicode(r_hostname)), -- realm=self.realm) -- services_dn = DN(api.env.container_service, api.env.basedn) -- -- mydn, remote_dn = tuple( -- DN(('krbprincipalname', unicode(p)), services_dn) for p in ( -- my_princ, remote_princ)) -+ my_dn = DN( -+ ('krbprincipalname', u'ldap/%s@%s' % (self.hostname, self.realm)), -+ api.env.container_service, -+ api.env.basedn -+ ) -+ remote_dn = DN( -+ ('krbprincipalname', u'ldap/%s@%s' % (r_hostname, self.realm)), -+ api.env.container_service, -+ api.env.basedn -+ ) - - try: - conn.get_entry(self.repl_man_group_dn) - except errors.NotFound: -- self._add_replica_bind_dn(conn, mydn) -+ self._add_replica_bind_dn(conn, my_dn) - self._add_replication_managers(conn) - -- self._add_dn_to_replication_managers(conn, mydn) -+ self._add_dn_to_replication_managers(conn, my_dn) - self._add_dn_to_replication_managers(conn, remote_dn) - - def add_temp_sasl_mapping(self, conn, r_hostname): -@@ -1690,7 +1707,10 @@ class ReplicationManager(object): - - entry = conn.get_entry(self.replica_dn()) - entry['nsDS5ReplicaBindDN'].append(replica_binddn) -- conn.update_entry(entry) -+ try: -+ conn.update_entry(entry) -+ except errors.EmptyModlist: -+ pass - - entry = conn.make_entry( - DN(('cn', 'Peer Master'), ('cn', 'mapping'), ('cn', 'sasl'), -@@ -1702,7 +1722,10 @@ class ReplicationManager(object): - nsSaslMapFilterTemplate=['(cn=&@%s)' % self.realm], - nsSaslMapPriority=['1'], - ) -- conn.add_entry(entry) -+ try: -+ conn.add_entry(entry) -+ except errors.DuplicateEntry: -+ pass - - def remove_temp_replication_user(self, conn, r_hostname): - """ -diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py -index 3b1e4da57a8e16e3d9b27eea24025de2caa53216..c0a0ed251f98cd06ccd13c873f38809d04d1b5d5 100644 ---- a/ipaserver/plugins/ldap2.py -+++ b/ipaserver/plugins/ldap2.py -@@ -422,7 +422,8 @@ class ldap2(CrudBackend, LDAPClient): - modlist = [(a, b, self.encode(c)) - for a, b, c in modlist] - self.conn.modify_s(str(group_dn), modlist) -- except errors.DatabaseError: -+ except errors.DuplicateEntry: -+ # TYPE_OR_VALUE_EXISTS - raise errors.AlreadyGroupMember() - - def remove_entry_from_group(self, dn, group_dn, member_attr='member'): --- -2.17.1 - diff --git a/SOURCES/0073-Fix-KRA-replica-installation-from-CA-master.patch b/SOURCES/0073-Fix-KRA-replica-installation-from-CA-master.patch deleted file mode 100644 index 82559bb..0000000 --- a/SOURCES/0073-Fix-KRA-replica-installation-from-CA-master.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 7746bb807a15137c6dbc36f9d0ea0c3e9377ab8c Mon Sep 17 00:00:00 2001 -From: Christian Heimes <cheimes@redhat.com> -Date: Tue, 17 Jul 2018 08:53:39 +0200 -Subject: [PATCH] Fix KRA replica installation from CA master - -ipa-replica-install --kra-install can fail when the topology already has -a KRA, but replica is installed from a master with just CA. In that -case, Custodia may pick a machine that doesn't have the KRA auditing and -signing certs in its NSSDB. - -Example: - * master with CA - * replica1 with CA and KRA - * new replica gets installed from master - -The replica installer now always picks a KRA peer. - -The change fixes test scenario TestInstallWithCA1::()::test_replica2_ipa_dns_install - -Fixes: https://pagure.io/freeipa/issue/7518 -See: https://pagure.io/freeipa/issue/7008 -Signed-off-by: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Rob Crittenden <rcritten@redhat.com> ---- - ipaserver/install/server/replicainstall.py | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index a47412e39b9e2c603206c56a935de17321c71e91..d8c55370d33d59efdf838f7ba01efedae7857406 100644 ---- a/ipaserver/install/server/replicainstall.py -+++ b/ipaserver/install/server/replicainstall.py -@@ -1482,7 +1482,10 @@ def install(installer): - otpd.create_instance('OTPD', config.host_name, - ipautil.realm_to_suffix(config.realm_name)) - -- if ca_enabled: -+ if kra_enabled: -+ # A KRA peer always provides a CA, too. -+ mode = custodiainstance.CustodiaModes.KRA_PEER -+ elif ca_enabled: - mode = custodiainstance.CustodiaModes.CA_PEER - else: - mode = custodiainstance.CustodiaModes.MASTER_PEER --- -2.17.1 - diff --git a/SOURCES/0074-DS-replication-settings-fix-regression-with-3.3-mast.patch b/SOURCES/0074-DS-replication-settings-fix-regression-with-3.3-mast.patch deleted file mode 100644 index 02929e0..0000000 --- a/SOURCES/0074-DS-replication-settings-fix-regression-with-3.3-mast.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 35d8d61d53c9d99ae8a04365faa510535921ae48 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud <flo@redhat.com> -Date: Tue, 21 Aug 2018 11:37:17 +0200 -Subject: [PATCH] DS replication settings: fix regression with <3.3 master - -Commit 811b0fdb4620938963f1a29d3fdd22257327562c introduced a regression -when configuring replication with a master < 3.3 -Even if 389-ds schema is extended with nsds5ReplicaReleaseTimeout, -nsds5ReplicaBackoffMax and nsDS5ReplicaBindDnGroupCheckInterval -attributes, it will return UNWILLING_TO_PERFORM when a mod -operation is performed on the cn=replica entry. - -This patch ignores the error and logs a debug msg. - -See: https://pagure.io/freeipa/issue/7617 -Reviewed-By: Christian Heimes <cheimes@redhat.com> ---- - ipaserver/install/replication.py | 16 +++++++++++++++- - 1 file changed, 15 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py -index ffda9a182f840317d96f1b3b914b38233022fb5b..be738b249e36ca98fb2eea9e4730cefd0d30a3ee 100644 ---- a/ipaserver/install/replication.py -+++ b/ipaserver/install/replication.py -@@ -21,6 +21,7 @@ from __future__ import print_function, absolute_import - - import itertools - -+import re - import six - import time - import datetime -@@ -598,7 +599,20 @@ class ReplicationManager(object): - r_conn.simple_bind(r_binddn, r_bindpw) - else: - r_conn.gssapi_bind() -- self._finalize_replica_settings(r_conn) -+ # If the remote server has 389-ds < 1.3, it does not -+ # support the attributes we are trying to set. -+ # Find which 389-ds is installed -+ rootdse = r_conn.get_entry(DN(''), ['vendorVersion']) -+ version = rootdse.single_value.get('vendorVersion') -+ mo = re.search(r'(\d+)\.(\d+)\.(\d+)[\.\d]*', version) -+ vendor_version = tuple(int(v) for v in mo.groups()) -+ if vendor_version >= (1, 3, 0): -+ # 389-ds understands the replication attributes, -+ # we can safely modify them -+ self._finalize_replica_settings(r_conn) -+ else: -+ root_logger.debug("replication attributes not supported " -+ "on remote master, skipping update.") - r_conn.close() - - def setup_chaining_backend(self, conn): --- -2.17.1 - diff --git a/SOURCES/0075-Do-not-set-ca_host-when-setup-ca-is-used.patch b/SOURCES/0075-Do-not-set-ca_host-when-setup-ca-is-used.patch deleted file mode 100644 index 87363e1..0000000 --- a/SOURCES/0075-Do-not-set-ca_host-when-setup-ca-is-used.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 37199834acaeee96136b096030198b2e9c8f16c8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Tibor=20Dudl=C3=A1k?= <tdudlak@redhat.com> -Date: Thu, 26 Jul 2018 11:46:55 +0200 -Subject: [PATCH] Do not set ca_host when --setup-ca is used - -Setting ca_host caused replication failures on DL0 -because it was trying to connect to wrong CA host. -Trying to avoid corner-case in ipaserver/plugins/dogtag.py -when api.env.host nor api.env.ca_host had not CA configured -and there was ca_host set to api.env.ca_host variable. - -See: https://pagure.io/freeipa/issue/7566 -Resolves: https://pagure.io/freeipa/issue/7629 -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> -Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> -Reviewed-By: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Rob Crittenden <rcritten@redhat.com> ---- - ipaserver/install/cainstance.py | 24 ++++++++++++++++++++++ - ipaserver/install/server/replicainstall.py | 7 +++++-- - 2 files changed, 29 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index e207911814e3553c5aa5310694170d3575337c55..cb8dc43096b8851d7554447f28c4537a35b47852 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -435,6 +435,11 @@ class CAInstance(DogtagInstance): - self.step("updating IPA configuration", update_ipa_conf) - self.step("enabling CA instance", self.__enable_instance) - if not promote: -+ if self.clone: -+ # DL0 workaround; see docstring of __expose_ca_in_ldap -+ self.step("exposing CA instance on LDAP", -+ self.__expose_ca_in_ldap) -+ - self.step("migrating certificate profiles to LDAP", - migrate_profiles_to_ldap) - self.step("importing IPA certificate profiles", -@@ -1222,6 +1227,25 @@ class CAInstance(DogtagInstance): - config = [] - self.ldap_configure('CA', self.fqdn, None, basedn, config) - -+ def __expose_ca_in_ldap(self): -+ """ -+ In a case when replica is created on DL0 we need to make -+ sure that query for CA service record of this replica in -+ ldap will succeed in time of installation. -+ This method is needed for sucessfull replica installation -+ on DL0 and should be removed alongside with code for DL0. -+ -+ To suppress deprecation warning message this method is -+ not invoking ldap_enable() but _ldap_enable() method. -+ """ -+ -+ basedn = ipautil.realm_to_suffix(self.realm) -+ if not self.clone: -+ config = ['caRenewalMaster'] -+ else: -+ config = [] -+ self._ldap_enable(u'enabledService', "CA", self.fqdn, basedn, config) -+ - def setup_lightweight_ca_key_retrieval(self): - if sysupgrade.get_upgrade_state('dogtag', 'setup_lwca_key_retrieval'): - return -diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index d8c55370d33d59efdf838f7ba01efedae7857406..8a659a0fc2675df0a8fba1d3d7d8a629b376c93e 100644 ---- a/ipaserver/install/server/replicainstall.py -+++ b/ipaserver/install/server/replicainstall.py -@@ -236,9 +236,12 @@ def create_ipa_conf(fstore, config, ca_enabled, master=None): - gopts.extend([ - ipaconf.setOption('enable_ra', 'True'), - ipaconf.setOption('ra_plugin', 'dogtag'), -- ipaconf.setOption('dogtag_version', '10'), -- ipaconf.setOption('ca_host', config.ca_host_name) -+ ipaconf.setOption('dogtag_version', '10') - ]) -+ -+ if not config.setup_ca: -+ gopts.append(ipaconf.setOption('ca_host', config.ca_host_name)) -+ - else: - gopts.extend([ - ipaconf.setOption('enable_ra', 'False'), --- -2.17.1 - diff --git a/SOURCES/0076-Clear-next-field-when-returnining-list-elements-in-q.patch b/SOURCES/0076-Clear-next-field-when-returnining-list-elements-in-q.patch deleted file mode 100644 index 478b0c5..0000000 --- a/SOURCES/0076-Clear-next-field-when-returnining-list-elements-in-q.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 81adf4db616f43704f0f1b8598149f6e2b123518 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood <rharwood@redhat.com> -Date: Wed, 22 Aug 2018 15:32:16 -0400 -Subject: [PATCH] Clear next field when returnining list elements in queue.c - -The ipa-otpd code occasionally removes elements from one queue, -inspects and modifies them, and then inserts them into -another (possibly identical, possibly different) queue. When the next -pointer isn't cleared, this can result in element membership in both -queues, leading to double frees, or even self-referential elements, -causing infinite loops at traversal time. - -Rather than eliminating the pattern, make it safe by clearing the next -field any time an element enters or exits a queue. - -Related https://pagure.io/freeipa/issue/7262 - -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> ---- - daemons/ipa-otpd/queue.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/daemons/ipa-otpd/queue.c b/daemons/ipa-otpd/queue.c -index 9e29fb238d5c7a7395bcf3860ce7445c27ca98ac..2944b7ea0db6f49d0a3230b5f33c7a89281fd8c6 100644 ---- a/daemons/ipa-otpd/queue.c -+++ b/daemons/ipa-otpd/queue.c -@@ -111,6 +111,8 @@ void otpd_queue_push(struct otpd_queue *q, struct otpd_queue_item *item) - q->head = q->tail = item; - else - q->tail = q->tail->next = item; -+ -+ item->next = NULL; - } - - void otpd_queue_push_head(struct otpd_queue *q, struct otpd_queue_item *item) -@@ -118,6 +120,8 @@ void otpd_queue_push_head(struct otpd_queue *q, struct otpd_queue_item *item) - if (item == NULL) - return; - -+ item->next = NULL; -+ - if (q->head == NULL) - q->tail = q->head = item; - else { -@@ -145,6 +149,8 @@ struct otpd_queue_item *otpd_queue_pop(struct otpd_queue *q) - if (q->head == NULL) - q->tail = NULL; - -+ if (item != NULL) -+ item->next = NULL; - return item; - } - -@@ -160,6 +166,7 @@ struct otpd_queue_item *otpd_queue_pop_msgid(struct otpd_queue *q, int msgid) - *prev = item->next; - if (q->head == NULL) - q->tail = NULL; -+ item->next = NULL; - return item; - } - } --- -2.17.1 - diff --git a/SOURCES/0077-Add-cmocka-unit-tests-for-ipa-otpd-queue-code.patch b/SOURCES/0077-Add-cmocka-unit-tests-for-ipa-otpd-queue-code.patch deleted file mode 100644 index 189974e..0000000 --- a/SOURCES/0077-Add-cmocka-unit-tests-for-ipa-otpd-queue-code.patch +++ /dev/null @@ -1,253 +0,0 @@ -From 1f47c51e592563339c13256ea02b8fa768b8fde2 Mon Sep 17 00:00:00 2001 -From: Robbie Harwood <rharwood@redhat.com> -Date: Thu, 30 Aug 2018 15:34:31 -0400 -Subject: [PATCH] Add cmocka unit tests for ipa otpd queue code - -Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com> ---- - daemons/ipa-otpd/Makefile.am | 12 + - .../ipa-otpd/ipa_otpd_queue_cmocka_tests.c | 212 ++++++++++++++++++ - 2 files changed, 224 insertions(+) - create mode 100644 daemons/ipa-otpd/ipa_otpd_queue_cmocka_tests.c - -diff --git a/daemons/ipa-otpd/Makefile.am b/daemons/ipa-otpd/Makefile.am -index 9ba6237566634cfa6a1e84c545ee1fc9cf2dc4f6..9ccc450a5e00db90b698ff9b25a496d09f0ff6e5 100644 ---- a/daemons/ipa-otpd/Makefile.am -+++ b/daemons/ipa-otpd/Makefile.am -@@ -20,3 +20,15 @@ ipa_otpd_SOURCES = bind.c forward.c main.c parse.c query.c queue.c stdio.c - $< > $@ - - CLEANFILES = $(systemdsystemunit_DATA) -+ -+TESTS = -+check_PROGRAMS = -+ -+if HAVE_CMOCKA -+TESTS += queue_tests -+check_PROGRAMS += queue_tests -+endif -+ -+queue_tests_SOURCES = ipa_otpd_queue_cmocka_tests.c queue.c -+queue_tests_CFLAGS = $(CMOCKA_CFLAGS) -+queue_tests_LDADD = $(CMOCKA_LIBS) -diff --git a/daemons/ipa-otpd/ipa_otpd_queue_cmocka_tests.c b/daemons/ipa-otpd/ipa_otpd_queue_cmocka_tests.c -new file mode 100644 -index 0000000000000000000000000000000000000000..068431e6475bb74b01acbcab22115915dec1a278 ---- /dev/null -+++ b/daemons/ipa-otpd/ipa_otpd_queue_cmocka_tests.c -@@ -0,0 +1,212 @@ -+/* -+ * FreeIPA 2FA companion daemon - internal queue tests -+ * -+ * Author: Robbie Harwood <rharwood@redhat.com> -+ * -+ * Copyright (C) 2018 Robbie Harwood, Red Hat -+ * see file 'COPYING' for use and warranty information -+ * -+ * This program is free software you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the Free -+ * Software Foundation, either version 3 of the License, or (at your option) -+ * any later version. -+ * -+ * This program is distributed in the hope that it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program. If not, see <http://www.gnu.org/licenses/>. -+ */ -+ -+#include <setjmp.h> -+#include <stdarg.h> -+#include <stddef.h> -+ -+#include <cmocka.h> -+ -+#include "internal.h" -+ -+/* Bypass otpd queue allocation/freeing to avoid calling into LDAP and -+ * krad. No effort is made to make the types match. */ -+static struct otpd_queue_item *new_elt(int id) -+{ -+ krb5_error_code ret; -+ struct otpd_queue_item *e = NULL; -+ -+ ret = otpd_queue_item_new(NULL, &e); -+ assert_int_equal(ret, 0); -+ assert_ptr_not_equal(e, NULL); -+ -+ e->msgid = id; -+ return e; -+} -+static void free_elt(struct otpd_queue_item **e) -+{ -+ assert_ptr_not_equal(e, NULL); -+ free(*e); -+ *e = NULL; -+} -+static void free_elts(struct otpd_queue *q) -+{ -+ assert_ptr_not_equal(q, NULL); -+ for (struct otpd_queue_item *e = otpd_queue_pop(q); e != NULL; -+ e = otpd_queue_pop(q)) -+ free_elt(&e); -+} -+#define otpd_queue_item_new new_elt -+#define otpd_queue_item_free free_elt -+#define otpd_queue_free_items free_elts -+ -+static void assert_elt_equal(struct otpd_queue_item *e1, -+ struct otpd_queue_item *e2) -+{ -+ if (e1 == NULL && e2 == NULL) -+ return; -+ assert_ptr_not_equal(e1, NULL); -+ assert_ptr_not_equal(e2, NULL); -+ assert_int_equal(e1->msgid, e2->msgid); -+} -+ -+static void test_single_insert() -+{ -+ struct otpd_queue q = { NULL }; -+ struct otpd_queue_item *ein, *eout; -+ -+ ein = new_elt(0); -+ otpd_queue_push(&q, ein); -+ -+ eout = otpd_queue_peek(&q); -+ assert_elt_equal(ein, eout); -+ -+ eout = otpd_queue_pop(&q); -+ assert_elt_equal(ein, eout); -+ free_elt(&eout); -+ -+ eout = otpd_queue_pop(&q); -+ assert_ptr_equal(eout, NULL); -+ -+ free_elts(&q); -+} -+ -+static void test_jump_insert() -+{ -+ struct otpd_queue q = { NULL }; -+ struct otpd_queue_item *echeck; -+ -+ for (int i = 0; i < 3; i++) { -+ struct otpd_queue_item *e = new_elt(i); -+ otpd_queue_push_head(&q, e); -+ -+ echeck = otpd_queue_peek(&q); -+ assert_elt_equal(e, echeck); -+ } -+ -+ free_elts(&q); -+} -+ -+static void test_garbage_insert() -+{ -+ struct otpd_queue q = { NULL }; -+ struct otpd_queue_item *e, *g; -+ -+ g = new_elt(0); -+ g->next = g; -+ otpd_queue_push(&q, g); -+ -+ e = otpd_queue_peek(&q); -+ assert_ptr_equal(e->next, NULL); -+ -+ free_elts(&q); -+} -+ -+static void test_removal() -+{ -+ struct otpd_queue q = { NULL }; -+ -+ for (int i = 0; i < 3; i++) { -+ struct otpd_queue_item *e = new_elt(i); -+ otpd_queue_push(&q, e); -+ } -+ for (int i = 0; i < 3; i++) { -+ struct otpd_queue_item *e = otpd_queue_pop(&q); -+ assert_ptr_not_equal(e, NULL); -+ assert_ptr_equal(e->next, NULL); -+ assert_int_equal(e->msgid, i); -+ free_elt(&e); -+ } -+} -+ -+static void pick_id(struct otpd_queue *q, int msgid) -+{ -+ struct otpd_queue_item *e; -+ -+ e = otpd_queue_pop_msgid(q, msgid); -+ assert_int_equal(e->msgid, msgid); -+ assert_ptr_equal(e->next, NULL); -+ free_elt(&e); -+ e = otpd_queue_pop_msgid(q, msgid); -+ assert_ptr_equal(e, NULL); -+} -+static void test_pick_removal() -+{ -+ struct otpd_queue q = { NULL }; -+ -+ for (int i = 0; i < 4; i++) { -+ struct otpd_queue_item *e = new_elt(i); -+ otpd_queue_push(&q, e); -+ } -+ -+ pick_id(&q, 0); /* first */ -+ pick_id(&q, 2); /* middle */ -+ pick_id(&q, 3); /* last */ -+ pick_id(&q, 1); /* singleton */ -+ -+ free_elts(&q); -+} -+ -+static void test_iter() -+{ -+ krb5_error_code ret; -+ struct otpd_queue q = { NULL }; -+ const struct otpd_queue *queues[3]; -+ struct otpd_queue_iter *iter = NULL; -+ const krad_packet *p = NULL; -+ -+ for (ptrdiff_t i = 1; i <= 3; i++) { -+ struct otpd_queue_item *e = new_elt(i); -+ e->req = (void *)i; -+ otpd_queue_push(&q, e); -+ } -+ -+ queues[0] = &q; -+ queues[1] = &q; -+ queues[2] = NULL; -+ ret = otpd_queue_iter_new(queues, &iter); -+ assert_int_equal(ret, 0); -+ assert_ptr_not_equal(iter, NULL); -+ -+ for (ptrdiff_t i = 0; i < 6; i++) { -+ p = otpd_queue_iter_func(iter, FALSE); -+ assert_ptr_equal(p, (void *) (i % 3 + 1)); -+ } -+ p = otpd_queue_iter_func(iter, FALSE); -+ assert_ptr_equal(p, NULL); -+ -+ free_elts(&q); -+} -+ -+int main(int argc, char *argv[]) -+{ -+ const struct CMUnitTest tests[] = { -+ cmocka_unit_test(test_single_insert), -+ cmocka_unit_test(test_jump_insert), -+ cmocka_unit_test(test_garbage_insert), -+ cmocka_unit_test(test_removal), -+ cmocka_unit_test(test_pick_removal), -+ cmocka_unit_test(test_iter), -+ }; -+ -+ return cmocka_run_group_tests(tests, NULL, NULL); -+} --- -2.17.1 - diff --git a/SOURCES/0078-ipa-replica-install-fix-pkinit-setup.patch b/SOURCES/0078-ipa-replica-install-fix-pkinit-setup.patch deleted file mode 100644 index a1470c8..0000000 --- a/SOURCES/0078-ipa-replica-install-fix-pkinit-setup.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 5aa15e551fe9b76c3e89862fe36b661825a807ce Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud <flo@redhat.com> -Date: Tue, 4 Sep 2018 14:15:50 +0200 -Subject: [PATCH] ipa-replica-install: fix pkinit setup - -commit 7284097 (Delay enabling services until end of installer) -introduced a regression in replica installation. -When the replica requests a cert for PKINIT, a check is done -to ensure that the hostname corresponds to a machine with a -KDC service enabled (ipaconfigstring attribute of -cn=KDC,cn=<hostname>,cn=masters,cn=ipa,cn=etc,$BASEDN must contain -'enabledService'). -With the commit mentioned above, the service is set to enabled only -at the end of the installation. - -The fix makes a less strict check, ensuring that 'enabledService' -or 'configuredService' is in ipaconfigstring. - -Fixes: https://pagure.io/freeipa/issue/7566 -Reviewed-By: Christian Heimes <cheimes@redhat.com> -Reviewed-By: Christian Heimes <cheimes@redhat.com> ---- - ipaserver/plugins/cert.py | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index 501fc9015468c864215cfb604de37cdf6d805e52..60ad140da3b1483ffe5918239a489030ccc7fe96 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -230,7 +230,8 @@ def ca_kdc_check(api_instance, hostname): - - ipaconfigstring = {val.lower() for val in kdc_entry['ipaConfigString']} - -- if 'enabledservice' not in ipaconfigstring: -+ if 'enabledservice' not in ipaconfigstring \ -+ and 'configuredservice' not in ipaconfigstring: - raise errors.NotFound() - - except errors.NotFound: --- -2.17.1 - diff --git a/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch b/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch index f3a7582..6e66d45 100644 --- a/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch +++ b/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch @@ -1,4 +1,4 @@ -From dfbf91e6463955a66e30eacf2bfbae4af586ef0a Mon Sep 17 00:00:00 2001 +From e94346d8c3d588056f04af1c1916617c962be4bc Mon Sep 17 00:00:00 2001 From: Jan Cholasta <jcholast@redhat.com> Date: Tue, 14 Mar 2017 15:48:07 +0000 Subject: [PATCH] Change branding to IPA and Identity Management @@ -12,7 +12,6 @@ Subject: [PATCH] Change branding to IPA and Identity Management client/man/ipa-join.1 | 2 +- client/man/ipa-rmkeytab.1 | 2 +- client/man/ipa.1 | 2 +- - install/html/browserconfig.html | 4 +- install/html/ssbrowser.html | 4 +- install/html/unauthorized.html | 4 +- install/migration/error.html | 4 +- @@ -47,21 +46,21 @@ Subject: [PATCH] Change branding to IPA and Identity Management install/tools/man/ipactl.8 | 2 +- install/ui/css/patternfly.css | 2 +- install/ui/index.html | 2 +- - install/ui/less/brand.less | 103 ++++++++++----------- - install/ui/less/patternfly.less | 48 ++++++++++ + install/ui/less/brand.less | 103 ++++++++++++++--------------- + install/ui/less/patternfly.less | 48 ++++++++++++++ install/ui/reset_password.html | 2 +- install/ui/src/freeipa/widgets/App.js | 2 +- install/ui/sync_otp.html | 2 +- - ipaserver/advise/plugins/legacy_clients.py | 8 +- + ipaserver/advise/plugins/legacy_clients.py | 8 +-- ipaserver/install/dns.py | 2 +- ipaserver/install/ipa_kra_install.py | 4 +- ipaserver/install/server/install.py | 2 +- ipaserver/install/server/replicainstall.py | 2 +- ipaserver/plugins/sudorule.py | 4 +- - 54 files changed, 167 insertions(+), 122 deletions(-) + 53 files changed, 165 insertions(+), 120 deletions(-) diff --git a/client/man/default.conf.5 b/client/man/default.conf.5 -index 35ce6bb9f871365ffbc74b66be46d49fdcb3f7ad..b519d15bca9b7ddf8d22a776fa4f4a8c7fac0ca8 100644 +index f21d9d5b7a02e9c9858bb44cf3f2f4c16655901a..d6c1e42d1af3a2085451f43240d7e719143bb10b 100644 --- a/client/man/default.conf.5 +++ b/client/man/default.conf.5 @@ -16,7 +16,7 @@ @@ -100,7 +99,7 @@ index 8b9989dec7a2e31f9ccbc0b79d336449bea9e70d..72562ab9582e987cde387583ba033464 ipa\-client\-automount \- Configure automount and NFS for IPA .SH "SYNOPSIS" diff --git a/client/man/ipa-client-install.1 b/client/man/ipa-client-install.1 -index 319952cb6ffe82339b578e8d7fe3eb7a83d53169..e631b89c6774b8ea43f5156293fee137c79dbb98 100644 +index b669b175af7df909f7b62dbce56cc219e154b153..9547288615698232458877afcd10a0de76f75259 100644 --- a/client/man/ipa-client-install.1 +++ b/client/man/ipa-client-install.1 @@ -1,7 +1,7 @@ @@ -161,7 +160,7 @@ index 53f775439dbdb5a4b9dfee7fe6c7277fce10893c..2c8218c94996b1411637a7c53f2f5bc5 ipa\-rmkeytab \- Remove a kerberos principal from a keytab .SH "SYNOPSIS" diff --git a/client/man/ipa.1 b/client/man/ipa.1 -index b843e7ba71ff400fa0712ba491b85e8b34f8a09f..0bd10a7edf8849dc6a77f364d662ee5841054d41 100644 +index d190677cf79af7a2b2225eb4a61f485120186e26..0988aaa93dd45f8a57af1aa23560b4844443c776 100644 --- a/client/man/ipa.1 +++ b/client/man/ipa.1 @@ -16,7 +16,7 @@ @@ -173,30 +172,8 @@ index b843e7ba71ff400fa0712ba491b85e8b34f8a09f..0bd10a7edf8849dc6a77f364d662ee58 .SH "NAME" ipa \- IPA command\-line interface .SH "SYNOPSIS" -diff --git a/install/html/browserconfig.html b/install/html/browserconfig.html -index 9c5cf68211281723e12b518f346aac43c1541cdc..14c4ca1f98a60cd8dfe486f8b942fcf9ae9de4c0 100644 ---- a/install/html/browserconfig.html -+++ b/install/html/browserconfig.html -@@ -2,7 +2,7 @@ - <html> - <head> - <meta charset="utf-8"> -- <title>IPA: Identity Policy Audit</title> -+ <title>Identity Management</title> - <script type="text/javascript" src="../ui/js/libs/loader.js"></script> - <script type="text/javascript"> - (function() { -@@ -26,7 +26,7 @@ - - <nav class="navbar navbar-default navbar-pf" role="navigation"> - <div class="navbar-header"> -- <a class="brand" href="../ui/index.html"><img src="../ui/images/header-logo.png" alt="FreeIPA"></a> -+ <a class="brand" href="../ui/index.html"><img src="../ui/images/header-logo.png" alt="Identity Management"></a> - </div> - </nav> - diff --git a/install/html/ssbrowser.html b/install/html/ssbrowser.html -index 49d8c5be1a5c07fca0593b6c7d0252a2faf15abf..3c67c484162ad9f1897fc1707a89869ff2dbfa2b 100644 +index 5ab871d8e3738ba94eafc6437647adc1c9ca2e99..44c46df47565428a0c8a854881a179cabf3d3496 100644 --- a/install/html/ssbrowser.html +++ b/install/html/ssbrowser.html @@ -2,7 +2,7 @@ @@ -208,7 +185,7 @@ index 49d8c5be1a5c07fca0593b6c7d0252a2faf15abf..3c67c484162ad9f1897fc1707a89869f <script type="text/javascript" src="../ui/js/libs/loader.js"></script> <script type="text/javascript"> (function() { -@@ -33,7 +33,7 @@ +@@ -24,7 +24,7 @@ <nav class="navbar navbar-default navbar-pf" role="navigation"> <div class="navbar-header"> @@ -218,7 +195,7 @@ index 49d8c5be1a5c07fca0593b6c7d0252a2faf15abf..3c67c484162ad9f1897fc1707a89869f </nav> diff --git a/install/html/unauthorized.html b/install/html/unauthorized.html -index 0b4414f55e7e2ab242e782b6824c2af7ae9eae59..37f2548591f691c79c0ac29afb9f4213ec5dc31a 100644 +index 8c57ce822b911728ec40c30ee9d5845803759983..60e021d1210711a5a653961c6a7224d3f5329501 100644 --- a/install/html/unauthorized.html +++ b/install/html/unauthorized.html @@ -2,7 +2,7 @@ @@ -303,10 +280,10 @@ index 19e3e6832bea774244bc949ce44a27f5ebebaed0..2a92ec6aebeb0932b58dd092ba4188e1 You may place your schema files in a subdirectory too, the code that loads schema files processes recursively all subdirectories of schema.d. diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install -index 4258f489873b4095a6672e20f2ac5f2858b71982..e6231b46e74d43af9895e51366e57df4e7a79e20 100755 +index d4e5d4c09cf6b7c1521bcecb79bb6fd7235fc799..e6618ef2e78e26f0cb74fadff214f564d000677c 100755 --- a/install/tools/ipa-adtrust-install +++ b/install/tools/ipa-adtrust-install -@@ -139,11 +139,11 @@ def main(): +@@ -141,11 +141,11 @@ def main(): "==============") print("This program will setup components needed to establish trust to " "AD domains for") @@ -321,28 +298,28 @@ index 4258f489873b4095a6672e20f2ac5f2858b71982..e6231b46e74d43af9895e51366e57df4 # print " * Add a SID to all users and Posix groups" print("") diff --git a/install/tools/ipa-replica-conncheck b/install/tools/ipa-replica-conncheck -index 545cdf00ca74289e6532a40de4c9abad5af4cee0..3741b87f7eb9bb9fe0a01ef1369ac934f288f939 100755 +index 067e47bcbf51048fd301ad48dfa29adecaa5bafb..ecb23c22da8a84a75c65b1dc4fc4889567a19cfc 100755 --- a/install/tools/ipa-replica-conncheck +++ b/install/tools/ipa-replica-conncheck -@@ -289,7 +289,7 @@ class PortResponder(threading.Thread): +@@ -290,7 +290,7 @@ class PortResponder(threading.Thread): self._sockets = [] self._close = False self._close_lock = threading.Lock() -- self.responder_data = 'FreeIPA' -+ self.responder_data = 'IPA' +- self.responder_data = b'FreeIPA' ++ self.responder_data = b'IPA' self.ports_opened = False self.ports_open_cond = threading.Condition() diff --git a/install/tools/man/ipa-adtrust-install.1 b/install/tools/man/ipa-adtrust-install.1 -index 058422b31a1a918fe3a53b9f2c2a54c29111194d..98d8cf0acd466bc1ee5b20d9dbaf40498c237a97 100644 +index b11065806f37174f0f2a0f84f9b606d981e0415d..9d535b72a382d6882263c17a2fec1646b890549c 100644 --- a/install/tools/man/ipa-adtrust-install.1 +++ b/install/tools/man/ipa-adtrust-install.1 @@ -16,7 +16,7 @@ .\" .\" Author: Sumit Bose <sbose@redhat.com> .\" --.TH "ipa-adtrust-install" "1" "Aug 23 2011" "FreeIPA" "FreeIPA Manual Pages" -+.TH "ipa-adtrust-install" "1" "Aug 23 2011" "IPA" "IPA Manual Pages" +-.TH "ipa-adtrust-install" "1" "April 11 2017" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-adtrust-install" "1" "April 11 2017" "IPA" "IPA Manual Pages" .SH "NAME" ipa\-adtrust\-install \- Prepare an IPA server to be able to establish trust relationships with AD domains .SH "SYNOPSIS" @@ -380,7 +357,7 @@ index ff9759ec77d54f32532c4ececfa5081daab9ec15..476f9b534d514b03200369212807fc6d ipa\-backup \- Back up an IPA master .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-ca-install.1 b/install/tools/man/ipa-ca-install.1 -index 79703a47c0d1f72151926565085c8943fcf311a4..895805296f45ba6effd58e196f1ee5cb73ff986e 100644 +index 99ff918789f2178c7b1132b2e7d911900430f3cf..fb6382fcdddcb7358671b67e72c72a4d0222391f 100644 --- a/install/tools/man/ipa-ca-install.1 +++ b/install/tools/man/ipa-ca-install.1 @@ -16,7 +16,7 @@ @@ -393,7 +370,7 @@ index 79703a47c0d1f72151926565085c8943fcf311a4..895805296f45ba6effd58e196f1ee5cb ipa\-ca\-install \- Install a CA on a server .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-cacert-manage.1 b/install/tools/man/ipa-cacert-manage.1 -index 03172814ffb603b656952ce5e9ad6af9c8238ab3..8708c545faf13ce4eb696e7dc3e1e35a22b87493 100644 +index bacd56b5a89f0c5f4453a6287f15d5004148be12..ed69e843528a7f013ede283b2b813304192891ee 100644 --- a/install/tools/man/ipa-cacert-manage.1 +++ b/install/tools/man/ipa-cacert-manage.1 @@ -16,7 +16,7 @@ @@ -532,7 +509,7 @@ index 5018ce8aa3f89470453d9cfc590a0c5f44f78f3c..50d63e9213c6e0a279c4de3c6a92024c ipa\-pkinit\-manage \- Enables or disables PKINIT .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-replica-conncheck.1 b/install/tools/man/ipa-replica-conncheck.1 -index 4fc55e8bf585f3612310f31282e9d3705c824dd1..6c4d94b7d67da016ec37a89b040ec8192dabe3dc 100644 +index 6451f3545e8a133efbcfcfeb21ffdda2a1849367..ed441e3bea9aa9b60fd589bd63897a37cbe6d86c 100644 --- a/install/tools/man/ipa-replica-conncheck.1 +++ b/install/tools/man/ipa-replica-conncheck.1 @@ -16,7 +16,7 @@ @@ -628,7 +605,7 @@ index 00fd03b6bc2184ec2bbc099fd9799551c07d2390..aa9bb7b8567beadcd068e03f7de21043 ipa\-server\-certinstall \- Install new SSL server certificates .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1 -index d5d28df8e72295296a9ac321623ead49fe4692a3..da73555a5be568fddd87ebc9936a938f0eaee76c 100644 +index ca1857d1dce8783095cb02f8176ee952e3abaf0f..5f444e829567cc7161166f0f943fd5acdc412905 100644 --- a/install/tools/man/ipa-server-install.1 +++ b/install/tools/man/ipa-server-install.1 @@ -1,7 +1,7 @@ @@ -640,7 +617,7 @@ index d5d28df8e72295296a9ac321623ead49fe4692a3..da73555a5be568fddd87ebc9936a938f .SH "NAME" ipa\-server\-install \- Configure an IPA server .SH "SYNOPSIS" -@@ -142,7 +142,7 @@ Install and configure a KRA on this server. +@@ -161,7 +161,7 @@ Install and configure a KRA on this server. .SS "DNS OPTIONS" IPA provides an integrated DNS server which can be used to simplify IPA deployment. If you decide to use it, IPA will automatically maintain SRV and other service records when you change your topology. @@ -923,10 +900,10 @@ index 5814b6c578c250d253c8eabeff7a787f1b24f10b..36a51ca62899790da3b8788fcd8a32ff <!--[if IE]> <meta id="ie-detector"> diff --git a/ipaserver/advise/plugins/legacy_clients.py b/ipaserver/advise/plugins/legacy_clients.py -index 7439f584aaa092590ec5ac4ebba408419d337cbe..950c2fe4c40b87aa0eeac52880dc6ce9894cb266 100644 +index 7916965dddfec7e4c2aa34b081d4c1ba6fc953a7..c0d6c73f4f3d55ac3eb3636273f475415ad1d877 100644 --- a/ipaserver/advise/plugins/legacy_clients.py +++ b/ipaserver/advise/plugins/legacy_clients.py -@@ -90,7 +90,7 @@ class config_redhat_sssd_before_1_9(config_base_legacy_client): +@@ -92,7 +92,7 @@ class config_redhat_sssd_before_1_9(config_base_legacy_client): Legacy client configuration for Red Hat based systems, using SSSD. """ description = ('Instructions for configuring a system with an old version ' @@ -935,7 +912,7 @@ index 7439f584aaa092590ec5ac4ebba408419d337cbe..950c2fe4c40b87aa0eeac52880dc6ce9 'instructions is targeted for platforms that include ' 'the authconfig utility, which are all Red Hat based ' 'platforms.') -@@ -125,7 +125,7 @@ class config_generic_linux_sssd_before_1_9(config_base_legacy_client): +@@ -127,7 +127,7 @@ class config_generic_linux_sssd_before_1_9(config_base_legacy_client): using SSSD. """ description = ('Instructions for configuring a system with an old version ' @@ -944,7 +921,7 @@ index 7439f584aaa092590ec5ac4ebba408419d337cbe..950c2fe4c40b87aa0eeac52880dc6ce9 'instructions is targeted for linux systems that do not ' 'include the authconfig utility.') -@@ -180,7 +180,7 @@ class config_redhat_nss_pam_ldapd(config_base_legacy_client): +@@ -182,7 +182,7 @@ class config_redhat_nss_pam_ldapd(config_base_legacy_client): using nss-pam-ldapd. """ description = ('Instructions for configuring a system with nss-pam-ldapd ' @@ -953,7 +930,7 @@ index 7439f584aaa092590ec5ac4ebba408419d337cbe..950c2fe4c40b87aa0eeac52880dc6ce9 'for platforms that include the authconfig utility, which ' 'are all Red Hat based platforms.') -@@ -348,7 +348,7 @@ class config_redhat_nss_ldap(config_base_legacy_client): +@@ -350,7 +350,7 @@ class config_redhat_nss_ldap(config_base_legacy_client): using nss-ldap. """ description = ('Instructions for configuring a system with nss-ldap ' @@ -963,10 +940,10 @@ index 7439f584aaa092590ec5ac4ebba408419d337cbe..950c2fe4c40b87aa0eeac52880dc6ce9 'are all Red Hat based platforms.') diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py -index 0046b78066cbb8e4f43e04af86da74118a5aa8c6..8446b192da287a903001bff7c5022b8ccf5dfcde 100644 +index e14b353e9cb655a6e7ef228d47dfc7a1badd7286..1cd851625f225538856b9b627b3d8190ccfa47dc 100644 --- a/ipaserver/install/dns.py +++ b/ipaserver/install/dns.py -@@ -147,7 +147,7 @@ def install_check(standalone, api, replica, options, hostname): +@@ -149,7 +149,7 @@ def install_check(standalone, api, replica, options, hostname): if standalone: print("==============================================================================") @@ -976,10 +953,10 @@ index 0046b78066cbb8e4f43e04af86da74118a5aa8c6..8446b192da287a903001bff7c5022b8c print("This includes:") print(" * Configure DNS (bind)") diff --git a/ipaserver/install/ipa_kra_install.py b/ipaserver/install/ipa_kra_install.py -index 3a639ac20f101293edd7449f8846a451469e2297..436d44f5d3ee6f5317585319903435d4941d3059 100644 +index 07e11ea69ded8832015dd69ea43ff338c5f9df95..76492c1dd9bf02d3e80ec5876214441d697e9765 100644 --- a/ipaserver/install/ipa_kra_install.py +++ b/ipaserver/install/ipa_kra_install.py -@@ -87,7 +87,7 @@ class KRAInstall(admintool.AdminTool): +@@ -90,7 +90,7 @@ class KRAInstall(admintool.AdminTool): if options.uninstall: sys.exit( 'ERROR: Standalone KRA uninstallation was removed in ' @@ -988,7 +965,7 @@ index 3a639ac20f101293edd7449f8846a451469e2297..436d44f5d3ee6f5317585319903435d4 'issues.') else: return KRAInstaller -@@ -98,7 +98,7 @@ class KRAInstaller(KRAInstall): +@@ -101,7 +101,7 @@ class KRAInstaller(KRAInstall): INSTALLER_START_MESSAGE = ''' =================================================================== @@ -998,10 +975,10 @@ index 3a639ac20f101293edd7449f8846a451469e2297..436d44f5d3ee6f5317585319903435d4 ''' diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py -index dcdd9aabb746c4973b3f73934d94225503728f0b..66c982058b7a7deecc25d17873d94d6be8d03b19 100644 +index e96ae97c74ee1598683d1ef3f2570e8de93c9943..b5290817e4b0f849ef77353d33bc6753a7c8b42d 100644 --- a/ipaserver/install/server/install.py +++ b/ipaserver/install/server/install.py -@@ -373,7 +373,7 @@ def install_check(installer): +@@ -377,7 +377,7 @@ def install_check(installer): print("=======================================" "=======================================") @@ -1011,10 +988,10 @@ index dcdd9aabb746c4973b3f73934d94225503728f0b..66c982058b7a7deecc25d17873d94d6b print("This includes:") if setup_ca: diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index 8a659a0fc2675df0a8fba1d3d7d8a629b376c93e..9a0432bc45dbb6e3a767a93913e44c4baedbfa8a 100644 +index 33f3ae9e616b34a3ab0ff8e4257552855e817e7c..356d17cf9a2d507e98952ae0477e473562a356e2 100644 --- a/ipaserver/install/server/replicainstall.py +++ b/ipaserver/install/server/replicainstall.py -@@ -615,7 +615,7 @@ def check_domain_level_is_supported(current): +@@ -616,7 +616,7 @@ def check_domain_level_is_supported(current): above_upper_bound = current > constants.MAX_DOMAIN_LEVEL if under_lower_bound or above_upper_bound: @@ -1024,7 +1001,7 @@ index 8a659a0fc2675df0a8fba1d3d7d8a629b376c93e..9a0432bc45dbb6e3a767a93913e44c4b "this domain. The Domain Level needs to be " "raised before installing a replica with " diff --git a/ipaserver/plugins/sudorule.py b/ipaserver/plugins/sudorule.py -index 28c3f21f113fd14160abd518663f2d582f8653fd..f70943576d861ce7b3a8bc4c29e9ded86b098e81 100644 +index 6037938330f13a30d0ccfbedcaac59c567bda0d6..b8a0c82d394edb8744de34394895b86fae2c321f 100644 --- a/ipaserver/plugins/sudorule.py +++ b/ipaserver/plugins/sudorule.py @@ -47,7 +47,7 @@ give certain users (or groups of users) the ability to run some (or all) @@ -1046,5 +1023,5 @@ index 28c3f21f113fd14160abd518663f2d582f8653fd..f70943576d861ce7b3a8bc4c29e9ded8 """) + _(""" To enable the binddn run the following command to set the password: -- -2.17.1 +2.14.4 diff --git a/SOURCES/1002-Package-copy-schema-to-ca.py.patch b/SOURCES/1002-Package-copy-schema-to-ca.py.patch index 23d8eb6..d412892 100644 --- a/SOURCES/1002-Package-copy-schema-to-ca.py.patch +++ b/SOURCES/1002-Package-copy-schema-to-ca.py.patch @@ -1,4 +1,4 @@ -From b0982e138e6ad0830b1903d8f58c0d0a25d3ace4 Mon Sep 17 00:00:00 2001 +From 5b587502716f71c9c71cd63e32d6b837613bc8dc Mon Sep 17 00:00:00 2001 From: Jan Cholasta <jcholast@redhat.com> Date: Tue, 14 Mar 2017 16:07:15 +0000 Subject: [PATCH] Package copy-schema-to-ca.py @@ -10,24 +10,24 @@ This reverts commit f4c7f1dd8a9ce530a8291219a904686ee47e59c7. 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/freeipa.spec.in b/freeipa.spec.in -index 80ae98c5515f64a8df8d981ad5e91b05c84e31c1..86189d56ded05dac695d3a7a19f726e197979dc5 100644 +index 93f996c5be670e0ae374a12a85c2465b8e740927..70482ceb65639465d60b0c48fd2ccd6eaa34e097 100644 --- a/freeipa.spec.in +++ b/freeipa.spec.in -@@ -1292,6 +1292,7 @@ fi +@@ -1475,6 +1475,7 @@ fi # END %dir %{_usr}/share/ipa %{_usr}/share/ipa/wsgi.py* +%{_usr}/share/ipa/copy-schema-to-ca.py* + %{_usr}/share/ipa/kdcproxy.wsgi %{_usr}/share/ipa/*.ldif %{_usr}/share/ipa/*.uldif - %{_usr}/share/ipa/*.template diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index cb8dc43096b8851d7554447f28c4537a35b47852..810ce882920490abc6fee4458082fe6611f317f5 100644 +index b58fbb4c881d247d6b5fb661f4085ec82c3cc811..cf6247a4b12e3fecc7c784c9d803670442c56fd5 100644 --- a/ipaserver/install/cainstance.py +++ b/ipaserver/install/cainstance.py -@@ -1355,9 +1355,11 @@ def replica_ca_install_check(config, promote): +@@ -1384,9 +1384,11 @@ def replica_ca_install_check(config, promote): else: - root_logger.critical( + logger.critical( 'The master CA directory server does not have necessary schema. ' - 'Please run copy-schema-to-ca.py on all CA masters.\n' + 'Please copy the following script to all CA masters and run it ' @@ -36,9 +36,9 @@ index cb8dc43096b8851d7554447f28c4537a35b47852..810ce882920490abc6fee4458082fe66 - '--skip-schema-check.') + '--skip-schema-check.', + os.path.join(paths.USR_SHARE_IPA_DIR, 'copy-schema-to-ca.py')) - exit('IPA schema missing on master CA directory server') + sys.exit('IPA schema missing on master CA directory server') -- -2.17.1 +2.14.4 diff --git a/SOURCES/1003-Revert-Increased-mod_wsgi-socket-timeout.patch b/SOURCES/1003-Revert-Increased-mod_wsgi-socket-timeout.patch index 4c78b44..a7566d3 100644 --- a/SOURCES/1003-Revert-Increased-mod_wsgi-socket-timeout.patch +++ b/SOURCES/1003-Revert-Increased-mod_wsgi-socket-timeout.patch @@ -1,4 +1,4 @@ -From 7a7d19b33cd669275323b70c6a295c991846f3be Mon Sep 17 00:00:00 2001 +From fa0db6fe2c7343d2ba86fadd55e9f4db78ec9f8a Mon Sep 17 00:00:00 2001 From: Jan Cholasta <jcholast@redhat.com> Date: Wed, 22 Jun 2016 13:53:46 +0200 Subject: [PATCH] Revert "Increased mod_wsgi socket-timeout" @@ -11,18 +11,18 @@ https://bugzilla.redhat.com/show_bug.cgi?id=1348948 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/conf/ipa.conf b/install/conf/ipa.conf -index 34ced2ab9d91ae174a42a580e1c4f9436c1a8c3b..39f67abed6a0895c4a66878193602d237efbf550 100644 +index 912a63c2240e0681dfbeeac223a902b15b304716..c5fc518f803d379287043b405efeb46dd53a6b28 100644 --- a/install/conf/ipa.conf +++ b/install/conf/ipa.conf -@@ -52,7 +52,7 @@ WSGISocketPrefix /run/httpd/wsgi +@@ -48,7 +48,7 @@ WSGISocketPrefix /run/httpd/wsgi # Configure mod_wsgi handler for /ipa WSGIDaemonProcess ipa processes=$WSGI_PROCESSES threads=1 maximum-requests=500 \ -- user=ipaapi group=ipaapi display-name=%{GROUP} socket-timeout=2147483647 -+ user=ipaapi group=ipaapi display-name=%{GROUP} +- user=ipaapi group=ipaapi display-name=%{GROUP} socket-timeout=2147483647 \ ++ user=ipaapi group=ipaapi display-name=%{GROUP} \ + lang=C.UTF-8 locale=C.UTF-8 WSGIImportScript /usr/share/ipa/wsgi.py process-group=ipa application-group=ipa WSGIScriptAlias /ipa /usr/share/ipa/wsgi.py - WSGIScriptReloading Off -- -2.17.1 +2.14.4 diff --git a/SOURCES/1004-Remove-csrgen.patch b/SOURCES/1004-Remove-csrgen.patch index be8adac..fc26b09 100644 --- a/SOURCES/1004-Remove-csrgen.patch +++ b/SOURCES/1004-Remove-csrgen.patch @@ -1,4 +1,4 @@ -From 5d84d3cd7e14b7d34fa1b756c027877be7562f5e Mon Sep 17 00:00:00 2001 +From b7082747c2b6bbe2e857bd4fa20af443073dbd02 Mon Sep 17 00:00:00 2001 From: Jan Cholasta <jcholast@redhat.com> Date: Thu, 16 Mar 2017 09:44:21 +0000 Subject: [PATCH] Remove csrgen @@ -19,90 +19,54 @@ This reverts commits: https://bugzilla.redhat.com/show_bug.cgi?id=1432630 --- - freeipa.spec.in | 18 - - ipaclient/csrgen.py | 398 ------------------ - .../csrgen/profiles/caIPAserviceCert.json | 15 - - ipaclient/csrgen/profiles/userCert.json | 15 - - ipaclient/csrgen/rules/dataDNS.json | 15 - - ipaclient/csrgen/rules/dataEmail.json | 15 - - ipaclient/csrgen/rules/dataHostCN.json | 15 - - ipaclient/csrgen/rules/dataSubjectBase.json | 15 - - ipaclient/csrgen/rules/dataUsernameCN.json | 15 - - ipaclient/csrgen/rules/syntaxSAN.json | 15 - - ipaclient/csrgen/rules/syntaxSubject.json | 16 - - ipaclient/csrgen/templates/certutil_base.tmpl | 11 - - ipaclient/csrgen/templates/openssl_base.tmpl | 35 -- - .../csrgen/templates/openssl_macros.tmpl | 29 -- - ipaclient/plugins/cert.py | 96 +---- - ipaclient/plugins/csrgen.py | 120 ------ - ipaclient/setup.py | 7 - - ipalib/errors.py | 28 -- - ipatests/setup.py | 2 - - ipatests/test_ipaclient/__init__.py | 7 - - .../data/test_csrgen/profiles/profile.json | 8 - - .../data/test_csrgen/rules/basic.json | 12 - - .../data/test_csrgen/rules/options.json | 18 - - .../scripts/caIPAserviceCert_certutil.sh | 11 - - .../scripts/caIPAserviceCert_openssl.sh | 34 -- - .../test_csrgen/scripts/userCert_certutil.sh | 11 - - .../test_csrgen/scripts/userCert_openssl.sh | 34 -- - .../test_csrgen/templates/identity_base.tmpl | 1 - - ipatests/test_ipaclient/test_csrgen.py | 298 ------------- - 29 files changed, 1 insertion(+), 1313 deletions(-) - delete mode 100644 ipaclient/csrgen.py + freeipa.spec.in | 18 ----- + ipaclient/csrgen/profiles/caIPAserviceCert.json | 15 ---- + ipaclient/csrgen/profiles/userCert.json | 15 ---- + ipaclient/csrgen/templates/openssl_macros.tmpl | 29 -------- + ipaclient/plugins/cert.py | 82 +--------------------- + ipaclient/setup.py | 7 -- + ipalib/errors.py | 28 -------- + ipatests/setup.py | 2 - + ipatests/test_ipaclient/__init__.py | 7 -- + .../data/test_csrgen/profiles/profile.json | 8 --- + .../data/test_csrgen/templates/identity_base.tmpl | 1 - + 11 files changed, 1 insertion(+), 211 deletions(-) delete mode 100644 ipaclient/csrgen/profiles/caIPAserviceCert.json delete mode 100644 ipaclient/csrgen/profiles/userCert.json - delete mode 100644 ipaclient/csrgen/rules/dataDNS.json - delete mode 100644 ipaclient/csrgen/rules/dataEmail.json - delete mode 100644 ipaclient/csrgen/rules/dataHostCN.json - delete mode 100644 ipaclient/csrgen/rules/dataSubjectBase.json - delete mode 100644 ipaclient/csrgen/rules/dataUsernameCN.json - delete mode 100644 ipaclient/csrgen/rules/syntaxSAN.json - delete mode 100644 ipaclient/csrgen/rules/syntaxSubject.json - delete mode 100644 ipaclient/csrgen/templates/certutil_base.tmpl - delete mode 100644 ipaclient/csrgen/templates/openssl_base.tmpl delete mode 100644 ipaclient/csrgen/templates/openssl_macros.tmpl - delete mode 100644 ipaclient/plugins/csrgen.py delete mode 100644 ipatests/test_ipaclient/__init__.py delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/profiles/profile.json - delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/rules/basic.json - delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/rules/options.json - delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/scripts/caIPAserviceCert_certutil.sh - delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/scripts/caIPAserviceCert_openssl.sh - delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/scripts/userCert_certutil.sh - delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/scripts/userCert_openssl.sh delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/templates/identity_base.tmpl - delete mode 100644 ipatests/test_ipaclient/test_csrgen.py diff --git a/freeipa.spec.in b/freeipa.spec.in -index 86189d56ded05dac695d3a7a19f726e197979dc5..3cefeeced78de60ced36759acce5ab5c1a0ddd0d 100644 +index 70482ceb65639465d60b0c48fd2ccd6eaa34e097..8d76217fc5a735f36d344b1b783d061b3b0f6271 100644 --- a/freeipa.spec.in +++ b/freeipa.spec.in -@@ -198,7 +198,6 @@ BuildRequires: python-sssdconfig - BuildRequires: python-nose - BuildRequires: python-paste - BuildRequires: systemd-python +@@ -245,7 +245,6 @@ BuildRequires: python2-sssdconfig + BuildRequires: python2-nose + BuildRequires: python2-paste + BuildRequires: python2-systemd -BuildRequires: python2-jinja2 - BuildRequires: python-augeas + BuildRequires: python2-augeas %if 0%{?with_python3} -@@ -236,7 +235,6 @@ BuildRequires: python3-libsss_nss_idmap +@@ -284,7 +283,6 @@ BuildRequires: python3-libsss_nss_idmap BuildRequires: python3-nose BuildRequires: python3-paste BuildRequires: python3-systemd -BuildRequires: python3-jinja2 BuildRequires: python3-augeas - %endif # with_python3 - %endif # with_lint -@@ -544,7 +542,6 @@ Requires: %{name}-client-common = %{version}-%{release} + BuildRequires: python3-netaddr + BuildRequires: python3-pyasn1 +@@ -640,7 +638,6 @@ Requires: %{name}-client-common = %{version}-%{release} Requires: %{name}-common = %{version}-%{release} Requires: python2-ipalib = %{version}-%{release} - Requires: python-dns >= 1.15 + Requires: python2-dns >= 1.15 -Requires: python2-jinja2 %description -n python2-ipaclient IPA is an integrated solution to provide centrally managed Identity (users, -@@ -567,7 +564,6 @@ Requires: %{name}-client-common = %{version}-%{release} +@@ -663,7 +660,6 @@ Requires: %{name}-client-common = %{version}-%{release} Requires: %{name}-common = %{version}-%{release} Requires: python3-ipalib = %{version}-%{release} Requires: python3-dns >= 1.15 @@ -110,7 +74,7 @@ index 86189d56ded05dac695d3a7a19f726e197979dc5..3cefeeced78de60ced36759acce5ab5c %description -n python3-ipaclient IPA is an integrated solution to provide centrally managed Identity (users, -@@ -1433,13 +1429,6 @@ fi +@@ -1609,13 +1605,6 @@ fi %{python_sitelib}/ipaclient/remote_plugins/*.py* %dir %{python_sitelib}/ipaclient/remote_plugins/2_* %{python_sitelib}/ipaclient/remote_plugins/2_*/*.py* @@ -124,7 +88,7 @@ index 86189d56ded05dac695d3a7a19f726e197979dc5..3cefeeced78de60ced36759acce5ab5c %{python_sitelib}/ipaclient-*.egg-info -@@ -1464,13 +1453,6 @@ fi +@@ -1640,13 +1629,6 @@ fi %dir %{python3_sitelib}/ipaclient/remote_plugins/2_* %{python3_sitelib}/ipaclient/remote_plugins/2_*/*.py %{python3_sitelib}/ipaclient/remote_plugins/2_*/__pycache__/*.py* @@ -138,410 +102,6 @@ index 86189d56ded05dac695d3a7a19f726e197979dc5..3cefeeced78de60ced36759acce5ab5c %{python3_sitelib}/ipaclient-*.egg-info %endif # with_python3 -diff --git a/ipaclient/csrgen.py b/ipaclient/csrgen.py -deleted file mode 100644 -index 8fb0b32c05490812b75f87db69f9df1ca38107f7..0000000000000000000000000000000000000000 ---- a/ipaclient/csrgen.py -+++ /dev/null -@@ -1,398 +0,0 @@ --# --# Copyright (C) 2016 FreeIPA Contributors see COPYING for license --# -- --import collections --import errno --import json --import os.path --import pipes --import traceback -- --import pkg_resources -- --import jinja2 --import jinja2.ext --import jinja2.sandbox --import six -- --from ipalib import api --from ipalib import errors --from ipalib.text import _ --from ipapython.ipa_log_manager import log_mgr -- --if six.PY3: -- unicode = str -- --__doc__ = _(""" --Routines for constructing certificate signing requests using IPA data and --stored templates. --""") -- --logger = log_mgr.get_logger(__name__) -- -- --class IndexableUndefined(jinja2.Undefined): -- def __getitem__(self, key): -- return jinja2.Undefined( -- hint=self._undefined_hint, obj=self._undefined_obj, -- name=self._undefined_name, exc=self._undefined_exception) -- -- --class IPAExtension(jinja2.ext.Extension): -- """Jinja2 extension providing useful features for CSR generation rules.""" -- -- def __init__(self, environment): -- super(IPAExtension, self).__init__(environment) -- -- environment.filters.update( -- quote=self.quote, -- required=self.required, -- ) -- -- def quote(self, data): -- return pipes.quote(data) -- -- def required(self, data, name): -- if not data: -- raise errors.CSRTemplateError( -- reason=_('Required CSR generation rule %(name)s is missing data') % -- {'name': name}) -- return data -- -- --class Formatter(object): -- """ -- Class for processing a set of CSR generation rules into a template. -- -- The template can be rendered with user and database data to produce a -- script, which generates a CSR when run. -- -- Subclasses of Formatter should set the value of base_template_name to the -- filename of a base template with spaces for the processed rules. -- Additionally, they should override the _get_template_params method to -- produce the correct output for the base template. -- """ -- base_template_name = None -- -- def __init__(self, csr_data_dir=None): -- # chain loaders: -- # 1) csr_data_dir/templates -- # 2) /etc/ipa/csrgen/templates -- # 3) ipaclient/csrgen/templates -- loaders = [] -- if csr_data_dir is not None: -- loaders.append(jinja2.FileSystemLoader( -- os.path.join(csr_data_dir, 'templates')) -- ) -- loaders.append(jinja2.FileSystemLoader( -- os.path.join(api.env.confdir, 'csrgen/templates')) -- ) -- loaders.append(jinja2.PackageLoader('ipaclient', 'csrgen/templates')) -- -- self.jinja2 = jinja2.sandbox.SandboxedEnvironment( -- loader=jinja2.ChoiceLoader(loaders), -- extensions=[jinja2.ext.ExprStmtExtension, IPAExtension], -- keep_trailing_newline=True, undefined=IndexableUndefined) -- -- self.passthrough_globals = {} -- -- def _define_passthrough(self, call): -- """Some macros are meant to be interpreted during the final render, not -- when data rules are interpolated into syntax rules. This method allows -- those macros to be registered so that calls to them are passed through -- to the prepared rule rather than interpreted. -- """ -- -- def passthrough(caller): -- return u'{%% call %s() %%}%s{%% endcall %%}' % (call, caller()) -- -- parts = call.split('.') -- current_level = self.passthrough_globals -- for part in parts[:-1]: -- if part not in current_level: -- current_level[part] = {} -- current_level = current_level[part] -- current_level[parts[-1]] = passthrough -- -- def build_template(self, rules): -- """ -- Construct a template that can produce CSR generator strings. -- -- :param rules: list of FieldMapping to use to populate the template. -- -- :returns: jinja2.Template that can be rendered to produce the CSR data. -- """ -- syntax_rules = [] -- for field_mapping in rules: -- data_rules_prepared = [ -- self._prepare_data_rule(rule) -- for rule in field_mapping.data_rules] -- -- data_sources = [] -- for rule in field_mapping.data_rules: -- data_source = rule.options.get('data_source') -- if data_source: -- data_sources.append(data_source) -- -- syntax_rules.append(self._prepare_syntax_rule( -- field_mapping.syntax_rule, data_rules_prepared, -- field_mapping.description, data_sources)) -- -- template_params = self._get_template_params(syntax_rules) -- base_template = self.jinja2.get_template( -- self.base_template_name, globals=self.passthrough_globals) -- -- try: -- combined_template_source = base_template.render(**template_params) -- except jinja2.UndefinedError: -- logger.debug(traceback.format_exc()) -- raise errors.CSRTemplateError(reason=_( -- 'Template error when formatting certificate data')) -- -- logger.debug( -- 'Formatting with template: %s' % combined_template_source) -- combined_template = self.jinja2.from_string(combined_template_source) -- -- return combined_template -- -- def _wrap_conditional(self, rule, condition): -- rule = '{%% if %s %%}%s{%% endif %%}' % (condition, rule) -- return rule -- -- def _wrap_required(self, rule, description): -- template = '{%% filter required("%s") %%}%s{%% endfilter %%}' % ( -- description, rule) -- -- return template -- -- def _prepare_data_rule(self, data_rule): -- template = data_rule.template -- -- data_source = data_rule.options.get('data_source') -- if data_source: -- template = self._wrap_conditional(template, data_source) -- -- return template -- -- def _prepare_syntax_rule( -- self, syntax_rule, data_rules, description, data_sources): -- logger.debug('Syntax rule template: %s' % syntax_rule.template) -- template = self.jinja2.from_string( -- syntax_rule.template, globals=self.passthrough_globals) -- is_required = syntax_rule.options.get('required', False) -- try: -- prepared_template = template.render(datarules=data_rules) -- except jinja2.UndefinedError: -- logger.debug(traceback.format_exc()) -- raise errors.CSRTemplateError(reason=_( -- 'Template error when formatting certificate data')) -- -- if data_sources: -- combinator = ' %s ' % syntax_rule.options.get( -- 'data_source_combinator', 'or') -- condition = combinator.join(data_sources) -- prepared_template = self._wrap_conditional( -- prepared_template, condition) -- -- if is_required: -- prepared_template = self._wrap_required( -- prepared_template, description) -- -- return prepared_template -- -- def _get_template_params(self, syntax_rules): -- """ -- Package the syntax rules into fields expected by the base template. -- -- :param syntax_rules: list of prepared syntax rules to be included in -- the template. -- -- :returns: dict of values needed to render the base template. -- """ -- raise NotImplementedError('Formatter class must be subclassed') -- -- --class OpenSSLFormatter(Formatter): -- """Formatter class supporting the openssl command-line tool.""" -- -- base_template_name = 'openssl_base.tmpl' -- -- # Syntax rules are wrapped in this data structure, to keep track of whether -- # each goes in the extension or the root section -- SyntaxRule = collections.namedtuple( -- 'SyntaxRule', ['template', 'is_extension']) -- -- def __init__(self, *args, **kwargs): -- super(OpenSSLFormatter, self).__init__(*args, **kwargs) -- self._define_passthrough('openssl.section') -- -- def _get_template_params(self, syntax_rules): -- parameters = [rule.template for rule in syntax_rules -- if not rule.is_extension] -- extensions = [rule.template for rule in syntax_rules -- if rule.is_extension] -- -- return {'parameters': parameters, 'extensions': extensions} -- -- def _prepare_syntax_rule( -- self, syntax_rule, data_rules, description, data_sources): -- """Overrides method to pull out whether rule is an extension or not.""" -- prepared_template = super(OpenSSLFormatter, self)._prepare_syntax_rule( -- syntax_rule, data_rules, description, data_sources) -- is_extension = syntax_rule.options.get('extension', False) -- return self.SyntaxRule(prepared_template, is_extension) -- -- --class CertutilFormatter(Formatter): -- base_template_name = 'certutil_base.tmpl' -- -- def _get_template_params(self, syntax_rules): -- return {'options': syntax_rules} -- -- --class FieldMapping(object): -- """Representation of the rules needed to construct a complete cert field. -- -- Attributes: -- description: str, a name or description of this field, to be used in -- messages -- syntax_rule: Rule, the rule defining the syntax of this field -- data_rules: list of Rule, the rules that produce data to be stored in -- this field -- """ -- __slots__ = ['description', 'syntax_rule', 'data_rules'] -- -- def __init__(self, description, syntax_rule, data_rules): -- self.description = description -- self.syntax_rule = syntax_rule -- self.data_rules = data_rules -- -- --class Rule(object): -- __slots__ = ['name', 'template', 'options'] -- -- def __init__(self, name, template, options): -- self.name = name -- self.template = template -- self.options = options -- -- --class RuleProvider(object): -- def rules_for_profile(self, profile_id, helper): -- """ -- Return the rules needed to build a CSR using the given profile. -- -- :param profile_id: str, name of the CSR generation profile to use -- :param helper: str, name of tool (e.g. openssl, certutil) that will be -- used to create CSR -- -- :returns: list of FieldMapping, filled out with the appropriate rules -- """ -- raise NotImplementedError('RuleProvider class must be subclassed') -- -- --class FileRuleProvider(RuleProvider): -- def __init__(self, csr_data_dir=None): -- self.rules = {} -- self._csrgen_data_dirs = [] -- if csr_data_dir is not None: -- self._csrgen_data_dirs.append(csr_data_dir) -- self._csrgen_data_dirs.append( -- os.path.join(api.env.confdir, 'csrgen') -- ) -- self._csrgen_data_dirs.append( -- pkg_resources.resource_filename('ipaclient', 'csrgen') -- ) -- -- def _open(self, subdir, filename): -- for data_dir in self._csrgen_data_dirs: -- path = os.path.join(data_dir, subdir, filename) -- try: -- return open(path) -- except IOError as e: -- if e.errno != errno.ENOENT: -- raise -- raise IOError( -- errno.ENOENT, -- "'{}' not found in {}".format( -- os.path.join(subdir, filename), -- ", ".join(self._csrgen_data_dirs) -- ) -- ) -- -- def _rule(self, rule_name, helper): -- if (rule_name, helper) not in self.rules: -- try: -- with self._open('rules', '%s.json' % rule_name) as f: -- ruleset = json.load(f) -- except IOError: -- raise errors.NotFound( -- reason=_('Ruleset %(ruleset)s does not exist.') % -- {'ruleset': rule_name}) -- -- matching_rules = [r for r in ruleset['rules'] -- if r['helper'] == helper] -- if len(matching_rules) == 0: -- raise errors.EmptyResult( -- reason=_('No transformation in "%(ruleset)s" rule supports' -- ' helper "%(helper)s"') % -- {'ruleset': rule_name, 'helper': helper}) -- elif len(matching_rules) > 1: -- raise errors.RedundantMappingRule( -- ruleset=rule_name, helper=helper) -- rule = matching_rules[0] -- -- options = {} -- if 'options' in ruleset: -- options.update(ruleset['options']) -- if 'options' in rule: -- options.update(rule['options']) -- -- self.rules[(rule_name, helper)] = Rule( -- rule_name, rule['template'], options) -- -- return self.rules[(rule_name, helper)] -- -- def rules_for_profile(self, profile_id, helper): -- try: -- with self._open('profiles', '%s.json' % profile_id) as f: -- profile = json.load(f) -- except IOError: -- raise errors.NotFound( -- reason=_('No CSR generation rules are defined for profile' -- ' %(profile_id)s') % {'profile_id': profile_id}) -- -- field_mappings = [] -- for field in profile: -- syntax_rule = self._rule(field['syntax'], helper) -- data_rules = [self._rule(name, helper) for name in field['data']] -- field_mappings.append(FieldMapping( -- syntax_rule.name, syntax_rule, data_rules)) -- return field_mappings -- -- --class CSRGenerator(object): -- FORMATTERS = { -- 'openssl': OpenSSLFormatter, -- 'certutil': CertutilFormatter, -- } -- -- def __init__(self, rule_provider): -- self.rule_provider = rule_provider -- -- def csr_script(self, principal, config, profile_id, helper): -- render_data = {'subject': principal, 'config': config} -- -- formatter = self.FORMATTERS[helper]() -- rules = self.rule_provider.rules_for_profile(profile_id, helper) -- template = formatter.build_template(rules) -- -- try: -- script = template.render(render_data) -- except jinja2.UndefinedError: -- logger.debug(traceback.format_exc()) -- raise errors.CSRTemplateError(reason=_( -- 'Template error when formatting certificate data')) -- -- return script diff --git a/ipaclient/csrgen/profiles/caIPAserviceCert.json b/ipaclient/csrgen/profiles/caIPAserviceCert.json deleted file mode 100644 index 114d2ffd4e0d8eae833eaa594f6a17a79da909be..0000000000000000000000000000000000000000 @@ -584,212 +144,6 @@ index d6cf5cfffcfadd604fc3e8283d1be15767278c7a..00000000000000000000000000000000 - ] - } -] -diff --git a/ipaclient/csrgen/rules/dataDNS.json b/ipaclient/csrgen/rules/dataDNS.json -deleted file mode 100644 -index 2663f114123a5a73b23f6a41c1b9b3162f157ea1..0000000000000000000000000000000000000000 ---- a/ipaclient/csrgen/rules/dataDNS.json -+++ /dev/null -@@ -1,15 +0,0 @@ --{ -- "rules": [ -- { -- "helper": "openssl", -- "template": "DNS = {{subject.krbprincipalname.0.partition('/')[2].partition('@')[0]}}" -- }, -- { -- "helper": "certutil", -- "template": "dns:{{subject.krbprincipalname.0.partition('/')[2].partition('@')[0]|quote}}" -- } -- ], -- "options": { -- "data_source": "subject.krbprincipalname.0.partition('/')[2].partition('@')[0]" -- } --} -diff --git a/ipaclient/csrgen/rules/dataEmail.json b/ipaclient/csrgen/rules/dataEmail.json -deleted file mode 100644 -index 2eae9fb25e4f09d52ec5e29e2643236641c5cecd..0000000000000000000000000000000000000000 ---- a/ipaclient/csrgen/rules/dataEmail.json -+++ /dev/null -@@ -1,15 +0,0 @@ --{ -- "rules": [ -- { -- "helper": "openssl", -- "template": "email = {{subject.mail.0}}" -- }, -- { -- "helper": "certutil", -- "template": "email:{{subject.mail.0|quote}}" -- } -- ], -- "options": { -- "data_source": "subject.mail.0" -- } --} -diff --git a/ipaclient/csrgen/rules/dataHostCN.json b/ipaclient/csrgen/rules/dataHostCN.json -deleted file mode 100644 -index 5c415bb8cf8911ad8c24820d2466beb57f0d9a82..0000000000000000000000000000000000000000 ---- a/ipaclient/csrgen/rules/dataHostCN.json -+++ /dev/null -@@ -1,15 +0,0 @@ --{ -- "rules": [ -- { -- "helper": "openssl", -- "template": "CN={{subject.krbprincipalname.0.partition('/')[2].partition('@')[0]}}" -- }, -- { -- "helper": "certutil", -- "template": "CN={{subject.krbprincipalname.0.partition('/')[2].partition('@')[0]|quote}}" -- } -- ], -- "options": { -- "data_source": "subject.krbprincipalname.0.partition('/')[2].partition('@')[0]" -- } --} -diff --git a/ipaclient/csrgen/rules/dataSubjectBase.json b/ipaclient/csrgen/rules/dataSubjectBase.json -deleted file mode 100644 -index 309dfb1ed57b0dfe282386181a4c887228545c55..0000000000000000000000000000000000000000 ---- a/ipaclient/csrgen/rules/dataSubjectBase.json -+++ /dev/null -@@ -1,15 +0,0 @@ --{ -- "rules": [ -- { -- "helper": "openssl", -- "template": "{{config.ipacertificatesubjectbase.0}}" -- }, -- { -- "helper": "certutil", -- "template": "{{config.ipacertificatesubjectbase.0|quote}}" -- } -- ], -- "options": { -- "data_source": "config.ipacertificatesubjectbase.0" -- } --} -diff --git a/ipaclient/csrgen/rules/dataUsernameCN.json b/ipaclient/csrgen/rules/dataUsernameCN.json -deleted file mode 100644 -index 37e7e0113ef3146a97383355285dc1d319029e0e..0000000000000000000000000000000000000000 ---- a/ipaclient/csrgen/rules/dataUsernameCN.json -+++ /dev/null -@@ -1,15 +0,0 @@ --{ -- "rules": [ -- { -- "helper": "openssl", -- "template": "CN={{subject.uid.0}}" -- }, -- { -- "helper": "certutil", -- "template": "CN={{subject.uid.0|quote}}" -- } -- ], -- "options": { -- "data_source": "subject.uid.0" -- } --} -diff --git a/ipaclient/csrgen/rules/syntaxSAN.json b/ipaclient/csrgen/rules/syntaxSAN.json -deleted file mode 100644 -index 122eb12443e053490ac50a3984d02a62be61e7aa..0000000000000000000000000000000000000000 ---- a/ipaclient/csrgen/rules/syntaxSAN.json -+++ /dev/null -@@ -1,15 +0,0 @@ --{ -- "rules": [ -- { -- "helper": "openssl", -- "template": "subjectAltName = @{% call openssl.section() %}{{ datarules|join('\n') }}{% endcall %}", -- "options": { -- "extension": true -- } -- }, -- { -- "helper": "certutil", -- "template": "--extSAN {{ datarules|join(',') }}" -- } -- ] --} -diff --git a/ipaclient/csrgen/rules/syntaxSubject.json b/ipaclient/csrgen/rules/syntaxSubject.json -deleted file mode 100644 -index af6ec03d3390ba8f9fac99ed3b6c485f4c1cd64f..0000000000000000000000000000000000000000 ---- a/ipaclient/csrgen/rules/syntaxSubject.json -+++ /dev/null -@@ -1,16 +0,0 @@ --{ -- "rules": [ -- { -- "helper": "openssl", -- "template": "distinguished_name = {% call openssl.section() %}{{ datarules|reverse|join('\n') }}{% endcall %}" -- }, -- { -- "helper": "certutil", -- "template": "-s {{ datarules|join(',') }}" -- } -- ], -- "options": { -- "required": true, -- "data_source_combinator": "and" -- } --} -diff --git a/ipaclient/csrgen/templates/certutil_base.tmpl b/ipaclient/csrgen/templates/certutil_base.tmpl -deleted file mode 100644 -index a5556fda0e6ed854dfe67b816044b36db77d5f76..0000000000000000000000000000000000000000 ---- a/ipaclient/csrgen/templates/certutil_base.tmpl -+++ /dev/null -@@ -1,11 +0,0 @@ --#!/bin/bash -e -- --if [[ $# -lt 1 ]]; then --echo "Usage: $0 <outfile> [<any> <certutil> <args>]" --echo "Called as: $0 $@" --exit 1 --fi -- --CSR="$1" --shift --certutil -R -a -z <(head -c 4096 /dev/urandom) -o "$CSR" {{ options|join(' ') }} "$@" -diff --git a/ipaclient/csrgen/templates/openssl_base.tmpl b/ipaclient/csrgen/templates/openssl_base.tmpl -deleted file mode 100644 -index 22b16862e88eb44c4176ee9c4580188f5b240854..0000000000000000000000000000000000000000 ---- a/ipaclient/csrgen/templates/openssl_base.tmpl -+++ /dev/null -@@ -1,35 +0,0 @@ --{% raw -%} --{% import "openssl_macros.tmpl" as openssl -%} --{%- endraw %} --#!/bin/bash -e -- --if [[ $# -lt 2 ]]; then --echo "Usage: $0 <outfile> <keyfile> <other openssl arguments>" --echo "Called as: $0 $@" --exit 1 --fi -- --CONFIG="$(mktemp)" --CSR="$1" --KEYFILE="$2" --shift; shift -- --echo \ --{% raw %}{% filter quote %}{% endraw -%} --[ req ] --prompt = no --encrypt_key = no -- --{{ parameters|join('\n') }} --{% raw %}{% set rendered_extensions -%}{% endraw %} --{{ extensions|join('\n') }} --{% raw -%} --{%- endset -%} --{% if rendered_extensions -%} --req_extensions = {% call openssl.section() %}{{ rendered_extensions }}{% endcall %} --{% endif %} --{{ openssl.openssl_sections|join('\n\n') }} --{% endfilter %}{%- endraw %} > "$CONFIG" -- --openssl req -new -config "$CONFIG" -out "$CSR" -key "$KEYFILE" "$@" --rm "$CONFIG" diff --git a/ipaclient/csrgen/templates/openssl_macros.tmpl b/ipaclient/csrgen/templates/openssl_macros.tmpl deleted file mode 100644 index d31b8fef5f2d85e1b3d5ecf425f00ec9c22ac301..0000000000000000000000000000000000000000 @@ -826,21 +180,19 @@ index d31b8fef5f2d85e1b3d5ecf425f00ec9c22ac301..00000000000000000000000000000000 -{{ contents -}} -{% endmacro %} diff --git a/ipaclient/plugins/cert.py b/ipaclient/plugins/cert.py -index 93cd3cef1a14925bc0795b32e97e44d69897be5c..8195e04fc43ffbd8ca6589d2652559198759d9e6 100644 +index 6d453d0d6ead9ac7d594bbb27da81de6de2b6862..b3619f30c1ca1f4e921b106d07fb5cb2219a7df0 100644 --- a/ipaclient/plugins/cert.py +++ b/ipaclient/plugins/cert.py -@@ -20,10 +20,6 @@ - # along with this program. If not, see <http://www.gnu.org/licenses/>. +@@ -21,8 +21,6 @@ import base64 --import subprocess --from tempfile import NamedTemporaryFile as NTF -- --import six +-import six +- from ipaclient.frontend import MethodOverride from ipalib import errors -@@ -33,9 +29,6 @@ from ipalib.parameters import File, Flag, Str + from ipalib import x509 +@@ -31,9 +29,6 @@ from ipalib.parameters import BinaryFile, File, Flag, Str from ipalib.plugable import Registry from ipalib.text import _ @@ -850,7 +202,7 @@ index 93cd3cef1a14925bc0795b32e97e44d69897be5c..8195e04fc43ffbd8ca6589d265255919 register = Registry() -@@ -77,99 +70,12 @@ class CertRetrieveOverride(MethodOverride): +@@ -74,87 +69,12 @@ class CertRetrieveOverride(MethodOverride): @register(override=True, no_fail=True) class cert_request(CertRetrieveOverride): @@ -891,55 +243,43 @@ index 93cd3cef1a14925bc0795b32e97e44d69897be5c..8195e04fc43ffbd8ca6589d265255919 - password_file = options.pop('password_file', None) - - if csr is None: +- # Deferred import, ipaclient.csrgen is expensive to load. +- # see https://pagure.io/freeipa/issue/7484 +- from ipaclient import csrgen +- - if database: -- helper = u'certutil' -- helper_args = ['-d', database] -- if password_file: -- helper_args += ['-f', password_file] +- adaptor = csrgen.NSSAdaptor(database, password_file) - elif private_key: -- helper = u'openssl' -- helper_args = [private_key] -- if password_file: -- helper_args += ['-passin', 'file:%s' % password_file] +- adaptor = csrgen.OpenSSLAdaptor( +- key_filename=private_key, password_filename=password_file) - else: - raise errors.InvocationError( - message=u"One of 'database' or 'private_key' is required") - -- with NTF() as scriptfile, NTF() as csrfile: -- # If csr_profile_id is passed, that takes precedence. -- # Otherwise, use profile_id. If neither are passed, the default -- # in cert_get_requestdata will be used. -- profile_id = csr_profile_id -- if profile_id is None: -- profile_id = options.get('profile_id') +- pubkey_info = adaptor.get_subject_public_key_info() +- pubkey_info_b64 = base64.b64encode(pubkey_info) +- +- # If csr_profile_id is passed, that takes precedence. +- # Otherwise, use profile_id. If neither are passed, the default +- # in cert_get_requestdata will be used. +- profile_id = csr_profile_id +- if profile_id is None: +- profile_id = options.get('profile_id') - -- self.api.Command.cert_get_requestdata( -- profile_id=profile_id, -- principal=options.get('principal'), -- out=unicode(scriptfile.name), -- helper=helper) +- response = self.api.Command.cert_get_requestdata( +- profile_id=profile_id, +- principal=options.get('principal'), +- public_key_info=pubkey_info_b64) - -- helper_cmd = [ -- 'bash', '-e', scriptfile.name, csrfile.name] + helper_args +- req_info_b64 = response['result']['request_info'] +- req_info = base64.b64decode(req_info_b64) - -- try: -- subprocess.check_output(helper_cmd) -- except subprocess.CalledProcessError as e: -- raise errors.CertificateOperationError( -- error=( -- _('Error running "%(cmd)s" to generate CSR:' -- ' %(err)s') % -- {'cmd': ' '.join(helper_cmd), 'err': e.output})) +- csr = adaptor.sign_csr(req_info) +- +- if not csr: +- raise errors.CertificateOperationError( +- error=(_('Generated CSR was empty'))) - -- try: -- csr = unicode(csrfile.read()) -- except IOError as e: -- raise errors.CertificateOperationError( -- error=(_('Unable to read generated CSR file: %(err)s') -- % {'err': e})) -- if not csr: -- raise errors.CertificateOperationError( -- error=(_('Generated CSR was empty'))) - else: - if database is not None or private_key is not None: - raise errors.MutuallyExclusiveError(reason=_( @@ -951,134 +291,8 @@ index 93cd3cef1a14925bc0795b32e97e44d69897be5c..8195e04fc43ffbd8ca6589d265255919 @register(override=True, no_fail=True) class cert_show(CertRetrieveOverride): -diff --git a/ipaclient/plugins/csrgen.py b/ipaclient/plugins/csrgen.py -deleted file mode 100644 -index a0d99ef06445de268cd1872a025d0613e245ae6c..0000000000000000000000000000000000000000 ---- a/ipaclient/plugins/csrgen.py -+++ /dev/null -@@ -1,120 +0,0 @@ --# --# Copyright (C) 2016 FreeIPA Contributors see COPYING for license --# -- --import six -- --from ipaclient.csrgen import CSRGenerator, FileRuleProvider --from ipalib import api --from ipalib import errors --from ipalib import output --from ipalib import util --from ipalib.frontend import Local, Str --from ipalib.parameters import Principal --from ipalib.plugable import Registry --from ipalib.text import _ --from ipapython import dogtag -- --if six.PY3: -- unicode = str -- --register = Registry() -- --__doc__ = _(""" --Commands to build certificate requests automatically --""") -- -- --@register() --class cert_get_requestdata(Local): -- __doc__ = _('Gather data for a certificate signing request.') -- -- NO_CLI = True -- -- takes_options = ( -- Principal( -- 'principal', -- label=_('Principal'), -- doc=_('Principal for this certificate (e.g.' -- ' HTTP/test.example.com)'), -- ), -- Str( -- 'profile_id?', -- label=_('Profile ID'), -- doc=_('CSR Generation Profile to use'), -- ), -- Str( -- 'helper', -- label=_('Name of CSR generation tool'), -- doc=_('Name of tool (e.g. openssl, certutil) that will be used to' -- ' create CSR'), -- ), -- Str( -- 'out?', -- doc=_('Write CSR generation script to file'), -- ), -- ) -- -- has_output = ( -- output.Output( -- 'result', -- type=dict, -- doc=_('Dictionary mapping variable name to value'), -- ), -- ) -- -- has_output_params = ( -- Str( -- 'script', -- label=_('Generation script'), -- ) -- ) -- -- def execute(self, *args, **options): -- if 'out' in options: -- util.check_writable_file(options['out']) -- -- principal = options.get('principal') -- profile_id = options.get('profile_id') -- if profile_id is None: -- profile_id = dogtag.DEFAULT_PROFILE -- helper = options.get('helper') -- -- if self.api.env.in_server: -- backend = self.api.Backend.ldap2 -- else: -- backend = self.api.Backend.rpcclient -- if not backend.isconnected(): -- backend.connect() -- -- try: -- if principal.is_host: -- principal_obj = api.Command.host_show( -- principal.hostname, all=True) -- elif principal.is_service: -- principal_obj = api.Command.service_show( -- unicode(principal), all=True) -- elif principal.is_user: -- principal_obj = api.Command.user_show( -- principal.username, all=True) -- except errors.NotFound: -- raise errors.NotFound( -- reason=_("The principal for this request doesn't exist.")) -- principal_obj = principal_obj['result'] -- config = api.Command.config_show()['result'] -- -- generator = CSRGenerator(FileRuleProvider()) -- -- script = generator.csr_script( -- principal_obj, config, profile_id, helper) -- -- result = {} -- if 'out' in options: -- with open(options['out'], 'wb') as f: -- f.write(script) -- else: -- result = dict(script=script) -- -- return dict( -- result=result -- ) diff --git a/ipaclient/setup.py b/ipaclient/setup.py -index d39235ab237fb2dbf902866ddcc5e92f8767bcc8..9c6a1558a2d2eace9afbc008a4cb86939fb0047f 100644 +index ac947e772e014051ff5f231c73651bfa2fe8b061..8faa17dd1850fefd127aff83913e052e8900e5d4 100644 --- a/ipaclient/setup.py +++ b/ipaclient/setup.py @@ -42,13 +42,6 @@ if __name__ == '__main__': @@ -1096,10 +310,10 @@ index d39235ab237fb2dbf902866ddcc5e92f8767bcc8..9c6a1558a2d2eace9afbc008a4cb8693 "cryptography", "ipalib", diff --git a/ipalib/errors.py b/ipalib/errors.py -index 6aaca708a02e609f11c4aa5ef5fe2b4a8ae8a941..88707ac313fa7c5ec247b3f9b71f96925f5627e2 100644 +index 3a40fa28dc4b7748b2c570943f4a27a22c152353..6356d523e8c0ac63e8892292dd9991c9ee8211aa 100644 --- a/ipalib/errors.py +++ b/ipalib/errors.py -@@ -1422,34 +1422,6 @@ class HTTPRequestError(RemoteRetrieveError): +@@ -1434,34 +1434,6 @@ class HTTPRequestError(RemoteRetrieveError): format = _('Request failed with status %(status)s: %(reason)s') @@ -1135,7 +349,7 @@ index 6aaca708a02e609f11c4aa5ef5fe2b4a8ae8a941..88707ac313fa7c5ec247b3f9b71f9692 """ **4100** Base class for builtin execution errors (*4100 - 4199*). diff --git a/ipatests/setup.py b/ipatests/setup.py -index c6c9cb69dbed0561365a10a08061ccc6fe0f372e..712576be6c7a523d3c23a23bdf55289e21ac8867 100644 +index 68a67da5f9590e068ad0ed3e30116264d70e5bce..2464822960a389a8c489babf7b034461396f55e2 100644 --- a/ipatests/setup.py +++ b/ipatests/setup.py @@ -39,7 +39,6 @@ if __name__ == '__main__': @@ -1144,15 +358,15 @@ index c6c9cb69dbed0561365a10a08061ccc6fe0f372e..712576be6c7a523d3c23a23bdf55289e "ipatests.test_integration", - "ipatests.test_ipaclient", "ipatests.test_ipalib", + "ipatests.test_ipaplatform", "ipatests.test_ipapython", - "ipatests.test_ipaserver", @@ -53,7 +52,6 @@ if __name__ == '__main__': package_data={ 'ipatests.test_install': ['*.update'], 'ipatests.test_integration': ['scripts/*'], - 'ipatests.test_ipaclient': ['data/*/*/*'], 'ipatests.test_ipalib': ['data/*'], - 'ipatests.test_pkcs10': ['*.csr'], + 'ipatests.test_ipaplatform': ['data/*'], "ipatests.test_ipaserver": ['data/*'], diff --git a/ipatests/test_ipaclient/__init__.py b/ipatests/test_ipaclient/__init__.py deleted file mode 100644 @@ -1181,162 +395,6 @@ index 676f91bef696109976826e6e61be091718172798..00000000000000000000000000000000 - ] - } -] -diff --git a/ipatests/test_ipaclient/data/test_csrgen/rules/basic.json b/ipatests/test_ipaclient/data/test_csrgen/rules/basic.json -deleted file mode 100644 -index feba3e91e53c5c9becb44c0d2190b5a98c04a928..0000000000000000000000000000000000000000 ---- a/ipatests/test_ipaclient/data/test_csrgen/rules/basic.json -+++ /dev/null -@@ -1,12 +0,0 @@ --{ -- "rules": [ -- { -- "helper": "openssl", -- "template": "openssl_rule" -- }, -- { -- "helper": "certutil", -- "template": "certutil_rule" -- } -- ] --} -diff --git a/ipatests/test_ipaclient/data/test_csrgen/rules/options.json b/ipatests/test_ipaclient/data/test_csrgen/rules/options.json -deleted file mode 100644 -index 111a6d80c8faf27376dac342a18aede1fb1242ef..0000000000000000000000000000000000000000 ---- a/ipatests/test_ipaclient/data/test_csrgen/rules/options.json -+++ /dev/null -@@ -1,18 +0,0 @@ --{ -- "rules": [ -- { -- "helper": "openssl", -- "template": "openssl_rule", -- "options": { -- "helper_option": true -- } -- }, -- { -- "helper": "certutil", -- "template": "certutil_rule" -- } -- ], -- "options": { -- "global_option": true -- } --} -diff --git a/ipatests/test_ipaclient/data/test_csrgen/scripts/caIPAserviceCert_certutil.sh b/ipatests/test_ipaclient/data/test_csrgen/scripts/caIPAserviceCert_certutil.sh -deleted file mode 100644 -index 74a704c2dd1765c7b775fded8ed957715b264b91..0000000000000000000000000000000000000000 ---- a/ipatests/test_ipaclient/data/test_csrgen/scripts/caIPAserviceCert_certutil.sh -+++ /dev/null -@@ -1,11 +0,0 @@ --#!/bin/bash -e -- --if [[ $# -lt 1 ]]; then --echo "Usage: $0 <outfile> [<any> <certutil> <args>]" --echo "Called as: $0 $@" --exit 1 --fi -- --CSR="$1" --shift --certutil -R -a -z <(head -c 4096 /dev/urandom) -o "$CSR" -s CN=machine.example.com,O=DOMAIN.EXAMPLE.COM --extSAN dns:machine.example.com "$@" -diff --git a/ipatests/test_ipaclient/data/test_csrgen/scripts/caIPAserviceCert_openssl.sh b/ipatests/test_ipaclient/data/test_csrgen/scripts/caIPAserviceCert_openssl.sh -deleted file mode 100644 -index 811bfd763e27678adaf681a430e909b24680aeda..0000000000000000000000000000000000000000 ---- a/ipatests/test_ipaclient/data/test_csrgen/scripts/caIPAserviceCert_openssl.sh -+++ /dev/null -@@ -1,34 +0,0 @@ --#!/bin/bash -e -- --if [[ $# -lt 2 ]]; then --echo "Usage: $0 <outfile> <keyfile> <other openssl arguments>" --echo "Called as: $0 $@" --exit 1 --fi -- --CONFIG="$(mktemp)" --CSR="$1" --KEYFILE="$2" --shift; shift -- --echo \ --'[ req ] --prompt = no --encrypt_key = no -- --distinguished_name = sec0 --req_extensions = sec2 -- --[ sec0 ] --O=DOMAIN.EXAMPLE.COM --CN=machine.example.com -- --[ sec1 ] --DNS = machine.example.com -- --[ sec2 ] --subjectAltName = @sec1 --' > "$CONFIG" -- --openssl req -new -config "$CONFIG" -out "$CSR" -key "$KEYFILE" "$@" --rm "$CONFIG" -diff --git a/ipatests/test_ipaclient/data/test_csrgen/scripts/userCert_certutil.sh b/ipatests/test_ipaclient/data/test_csrgen/scripts/userCert_certutil.sh -deleted file mode 100644 -index 4aaeda07aabd4c36d277e339d0b761f7a8a54baf..0000000000000000000000000000000000000000 ---- a/ipatests/test_ipaclient/data/test_csrgen/scripts/userCert_certutil.sh -+++ /dev/null -@@ -1,11 +0,0 @@ --#!/bin/bash -e -- --if [[ $# -lt 1 ]]; then --echo "Usage: $0 <outfile> [<any> <certutil> <args>]" --echo "Called as: $0 $@" --exit 1 --fi -- --CSR="$1" --shift --certutil -R -a -z <(head -c 4096 /dev/urandom) -o "$CSR" -s CN=testuser,O=DOMAIN.EXAMPLE.COM --extSAN email:testuser@example.com "$@" -diff --git a/ipatests/test_ipaclient/data/test_csrgen/scripts/userCert_openssl.sh b/ipatests/test_ipaclient/data/test_csrgen/scripts/userCert_openssl.sh -deleted file mode 100644 -index 2edf067a528456877025f63dca76d68e7edde41e..0000000000000000000000000000000000000000 ---- a/ipatests/test_ipaclient/data/test_csrgen/scripts/userCert_openssl.sh -+++ /dev/null -@@ -1,34 +0,0 @@ --#!/bin/bash -e -- --if [[ $# -lt 2 ]]; then --echo "Usage: $0 <outfile> <keyfile> <other openssl arguments>" --echo "Called as: $0 $@" --exit 1 --fi -- --CONFIG="$(mktemp)" --CSR="$1" --KEYFILE="$2" --shift; shift -- --echo \ --'[ req ] --prompt = no --encrypt_key = no -- --distinguished_name = sec0 --req_extensions = sec2 -- --[ sec0 ] --O=DOMAIN.EXAMPLE.COM --CN=testuser -- --[ sec1 ] --email = testuser@example.com -- --[ sec2 ] --subjectAltName = @sec1 --' > "$CONFIG" -- --openssl req -new -config "$CONFIG" -out "$CSR" -key "$KEYFILE" "$@" --rm "$CONFIG" diff --git a/ipatests/test_ipaclient/data/test_csrgen/templates/identity_base.tmpl b/ipatests/test_ipaclient/data/test_csrgen/templates/identity_base.tmpl deleted file mode 100644 index 79111ab686b4fe25227796509b3cd3fcb54af728..0000000000000000000000000000000000000000 @@ -1344,310 +402,6 @@ index 79111ab686b4fe25227796509b3cd3fcb54af728..00000000000000000000000000000000 +++ /dev/null @@ -1 +0,0 @@ -{{ options|join(";") }} -diff --git a/ipatests/test_ipaclient/test_csrgen.py b/ipatests/test_ipaclient/test_csrgen.py -deleted file mode 100644 -index 556f8e096976387d24057084c06d53bcb9998a69..0000000000000000000000000000000000000000 ---- a/ipatests/test_ipaclient/test_csrgen.py -+++ /dev/null -@@ -1,298 +0,0 @@ --# --# Copyright (C) 2016 FreeIPA Contributors see COPYING for license --# -- --import os --import pytest -- --from ipaclient import csrgen --from ipalib import errors -- --BASE_DIR = os.path.dirname(__file__) --CSR_DATA_DIR = os.path.join(BASE_DIR, 'data', 'test_csrgen') -- -- --@pytest.fixture --def formatter(): -- return csrgen.Formatter(csr_data_dir=CSR_DATA_DIR) -- -- --@pytest.fixture --def rule_provider(): -- return csrgen.FileRuleProvider(csr_data_dir=CSR_DATA_DIR) -- -- --@pytest.fixture --def generator(): -- return csrgen.CSRGenerator(csrgen.FileRuleProvider()) -- -- --class StubRuleProvider(csrgen.RuleProvider): -- def __init__(self): -- self.syntax_rule = csrgen.Rule( -- 'syntax', '{{datarules|join(",")}}', {}) -- self.data_rule = csrgen.Rule('data', 'data_template', {}) -- self.field_mapping = csrgen.FieldMapping( -- 'example', self.syntax_rule, [self.data_rule]) -- self.rules = [self.field_mapping] -- -- def rules_for_profile(self, profile_id, helper): -- return self.rules -- -- --class IdentityFormatter(csrgen.Formatter): -- base_template_name = 'identity_base.tmpl' -- -- def __init__(self): -- super(IdentityFormatter, self).__init__(csr_data_dir=CSR_DATA_DIR) -- -- def _get_template_params(self, syntax_rules): -- return {'options': syntax_rules} -- -- --class IdentityCSRGenerator(csrgen.CSRGenerator): -- FORMATTERS = {'identity': IdentityFormatter} -- -- --class test_Formatter(object): -- def test_prepare_data_rule_with_data_source(self, formatter): -- data_rule = csrgen.Rule('uid', '{{subject.uid.0}}', -- {'data_source': 'subject.uid.0'}) -- prepared = formatter._prepare_data_rule(data_rule) -- assert prepared == '{% if subject.uid.0 %}{{subject.uid.0}}{% endif %}' -- -- def test_prepare_data_rule_no_data_source(self, formatter): -- """Not a normal case, but we should handle it anyway""" -- data_rule = csrgen.Rule('uid', 'static_text', {}) -- prepared = formatter._prepare_data_rule(data_rule) -- assert prepared == 'static_text' -- -- def test_prepare_syntax_rule_with_data_sources(self, formatter): -- syntax_rule = csrgen.Rule( -- 'example', '{{datarules|join(",")}}', {}) -- data_rules = ['{{subject.field1}}', '{{subject.field2}}'] -- data_sources = ['subject.field1', 'subject.field2'] -- prepared = formatter._prepare_syntax_rule( -- syntax_rule, data_rules, 'example', data_sources) -- -- assert prepared == ( -- '{% if subject.field1 or subject.field2 %}{{subject.field1}},' -- '{{subject.field2}}{% endif %}') -- -- def test_prepare_syntax_rule_with_combinator(self, formatter): -- syntax_rule = csrgen.Rule('example', '{{datarules|join(",")}}', -- {'data_source_combinator': 'and'}) -- data_rules = ['{{subject.field1}}', '{{subject.field2}}'] -- data_sources = ['subject.field1', 'subject.field2'] -- prepared = formatter._prepare_syntax_rule( -- syntax_rule, data_rules, 'example', data_sources) -- -- assert prepared == ( -- '{% if subject.field1 and subject.field2 %}{{subject.field1}},' -- '{{subject.field2}}{% endif %}') -- -- def test_prepare_syntax_rule_required(self, formatter): -- syntax_rule = csrgen.Rule('example', '{{datarules|join(",")}}', -- {'required': True}) -- data_rules = ['{{subject.field1}}'] -- data_sources = ['subject.field1'] -- prepared = formatter._prepare_syntax_rule( -- syntax_rule, data_rules, 'example', data_sources) -- -- assert prepared == ( -- '{% filter required("example") %}{% if subject.field1 %}' -- '{{subject.field1}}{% endif %}{% endfilter %}') -- -- def test_prepare_syntax_rule_passthrough(self, formatter): -- """ -- Calls to macros defined as passthrough are still call tags in the final -- template. -- """ -- formatter._define_passthrough('example.macro') -- -- syntax_rule = csrgen.Rule( -- 'example', -- '{% call example.macro() %}{{datarules|join(",")}}{% endcall %}', -- {}) -- data_rules = ['{{subject.field1}}'] -- data_sources = ['subject.field1'] -- prepared = formatter._prepare_syntax_rule( -- syntax_rule, data_rules, 'example', data_sources) -- -- assert prepared == ( -- '{% if subject.field1 %}{% call example.macro() %}' -- '{{subject.field1}}{% endcall %}{% endif %}') -- -- def test_prepare_syntax_rule_no_data_sources(self, formatter): -- """Not a normal case, but we should handle it anyway""" -- syntax_rule = csrgen.Rule( -- 'example', '{{datarules|join(",")}}', {}) -- data_rules = ['rule1', 'rule2'] -- data_sources = [] -- prepared = formatter._prepare_syntax_rule( -- syntax_rule, data_rules, 'example', data_sources) -- -- assert prepared == 'rule1,rule2' -- -- --class test_FileRuleProvider(object): -- def test_rule_basic(self, rule_provider): -- rule_name = 'basic' -- -- rule1 = rule_provider._rule(rule_name, 'openssl') -- rule2 = rule_provider._rule(rule_name, 'certutil') -- -- assert rule1.template == 'openssl_rule' -- assert rule2.template == 'certutil_rule' -- -- def test_rule_global_options(self, rule_provider): -- rule_name = 'options' -- -- rule1 = rule_provider._rule(rule_name, 'openssl') -- rule2 = rule_provider._rule(rule_name, 'certutil') -- -- assert rule1.options['global_option'] is True -- assert rule2.options['global_option'] is True -- -- def test_rule_helper_options(self, rule_provider): -- rule_name = 'options' -- -- rule1 = rule_provider._rule(rule_name, 'openssl') -- rule2 = rule_provider._rule(rule_name, 'certutil') -- -- assert rule1.options['helper_option'] is True -- assert 'helper_option' not in rule2.options -- -- def test_rule_nosuchrule(self, rule_provider): -- with pytest.raises(errors.NotFound): -- rule_provider._rule('nosuchrule', 'openssl') -- -- def test_rule_nosuchhelper(self, rule_provider): -- with pytest.raises(errors.EmptyResult): -- rule_provider._rule('basic', 'nosuchhelper') -- -- def test_rules_for_profile_success(self, rule_provider): -- rules = rule_provider.rules_for_profile('profile', 'certutil') -- -- assert len(rules) == 1 -- field_mapping = rules[0] -- assert field_mapping.syntax_rule.name == 'basic' -- assert len(field_mapping.data_rules) == 1 -- assert field_mapping.data_rules[0].name == 'options' -- -- def test_rules_for_profile_nosuchprofile(self, rule_provider): -- with pytest.raises(errors.NotFound): -- rule_provider.rules_for_profile('nosuchprofile', 'certutil') -- -- --class test_CSRGenerator(object): -- def test_userCert_OpenSSL(self, generator): -- principal = { -- 'uid': ['testuser'], -- 'mail': ['testuser@example.com'], -- } -- config = { -- 'ipacertificatesubjectbase': [ -- 'O=DOMAIN.EXAMPLE.COM' -- ], -- } -- -- script = generator.csr_script(principal, config, 'userCert', 'openssl') -- with open(os.path.join( -- CSR_DATA_DIR, 'scripts', 'userCert_openssl.sh')) as f: -- expected_script = f.read() -- assert script == expected_script -- -- def test_userCert_Certutil(self, generator): -- principal = { -- 'uid': ['testuser'], -- 'mail': ['testuser@example.com'], -- } -- config = { -- 'ipacertificatesubjectbase': [ -- 'O=DOMAIN.EXAMPLE.COM' -- ], -- } -- -- script = generator.csr_script( -- principal, config, 'userCert', 'certutil') -- -- with open(os.path.join( -- CSR_DATA_DIR, 'scripts', 'userCert_certutil.sh')) as f: -- expected_script = f.read() -- assert script == expected_script -- -- def test_caIPAserviceCert_OpenSSL(self, generator): -- principal = { -- 'krbprincipalname': [ -- 'HTTP/machine.example.com@DOMAIN.EXAMPLE.COM' -- ], -- } -- config = { -- 'ipacertificatesubjectbase': [ -- 'O=DOMAIN.EXAMPLE.COM' -- ], -- } -- -- script = generator.csr_script( -- principal, config, 'caIPAserviceCert', 'openssl') -- with open(os.path.join( -- CSR_DATA_DIR, 'scripts', 'caIPAserviceCert_openssl.sh')) as f: -- expected_script = f.read() -- assert script == expected_script -- -- def test_caIPAserviceCert_Certutil(self, generator): -- principal = { -- 'krbprincipalname': [ -- 'HTTP/machine.example.com@DOMAIN.EXAMPLE.COM' -- ], -- } -- config = { -- 'ipacertificatesubjectbase': [ -- 'O=DOMAIN.EXAMPLE.COM' -- ], -- } -- -- script = generator.csr_script( -- principal, config, 'caIPAserviceCert', 'certutil') -- with open(os.path.join( -- CSR_DATA_DIR, 'scripts', 'caIPAserviceCert_certutil.sh')) as f: -- expected_script = f.read() -- assert script == expected_script -- -- --class test_rule_handling(object): -- def test_optionalAttributeMissing(self, generator): -- principal = {'uid': 'testuser'} -- rule_provider = StubRuleProvider() -- rule_provider.data_rule.template = '{{subject.mail}}' -- rule_provider.data_rule.options = {'data_source': 'subject.mail'} -- generator = IdentityCSRGenerator(rule_provider) -- -- script = generator.csr_script( -- principal, {}, 'example', 'identity') -- assert script == '\n' -- -- def test_twoDataRulesOneMissing(self, generator): -- principal = {'uid': 'testuser'} -- rule_provider = StubRuleProvider() -- rule_provider.data_rule.template = '{{subject.mail}}' -- rule_provider.data_rule.options = {'data_source': 'subject.mail'} -- rule_provider.field_mapping.data_rules.append(csrgen.Rule( -- 'data2', '{{subject.uid}}', {'data_source': 'subject.uid'})) -- generator = IdentityCSRGenerator(rule_provider) -- -- script = generator.csr_script(principal, {}, 'example', 'identity') -- assert script == ',testuser\n' -- -- def test_requiredAttributeMissing(self): -- principal = {'uid': 'testuser'} -- rule_provider = StubRuleProvider() -- rule_provider.data_rule.template = '{{subject.mail}}' -- rule_provider.data_rule.options = {'data_source': 'subject.mail'} -- rule_provider.syntax_rule.options = {'required': True} -- generator = IdentityCSRGenerator(rule_provider) -- -- with pytest.raises(errors.CSRTemplateError): -- _script = generator.csr_script( -- principal, {}, 'example', 'identity') -- -2.17.1 +2.14.4 diff --git a/SOURCES/1005-Removing-filesystem-encoding-check.patch b/SOURCES/1005-Removing-filesystem-encoding-check.patch new file mode 100644 index 0000000..18fca0b --- /dev/null +++ b/SOURCES/1005-Removing-filesystem-encoding-check.patch @@ -0,0 +1,127 @@ +From 5f659d56bea124335d1813ae32c809cbc8582fb6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Tibor=20Dudl=C3=A1k?= <tdudlak@redhat.com> +Date: Fri, 10 Aug 2018 13:16:38 +0200 +Subject: [PATCH] Removing filesystem encoding check + +RHEL doesn't support the generic locale "C.UTF-8" +See BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1590680 + +Revertis commit: e1bd827bbf56970ddd02ec174bf2317b64e75514 +--- + install/conf/ipa.conf | 3 +-- + install/share/ipa-httpd.conf.template | 1 - + ipalib/errors.py | 11 ----------- + ipalib/plugable.py | 5 ----- + ipatests/test_cmdline/test_cli.py | 24 +----------------------- + 5 files changed, 2 insertions(+), 42 deletions(-) + +diff --git a/install/conf/ipa.conf b/install/conf/ipa.conf +index c5fc518f803d379287043b405efeb46dd53a6b28..e15437b1804203ab85caaea420dde8fc12b15070 100644 +--- a/install/conf/ipa.conf ++++ b/install/conf/ipa.conf +@@ -48,8 +48,7 @@ WSGISocketPrefix /run/httpd/wsgi + + # Configure mod_wsgi handler for /ipa + WSGIDaemonProcess ipa processes=$WSGI_PROCESSES threads=1 maximum-requests=500 \ +- user=ipaapi group=ipaapi display-name=%{GROUP} \ +- lang=C.UTF-8 locale=C.UTF-8 ++ user=ipaapi group=ipaapi display-name=%{GROUP} + WSGIImportScript /usr/share/ipa/wsgi.py process-group=ipa application-group=ipa + WSGIScriptAlias /ipa /usr/share/ipa/wsgi.py + WSGIScriptReloading Off +diff --git a/install/share/ipa-httpd.conf.template b/install/share/ipa-httpd.conf.template +index 210d5d3883705b25b36050f50fdc1b49e830eb81..39bcfcca791c76f034224c00c9c2f85b652f78bb 100644 +--- a/install/share/ipa-httpd.conf.template ++++ b/install/share/ipa-httpd.conf.template +@@ -4,5 +4,4 @@ + Environment=KRB5CCNAME=$KRB5CC_HTTPD + Environment=GSS_USE_PROXY=yes + Environment=KDCPROXY_CONFIG=$KDCPROXY_CONFIG +-Environment=LC_ALL=C.UTF-8 + ExecStartPre=$IPA_HTTPD_KDCPROXY +diff --git a/ipalib/errors.py b/ipalib/errors.py +index 6356d523e8c0ac63e8892292dd9991c9ee8211aa..ae940798779d20cb83b7f96a625c6facfe983f95 100644 +--- a/ipalib/errors.py ++++ b/ipalib/errors.py +@@ -453,17 +453,6 @@ class EnvironmentError(PublicError): + errno = 912 + + +-class SystemEncodingError(PublicError): +- """ +- **913** Raised when system encoding is not UTF-8 +- """ +- +- errno = 913 +- format = _( +- "System encoding must be UTF-8, '%(encoding)s' is not supported. " +- "Set LC_ALL=\"C.UTF-8\", or LC_ALL=\"\" and LC_CTYPE=\"C.UTF-8\"." +- ) +- + ############################################################################## + # 1000 - 1999: Authentication errors + class AuthenticationError(PublicError): +diff --git a/ipalib/plugable.py b/ipalib/plugable.py +index d78a607123907813d6327212ee6e85b356112791..6aad8d90c9df071b5372cae920e800daae563133 100644 +--- a/ipalib/plugable.py ++++ b/ipalib/plugable.py +@@ -485,11 +485,6 @@ class API(ReadOnly): + handler.setFormatter(ipa_log_manager.Formatter(LOGGING_FORMAT_STDERR)) + root_logger.addHandler(handler) + +- # check after logging is set up but before we create files. +- fse = sys.getfilesystemencoding() +- if fse.lower() not in {'utf-8', 'utf8'}: +- raise errors.SystemEncodingError(encoding=fse) +- + # Add file handler: + if self.env.mode in ('dummy', 'unit_test'): + return # But not if in unit-test mode +diff --git a/ipatests/test_cmdline/test_cli.py b/ipatests/test_cmdline/test_cli.py +index 8211c03515bf70b681da49d27ae11a4e8cb3b44d..a40b5d45ff8406c3ebbb69465e8d71d7d5bdb63a 100644 +--- a/ipatests/test_cmdline/test_cli.py ++++ b/ipatests/test_cmdline/test_cli.py +@@ -1,8 +1,6 @@ +-import contextlib +-import os + import shlex +-import subprocess + import sys ++import contextlib + import tempfile + + import nose +@@ -19,8 +17,6 @@ if six.PY3: + + TEST_ZONE = u'zoneadd.%(domain)s' % api.env + +-HERE = os.path.abspath(os.path.dirname(__file__)) +-BASE_DIR = os.path.abspath(os.path.join(HERE, os.pardir, os.pardir)) + + + @pytest.mark.tier0 +@@ -324,21 +320,3 @@ class TestCLIParsing(object): + file=goodcert_headers + ) + +- +-def test_cli_fsencoding(): +- # https://pagure.io/freeipa/issue/5887 +- env = { +- key: value for key, value in os.environ.items() +- if not key.startswith(('LC_', 'LANG')) +- } +- env['LC_ALL'] = 'C' +- env['PYTHONPATH'] = BASE_DIR +- p = subprocess.Popen( +- [sys.executable, '-m', 'ipaclient', 'help'], +- stdout=subprocess.PIPE, +- stderr=subprocess.PIPE, +- env=env, +- ) +- out, err = p.communicate() +- assert p.returncode > 0, (out, err) +- assert b'System encoding must be UTF-8' in err, (out, err) +-- +2.17.1 + diff --git a/SOURCES/ipa-centos-branding.patch b/SOURCES/ipa-centos-branding.patch deleted file mode 100644 index 673cd2f..0000000 --- a/SOURCES/ipa-centos-branding.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 99efecaf87dc1fc9517efaff441a6a7ce46444eb Mon Sep 17 00:00:00 2001 -From: Jim Perrin <jperrin@centos.org> -Date: Wed, 11 Mar 2015 10:37:03 -0500 -Subject: [PATCH] update for new ntp server method - ---- - ipaplatform/base/paths.py | 1 + - ipaserver/install/ntpinstance.py | 2 ++ - 2 files changed, 3 insertions(+) - -diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py -index af50262..5090062 100644 ---- a/ipaplatform/base/paths.py -+++ b/ipaplatform/base/paths.py -@@ -99,6 +99,7 @@ class BasePathNamespace(object): - PKI_TOMCAT_ALIAS_DIR = "/etc/pki/pki-tomcat/alias/" - PKI_TOMCAT_PASSWORD_CONF = "/etc/pki/pki-tomcat/password.conf" - ETC_REDHAT_RELEASE = "/etc/redhat-release" -+ ETC_CENTOS_RELEASE = "/etc/centos-release" - RESOLV_CONF = "/etc/resolv.conf" - SAMBA_KEYTAB = "/etc/samba/samba.keytab" - SMB_CONF = "/etc/samba/smb.conf" -diff --git a/ipaserver/install/ntpinstance.py b/ipaserver/install/ntpinstance.py -index c653525..4b0578b 100644 ---- a/ipaserver/install/ntpinstance.py -+++ b/ipaserver/install/ntpinstance.py -@@ -44,6 +44,8 @@ class NTPInstance(service.Service): - os = "" - if ipautil.file_exists(paths.ETC_FEDORA_RELEASE): - os = "fedora" -+ elif ipautil.file_exists(paths.ETC_CENTOS_RELEASE): -+ os = "centos" - elif ipautil.file_exists(paths.ETC_REDHAT_RELEASE): - os = "rhel" - --- -1.8.3.1 - diff --git a/SPECS/ipa.spec b/SPECS/ipa.spec index b4527d0..b625267 100644 --- a/SPECS/ipa.spec +++ b/SPECS/ipa.spec @@ -1,3 +1,11 @@ +# 389-ds-base 1.4 no longer supports i686 platform, build only client +# packages, https://bugzilla.redhat.com/show_bug.cgi?id=1544386 +%if 0%{?fedora} >= 28 || 0%{?rhel} > 7 +%ifarch %{ix86} +%{!?ONLY_CLIENT:%global ONLY_CLIENT 1} +%endif +%endif + # Define ONLY_CLIENT to only make the ipa-client and ipa-python # subpackages %{!?ONLY_CLIENT:%global ONLY_CLIENT 0} @@ -40,8 +48,9 @@ %global samba_version 4.7.0 # 0.7.16: https://github.com/drkjam/netaddr/issues/71 %global python_netaddr_version 0.7.5-9 -%global selinux_policy_version 3.13.1-70 +%global selinux_policy_version 3.13.1-224 %global slapi_nis_version 0.56.0-4 +%global python2_ldap_version 2.4.15 %else # 1.15.1-7: certauth (http://krbdev.mit.edu/rt/Ticket/Display.html?id=8561) %global krb5_version 1.15.1-7 @@ -51,6 +60,18 @@ %global python_netaddr_version 0.7.16 %global selinux_policy_version 3.13.1-158.4 %global slapi_nis_version 0.56.1 + +# Use python3-pyldap to be compatible with old python3-pyldap 2.x and new +# python3-ldap 3.0. The python3-ldap package also provides python3-pyldap. +%if 0%{?fedora} >= 28 +# https://pagure.io/freeipa/issue/7257 DNSSEC daemons on Python 3 +%global python2_ldap_version 3.0.0-0.4.b4 +%global python3_ldap_version 3.0.0-0.4.b4 +%else +%global python2_ldap_version 2.4.15 +%global python3_ldap_version 2.4.35.1-2 +%endif + %endif %define krb5_base_version %(LC_ALL=C rpm -q --qf '%%{VERSION}' krb5-devel | grep -Eo '^[^.]+\.[^.]+') @@ -63,7 +84,7 @@ # Work-around fact that RPM SPEC parser does not accept # "Version: @VERSION@" in freeipa.spec.in used for Autoconf string replacement -%define IPA_VERSION 4.5.4 +%define IPA_VERSION 4.6.4 %define AT_SIGN @ # redefine IPA_VERSION only if its value matches the Autoconf placeholder %if "%{IPA_VERSION}" == "%{AT_SIGN}VERSION%{AT_SIGN}" @@ -72,7 +93,7 @@ Name: ipa Version: %{IPA_VERSION} -Release: 10%{?dist}.4.4 +Release: 10%{?dist} Summary: The Identity, Policy and Audit system Group: System Environment/Base @@ -80,96 +101,64 @@ License: GPLv3+ URL: http://www.freeipa.org/ Source0: https://releases.pagure.org/freeipa/freeipa-%{version}.tar.gz # RHEL spec file only: START: Change branding to IPA and Identity Management -#Source1: header-logo.png -#Source2: login-screen-background.jpg -#Source3: login-screen-logo.png -#Source4: product-name.png +Source1: header-logo.png +Source2: login-screen-background.jpg +Source3: login-screen-logo.png +Source4: product-name.png # RHEL spec file only: END: Change branding to IPA and Identity Management BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) # RHEL spec file only: START -Patch0001: 0001-ds-ignore-time-skew-during-initial-replication-step.patch -Patch0002: 0002-ipa-replica-manage-implicitly-ignore-initial-time-sk.patch -Patch0003: 0003-Checks-if-replica-s4u2proxy.ldif-should-be-applied.patch -Patch0004: 0004-ldap-limit-the-retro-changelog-to-dns-subtree.patch -Patch0005: 0005-Fix-ipa-replica-conncheck-when-called-with-principal.patch -Patch0006: 0006-Include-the-CA-basic-constraint-in-CSRs-when-renewin.patch -Patch0007: 0007-ipa-extdom-extop-refactor-nsswitch-operations.patch -Patch0008: 0008-Add-the-sub-operation-for-fqdn-index-config.patch -Patch0009: 0009-Add-indexing-to-improve-host-find-performance.patch -Patch0010: 0010-ipa-getkeytab-man-page-add-more-details-about-the-r-.patch -Patch0011: 0011-Don-t-allow-OTP-or-RADIUS-in-FIPS-mode.patch -Patch0012: 0012-Fix-cert-find-for-CA-less-installations.patch -Patch0013: 0013-Fix-ipa-restore-python2.patch -Patch0014: 0014-Backup-ipa-custodia-conf-and-keys.patch -Patch0015: 0015-adtrust-filter-out-subdomains-when-defining-our-topo.patch -Patch0016: 0016-Fix-ca-less-IPA-install-on-fips-mode.patch -Patch0017: 0017-trust-detect-and-error-out-when-non-AD-trust-with-IP.patch -Patch0018: 0018-ipaserver-plugins-trust.py-fix-some-indenting-issues.patch -Patch0019: 0019-ipaserver-plugins-trust.py-pep8-compliance.patch -Patch0020: 0020-Don-t-use-admin-cert-during-KRA-installation.patch -Patch0021: 0021-389-ds-base-crashed-as-part-of-ipa-server-intall-in-.patch -Patch0022: 0022-Prevent-set_directive-from-clobbering-other-keys.patch -Patch0023: 0023-pep8-reduce-line-lengths-in-CAInstance.__enable_crl_.patch -Patch0024: 0024-installutils-refactor-set_directive.patch -Patch0025: 0025-Add-tests-for-installutils.set_directive.patch -Patch0026: 0026-Add-safe-DirectiveSetter-context-manager.patch -Patch0027: 0027-Old-pylint-doesn-t-support-bad-python3-option.patch -Patch0028: 0028-WebUI-make-keytab-tables-on-service-and-host-pages-w.patch -Patch0029: 0029-Idviews-fix-objectclass-violation-on-idview-add.patch -Patch0030: 0030-Fixing-the-cert-request-comparing-whole-email-addres.patch -Patch0031: 0031-Add-force-join-into-ipa-replica-install-manpage.patch -Patch0032: 0032-Changed-ownership-of-ldiffile-to-DS_USER.patch -Patch0033: 0033-Checks-if-Dir-Server-is-installed-and-running-before.patch -Patch0034: 0034-WebUI-Add-positive-number-validator.patch -Patch0035: 0035-WebUI-change-validator-of-page-size-settings.patch -Patch0036: 0036-WebUI-fix-jslint-error.patch -Patch0037: 0037-ipa-advise-for-smartcards-updated.patch -Patch0038: 0038-Add-a-notice-to-restart-ipa-services-after-certs-are.patch -Patch0039: 0039-Fix-OTP-validation-in-FIPS-mode.patch -Patch0040: 0040-Increase-the-default-token-key-size.patch -Patch0041: 0041-Revert-Don-t-allow-OTP-or-RADIUS-in-FIPS-mode.patch -Patch0042: 0042-Log-errors-from-NSS-during-FIPS-OTP-key-import.patch -Patch0043: 0043-ipa-replica-install-make-sure-that-certmonger-picks-.patch -Patch0044: 0044-replica-install-pass-ip-address-to-client-install.patch -Patch0045: 0045-Add-nsds5ReplicaReleaseTimeout-to-replica-config.patch -Patch0046: 0046-Fix-upgrade-update_replica_config-in-single-master-m.patch -Patch0047: 0047-Use-single-Custodia-instance-in-installers.patch -Patch0048: 0048-Don-t-try-to-backup-CS.cfg-during-upgrade-if-CA-is-n.patch -Patch0049: 0049-Use-one-Custodia-peer-to-retrieve-all-secrets.patch -Patch0050: 0050-Fix-elements-not-being-removed-in-otpd_queue_pop_msg.patch -Patch0051: 0051-Tune-DS-replication-settings.patch -Patch0052: 0052-In-IPA-4.4-when-updating-userpassword-with-ldapmodif.patch -Patch0053: 0053-Tests-add-integration-test-for-password-changes-by-d.patch -Patch0054: 0054-Check-if-replication-agreement-exist-before-enable-d.patch -Patch0055: 0055-Fix-ipa-restore-create-var-run-ipa-files.patch -Patch0056: 0056-Sort-and-shuffle-SRV-record-by-priority-and-weight.patch -Patch0057: 0057-Always-set-ca_host-when-installing-replica.patch -Patch0058: 0058-Improve-and-fix-timeout-bug-in-wait_for_entry.patch -Patch0059: 0059-Use-common-replication-wait-timeout-of-5min.patch -Patch0060: 0060-Fix-replication-races-in-Dogtag-admin-code.patch -Patch0061: 0061-Increase-WSGI-process-count-to-5-on-64bit.patch -Patch0062: 0062-Use-4-WSGI-workers-on-64bit-systems.patch -Patch0063: 0063-Catch-ACIError-instead-of-invalid-credentials.patch -Patch0064: 0064-Query-for-server-role-IPA-master.patch -Patch0065: 0065-Only-create-DNS-SRV-records-for-ready-server.patch -Patch0066: 0066-Delay-enabling-services-until-end-of-installer.patch -Patch0067: 0067-replicainstall-DS-SSL-replica-install-pick-right-cer.patch -Patch0068: 0068-Fix-race-condition-in-get_locations_records.patch -Patch0069: 0069-Auto-retry-failed-certmonger-requests.patch -Patch0070: 0070-Wait-for-client-certificates.patch -Patch0071: 0071-Fix-DNSSEC-install-regression.patch -Patch0072: 0072-Handle-races-in-replica-config.patch -Patch0073: 0073-Fix-KRA-replica-installation-from-CA-master.patch -Patch0074: 0074-DS-replication-settings-fix-regression-with-3.3-mast.patch -Patch0075: 0075-Do-not-set-ca_host-when-setup-ca-is-used.patch -Patch0076: 0076-Clear-next-field-when-returnining-list-elements-in-q.patch -Patch0077: 0077-Add-cmocka-unit-tests-for-ipa-otpd-queue-code.patch -Patch0078: 0078-ipa-replica-install-fix-pkinit-setup.patch +Patch0001: 0001-Use-replace-instead-of-add-to-set-new-default-ipaSEL.patch +Patch0002: 0002-Sort-and-shuffle-SRV-record-by-priority-and-weight.patch +Patch0003: 0003-Increase-WSGI-process-count-to-5-on-64bit.patch +Patch0004: 0004-Always-set-ca_host-when-installing-replica.patch +Patch0005: 0005-ipaserver-config-plugin-Increase-search-records-mini.patch +Patch0006: 0006-Improve-and-fix-timeout-bug-in-wait_for_entry.patch +Patch0007: 0007-Use-common-replication-wait-timeout-of-5min.patch +Patch0008: 0008-Fix-replication-races-in-Dogtag-admin-code.patch +Patch0009: 0009-Allow-anonymous-access-to-ParentID-attribute.patch +Patch0010: 0010-Use-4-WSGI-workers-on-64bit-systems.patch +Patch0011: 0011-Query-for-server-role-IPA-master.patch +Patch0012: 0012-Only-create-DNS-SRV-records-for-ready-server.patch +Patch0013: 0013-Delay-enabling-services-until-end-of-installer.patch +Patch0014: 0014-ipa-client-uninstall-clean-the-state-store-when-rest.patch +Patch0015: 0015-Fix-CA-topology-warning.patch +Patch0016: 0016-replicainstall-DS-SSL-replica-install-pick-right-cer.patch +Patch0017: 0017-Fix-race-condition-in-get_locations_records.patch +Patch0018: 0018-Tune-DS-replication-settings.patch +Patch0019: 0019-Fix-DNSSEC-install-regression.patch +Patch0020: 0020-Handle-races-in-replica-config.patch +Patch0021: 0021-Fix-regression-Handle-unicode-where-str-is-expected.patch +Patch0022: 0022-In-IPA-4.4-when-updating-userpassword-with-ldapmodif.patch +Patch0023: 0023-Move-fips_enabled-to-a-common-library-to-share-acros.patch +Patch0024: 0024-ipasam-do-not-use-RC4-in-FIPS-mode.patch +Patch0025: 0025-Re-open-the-ldif-file-to-prevent-error-message.patch +Patch0026: 0026-Catch-ACIError-instead-of-invalid-credentials.patch +Patch0027: 0027-Auto-retry-failed-certmonger-requests.patch +Patch0028: 0028-Wait-for-client-certificates.patch +Patch0029: 0029-Fix-KRA-replica-installation-from-CA-master.patch +Patch0030: 0030-ipaserver-plugins-cert.py-Added-reason-to-raise-of-e.patch +Patch0031: 0031-ipa-commands-print-IPA-is-not-configured-when-ipa-is.patch +Patch0032: 0032-DS-replication-settings-fix-regression-with-3.3-mast.patch +Patch0033: 0033-Disable-message-about-log-in-ipa-backup-if-IPA-is-no.patch +Patch0034: 0034-uninstall-v-remove-Tracebacks.patch +Patch0035: 0035-Do-not-set-ca_host-when-setup-ca-is-used.patch +Patch0036: 0036-Fix-ipa-replica-install-when-key-not-protected-by-PI.patch +Patch0037: 0037-Clear-next-field-when-returnining-list-elements-in-q.patch +Patch0038: 0038-Add-cmocka-unit-tests-for-ipa-otpd-queue-code.patch +Patch0039: 0039-ipa-server-install-do-not-perform-forwarder-validati.patch +Patch0040: 0040-ipa-replica-install-fix-pkinit-setup.patch +Patch0041: 0041-ipa-replica-install-properly-use-the-file-store.patch +Patch0042: 0042-Ensure-that-public-cert-and-CA-bundle-are-readable.patch +Patch0043: 0043-Always-make-ipa.p11-kit-world-readable.patch +Patch0044: 0044-Make-etc-httpd-alias-world-readable-executable.patch +Patch0045: 0045-Fix-permission-of-public-files-in-upgrader.patch Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch Patch1002: 1002-Package-copy-schema-to-ca.py.patch Patch1003: 1003-Revert-Increased-mod_wsgi-socket-timeout.patch Patch1004: 1004-Remove-csrgen.patch +Patch1005: 1005-Removing-filesystem-encoding-check.patch # RHEL spec file only: END BuildRequires: libtool, automake, autoconf @@ -237,7 +226,7 @@ BuildRequires: python-lesscpy # Build dependencies for makeapi/makeaci # makeapi/makeaci is using Python 2 only for now # -BuildRequires: python-ldap +BuildRequires: python-ldap >= %{python2_ldap_version} BuildRequires: python-nss BuildRequires: python-netaddr BuildRequires: python-pyasn1 @@ -260,7 +249,7 @@ BuildRequires: python3-wheel %endif # with_wheels # -# Build dependencies for lint +# Build dependencies for lint and fastcheck # %if 0%{?with_lint} BuildRequires: samba-python @@ -268,6 +257,7 @@ BuildRequires: samba-python BuildRequires: python2-cryptography >= 1.4 # Bump because of #1457942 certauth: use canonical principal for lookups BuildRequires: python-gssapi >= 1.2.0-3 +BuildRequires: softhsm BuildRequires: pylint >= 1.6 # workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1096506 BuildRequires: python2-polib @@ -280,7 +270,7 @@ BuildRequires: python-dns >= 1.12.0-3 BuildRequires: jsl BuildRequires: python-yubico # pki Python package -BuildRequires: pki-base-python2 +BuildRequires: pki-base-python2 >= 10.5.1-2 BuildRequires: python-pytest-multihost BuildRequires: python-pytest-sourceorder BuildRequires: python-jwcrypto @@ -307,6 +297,7 @@ BuildRequires: python-augeas >= 0.5 BuildRequires: python3-cryptography >= 1.4 BuildRequires: python3-gssapi >= 1.2.0 BuildRequires: python3-pylint >= 1.6 +BuildRequires: python3-pycodestyle # workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1096506 BuildRequires: python3-polib BuildRequires: python3-libipa_hbac @@ -318,7 +309,7 @@ BuildRequires: python3-qrcode-core >= 5.0.0 BuildRequires: python3-dns >= 1.12.0-3 BuildRequires: python3-yubico # pki Python package -BuildRequires: pki-base-python3 +BuildRequires: pki-base-python3 >= 10.5.1-2 BuildRequires: python3-pytest-multihost BuildRequires: python3-pytest-sourceorder BuildRequires: python3-jwcrypto @@ -338,6 +329,7 @@ BuildRequires: python3-systemd # RHEL spec file only: DELETED: Remove csrgen # python-augeas >= 0.5 supports replace method BuildRequires: python3-augeas >= 0.5 +BuildRequires: python3-ldap >= %{python3_ldap_version} %endif # with_python3 %endif # with_lint @@ -367,7 +359,11 @@ Requires: %{name}-server-common = %{version}-%{release} Requires: %{name}-client = %{version}-%{release} Requires: %{name}-common = %{version}-%{release} Requires: python2-ipaserver = %{version}-%{release} -Requires: 389-ds-base >= 1.3.5.14 +Requires: python-ldap >= %{python2_ldap_version} +# 1.3.7.9-1: https://bugzilla.redhat.com/show_bug.cgi?id=1459946 +# https://bugzilla.redhat.com/show_bug.cgi?id=1511462 +# https://bugzilla.redhat.com/show_bug.cgi?id=1514033 +Requires: 389-ds-base >= 1.3.7.9-1 Requires: openldap-clients > 2.4.35-4 Requires: nss >= 3.14.3-12.0 Requires: nss-tools >= 3.14.3-12.0 @@ -377,16 +373,15 @@ Requires: krb5-pkinit-openssl >= %{krb5_version} Requires: cyrus-sasl-gssapi%{?_isa} Requires: ntp Requires: httpd >= 2.4.6-31 +Requires: python-gssapi >= 1.2.0-3 +Requires: systemd-python Requires: mod_wsgi Requires: mod_auth_gssapi >= 1.5.0 -# 1.0.14-2: https://bugzilla.redhat.com/show_bug.cgi?id=1347298 -Requires: mod_nss >= 1.0.14-2 +# 1.0.14-7: https://pagure.io/mod_nss/issue/45 +Requires: mod_nss >= 1.0.14-7 Requires: mod_session # 0.9.9: https://github.com/adelton/mod_lookup_identity/pull/3 Requires: mod_lookup_identity >= 0.9.9 -Requires: python-ldap >= 2.4.15 -# Bump because of #1457942 certauth: use canonical principal for lookups -Requires: python-gssapi >= 1.2.0-3 Requires: acl Requires: systemd-units >= 38 Requires(pre): shadow-utils @@ -397,20 +392,22 @@ Requires(post): selinux-policy-base >= %{selinux_policy_version} Requires: slapi-nis >= %{slapi_nis_version} # Required because of: https://bugzilla.redhat.com/show_bug.cgi?id=1475238 # related pki-core update: https://bugzilla.redhat.com/show_bug.cgi?id=1305993 -Requires: pki-ca >= 10.4.0-1 -Requires: pki-kra >= 10.4.0-1 +Requires: pki-ca >= 10.5.1-2 +Requires: pki-kra >= 10.5.1-2 Requires(preun): python systemd-units Requires(postun): python systemd-units Requires: policycoreutils >= 2.1.14-37 Requires: tar -Requires(pre): certmonger >= 0.78 -Requires(pre): 389-ds-base >= 1.3.5.14 +Requires(pre): certmonger >= 0.78.4-10 +# 1.3.7.9-1: https://bugzilla.redhat.com/show_bug.cgi?id=1459946 +# https://bugzilla.redhat.com/show_bug.cgi?id=1511462 +# https://bugzilla.redhat.com/show_bug.cgi?id=1514033 +Requires(pre): 389-ds-base >= 1.3.7.9-1 Requires: fontawesome-fonts Requires: open-sans-fonts Requires: openssl >= 1:1.0.1e-42 Requires: softhsm >= 2.0.0rc1-1 Requires: p11-kit -Requires: systemd-python Requires: %{etc_systemd_dir} Requires: gzip Requires: oddjob @@ -462,7 +459,7 @@ Requires: %{name}-server-common = %{version}-%{release} Requires: %{name}-common = %{version}-%{release} Requires: python2-ipaclient = %{version}-%{release} Requires: python-custodia >= 0.3.0-4 -Requires: python-ldap >= 2.4.15 +Requires: python-ldap >= %{python2_ldap_version} Requires: python-lxml # Bump because of #1457942 certauth: use canonical principal for lookups Requires: python-gssapi >= 1.2.0-3 @@ -472,7 +469,7 @@ Requires: dbus-python Requires: python-dns >= 1.12.0-3 Requires: python-kdcproxy >= 0.3 Requires: rpm-libs -Requires: pki-base-python2 +Requires: pki-base-python2 >= 10.5.1-2 # python-augeas >= 0.5 supports replace method Requires: python-augeas >= 0.5 @@ -496,7 +493,7 @@ Requires: %{name}-server-common = %{version}-%{release} Requires: %{name}-common = %{version}-%{release} Requires: python3-ipaclient = %{version}-%{release} Requires: python3-custodia >= 0.3.0-4 -Requires: python3-pyldap >= 2.4.15 +Requires(pre): python3-ldap >= %{python3_ldap_version} Requires: python3-lxml Requires: python3-gssapi >= 1.2.0 Requires: python3-sssdconfig @@ -507,7 +504,7 @@ Requires: python3-kdcproxy >= 0.3 # python3-augeas >= 0.5 supports replace method Requires: python3-augeas >= 0.5 Requires: rpm-libs -Requires: pki-base-python3 +Requires: pki-base-python3 >= 10.5.1-2 %description -n python3-ipaserver IPA is an integrated solution to provide centrally managed Identity (users, @@ -575,6 +572,7 @@ Requires: %{name}-common = %{version}-%{release} Requires: samba-python Requires: samba >= %{samba_version} Requires: samba-winbind +Requires(post): python Requires: libsss_idmap Requires: python-libsss_nss_idmap Requires: python-sss @@ -583,7 +581,6 @@ Requires: python-sss # IPA AD trusts cannot be used at the same time with the locator plugin # since Winbindd will be configured in a different mode Requires(post): %{_sbindir}/update-alternatives -Requires(post): python Requires(postun): %{_sbindir}/update-alternatives Requires(preun): %{_sbindir}/update-alternatives @@ -604,8 +601,9 @@ Summary: IPA authentication for use on clients Group: System Environment/Base Requires: %{name}-client-common = %{version}-%{release} Requires: %{name}-common = %{version}-%{release} +Requires: python-gssapi >= 1.2.0-3 Requires: python2-ipaclient = %{version}-%{release} -Requires: python-ldap +Requires: python-ldap >= %{python2_ldap_version} Requires: cyrus-sasl-gssapi%{?_isa} Requires: ntp Requires: krb5-workstation >= %{krb5_version} @@ -617,12 +615,10 @@ Requires: libcurl >= 7.21.7-2 Requires: xmlrpc-c >= 1.27.4 Requires: sssd >= 1.14.0 Requires: python-sssdconfig -Requires: certmonger >= 0.78 +Requires: certmonger >= 0.78.4-10 Requires: nss-tools Requires: bind-utils Requires: oddjob-mkhomedir -# Bump because of #1457942 certauth: use canonical principal for lookups -Requires: python-gssapi >= 1.2.0-3 Requires: libsss_autofs Requires: autofs Requires: libnfsidmap @@ -763,7 +759,6 @@ Requires: %{name}-common = %{version}-%{release} Requires: python-gssapi >= 1.2.0-3 Requires: gnupg Requires: keyutils -Requires: pyOpenSSL Requires: python >= 2.7.5-24 Requires: python-nss >= 0.16 Requires: python2-cryptography >= 1.4 @@ -780,7 +775,7 @@ Requires: python-setuptools Requires: python-six Requires: python-jwcrypto Requires: python-cffi -Requires: python-ldap >= 2.4.15 +Requires: python-ldap >= %{python2_ldap_version} Requires: python-requests Requires: python-dns >= 1.12.0-3 Requires: python-enum34 @@ -813,7 +808,6 @@ Requires: %{name}-common = %{version}-%{release} Requires: python3-gssapi >= 1.2.0 Requires: gnupg Requires: keyutils -Requires: python3-pyOpenSSL Requires: python3-nss >= 0.16 Requires: python3-cryptography >= 1.4 Requires: python3-netaddr >= %{python_netaddr_version} @@ -829,7 +823,7 @@ Requires: python3-setuptools Requires: python3-six Requires: python3-jwcrypto Requires: python3-cffi -Requires: python3-pyldap >= 2.4.15 +Requires(pre): python3-ldap >= %{python3_ldap_version} Requires: python3-requests Requires: python3-dns >= 1.12.0-3 Requires: python3-netifaces >= 0.10.4 @@ -970,10 +964,10 @@ cp -r %{_builddir}/freeipa-%{version} %{_builddir}/freeipa-%{version}-python3 %endif # with_python3 # RHEL spec file only: START: Change branding to IPA and Identity Management -#cp %SOURCE1 install/ui/images/header-logo.png -#cp %SOURCE2 install/ui/images/login-screen-background.jpg -#cp %SOURCE3 install/ui/images/login-screen-logo.png -#cp %SOURCE4 install/ui/images/product-name.png +cp %SOURCE1 install/ui/images/header-logo.png +cp %SOURCE2 install/ui/images/login-screen-background.jpg +cp %SOURCE3 install/ui/images/login-screen-logo.png +cp %SOURCE4 install/ui/images/product-name.png # RHEL spec file only: END: Change branding to IPA and Identity Management @@ -997,8 +991,7 @@ find \ %configure --with-vendor-suffix=-%{release} \ %{enable_server_option} \ %{with_ipatests_option} \ - %{linter_options} \ - --with-ipaplatform=rhel + %{linter_options} %make_build @@ -1019,8 +1012,7 @@ find \ %configure --with-vendor-suffix=-%{release} \ %{enable_server_option} \ %{with_ipatests_option} \ - %{linter_options} \ - --with-ipaplatform=rhel + %{linter_options} popd %endif # with_python3 @@ -1079,10 +1071,21 @@ mv %{buildroot}%{_bindir}/ipa-test-task %{buildroot}%{_bindir}/ipa-test-task-%{p ln -s %{_bindir}/ipa-run-tests-%{python2_version} %{buildroot}%{_bindir}/ipa-run-tests-2 ln -s %{_bindir}/ipa-test-config-%{python2_version} %{buildroot}%{_bindir}/ipa-test-config-2 ln -s %{_bindir}/ipa-test-task-%{python2_version} %{buildroot}%{_bindir}/ipa-test-task-2 -# test framework defaults to Python 2 +%endif # with_ipatests + +# Decide which Python (2 or 3) should be used as default for tests +%if 0%{?with_ipatests} +%if 0%{?with_python3} +# Building with python3 => make it default for tests +ln -s %{_bindir}/ipa-run-tests-%{python3_version} %{buildroot}%{_bindir}/ipa-run-tests +ln -s %{_bindir}/ipa-test-config-%{python3_version} %{buildroot}%{_bindir}/ipa-test-config +ln -s %{_bindir}/ipa-test-task-%{python3_version} %{buildroot}%{_bindir}/ipa-test-task +%else +# Building python2 only => make it default for tests ln -s %{_bindir}/ipa-run-tests-%{python2_version} %{buildroot}%{_bindir}/ipa-run-tests ln -s %{_bindir}/ipa-test-config-%{python2_version} %{buildroot}%{_bindir}/ipa-test-config ln -s %{_bindir}/ipa-test-task-%{python2_version} %{buildroot}%{_bindir}/ipa-test-task +%endif # with_python3 %endif # with_ipatests # remove files which are useful only for make uninstall @@ -1119,9 +1122,7 @@ mkdir -p %{buildroot}%{_sysconfdir}/httpd/conf.d/ /bin/touch %{buildroot}%{_sysconfdir}/httpd/conf.d/ipa-pki-proxy.conf /bin/touch %{buildroot}%{_sysconfdir}/httpd/conf.d/ipa-rewrite.conf /bin/touch %{buildroot}%{_usr}/share/ipa/html/ca.crt -/bin/touch %{buildroot}%{_usr}/share/ipa/html/kerberosauth.xpi /bin/touch %{buildroot}%{_usr}/share/ipa/html/krb.con -/bin/touch %{buildroot}%{_usr}/share/ipa/html/krb.js /bin/touch %{buildroot}%{_usr}/share/ipa/html/krb5.ini /bin/touch %{buildroot}%{_usr}/share/ipa/html/krbrealm.con @@ -1158,23 +1159,20 @@ fi /bin/systemctl reload-or-try-restart dbus /bin/systemctl reload-or-try-restart oddjobd +%tmpfiles_create ipa.conf %posttrans server # don't execute upgrade and restart of IPA when server is not installed python2 -c "import sys; from ipaserver.install import installutils; sys.exit(0 if installutils.is_ipa_configured() else 1);" > /dev/null 2>&1 if [ $? -eq 0 ]; then - # This must be run in posttrans so that updates from previous - # execution that may no longer be shipped are not applied. - /usr/sbin/ipa-server-upgrade --quiet >/dev/null || : - # Restart IPA processes. This must be also run in postrans so that plugins # and software is in consistent state # NOTE: systemd specific section /bin/systemctl is-enabled ipa.service >/dev/null 2>&1 if [ $? -eq 0 ]; then - /bin/systemctl restart ipa.service >/dev/null 2>&1 || : + /bin/systemctl restart ipa.service >/dev/null fi fi # END @@ -1350,6 +1348,7 @@ fi %{_libexecdir}/certmonger/ipa-server-guard %dir %{_libexecdir}/ipa %{_libexecdir}/ipa/ipa-custodia +%{_libexecdir}/ipa/ipa-custodia-check %{_libexecdir}/ipa/ipa-dnskeysyncd %{_libexecdir}/ipa/ipa-dnskeysync-replica %{_libexecdir}/ipa/ipa-ods-exporter @@ -1360,7 +1359,6 @@ fi %attr(0755,root,root) %{_libexecdir}/ipa/oddjob/org.freeipa.server.conncheck %config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freeipa.server.conf %config(noreplace) %{_sysconfdir}/oddjobd.conf.d/ipa-server.conf -%config(noreplace) %{_sysconfdir}/krb5.conf.d/ipa-certauth %dir %{_libexecdir}/ipa/certmonger %attr(755,root,root) %{_libexecdir}/ipa/certmonger/* # NOTE: systemd specific section @@ -1440,28 +1438,28 @@ fi %config(noreplace) %{_sysconfdir}/sysconfig/ipa-dnskeysyncd %config(noreplace) %{_sysconfdir}/sysconfig/ipa-ods-exporter %config(noreplace) %{_sysconfdir}/ipa/kdcproxy/kdcproxy.conf +# NOTE: systemd specific section +%{_tmpfilesdir}/ipa.conf %attr(644,root,root) %{_unitdir}/ipa-custodia.service %ghost %attr(644,root,root) %{etc_systemd_dir}/httpd.d/ipa.conf # END %dir %{_usr}/share/ipa %{_usr}/share/ipa/wsgi.py* +%{_usr}/share/ipa/kdcproxy.wsgi # RHEL spec file only: START: Package copy-schema-to-ca.py %{_usr}/share/ipa/copy-schema-to-ca.py* # RHEL spec file only: END: Package copy-schema-to-ca.py %{_usr}/share/ipa/*.ldif %{_usr}/share/ipa/*.uldif %{_usr}/share/ipa/*.template -%{_usr}/share/ipa/ipa.conf.tmpfiles %dir %{_usr}/share/ipa/advise %dir %{_usr}/share/ipa/advise/legacy %{_usr}/share/ipa/advise/legacy/*.template %dir %{_usr}/share/ipa/profiles +%{_usr}/share/ipa/profiles/README %{_usr}/share/ipa/profiles/*.cfg %dir %{_usr}/share/ipa/html -%{_usr}/share/ipa/html/ffconfig.js -%{_usr}/share/ipa/html/ffconfig_page.js %{_usr}/share/ipa/html/ssbrowser.html -%{_usr}/share/ipa/html/browserconfig.html %{_usr}/share/ipa/html/unauthorized.html %dir %{_usr}/share/ipa/migration %{_usr}/share/ipa/migration/error.html @@ -1493,11 +1491,8 @@ fi %{_usr}/share/ipa/wsgi/plugins.py* %dir %{_sysconfdir}/ipa %dir %{_sysconfdir}/ipa/html -%config(noreplace) %{_sysconfdir}/ipa/html/ffconfig.js -%config(noreplace) %{_sysconfdir}/ipa/html/ffconfig_page.js %config(noreplace) %{_sysconfdir}/ipa/html/ssbrowser.html %config(noreplace) %{_sysconfdir}/ipa/html/unauthorized.html -%config(noreplace) %{_sysconfdir}/ipa/html/browserconfig.html %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-rewrite.conf %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa.conf %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-kdc-proxy.conf @@ -1508,9 +1503,7 @@ fi %{_usr}/share/ipa/ipa-rewrite.conf %{_usr}/share/ipa/ipa-pki-proxy.conf %ghost %attr(0644,root,apache) %config(noreplace) %{_usr}/share/ipa/html/ca.crt -%ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/kerberosauth.xpi %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krb.con -%ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krb.js %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krb5.ini %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krbrealm.con %dir %{_usr}/share/ipa/updates/ @@ -1518,7 +1511,7 @@ fi %dir %{_localstatedir}/lib/ipa %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/backup %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/gssproxy -%attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysrestore +%attr(711,root,root) %dir %{_localstatedir}/lib/ipa/sysrestore %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysupgrade %attr(755,root,root) %dir %{_localstatedir}/lib/ipa/pki-ca %ghost %{_localstatedir}/lib/ipa/pki-ca/publish @@ -1627,9 +1620,14 @@ fi %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/default.conf %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/ca.crt %dir %attr(0755,root,root) %{_sysconfdir}/ipa/nssdb +# old dbm format %ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/cert8.db %ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/key3.db %ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/secmod.db +# new sql format +%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/cert9.db +%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/key4.db +%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/pkcs11.txt %ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/pwdfile.txt %ghost %config(noreplace) %{_sysconfdir}/pki/ca-trust/source/ipa.p11-kit %dir %{_localstatedir}/lib/ipa-client @@ -1661,6 +1659,7 @@ fi %{python_sitelib}/ipapython-*.egg-info %{python_sitelib}/ipalib-*.egg-info %{python_sitelib}/ipaplatform-*.egg-info +%{python_sitelib}/ipaplatform-*-nspkg.pth %files common -f %{gettext_domain}.lang @@ -1682,6 +1681,7 @@ fi %{python3_sitelib}/ipapython-*.egg-info %{python3_sitelib}/ipalib-*.egg-info %{python3_sitelib}/ipaplatform-*.egg-info +%{python3_sitelib}/ipaplatform-*-nspkg.pth %endif # with_python3 @@ -1728,83 +1728,170 @@ fi %changelog -* Tue Sep 25 2018 CentOS Sources <bugs@centos.org> - 4.5.4-10.el7.centos.4.4 -- Roll in CentOS Branding - -* Fri Sep 7 2018 Florence Blanc-Renaud <frenaud@redhat.com> - 4.5.4-10.el7_5.4.4 -- Resolves: #1626379 PKINIT configuration did not succeed message is received during Replica-install +* Tue Sep 18 2018 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.4-10.el7 +- Resolves: 1630361 PKINIT fails in FIPS mode + - Ensure that public cert and CA bundle are readable + - Always make ipa.p11-kit world-readable + - Make /etc/httpd/alias world readable & executable + - Fix permission of public files in upgrader + +* Mon Sep 10 2018 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.4-9.el7 +- Resolves: #1624755 Re-installing replica on the same system displays 'WARNING: cannot check if port 443 is already configured' + - ipa-replica-install: properly use the file store +- Resolves: #1623486 PKINIT configuration did not succeed message is received during Replica-install - ipa-replica-install: fix pkinit setup +- Related: #1624289 AVC denials noticed during test execution for SUB-CA test-suite in FIPS mode + - Update minimum selinux-policy to 3.13.1-224 -* Mon Sep 3 2018 Florence Blanc-Renaud <frenaud@redhat.com> - 4.5.4-10.el7.4.3 -- Resolves: #1624811 ipa-otpd: fix potential double-free and infinite loop in queue code +* Tue Sep 04 2018 Tibor Dudlák <tdudlak@redhat.com> - 4.6.4-8.el7 +- Resolves #1508498 Authn/TOTP defined users periodically prompt for just password credentials to access resources - Clear next field when returnining list elements in queue.c - Add cmocka unit tests for ipa otpd queue code +- Resolves #1622168 ipa-otpd: fix potential double-free and infinite loop in queue code + - Clear next field when returnining list elements in queue.c + - Add cmocka unit tests for ipa otpd queue code +- Resolves #1603444 ipa-server-install script is failing when using the "--no-dnssec-validation" parameter combined with the "--forwarder" + - ipa-server-install: do not perform forwarder validation with --no-dnssec-validation -* Thu Aug 30 2018 Florence Blanc-Renaud <frenaud@redhat.com> - 4.5.4-10.el7.4.2 -- Resolves: #1623673 SRV lookup doesn't correctly sort results - - Sort and shuffle SRV record by priority and weight -- Resolves: #1623679 Installation of replica against a specific master - - Always set ca_host when installing replica +* Wed Aug 29 2018 Tibor Dudlák <tdudlak@redhat.com> - 4.6.4-7.el7 +- Resolves: #1609882 ipaserver/plugins/cert.py: Add reason to raise of errors.NotFound + - ipaserver/plugins/cert.py: Added reason to raise of errors.NotFound +- Resolves: #1598662 Replica installation fails with connection refused error + - Do not set ca_host when --setup-ca is used +- Resolves: #1577108 Improve Custodia client and key distribution handling + - Fix KRA replica installation from CA master +- Resolves: #1515314 ipa-replica-install fails with PIN error [ CA-less environment ] + - Fix ipa-replica-install when key not protected by PIN +- Resolves: #1480502 ipa server uninstall with -v option displays "IOError: [Errno 9] Bad file descriptor Logged from file ipautil.py, line 442" + - uninstall -v: remove Tracebacks +- Resolves: #1368345 Replace ERROR: cannot connect to 'http://localhost:8888/ipa/json': [Errno 111] Connection refused with 'IPA is not configured on this system' + - ipa commands: print 'IPA is not configured' when ipa is not setup + - Disable message about log in ipa-backup if IPA is not configured +- Resolves: #1591824 Installation of replica against a specific master + - Do not set ca_host when --setup-ca is used +- Resolves: #1594141 Replication races in DogtagInstance.setup_admin + - Catch ACIError instead of invalid credentials +- Resolves: #1623112 ipa-replica-install defines nsds5replicabinddngroup before the group contains the DN of the replication manager + - DS replication settings: fix regression with <3.3 master +- Resolves: #1623113 Replica install: certmonger sometimes fails + - Wait for client certificates + - Auto-retry failed certmonger requests + +* Fri Aug 17 2018 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.4-6.el7 +- Resolves: #1590647 ldapmodify userPassword reflects on krblastpwdchange on RHEL6 but not RHEL7 + - In IPA 4.4 when updating userpassword with ldapmodify does not update krbPasswordExpiration nor krbLastPwdChange +- Resolves: #1600074 ipa-server-upgrade displays 'DN: cn=Schema Compatibility,cn=plugins,cn=config does not exists or haven't been updated' + - Re-open the ldif file to prevent error message +- Resolves: #1608783 ipa trust-add fails in FIPS mode. + - Move fips_enabled to a common library to share across different plugins + - ipasam: do not use RC4 in FIPS mode + +* Mon Aug 13 2018 Tibor Dudlák <tdudlak@redhat.com> - 4.6.4-5.el7 +- Resolves: #1607616 Traceback in messages file during ipa-server-install: File "/usr/libexec/certmonger/dogtag-ipa-ca-renew-agent-submit", line 541, in <module>#012 + - Removing filesystem encoding check +- Resolves: #1598044 plugable.py:491:bootstrap:SystemEncodingError: System encoding must be UTF-8, 'ANSI_X3.4-1968' is not supported. + - Removing filesystem encoding check + +* Fri Aug 10 2018 Tibor Dudlák <tdudlak@redhat.com> - 4.6.4-4.el7 +- Resolves: #1600525 ipa-client-install --uninstall fails to uninstall client. + - ipa client uninstall: clean the state store when restoring hostname +- Resolves: #1598117 client uninstall fails when installed using non-existing hostname + - ipa client uninstall: clean the state store when restoring hostname +- Resolves: #1596168 ipa help topics displays 'ipa: ERROR: an internal error has occurred' + - Fix regression: Handle unicode where str is expected +- Resolves: #1591824 Installation of replica against a specific master - Query for server role IPA master - Only create DNS SRV records for ready server - Delay enabling services until end of installer - replicainstall: DS SSL replica install pick right certmonger host + - Fix CA topology warning - Fix race condition in get_locations_records() - Fix DNSSEC install regression - Handle races in replica config - - Fix KRA replica installation from CA master - - Do not set ca_host when --setup-ca is used -- Resolves: #1623676 Replication races in DogtagInstance.setup_admin - - Improve and fix timeout bug in wait_for_entry() - - Use common replication wait timeout of 5min - - Fix replication races in Dogtag admin code - - Catch ACIError instead of invalid credentials -- Resolves: #1623680 Increase WSGI worker process count - - Increase WSGI process count to 5 on 64bit +- Resolves: #1591647 Increase WSGI worker process count - Use 4 WSGI workers on 64bit systems -- Resolves: #1623669 ipa-replica-install defines nsds5replicabinddngroup before the group contains the DN of the replication manager - - DS replication settings: fix regression with <3.3 master -- Resolves: #1623668 Replica install: certmonger sometimes fails - - Auto-retry failed certmonger requests - - Wait for client certificates - -* Thu Aug 16 2018 Florence Blanc-Renaud <frenaud@redhat.com> - 4.5.4-10.el7.4 -- Resolves: #1615983 ipa-restore fails on newly installed system. - - Fix ipa-restore: create /var/run/ipa files -- Resolves: #1615966 ipa-replica-manage re-initialize TypeError: 'NoneType' object does not support item assignment - - Check if replication agreement exist before enable/disable it -- Resolves: #1615984 ldapmodify userPassword reflects on krblastpwdchange on RHEL6 but not RHEL7 - - Tests: add integration test for password changes by dir mgr - - In IPA 4.4 when updating userpassword with ldapmodify does not update krbPasswordExpiration nor krbLastPwdChange -- Resolves: #1615893 nsds5ReplicaReleaseTimeout should be set by default. +- Resolves: #1565633 nsds5ReplicaReleaseTimeout should be set by default. - Tune DS replication settings -- Resolves: #1615964 Authn/TOTP defined users periodically prompt for just password credentials to access resources - - Fix elements not being removed in otpd_queue_pop_msgid() +- Resolves: #1607616 Traceback in messages file during ipa-server-install: File "/usr/libexec/certmonger/dogtag-ipa-ca-renew-agent-submit", line 541, in <module>#012 + - Removing filesystem encoding check +- Resolves: #1598044 plugable.py:491:bootstrap:SystemEncodingError: System encoding must be UTF-8, 'ANSI_X3.4-1968' is not supported. + - Removing filesystem encoding check -* Mon Jun 11 2018 Rob Crittenden <rcritten@redhat.com> - 4.5.4-10.el7.3 -- Resolves: #1579190 Improve Custodia client and key distribution handling - - Use single Custodia instance in installers +* Mon Jul 23 2018 Alexander Bokovoy <abokovoy@redhat.com> - 4.6.4-3.el7 +- Resolves: #1603514 Replica install fails with "Certificate issuance failed (CA_REJECTED)" - ACIError +* Fri Jun 22 2018 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.4-2.el7 +- Resolves: #1594142 SRV lookup doesn't correctly sort results + - Sort and shuffle SRV record by priority and weight +- Resolves: #1594141 Replication races in DogtagInstance.setup_admin + - Fix replication races in Dogtag admin code + - Use common replication wait timeout of 5min + - Improve and fix timeout bug in wait_for_entry() +- Resolves: #1591824 Installation of replica against a specific master + - Always set ca_host when installing replica +- Resolves: #1591647 Increase WSGI worker process count + - Increase WSGI process count to 5 on 64bit +- Resolves: #1394034 Custom SELinux User Map order is changed after updating IPA + - Use replace instead of add to set new default ipaSELinuxUserMapOrder +- Resolves: #1381535 ipa config-mod returns "Configured size limit exceeded" + - ipaserver config plugin: Increase search records minimum limit +* Mon Jun 11 2018 Florence Blanc-Renaud <frenaud@redhat.com> - 4.6.4-1.el7 +- Resolves: #1561581 Rebase IPA to latest 4.6.x version +- Resolves: #1234219 [WebUI] Error message could be better while adding idrange with untrusted domain name. +- Resolves: #1274488 ipa-client-install should use previously entered username when performing setup validation +- Resolves: #1289487 Priority field missing in Password Policy detail tab +- Resolves: #1339129 ipa vault-archive overwrites an existing value without warning +- Resolves: #1368345 Replace ERROR: cannot connect to 'http://localhost:8888/ipa/json': [Errno 111] Connection refused with 'IPA is not configured on this system' +- Resolves: #1424735 While performing ipa-server-upgrade, sssd goes offline and stalls the upgrade process +- Resolves: #1427105 RFE - Option to add custom OID or display name in IPA Cert +- Resolves: #1434924 ipa-restore fails when umask is set to 0027 +- Resolves: #1441262 ipa group-del gives ipa: ERROR: Insufficient access: but still deletes group +- Resolves: #1452081 Suggest user to install libyubikey package instead of traceback +- Resolves: #1458183 Users can delete their last active OTP token +- Resolves: #1478366 Crash noticed during IPA upgrade process due to ipa package +- Resolves: #1480502 ipa server uninstall with -v option displays "IOError: [Errno 9] Bad file descriptor Logged from file ipautil.py, line 442" +- Resolves: #1481936 Limit number of times the DNS response for the ipa-server A and AAAA records are done during uninstallation. +- Resolves: #1483139 ipa-restore command doesn't exit with failure if wrong directory manager's password is provided +- Resolves: #1485429 domain resolution order field in Identity->ID Views->Settings tab missing in WebUI +- Resolves: #1485851 ipa param-find: command displays internal error +- Resolves: #1494198 ipa-replica-manage re-initialize TypeError: 'NoneType' object does not support item assignment +- Resolves: #1504565 API schema generated by server doesn't follow language requested by client. +- Resolves: #1505925 kdc segfault in openldap libs when ipa-server is installed and custom pkinit is configured +- Resolves: #1506709 ipa trust-add - Filter out overlapping namespace domains automatically +- Resolves: #1513041 ipa-restore does not enable/start oddjobd +- Resolves: #1515314 ipa-replica-install fails with PIN error [ CA-less environment ] +- Resolves: #1515374 Custodia keys are not removed on uninstall +- Resolves: #1518932 The Issuer DN field in IPA is not updating properly +- Resolves: #1519723 admins group is not including all permissions of Role "User Administrator" +- Resolves: #1527020 nsslapd-sasl-max-buffer-size is hardcoded to '2097152' during install even if another value was provided in an LDIF ( --dirsrv-config-file ) +- Resolves: #1534726 IPA 'Generate OTP' option in web gui does not show OTP code when no reverse zone is managed +- Resolves: #1547641 ipa: Please log something after restarting the KDC +- Resolves: #1547995 CRL url on replicas gets incorrectly redirected +- Resolves: #1549187 IdM servers:/usr/share/ipa/html/ca.crt does not include the complete chain +- Resolves: #1553594 ldappasswd cause the IPA embedded Directory server to SIGSEGV +- Resolves: #1568748 Allow hosts to delete their own services +- Resolves: #1576133 Radius Proxy OTP Auth in IPA is not failing over to the second server in a radius-proxy +- Resolves: #1577108 Improve Custodia client and key distribution handling * Tue May 15 2018 Florence Blanc-Renaud <frenaud@redhat.com> - 4.5.4-10.el7.2 -- Resolves: #1579189 nsds5ReplicaReleaseTimeout should be set by default +- Resolves: #1565633 nsds5ReplicaReleaseTimeout should be set by default - Add nsds5ReplicaReleaseTimeout to replica config - Fix upgrade (update_replica_config) in single master mode -- Resolves: #1579190 Improve Custodia client and key distribution handling +- Resolves: #1577108 Improve Custodia client and key distribution handling - Use single Custodia instance in installers -- Resolves: #1579203 4.5.0 -> 4.5.4 upgrade breaks in ipa-server-upgrade: No such file or directory: '/var/lib/pki/pki-tomcat/conf/ca/CS.cfg' +- Resolves: #1577805 4.5.0 -> 4.5.4 upgrade breaks in ipa-server-upgrade: No such file or directory: '/var/lib/pki/pki-tomcat/conf/ca/CS.cfg' - Don't try to backup CS.cfg during upgrade if CA is not configured -* Tue Apr 10 2018 Florence Blanc-Renaud <frenaud@redhat.com> - 4.5.4-10.el7.1 -- Resolves: #1565519 Clarify the need to restart services in ipa-server-certinstall(1) +* Tue Apr 10 2018 Florence Blanc-Renaud <frenaud@redhat.com> - 4.5.4-11.el7 +- Resolves: #1518157 Clarify the need to restart services in ipa-server-certinstall(1) - Add a notice to restart ipa services after certs are installed -- Resolves: #1564390 OTP and Radius Authentication does not work in FIPS mode +- Resolves: #1544679 OTP and Radius Authentication does not work in FIPS mode - Fix OTP validation in FIPS mode - Increase the default token key size - Revert "Don't allow OTP or RADIUS in FIPS mode" - Log errors from NSS during FIPS OTP key import -- Resolves: #1565520 ipa client pointing to replica shows KDC has no support for encryption type +- Resolves: #1470916 ipa client pointing to replica shows KDC has no support for encryption type - ipa-replica-install: make sure that certmonger picks the right master -- Resolves: #1565605 DNS records updated with all IPAddresses of an interface when IPA server/replica try to install with Specific IP address of that interface +- Resolves: #1542627 DNS records updated with all IPAddresses of an interface when IPA server/replica try to install with Specific IP address of that interface - replica-install: pass --ip-address to client install * Wed Feb 07 2018 Florence Blanc-Renaud <frenaud@redhat.com> - 4.5.4-10.el7