diff --git a/0002-Fix-IP-Address-Checks.patch b/0002-Fix-IP-Address-Checks.patch new file mode 100644 index 0000000..97d3f84 --- /dev/null +++ b/0002-Fix-IP-Address-Checks.patch @@ -0,0 +1,532 @@ +From d010191d170c0ebb5f46bac2fc528f788e8ffc41 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Tue, 13 Jun 2017 17:03:30 +0200 +Subject: [PATCH 1/7] Fix local IP address validation + +Previously bf9886a84393d1d1546db7e49b102e08a16a83e7 match_local has +undesirable side effect that CheckedIPAddress object has set self._net +from local interface. + +However with the recent changes, match_local is usually set to False, +thus this side effect stops happening and default mask per address class +is used. This causes validation error because mask on interface and mask +used for provided IP addresses differ (reporducible only with classless +masks). + +FreeIPA should compare only IP addresses with local addresses without masks + +https://pagure.io/freeipa/issue/4317 + +Reviewed-By: David Kupka +--- + ipapython/ipautil.py | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py +index a277ed8..647ee83 100644 +--- a/ipapython/ipautil.py ++++ b/ipapython/ipautil.py +@@ -216,10 +216,10 @@ class CheckedIPAddress(UnsafeIPAddress): + addr=ifaddr, + netmask=ifdata['netmask'] + )) +- if ifnet == self._net or ( +- self._net is None and ifnet.ip == self): +- self._net = ifnet ++ ++ if ifnet.ip == self: + iface = interface ++ self._net = ifnet + break + + return iface +-- +2.9.4 + + +From 4d06f0c52200a4345db36dae3fdbc178f18f2f01 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Wed, 14 Jun 2017 14:45:03 +0200 +Subject: [PATCH 2/7] ipa-dns-install: remove check for local ip address + +This check was forgotten and will be removed now. + +https://pagure.io/freeipa/issue/4317 + +Reviewed-By: David Kupka +--- + install/tools/ipa-dns-install | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install +index 5bd0ba6..cb6c5d8 100755 +--- a/install/tools/ipa-dns-install ++++ b/install/tools/ipa-dns-install +@@ -47,7 +47,9 @@ def parse_options(): + default=False, help="print debugging information") + parser.add_option("--ip-address", dest="ip_addresses", metavar="IP_ADDRESS", + default=[], action="append", +- type="ip", ip_local=True, help="Master Server IP Address. This option can be used multiple times") ++ type="ip", ++ help="Master Server IP Address. This option can be used " ++ "multiple times") + parser.add_option("--forwarder", dest="forwarders", action="append", + type="ip", help="Add a DNS forwarder. This option can be used multiple times") + parser.add_option("--no-forwarders", dest="no_forwarders", action="store_true", +-- +2.9.4 + + +From 0aa0041149f359f1954409baf886d4b31fdadc16 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Wed, 14 Jun 2017 14:47:23 +0200 +Subject: [PATCH 3/7] refactor CheckedIPAddress class + +Make methods without side effects (setting mask) + +https://pagure.io/freeipa/issue/4317 + +Reviewed-By: David Kupka +--- + ipapython/ipautil.py | 29 ++++++++++++++++++++++------- + 1 file changed, 22 insertions(+), 7 deletions(-) + +diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py +index 647ee83..2c020e3 100644 +--- a/ipapython/ipautil.py ++++ b/ipapython/ipautil.py +@@ -62,6 +62,12 @@ PROTOCOL_NAMES = { + socket.SOCK_DGRAM: 'udp' + } + ++InterfaceDetails = collections.namedtuple( ++ 'InterfaceDetails', [ ++ 'name', # interface name ++ 'ifnet' # network details of interface ++ ]) ++ + + class UnsafeIPAddress(netaddr.IPAddress): + """Any valid IP address with or without netmask.""" +@@ -161,9 +167,12 @@ class CheckedIPAddress(UnsafeIPAddress): + raise ValueError("cannot use multicast IP address {}".format(addr)) + + if match_local: +- if not self.get_matching_interface(): ++ intf_details = self.get_matching_interface() ++ if not intf_details: + raise ValueError('no network interface matches the IP address ' + 'and netmask {}'.format(addr)) ++ else: ++ self.set_ip_net(intf_details.ifnet) + + if self._net is None: + if self.version == 4: +@@ -193,7 +202,8 @@ class CheckedIPAddress(UnsafeIPAddress): + + def get_matching_interface(self): + """Find matching local interface for address +- :return: Interface name or None if no interface has this address ++ :return: InterfaceDetails named tuple or None if no interface has ++ this address + """ + if self.version == 4: + family = netifaces.AF_INET +@@ -204,7 +214,6 @@ class CheckedIPAddress(UnsafeIPAddress): + "Unsupported address family ({})".format(self.version) + ) + +- iface = None + for interface in netifaces.interfaces(): + for ifdata in netifaces.ifaddresses(interface).get(family, []): + +@@ -218,11 +227,17 @@ class CheckedIPAddress(UnsafeIPAddress): + )) + + if ifnet.ip == self: +- iface = interface +- self._net = ifnet +- break ++ return InterfaceDetails(interface, ifnet) + +- return iface ++ def set_ip_net(self, ifnet): ++ """Set IP Network details for this address. IPNetwork is valid only ++ locally, so this should be set only for local IP addresses ++ ++ :param ifnet: netaddr.IPNetwork object with information about IP ++ network where particula address belongs locally ++ """ ++ assert isinstance(ifnet, netaddr.IPNetwork) ++ self._net = ifnet + + + def valid_ip(addr): +-- +2.9.4 + + +From 9a924dd8cc27507a70f4ec5020d97417e149e350 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Wed, 14 Jun 2017 14:54:43 +0200 +Subject: [PATCH 4/7] CheckedIPAddress: remove match_local param + +This parameter is unused in code. We are no longer testing if IP address +matches an interface in constructor. + +https://pagure.io/freeipa/issue/4317 + +Reviewed-By: David Kupka +--- + ipapython/config.py | 5 ++--- + ipapython/ipautil.py | 10 +--------- + ipaserver/install/installutils.py | 2 +- + ipaserver/plugins/dns.py | 4 ++-- + ipaserver/plugins/host.py | 2 +- + ipatests/test_ipapython/test_ipautil.py | 3 +-- + 6 files changed, 8 insertions(+), 18 deletions(-) + +diff --git a/ipapython/config.py b/ipapython/config.py +index 9db2dcd..6349892 100644 +--- a/ipapython/config.py ++++ b/ipapython/config.py +@@ -68,10 +68,9 @@ class IPAFormatter(IndentedHelpFormatter): + def check_ip_option(option, opt, value): + from ipapython.ipautil import CheckedIPAddress + +- ip_local = option.ip_local is True + ip_netmask = option.ip_netmask is True + try: +- return CheckedIPAddress(value, parse_netmask=ip_netmask, match_local=ip_local) ++ return CheckedIPAddress(value, parse_netmask=ip_netmask) + except Exception as e: + raise OptionValueError("option %s: invalid IP address %s: %s" % (opt, value, e)) + +@@ -86,7 +85,7 @@ class IPAOption(Option): + optparse.Option subclass with support of options labeled as + security-sensitive such as passwords. + """ +- ATTRS = Option.ATTRS + ["sensitive", "ip_local", "ip_netmask"] ++ ATTRS = Option.ATTRS + ["sensitive", "ip_netmask"] + TYPES = Option.TYPES + ("ip", "dn") + TYPE_CHECKER = copy(Option.TYPE_CHECKER) + TYPE_CHECKER["ip"] = check_ip_option +diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py +index 2c020e3..5a6bf5a 100644 +--- a/ipapython/ipautil.py ++++ b/ipapython/ipautil.py +@@ -135,7 +135,7 @@ class CheckedIPAddress(UnsafeIPAddress): + + Reserved or link-local addresses are never accepted. + """ +- def __init__(self, addr, match_local=False, parse_netmask=True, ++ def __init__(self, addr, parse_netmask=True, + allow_loopback=False, allow_multicast=False): + try: + super(CheckedIPAddress, self).__init__(addr) +@@ -166,14 +166,6 @@ class CheckedIPAddress(UnsafeIPAddress): + if not allow_multicast and self.is_multicast(): + raise ValueError("cannot use multicast IP address {}".format(addr)) + +- if match_local: +- intf_details = self.get_matching_interface() +- if not intf_details: +- raise ValueError('no network interface matches the IP address ' +- 'and netmask {}'.format(addr)) +- else: +- self.set_ip_net(intf_details.ifnet) +- + if self._net is None: + if self.version == 4: + self._net = netaddr.IPNetwork( +diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py +index 3521d55..01930c4 100644 +--- a/ipaserver/install/installutils.py ++++ b/ipaserver/install/installutils.py +@@ -585,7 +585,7 @@ def get_server_ip_address(host_name, unattended, setup_dns, ip_addresses): + if len(hostaddr): + for ha in hostaddr: + try: +- ips.append(ipautil.CheckedIPAddress(ha, match_local=False)) ++ ips.append(ipautil.CheckedIPAddress(ha)) + except ValueError as e: + root_logger.warning("Invalid IP address %s for %s: %s", ha, host_name, unicode(e)) + +diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py +index f0e6c48..f01baf5 100644 +--- a/ipaserver/plugins/dns.py ++++ b/ipaserver/plugins/dns.py +@@ -567,7 +567,7 @@ def add_records_for_host_validation(option_name, host, domain, ip_addresses, che + for ip_address in ip_addresses: + try: + ip = CheckedIPAddress( +- ip_address, match_local=False, allow_multicast=True) ++ ip_address, allow_multicast=True) + except Exception as e: + raise errors.ValidationError(name=option_name, error=unicode(e)) + +@@ -599,7 +599,7 @@ def add_records_for_host(host, domain, ip_addresses, add_forward=True, add_rever + + for ip_address in ip_addresses: + ip = CheckedIPAddress( +- ip_address, match_local=False, allow_multicast=True) ++ ip_address, allow_multicast=True) + + if add_forward: + add_forward_record(domain, host, unicode(ip)) +diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py +index 1e1f9d8..364e5be 100644 +--- a/ipaserver/plugins/host.py ++++ b/ipaserver/plugins/host.py +@@ -245,7 +245,7 @@ def validate_ipaddr(ugettext, ipaddr): + Verify that we have either an IPv4 or IPv6 address. + """ + try: +- CheckedIPAddress(ipaddr, match_local=False) ++ CheckedIPAddress(ipaddr) + except Exception as e: + return unicode(e) + return None +diff --git a/ipatests/test_ipapython/test_ipautil.py b/ipatests/test_ipapython/test_ipautil.py +index 6427935..9c351bd 100644 +--- a/ipatests/test_ipapython/test_ipautil.py ++++ b/ipatests/test_ipapython/test_ipautil.py +@@ -30,11 +30,10 @@ from ipapython import ipautil + + pytestmark = pytest.mark.tier0 + +- + def make_ipaddress_checker(addr, words=None, prefixlen=None): + def check_ipaddress(): + try: +- ip = ipautil.CheckedIPAddress(addr, match_local=False) ++ ip = ipautil.CheckedIPAddress(addr) + assert ip.words == words and ip.prefixlen == prefixlen + except Exception: + assert words is None and prefixlen is None +-- +2.9.4 + + +From 217905a20071b55b50568e8fbb36a8ecde974432 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Wed, 14 Jun 2017 15:02:21 +0200 +Subject: [PATCH 5/7] Remove ip_netmask from option parser + +ipa-dns-install uses ip_netmask=False --> parse_netmask=False, other installers uses default (parse_netmask=True). +Use this consistent accross all installers. + +Also this option is unused (and shouldn't be used). + +https://pagure.io/freeipa/issue/4317 + +Reviewed-By: David Kupka +--- + ipapython/config.py | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/ipapython/config.py b/ipapython/config.py +index 6349892..19abfc5 100644 +--- a/ipapython/config.py ++++ b/ipapython/config.py +@@ -68,9 +68,8 @@ class IPAFormatter(IndentedHelpFormatter): + def check_ip_option(option, opt, value): + from ipapython.ipautil import CheckedIPAddress + +- ip_netmask = option.ip_netmask is True + try: +- return CheckedIPAddress(value, parse_netmask=ip_netmask) ++ return CheckedIPAddress(value) + except Exception as e: + raise OptionValueError("option %s: invalid IP address %s: %s" % (opt, value, e)) + +@@ -85,7 +84,7 @@ class IPAOption(Option): + optparse.Option subclass with support of options labeled as + security-sensitive such as passwords. + """ +- ATTRS = Option.ATTRS + ["sensitive", "ip_netmask"] ++ ATTRS = Option.ATTRS + ["sensitive"] + TYPES = Option.TYPES + ("ip", "dn") + TYPE_CHECKER = copy(Option.TYPE_CHECKER) + TYPE_CHECKER["ip"] = check_ip_option +-- +2.9.4 + + +From 93ef10292ca674842c79da0dab6de6fb63261881 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Thu, 15 Jun 2017 10:26:03 +0200 +Subject: [PATCH 6/7] replica install: add missing check for non-local IP + address + +Add missing warning for used non-local IP address. + +https://pagure.io/freeipa/issue/4317 + +Reviewed-By: David Kupka +--- + ipaserver/install/server/replicainstall.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 6620f02..9e328bf 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -854,6 +854,7 @@ def install_check(installer): + # check addresses here, dns module is doing own check + network_ip_address_warning(config.ips) + broadcast_ip_address_warning(config.ips) ++ no_matching_interface_for_ip_address_warning(config.ips) + + if options.setup_adtrust: + adtrust.install_check(False, options, remote_api) +-- +2.9.4 + + +From 1c961161873c37cb29a51baeeed0e782cd4a1d4d Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Thu, 15 Jun 2017 10:27:55 +0200 +Subject: [PATCH 7/7] Remove network and broadcast address warnings + +We cannot reliably determine when an IP Address is network or broadcast. +We allowed to use non-local IP addresses due container use cases, we +don't know subnets of used IP addresses. + +https://pagure.io/freeipa/issue/4317 + +Reviewed-By: David Kupka +--- + ipaclient/install/client.py | 4 ---- + ipalib/util.py | 20 -------------------- + ipaserver/install/dns.py | 2 -- + ipaserver/install/server/install.py | 4 ---- + ipaserver/install/server/replicainstall.py | 10 +--------- + 5 files changed, 1 insertion(+), 39 deletions(-) + +diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py +index b0de596..c880613 100644 +--- a/ipaclient/install/client.py ++++ b/ipaclient/install/client.py +@@ -38,8 +38,6 @@ from ipalib.install.kinit import kinit_keytab, kinit_password + from ipalib.install.service import enroll_only, prepare_only + from ipalib.rpc import delete_persistent_client_session_data + from ipalib.util import ( +- broadcast_ip_address_warning, +- network_ip_address_warning, + normalize_hostname, + no_matching_interface_for_ip_address_warning, + verify_host_resolvable, +@@ -1299,8 +1297,6 @@ def update_dns(server, hostname, options): + root_logger.info("Failed to determine this machine's ip address(es).") + return + +- network_ip_address_warning(update_ips) +- broadcast_ip_address_warning(update_ips) + no_matching_interface_for_ip_address_warning(update_ips) + + update_txt = "debug\n" +diff --git a/ipalib/util.py b/ipalib/util.py +index 1bd8495..31e7323 100644 +--- a/ipalib/util.py ++++ b/ipalib/util.py +@@ -1110,26 +1110,6 @@ def check_principal_realm_in_trust_namespace(api_instance, *keys): + 'namespace')) + + +-def network_ip_address_warning(addr_list): +- for ip in addr_list: +- if ip.is_network_addr(): +- root_logger.warning("IP address %s might be network address", ip) +- # fixme: once when loggers will be fixed, we can remove this +- # print +- print("WARNING: IP address {} might be network address".format(ip), +- file=sys.stderr) +- +- +-def broadcast_ip_address_warning(addr_list): +- for ip in addr_list: +- if ip.is_broadcast_addr(): +- root_logger.warning("IP address %s might be broadcast address", ip) +- # fixme: once when loggers will be fixed, we can remove this +- # print +- print("WARNING: IP address {} might be broadcast address".format( +- ip), file=sys.stderr) +- +- + def no_matching_interface_for_ip_address_warning(addr_list): + for ip in addr_list: + if not ip.get_matching_interface(): +diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py +index 090b794..1c1aac0 100644 +--- a/ipaserver/install/dns.py ++++ b/ipaserver/install/dns.py +@@ -264,8 +264,6 @@ def install_check(standalone, api, replica, options, hostname): + ip_addresses = get_server_ip_address(hostname, options.unattended, + True, options.ip_addresses) + +- util.network_ip_address_warning(ip_addresses) +- util.broadcast_ip_address_warning(ip_addresses) + util.no_matching_interface_for_ip_address_warning(ip_addresses) + + if not options.forward_policy: +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index 7eb291e..dced253 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -27,8 +27,6 @@ from ipalib import api, errors, x509 + from ipalib.constants import DOMAIN_LEVEL_0 + from ipalib.util import ( + validate_domain_name, +- network_ip_address_warning, +- broadcast_ip_address_warning, + no_matching_interface_for_ip_address_warning, + ) + import ipaclient.install.ntpconf +@@ -616,8 +614,6 @@ def install_check(installer): + options.ip_addresses) + + # check addresses here, dns module is doing own check +- network_ip_address_warning(ip_addresses) +- broadcast_ip_address_warning(ip_addresses) + no_matching_interface_for_ip_address_warning(ip_addresses) + + if options.setup_adtrust: +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 9e328bf..4f28de2 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -32,11 +32,7 @@ from ipaplatform.tasks import tasks + from ipaplatform.paths import paths + from ipalib import api, constants, create_api, errors, rpc, x509 + from ipalib.config import Env +-from ipalib.util import ( +- network_ip_address_warning, +- broadcast_ip_address_warning, +- no_matching_interface_for_ip_address_warning, +-) ++from ipalib.util import no_matching_interface_for_ip_address_warning + from ipaclient.install.client import configure_krb5_conf, purge_host_keytab + from ipaserver.install import ( + adtrust, bindinstance, ca, certs, dns, dsinstance, httpinstance, +@@ -852,8 +848,6 @@ def install_check(installer): + options.ip_addresses) + + # check addresses here, dns module is doing own check +- network_ip_address_warning(config.ips) +- broadcast_ip_address_warning(config.ips) + no_matching_interface_for_ip_address_warning(config.ips) + + if options.setup_adtrust: +@@ -1285,8 +1279,6 @@ def promote_check(installer): + False, options.ip_addresses) + + # check addresses here, dns module is doing own check +- network_ip_address_warning(config.ips) +- broadcast_ip_address_warning(config.ips) + no_matching_interface_for_ip_address_warning(config.ips) + + if options.setup_adtrust: +-- +2.9.4 + diff --git a/0003-python-netifaces-update-to-reflect-upstream-changes.patch b/0003-python-netifaces-update-to-reflect-upstream-changes.patch new file mode 100644 index 0000000..50fad2e --- /dev/null +++ b/0003-python-netifaces-update-to-reflect-upstream-changes.patch @@ -0,0 +1,56 @@ +From 56d04b3dccc967630d869006dfbd0003fcfedabe Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Fri, 16 Jun 2017 13:42:53 +0200 +Subject: [PATCH] python-netifaces: update to reflect upstream changes + +python-netifaces now provides IPv6 netmask in format mask/prefix. It +breaks freeipa as it is unexpected format for python-netaddr. We must +split netmask and provide only prefix for netaddr. + +https://pagure.io/freeipa/issue/7021 + +Reviewed-By: Martin Babinsky +Reviewed-By: Petr Vobornik +--- + ipapython/ipautil.py | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py +index 5a6bf5a..1bb48d4 100644 +--- a/ipapython/ipautil.py ++++ b/ipapython/ipautil.py +@@ -197,6 +197,7 @@ class CheckedIPAddress(UnsafeIPAddress): + :return: InterfaceDetails named tuple or None if no interface has + this address + """ ++ root_logger.debug("Searching for an interface of IP address: %s", self) + if self.version == 4: + family = netifaces.AF_INET + elif self.version == 6: +@@ -213,10 +214,20 @@ class CheckedIPAddress(UnsafeIPAddress): + # errors in IPNetwork + ifaddr = ifdata['addr'].split(u'%', 1)[0] + +- ifnet = netaddr.IPNetwork('{addr}/{netmask}'.format( ++ # newer versions of netifaces provide IPv6 netmask in format ++ # 'ffff:ffff:ffff:ffff::/64'. We have to split and use prefix ++ # or the netmask with older versions ++ ifmask = ifdata['netmask'].split(u'/')[-1] ++ ++ ifaddrmask = '{addr}/{netmask}'.format( + addr=ifaddr, +- netmask=ifdata['netmask'] +- )) ++ netmask=ifmask ++ ) ++ root_logger.debug( ++ "Testing local IP address: %s (interface: %s)", ++ ifaddrmask, interface) ++ ++ ifnet = netaddr.IPNetwork(ifaddrmask) + + if ifnet.ip == self: + return InterfaceDetails(interface, ifnet) +-- +2.9.4 + diff --git a/freeipa.spec b/freeipa.spec index 9ab7b55..6548487 100644 --- a/freeipa.spec +++ b/freeipa.spec @@ -69,7 +69,7 @@ Name: freeipa Version: %{VERSION} -Release: 1%{?dist} +Release: 2%{?dist} Summary: The Identity, Policy and Audit system Group: System Environment/Base @@ -80,6 +80,9 @@ Source1: https://releases.pagure.org/freeipa/freeipa-%{VERSION}.tar.gz.as BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Patch0001: 0001-Workarounds-for-SELinux-execmem-violations-in-crypto.patch +# remove Patch000[2-3] in 4.5.3 +Patch0002: 0002-Fix-IP-Address-Checks.patch +Patch0003: 0003-python-netifaces-update-to-reflect-upstream-changes.patch BuildRequires: openldap-devel # For KDB DAL version, make explicit dependency so that increase of version @@ -1610,6 +1613,10 @@ fi %endif # with_ipatests %changelog +* Tue Jun 20 2017 Tomas Krizek - 4.5.2-2 +- Patch: Fix IP address checks +- Patch: python-netifaces fix + * Sun Jun 18 2017 Tomas Krizek - 4.5.2-1 - Update to upstream 4.5.2 - see https://www.freeipa.org/page/Releases/4.5.2