[Pkg-freeipa-devel] freeipa: Changes to 'upstream'

Timo Aaltonen tjaalton at moszumanska.debian.org
Mon Aug 29 23:29:52 UTC 2016


Rebased ref, commits from common ancestor:
commit 78a6434e323ebc357472745d97627065ae5b8169
Author: Petr Vobornik <pvoborni at redhat.com>
Date:   Fri Jul 22 15:46:51 2016 +0200

    Become IPA 4.3.2

diff --git a/VERSION b/VERSION
index 92ecb6d..e135abf 100644
--- a/VERSION
+++ b/VERSION
@@ -21,7 +21,7 @@
 ########################################################
 IPA_VERSION_MAJOR=4
 IPA_VERSION_MINOR=3
-IPA_VERSION_RELEASE=1
+IPA_VERSION_RELEASE=2
 
 ########################################################
 # For 'alpha' releases the version will be             #

commit 64bbbb52a20200025017d0b29c9fa2dcdd7ad83d
Author: Martin Basti <mbasti at redhat.com>
Date:   Thu Jul 21 18:49:57 2016 +0200

    Use copy when replacing files to keep SELinux context
    
    When installer replaces any file with newer, it must use 'copy' instead of
    'mv' to keep SELinux context valid.
    
    https://fedorahosted.org/freeipa/ticket/6111
    
    Reviewed-By: Petr Spacek <pspacek at redhat.com>

diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index b329cdb..1a868b1 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -539,10 +539,14 @@ def dir_exists(filename):
     except:
         return False
 
+
 def install_file(fname, dest):
+    # SELinux: use copy to keep the right context
     if file_exists(dest):
         os.rename(dest, dest + ".orig")
-    shutil.move(fname, dest)
+    shutil.copy(fname, dest)
+    os.remove(fname)
+
 
 def backup_file(fname):
     if file_exists(fname):

commit 268d835556e677c80501349fc96a531ccd63f3f6
Author: Florence Blanc-Renaud <flo at redhat.com>
Date:   Thu Jul 21 16:54:43 2016 +0200

    Fix session cookies
    
    The CLI was not using session cookies for communication with IPA API.
    The kernel_keyring code was expecting the keyname to be a string, but
    in python 2 a unicode was supplied (the key is built using
    ipa_session_cookie:%principal and principal is a unicode).
    
    The patch fixes the assertions, allowing to store and retrieve the cookie.
    It also adds a test with unicode key name.
    
    https://fedorahosted.org/freeipa/ticket/5984
    
    Reviewed-By: Petr Spacek <pspacek at redhat.com>

diff --git a/ipapython/kernel_keyring.py b/ipapython/kernel_keyring.py
index ed4868a..651fd70 100644
--- a/ipapython/kernel_keyring.py
+++ b/ipapython/kernel_keyring.py
@@ -18,6 +18,7 @@
 #
 
 import os
+import six
 
 from ipapython.ipautil import run
 
@@ -45,7 +46,7 @@ def get_real_key(key):
     One cannot request a key based on the description it was created with
     so find the one we're looking for.
     """
-    assert isinstance(key, str)
+    assert isinstance(key, six.string_types)
     result = run(['keyctl', 'search', KEYRING, KEYTYPE, key],
                  raiseonerr=False, capture_output=True)
     if result.returncode:
@@ -53,7 +54,7 @@ def get_real_key(key):
     return result.raw_output.rstrip()
 
 def get_persistent_key(key):
-    assert isinstance(key, str)
+    assert isinstance(key, six.string_types)
     result = run(['keyctl', 'get_persistent', KEYRING, key],
                  raiseonerr=False, capture_output=True)
     if result.returncode:
@@ -73,7 +74,7 @@ def has_key(key):
     """
     Returns True/False whether the key exists in the keyring.
     """
-    assert isinstance(key, str)
+    assert isinstance(key, six.string_types)
     try:
         get_real_key(key)
         return True
@@ -86,7 +87,7 @@ def read_key(key):
 
     Use pipe instead of print here to ensure we always get the raw data.
     """
-    assert isinstance(key, str)
+    assert isinstance(key, six.string_types)
     real_key = get_real_key(key)
     result = run(['keyctl', 'pipe', real_key], raiseonerr=False,
                  capture_output=True)
@@ -99,7 +100,7 @@ def update_key(key, value):
     """
     Update the keyring data. If they key doesn't exist it is created.
     """
-    assert isinstance(key, str)
+    assert isinstance(key, six.string_types)
     assert isinstance(value, bytes)
     if has_key(key):
         real_key = get_real_key(key)
@@ -114,7 +115,7 @@ def add_key(key, value):
     """
     Add a key to the kernel keyring.
     """
-    assert isinstance(key, str)
+    assert isinstance(key, six.string_types)
     assert isinstance(value, bytes)
     if has_key(key):
         raise ValueError('key %s already exists' % key)
@@ -127,7 +128,7 @@ def del_key(key):
     """
     Remove a key from the keyring
     """
-    assert isinstance(key, str)
+    assert isinstance(key, six.string_types)
     real_key = get_real_key(key)
     result = run(['keyctl', 'unlink', real_key, KEYRING],
                  raiseonerr=False)
diff --git a/ipatests/test_ipapython/test_keyring.py b/ipatests/test_ipapython/test_keyring.py
index 02fd29e..5ab5191 100644
--- a/ipatests/test_ipapython/test_keyring.py
+++ b/ipatests/test_ipapython/test_keyring.py
@@ -28,6 +28,7 @@ import pytest
 pytestmark = pytest.mark.tier0
 
 TEST_KEY = 'ipa_test'
+TEST_UNICODEKEY = u'ipa_unicode'
 TEST_VALUE = b'abc123'
 UPDATE_VALUE = b'123abc'
 
@@ -49,6 +50,10 @@ class test_keyring(object):
             kernel_keyring.del_key(SIZE_256)
         except ValueError:
             pass
+        try:
+            kernel_keyring.del_key(TEST_UNICODEKEY)
+        except ValueError:
+            pass
 
     def test_01(self):
         """
@@ -150,3 +155,13 @@ class test_keyring(object):
         assert(result == SIZE_1024.encode('ascii'))
 
         kernel_keyring.del_key(TEST_KEY)
+
+    def test_10(self):
+        """
+        Test a unicode key
+        """
+        kernel_keyring.add_key(TEST_UNICODEKEY, TEST_VALUE)
+        result = kernel_keyring.read_key(TEST_UNICODEKEY)
+        assert(result == TEST_VALUE)
+
+        kernel_keyring.del_key(TEST_UNICODEKEY)

commit 844364bd2770b267c6e913de75b7caa926489c75
Author: Oleg Fayans <ofayans at redhat.com>
Date:   Fri Jul 1 16:52:22 2016 +0200

    Test for incorrect client domain
    
    https://fedorahosted.org/freeipa/ticket/5976
    
    Reviewed-By: Martin Basti <mbasti at redhat.com>

diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py
index 1f683b6..7bc1d52 100644
--- a/ipatests/test_integration/test_replica_promotion.py
+++ b/ipatests/test_integration/test_replica_promotion.py
@@ -377,3 +377,55 @@ class TestOldReplicaWorksAfterDomainUpgrade(IntegrationTest):
         result1 = self.master.run_command(['ipa', 'user-show', self.username],
                                           raiseonerr=False)
         assert_error(result1, "%s: user not found" % self.username, 2)
+
+
+class TestWrongClientDomain(IntegrationTest):
+    topology = "star"
+    num_clients = 1
+    domain_name = 'exxample.test'
+
+    @classmethod
+    def install(cls, mh):
+        tasks.install_master(cls.master, domain_level=cls.domain_level)
+
+    def teardown_method(self, method):
+        self.clients[0].run_command(['ipa-client-install',
+                                     '--uninstall', '-U'],
+                                    raiseonerr=False)
+        tasks.kinit_admin(self.master)
+        self.master.run_command(['ipa', 'host-del',
+                                 self.clients[0].hostname],
+                                raiseonerr=False)
+
+    def test_wrong_client_domain(self):
+        client = self.clients[0]
+        client.run_command(['ipa-client-install', '-U',
+                            '--domain', self.domain_name,
+                            '--realm', self.master.domain.realm,
+                            '-p', 'admin',
+                            '-w', self.master.config.admin_password,
+                            '--server', self.master.hostname,
+                            '--force-join'])
+        result = client.run_command(['ipa-replica-install', '-U', '-w',
+                                     self.master.config.dirman_password],
+                                    raiseonerr=False)
+        assert_error(result,
+                     "Cannot promote this client to a replica. Local domain "
+                     "'%s' does not match IPA domain "
+                     "'%s'" % (self.domain_name, self.master.domain.name))
+
+    def test_upcase_client_domain(self):
+        client = self.clients[0]
+        result = client.run_command(['ipa-client-install', '-U', '--domain',
+                                     self.master.domain.name.upper(), '-w',
+                                     self.master.config.admin_password,
+                                     '-p', 'admin',
+                                     '--server', self.master.hostname,
+                                     '--force-join'], raiseonerr=False)
+        assert(result.returncode == 0), (
+            'Failed to setup client with the upcase domain name')
+        result1 = client.run_command(['ipa-replica-install', '-U', '-w',
+                                      self.master.config.dirman_password],
+                                     raiseonerr=False)
+        assert(result1.returncode == 0), (
+            'Failed to promote the client installed with the upcase domain name')

commit b8d5881ba93b00653ba42c61369f19ca27fb7a64
Author: Petr Spacek <pspacek at redhat.com>
Date:   Thu Jun 30 20:41:48 2016 +0200

    Fix internal errors in host-add and other commands caused by DNS resolution
    
    Previously resolver was returning CheckedIPAddress objects. This
    internal server error in cases where DNS actually returned reserved IP
    addresses.
    
    Now the resolver is returning UnsafeIPAddress objects which do syntactic
    checks but do not filter IP addresses.
    
    From now on we can decide if some IP address should be accepted as-is or
    if it needs to be contrained to some subset of IP addresses using
    CheckedIPAddress class.
    
    This regression was caused by changes for
    https://fedorahosted.org/freeipa/ticket/5710
    
    Reviewed-By: Martin Basti <mbasti at redhat.com>

diff --git a/ipapython/dnsutil.py b/ipapython/dnsutil.py
index aca5061..16549c8 100644
--- a/ipapython/dnsutil.py
+++ b/ipapython/dnsutil.py
@@ -24,7 +24,7 @@ import copy
 
 import six
 
-from ipapython.ipautil import CheckedIPAddress
+from ipapython.ipautil import UnsafeIPAddress
 from ipapython.ipa_log_manager import root_logger
 
 if six.PY3:
@@ -323,18 +323,12 @@ def resolve_rrsets(fqdn, rdtypes):
 def resolve_ip_addresses(fqdn):
     """Get IP addresses from DNS A/AAAA records for given host (using DNS).
     :returns:
-        list of IP addresses as CheckedIPAddress objects
+        list of IP addresses as UnsafeIPAddress objects
     """
     rrsets = resolve_rrsets(fqdn, ['A', 'AAAA'])
     ip_addresses = set()
     for rrset in rrsets:
-        ip_addresses.update({CheckedIPAddress(ip,  # accept whatever is in DNS
-                                              parse_netmask=False,
-                                              allow_network=True,
-                                              allow_loopback=True,
-                                              allow_broadcast=True,
-                                              allow_multicast=True)
-                             for ip in rrset})
+        ip_addresses.update({UnsafeIPAddress(ip) for ip in rrset})
     return ip_addresses
 
 
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index 041951d..b329cdb 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -86,102 +86,132 @@ def get_domain_name():
 
     return domain_name
 
-class CheckedIPAddress(netaddr.IPAddress):
+
+class UnsafeIPAddress(netaddr.IPAddress):
+    """Any valid IP address with or without netmask."""
 
     # Use inet_pton() rather than inet_aton() for IP address parsing. We
     # will use the same function in IPv4/IPv6 conversions + be stricter
     # and don't allow IP addresses such as '1.1.1' in the same time
     netaddr_ip_flags = netaddr.INET_PTON
 
+    def __init__(self, addr):
+        if isinstance(addr, UnsafeIPAddress):
+            self._net = addr._net
+            super(UnsafeIPAddress, self).__init__(addr,
+                                                  flags=self.netaddr_ip_flags)
+            return
+
+        elif isinstance(addr, netaddr.IPAddress):
+            self._net = None  # no information about netmask
+            super(UnsafeIPAddress, self).__init__(addr,
+                                                  flags=self.netaddr_ip_flags)
+            return
+
+        elif isinstance(addr, netaddr.IPNetwork):
+            self._net = addr
+            super(UnsafeIPAddress, self).__init__(self._net.ip,
+                                                  flags=self.netaddr_ip_flags)
+            return
+
+        # option of last resort: parse it as string
+        self._net = None
+        addr = str(addr)
+        try:
+            try:
+                addr = netaddr.IPAddress(addr, flags=self.netaddr_ip_flags)
+            except netaddr.AddrFormatError:
+                # netaddr.IPAddress doesn't handle zone indices in textual
+                # IPv6 addresses. Try removing zone index and parse the
+                # address again.
+                addr, sep, foo = addr.partition('%')
+                if sep != '%':
+                    raise
+                addr = netaddr.IPAddress(addr, flags=self.netaddr_ip_flags)
+                if addr.version != 6:
+                    raise
+        except ValueError:
+            self._net = netaddr.IPNetwork(addr, flags=self.netaddr_ip_flags)
+            addr = self._net.ip
+        super(UnsafeIPAddress, self).__init__(addr,
+                                              flags=self.netaddr_ip_flags)
+
+
+class CheckedIPAddress(UnsafeIPAddress):
+    """IPv4 or IPv6 address with additional constraints.
+
+    Reserved or link-local addresses are never accepted.
+    """
     def __init__(self, addr, match_local=False, parse_netmask=True,
                  allow_network=False, allow_loopback=False,
                  allow_broadcast=False, allow_multicast=False):
+
+        super(CheckedIPAddress, self).__init__(addr)
         if isinstance(addr, CheckedIPAddress):
-            super(CheckedIPAddress, self).__init__(addr, flags=self.netaddr_ip_flags)
             self.prefixlen = addr.prefixlen
             return
 
-        net = None
-        iface = None
-
-        if isinstance(addr, netaddr.IPNetwork):
-            net = addr
-            addr = net.ip
-        elif isinstance(addr, netaddr.IPAddress):
-            pass
-        else:
-            try:
-                try:
-                    addr = netaddr.IPAddress(str(addr), flags=self.netaddr_ip_flags)
-                except netaddr.AddrFormatError:
-                    # netaddr.IPAddress doesn't handle zone indices in textual
-                    # IPv6 addresses. Try removing zone index and parse the
-                    # address again.
-                    if not isinstance(addr, six.string_types):
-                        raise
-                    addr, sep, foo = addr.partition('%')
-                    if sep != '%':
-                        raise
-                    addr = netaddr.IPAddress(str(addr), flags=self.netaddr_ip_flags)
-                    if addr.version != 6:
-                        raise
-            except ValueError:
-                net = netaddr.IPNetwork(str(addr), flags=self.netaddr_ip_flags)
-                if not parse_netmask:
-                    raise ValueError("netmask and prefix length not allowed here")
-                addr = net.ip
+        if not parse_netmask and self._net:
+            raise ValueError(
+                "netmask and prefix length not allowed here: {}".format(addr))
 
-        if addr.version not in (4, 6):
-            raise ValueError("unsupported IP version")
+        if self.version not in (4, 6):
+            raise ValueError("unsupported IP version {}".format(self.version))
 
-        if not allow_loopback and addr.is_loopback():
-            raise ValueError("cannot use loopback IP address")
-        if (not addr.is_loopback() and addr.is_reserved()) \
-                or addr in netaddr.ip.IPV4_6TO4:
-            raise ValueError("cannot use IANA reserved IP address")
+        if not allow_loopback and self.is_loopback():
+            raise ValueError("cannot use loopback IP address {}".format(addr))
+        if (not self.is_loopback() and self.is_reserved()) \
+                or self in netaddr.ip.IPV4_6TO4:
+            raise ValueError(
+                "cannot use IANA reserved IP address {}".format(addr))
 
-        if addr.is_link_local():
-            raise ValueError("cannot use link-local IP address")
-        if not allow_multicast and addr.is_multicast():
-            raise ValueError("cannot use multicast IP address")
+        if self.is_link_local():
+            raise ValueError(
+                "cannot use link-local IP address {}".format(addr))
+        if not allow_multicast and self.is_multicast():
+            raise ValueError("cannot use multicast IP address {}".format(addr))
 
         if match_local:
-            if addr.version == 4:
+            if self.version == 4:
                 family = 'inet'
-            elif addr.version == 6:
+            elif self.version == 6:
                 family = 'inet6'
 
             result = run(
                 [paths.IP, '-family', family, '-oneline', 'address', 'show'],
                 capture_output=True)
             lines = result.output.split('\n')
+            iface = None
             for line in lines:
                 fields = line.split()
                 if len(fields) < 4:
                     continue
 
                 ifnet = netaddr.IPNetwork(fields[3])
-                if ifnet == net or (net is None and ifnet.ip == addr):
-                    net = ifnet
+                if ifnet == self._net or (self._net is None and ifnet.ip == self):
+                    self._net = ifnet
                     iface = fields[1]
                     break
 
             if iface is None:
-                raise ValueError('No network interface matches the provided IP address and netmask')
+                raise ValueError('no network interface matches the IP address '
+                                 'and netmask {}'.format(addr))
+
+        if self._net is None:
+            if self.version == 4:
+                self._net = netaddr.IPNetwork(
+                    netaddr.cidr_abbrev_to_verbose(str(self)))
+            elif self.version == 6:
+                self._net = netaddr.IPNetwork(str(self) + '/64')
 
-        if net is None:
-            if addr.version == 4:
-                net = netaddr.IPNetwork(netaddr.cidr_abbrev_to_verbose(str(addr)))
-            elif addr.version == 6:
-                net = netaddr.IPNetwork(str(addr) + '/64')
+        if not allow_network and self == self._net.network:
+            raise ValueError("cannot use IP network address {}".format(addr))
+        if not allow_broadcast and (self.version == 4 and
+                                    self == self._net.broadcast):
+            raise ValueError("cannot use broadcast IP address {}".format(addr))
 
-        if not allow_network and  addr == net.network:
-            raise ValueError("cannot use IP network address")
-        if not allow_broadcast and addr.version == 4 and addr == net.broadcast:
-            raise ValueError("cannot use broadcast IP address")
+        self.prefixlen = self._net.prefixlen
 
-        super(CheckedIPAddress, self).__init__(addr, flags=self.netaddr_ip_flags)
-        self.prefixlen = net.prefixlen
 
 def valid_ip(addr):
     return netaddr.valid_ipv4(addr) or netaddr.valid_ipv6(addr)
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index 49336a8..ec1d9de 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -450,7 +450,7 @@ def create_keytab(path, principal):
 def resolve_ip_addresses_nss(fqdn):
     """Get list of IP addresses for given host (using NSS/getaddrinfo).
     :returns:
-        list of IP addresses as CheckedIPAddress objects
+        list of IP addresses as UnsafeIPAddress objects
     """
     # make sure the name is fully qualified
     # so search path from resolv.conf does not apply
@@ -470,13 +470,7 @@ def resolve_ip_addresses_nss(fqdn):
     ip_addresses = set()
     for ai in addrinfos:
         try:
-            ip = ipautil.CheckedIPAddress(ai[4][0],
-                                          parse_netmask=False,
-                                          # these are unreliable, disable them
-                                          allow_network=True,
-                                          allow_loopback=True,
-                                          allow_broadcast=True,
-                                          allow_multicast=True)
+            ip = ipautil.UnsafeIPAddress(ai[4][0])
         except ValueError as ex:
             # getaddinfo may return link-local address other similar oddities
             # which are not accepted by CheckedIPAddress - skip these
@@ -503,8 +497,7 @@ def get_host_name(no_host_dns):
 def get_server_ip_address(host_name, unattended, setup_dns, ip_addresses):
     hostaddr = resolve_ip_addresses_nss(host_name)
     if hostaddr.intersection(
-            {ipautil.CheckedIPAddress(ip, allow_loopback=True)
-             for ip in ['127.0.0.1', '::1']}):
+            {ipautil.UnsafeIPAddress(ip) for ip in ['127.0.0.1', '::1']}):
         print("The hostname resolves to the localhost address (127.0.0.1/::1)", file=sys.stderr)
         print("Please change your /etc/hosts file so that the hostname", file=sys.stderr)
         print("resolves to the ip address of your network interface.", file=sys.stderr)

commit 0db277eb224b92319aede319999d1840db781c10
Author: Petr Spacek <pspacek at redhat.com>
Date:   Thu Jun 30 13:57:52 2016 +0200

    Remove unused is_local(), interface, and defaultnet from CheckedIPAddress
    
    All these were unused so I'm removing them to keep the code clean and
    easier to read. At this point it is clear that only difference between
    netaddr.IPAddress and CheckedIPAddress is prefixlen attribute.
    
    Reviewed-By: Martin Basti <mbasti at redhat.com>

diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index 55386ac..041951d 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -99,13 +99,10 @@ class CheckedIPAddress(netaddr.IPAddress):
         if isinstance(addr, CheckedIPAddress):
             super(CheckedIPAddress, self).__init__(addr, flags=self.netaddr_ip_flags)
             self.prefixlen = addr.prefixlen
-            self.defaultnet = addr.defaultnet
-            self.interface = addr.interface
             return
 
         net = None
         iface = None
-        defnet = False
 
         if isinstance(addr, netaddr.IPNetwork):
             net = addr
@@ -173,7 +170,6 @@ class CheckedIPAddress(netaddr.IPAddress):
                 raise ValueError('No network interface matches the provided IP address and netmask')
 
         if net is None:
-            defnet = True
             if addr.version == 4:
                 net = netaddr.IPNetwork(netaddr.cidr_abbrev_to_verbose(str(addr)))
             elif addr.version == 6:
@@ -186,11 +182,6 @@ class CheckedIPAddress(netaddr.IPAddress):
 
         super(CheckedIPAddress, self).__init__(addr, flags=self.netaddr_ip_flags)
         self.prefixlen = net.prefixlen
-        self.defaultnet = defnet
-        self.interface = iface
-
-    def is_local(self):
-        return self.interface is not None
 
 def valid_ip(addr):
     return netaddr.valid_ipv4(addr) or netaddr.valid_ipv6(addr)

commit 4edd39fb05dfd92924fc7f0c37fee3d269edf298
Author: Martin Basti <mbasti at redhat.com>
Date:   Thu Jun 30 16:00:08 2016 +0200

    Fix replica install with CA
    
    The incorrect api was used, and CA record updated was duplicated.
    
    https://fedorahosted.org/freeipa/ticket/5966
    
    Reviewed-By: Petr Spacek <pspacek at redhat.com>

diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index abd1452..0068ff3 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -1082,6 +1082,9 @@ class BindInstance(service.Service):
         self.__add_ipa_ca_record()
 
     def add_ipa_ca_dns_records(self, fqdn, domain_name, ca_configured=True):
+        if not self.api.Backend.ldap2.isconnected():
+            self.api.Backend.ldap2.connect(autobind=True)
+
         host, zone = fqdn.split(".", 1)
         if dns_zone_exists(zone, self.api):
             addrs = get_fwd_rr(zone, host, api=self.api)
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index fa92aec..3d6c1c0 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -309,7 +309,7 @@ class CAInstance(DogtagInstance):
     server_cert_name = 'Server-Cert cert-pki-ca'
 
     def __init__(self, realm=None, ra_db=None, host_name=None,
-                 dm_password=None, ldapi=True):
+                 dm_password=None, ldapi=True, api=api):
         super(CAInstance, self).__init__(
             realm=realm,
             subsystem="CA",
@@ -325,6 +325,7 @@ class CAInstance(DogtagInstance):
         self.cert_file = None
         self.cert_chain_file = None
         self.create_ra_agent_db = True
+        self.api = api
 
         if realm is not None:
             self.canickname = get_ca_nickname(realm)
@@ -1294,7 +1295,7 @@ class CAInstance(DogtagInstance):
         if bindinstance.dns_container_exists(
             api.env.host, api.env.basedn, ldapi=True, realm=api.env.realm
         ):
-            bind = bindinstance.BindInstance(ldapi=True)
+            bind = bindinstance.BindInstance(ldapi=True, api=self.api)
             bind.add_ipa_ca_dns_records(api.env.host, api.env.domain)
 
     def configure_replica(self, master_host, subject_base=None,
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index 9ed6ef4..7601ce1 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -1477,7 +1477,8 @@ def promote(installer):
 
         ca = cainstance.CAInstance(config.realm_name, certs.NSS_DIR,
                                    host_name=config.host_name,
-                                   dm_password=config.dirman_password)
+                                   dm_password=config.dirman_password,
+                                   api=remote_api)
         ca.configure_replica(config.ca_host_name,
                              subject_base=config.subject_base,
                              ca_cert_bundle=ca_data)

commit 8ce40940300e0e37191251a8a26bb8a4b5fcd604
Author: Fraser Tweedale <ftweedal at redhat.com>
Date:   Thu Jun 30 14:30:30 2016 +1000

    Move normalize_hostname to where it is expected
    
    Commit 3d71c43504ea7837ea14bb9dd4a469c07337293f broke
    ipa-client-install by importing normalize_hostname from the wrong
    module.  Move the function.
    
    https://fedorahosted.org/freeipa/ticket/5976
    
    Reviewed-By: Martin Basti <mbasti at redhat.com>

diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py
index 3fe9c5f..0bb5a53 100644
--- a/ipalib/plugins/host.py
+++ b/ipalib/plugins/host.py
@@ -44,7 +44,7 @@ from ipalib import x509
 from ipalib import output
 from ipalib.request import context
 from ipalib.util import (normalize_sshpubkey, validate_sshpubkey_no_options,
-    convert_sshpubkey_post, validate_hostname)
+    convert_sshpubkey_post, validate_hostname, normalize_hostname)
 from ipapython.ipautil import ipa_generate_password, CheckedIPAddress
 from ipapython.dnsutil import DNSName
 from ipapython.ssh import SSHPublicKey
@@ -267,14 +267,6 @@ def validate_ipaddr(ugettext, ipaddr):
     return None
 
 
-def normalize_hostname(hostname):
-    """Use common fqdn form without the trailing dot"""
-    if hostname.endswith(u'.'):
-        hostname = hostname[:-1]
-    hostname = hostname.lower()
-    return hostname
-
-
 def _hostname_validator(ugettext, value):
     try:
         validate_hostname(value)
diff --git a/ipalib/util.py b/ipalib/util.py
index 7a99149..6caf396 100644
--- a/ipalib/util.py
+++ b/ipalib/util.py
@@ -844,3 +844,11 @@ def detect_dns_zone_realm_type(api, domain):
 def has_managed_topology(api):
     domainlevel = api.Command['domainlevel_get']().get('result', DOMAIN_LEVEL_0)
     return domainlevel > DOMAIN_LEVEL_0
+
+
+def normalize_hostname(hostname):
+    """Use common fqdn form without the trailing dot"""
+    if hostname.endswith(u'.'):
+        hostname = hostname[:-1]
+    hostname = hostname.lower()
+    return hostname

commit 4ce0ff61a8e46de4a2f2dfca41610323f9569d8a
Author: Florence Blanc-Renaud <frenaud at redhat.com>
Date:   Mon Jun 27 10:23:14 2016 +0200

    Do not allow installation in FIPS mode
    
    https://fedorahosted.org/freeipa/ticket/5761
    
    Reviewed-By: Martin Basti <mbasti at redhat.com>
    Reviewed-By: Rob Crittenden <rcritten at redhat.com>

diff --git a/client/ipa-client-install b/client/ipa-client-install
index b900eca..088e794 100755
--- a/client/ipa-client-install
+++ b/client/ipa-client-install
@@ -45,7 +45,7 @@ try:
     import ipaclient.ntpconf
     from ipapython.ipautil import (
         run, user_input, CalledProcessError, file_exists, dir_exists,
-        realm_to_suffix)
+        realm_to_suffix, is_fips_enabled)
     from ipaplatform.tasks import tasks
     from ipaplatform import services
     from ipaplatform.paths import paths
@@ -3064,6 +3064,9 @@ def main():
 
     if not os.getegid() == 0:
         sys.exit("\nYou must be root to run ipa-client-install.\n")
+    if is_fips_enabled():
+        sys.exit("Installing IPA client in FIPS mode is not supported")
+
     tasks.check_selinux_status()
     logging_setup(options)
     root_logger.debug(
diff --git a/install/tools/ipactl b/install/tools/ipactl
index 9c2d5b2..51d9ff8 100755
--- a/install/tools/ipactl
+++ b/install/tools/ipactl
@@ -31,7 +31,8 @@ from ipaserver.install.dsinstance import config_dirname
 from ipaserver.install.installutils import is_ipa_configured, ScriptError
 from ipalib import api, errors
 from ipapython.ipaldap import IPAdmin
-from ipapython.ipautil import wait_for_open_ports, wait_for_open_socket
+from ipapython.ipautil import (
+    wait_for_open_ports, wait_for_open_socket, is_fips_enabled)
 from ipapython import config, dogtag
 from ipaplatform.tasks import tasks
 from ipapython.dn import DN
@@ -537,6 +538,9 @@ def main():
     elif args[0] != "start" and args[0] != "stop" and args[0] != "restart" and args[0] != "status":
         raise IpactlError("Unrecognized action [" + args[0] + "]", 2)
 
+    if is_fips_enabled():
+        raise IpactlError("Starting IPA server in FIPS mode is not supported")
+
     # check if IPA is configured at all
     try:
         check_IPA_configuration()
diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
index 6b0ec9b..c005cd3 100644
--- a/ipaplatform/base/paths.py
+++ b/ipaplatform/base/paths.py
@@ -133,6 +133,7 @@ class BasePathNamespace(object):
     SYSTEMD_PKI_TOMCAT_SERVICE = "/etc/systemd/system/pki-tomcatd.target.wants/pki-tomcatd at pki-tomcat.service"
     DNSSEC_TRUSTED_KEY = "/etc/trusted-key.key"
     HOME_DIR = "/home"
+    PROC_FIPS_ENABLED = "/proc/sys/crypto/fips_enabled"
     ROOT_IPA_CACHE = "/root/.ipa_cache"
     ROOT_PKI = "/root/.pki"
     DOGTAG_ADMIN_P12 = "/root/ca-agent.p12"
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index 7740986..55386ac 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -1452,3 +1452,22 @@ if six.PY2:
                 type(value).__name__))
 else:
     fsdecode = os.fsdecode  #pylint: disable=no-member
+
+
+def is_fips_enabled():
+    """
+    Checks whether this host is FIPS-enabled.
+
+    Returns a boolean indicating if the host is FIPS-enabled, i.e. if the
+    file /proc/sys/crypto/fips_enabled contains a non-0 value. Otherwise,
+    or if the file /proc/sys/crypto/fips_enabled does not exist,
+    the function returns False.
+    """
+    try:
+        with open(paths.PROC_FIPS_ENABLED, 'r') as f:
+            if f.read().strip() != '0':
+                return True
+    except IOError:
+        # Consider that the host is not fips-enabled if the file does not exist
+        pass
+    return False
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
index 6c906c9..056a6a9 100644
--- a/ipaserver/install/server/install.py
+++ b/ipaserver/install/server/install.py
@@ -23,7 +23,8 @@ from ipapython.install.common import step
 from ipapython.install.core import Knob
 from ipapython.ipa_log_manager import root_logger
 from ipapython.ipautil import (
-    decrypt_file, format_netloc, ipa_generate_password, run, user_input)
+    decrypt_file, format_netloc, ipa_generate_password, run, user_input,
+    is_fips_enabled)
 from ipaplatform import services
 from ipaplatform.paths import paths
 from ipaplatform.tasks import tasks
@@ -437,6 +438,10 @@ def install_check(installer):
     external_ca_file = installer._external_ca_file
     http_ca_cert = installer._ca_cert
 
+    if is_fips_enabled():
+        raise RuntimeError(
+            "Installing IPA server in FIPS mode is not supported")
+
     tasks.check_selinux_status()
 
     if options.master_password:
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index fa23fe8..9ed6ef4 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -497,6 +497,10 @@ def install_check(installer):
     options = installer
     filename = installer.replica_file
 
+    if ipautil.is_fips_enabled():
+        raise RuntimeError(
+            "Installing IPA server in FIPS mode is not supported")
+
     tasks.check_selinux_status()
 
     if is_ipa_configured():

commit ced5124508a47415b3ff86159eb55b96f57bb29a
Author: Petr Spacek <pspacek at redhat.com>
Date:   Tue Jun 28 18:18:01 2016 +0200

    DNS: Remove unnecessary DNS check from installer
    
    Previously we were checking content of DNS before actually adding DNS
    records for replicas. This is causing cycle in logic and adds weird
    corner cases to the installer which can blow up on DNS timeout or so.
    
    The check was completely unnecessary because the installer knows IP
    addresses and name of the machine. Removal of the check makes
    the installer more reliable.
    
    https://fedorahosted.org/freeipa/ticket/5962
    
    Reviewed-By: Martin Basti <mbasti at redhat.com>

diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index efabab1..abd1452 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -50,7 +50,7 @@ from ipalib.util import (validate_zonemgr_str, normalize_zonemgr,
                          normalize_zone, get_reverse_zone_default,
                          zone_is_reverse, validate_dnssec_global_forwarder,
                          DNSSECSignatureMissingError, EDNS0UnsupportedError,
-                         UnresolvableRecordError, verify_host_resolvable)
+                         UnresolvableRecordError)
 from ipalib.constants import CACERT
 
 if six.PY3:
@@ -877,14 +877,6 @@ class BindInstance(service.Service):
             add_rr(self.domain, rname, "SRV", rdata, self.dns_backup,
                    api=self.api)
 
-        if not dns_zone_exists(zone, self.api):
-            # check if master hostname is resolvable
-            try:
-                verify_host_resolvable(fqdn)
-            except errors.DNSNotARecordError:
-                root_logger.warning("Master FQDN (%s) is not resolvable.",
-                                    fqdn)
-
         # Add forward and reverse records to self
         for addr in addrs:
             try:

commit dc7413234361eed1a63d78c9ac932a38b53d838b
Author: Petr Spacek <pspacek at redhat.com>
Date:   Tue Jun 28 13:53:58 2016 +0200

    Use NSS for name->resolution in IPA installer
    
    This fixes scenarios where IPA server is not able to resolve own name
    and option --ip-address was not specified by the user.
    
    This partially reverts changes from commit
    dc405005f537cf278fd6ddfe6b87060bd13d9a67
    
    https://fedorahosted.org/freeipa/ticket/5962
    
    Reviewed-By: Martin Basti <mbasti at redhat.com>

diff --git a/ipapython/dnsutil.py b/ipapython/dnsutil.py
index 6aa0e07..aca5061 100644
--- a/ipapython/dnsutil.py
+++ b/ipapython/dnsutil.py
@@ -321,7 +321,7 @@ def resolve_rrsets(fqdn, rdtypes):
 
 
 def resolve_ip_addresses(fqdn):
-    """Get IP addresses from DNS A/AAAA records for given host.
+    """Get IP addresses from DNS A/AAAA records for given host (using DNS).
     :returns:
         list of IP addresses as CheckedIPAddress objects
     """
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index 3e6e26c..efabab1 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -910,9 +910,7 @@ class BindInstance(service.Service):
             if fqdn == self.fqdn:
                 continue
 
-            addrs = dnsutil.resolve_ip_addresses(fqdn)
-            # hack, will go away with locations
-            addrs = [str(addr) for addr in addrs]
+            addrs = installutils.resolve_ip_addresses_nss(fqdn)
 
             root_logger.debug("Adding DNS records for master %s" % fqdn)
             self.__add_master_records(fqdn, addrs)
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index baa0d3d..49336a8 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -447,6 +447,46 @@ def create_keytab(path, principal):
 
     kadmin("ktadd -k " + path + " " + principal)
 
+def resolve_ip_addresses_nss(fqdn):
+    """Get list of IP addresses for given host (using NSS/getaddrinfo).
+    :returns:
+        list of IP addresses as CheckedIPAddress objects
+    """
+    # make sure the name is fully qualified
+    # so search path from resolv.conf does not apply
+    fqdn = str(dnsutil.DNSName(fqdn).make_absolute())
+    try:
+        addrinfos = socket.getaddrinfo(fqdn, None,
+                                       socket.AF_UNSPEC, socket.SOCK_STREAM)
+    except socket.error as ex:
+        if ex.errno == socket.EAI_NODATA or ex.errno == socket.EAI_NONAME:
+            root_logger.debug('Name %s does not have any address: %s',
+                              fqdn, ex)
+            return set()
+        else:
+            raise
+
+    # accept whatever we got from NSS
+    ip_addresses = set()
+    for ai in addrinfos:
+        try:
+            ip = ipautil.CheckedIPAddress(ai[4][0],
+                                          parse_netmask=False,
+                                          # these are unreliable, disable them
+                                          allow_network=True,
+                                          allow_loopback=True,
+                                          allow_broadcast=True,
+                                          allow_multicast=True)
+        except ValueError as ex:
+            # getaddinfo may return link-local address other similar oddities
+            # which are not accepted by CheckedIPAddress - skip these
+            root_logger.warning('Name %s resolved to an unacceptable IP '
+                                'address %s: %s', fqdn, ai[4][0], ex)



More information about the Pkg-freeipa-devel mailing list