When installing the client, we need to take extra case to only contact the one server we're installing against. Otherwise, in the real world, we might hit a server that hasn't replicated info about the client yet.

This patch fixes a bug where kinit attempted to contact a KDC that didn't have the host principal yet.


To reproduce:

- Install a "master" and "replica"
- Change the Kerberos DNS entries to only point to the replica:
for REC_NAME in '_kerberos-master._tcp' '_kerberos-master._udp' '_kerberos._tcp' '_kerberos._udp' '_kpasswd._tcp' '_kpasswd._udp'; do ipa dnsrecord-mod $DOMAIN $REC_NAME --srv-rec="0 100 88 $REPLICA_HOSTNAME"
    done
ipa dnsrecord-mod $DOMAIN _ldap._tcp --srv-rec="0 100 389 $MASTER_HOSTNAME"
    ipa dnsrecord-find $DOMAIN  # check
- Sever communication between the hosts to disable replication:
    (on master)
    iptables -A INPUT -j DROP -p all --source $REPLICA_IP
- On client machine, put master as nameserver in /etc/resolv.conf & install client

This will fail without the patch.


Thanks to Petr Spacek, Simo, and Scott for helping to reproduce and explain the bug. I learned a lot.

https://fedorahosted.org/freeipa/ticket/2982

--
PetrĀ³
From a552f6f42035908c8f0774065575e14c8b135648 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pvikt...@redhat.com>
Date: Thu, 6 Sep 2012 03:52:20 -0400
Subject: [PATCH] ipa-client-install: Obtain host TGT from one specific KDC

When clients install, they use kinit to obtain a TGT, which uses DNS to find
the KDC to connect to. It might happen that the newly created principal
has not replicated to selected KDC yet, making kinit fail and aborting the
install.

The client sets a temporary krb5 config file while installing via $KRB5_CONFIG.
Modify this file so that the kerberos library only uses the specific server
we're installing under, and call kinit while it's still in place.

Clean up the configure_krb5_conf function to remove unused arguments. For
clarity, use keyword arguments when calling it.

https://fedorahosted.org/freeipa/ticket/2982
---
 ipa-client/ipa-install/ipa-client-install | 54 ++++++++++++++++++++++---------
 1 file changed, 39 insertions(+), 15 deletions(-)

diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install
index d87fcc2a662b73c8ff269b65437d7d3023509b62..053305f780c87cbe233eb896c55886ecad539067 100755
--- a/ipa-client/ipa-install/ipa-client-install
+++ b/ipa-client/ipa-install/ipa-client-install
@@ -639,7 +639,8 @@ def hardcode_ldap_server(cli_server):
 
     return
 
-def configure_krb5_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server, cli_kdc, dnsok, options, filename, client_domain):
+def configure_krb5_conf(cli_realm, cli_domain, cli_server, cli_kdc, dnsok,
+        options, filename, client_domain):
 
     krbconf = ipaclient.ipachangeconf.IPAChangeConf("IPA Installer")
     krbconf.setOptionAssignment(" = ")
@@ -1431,7 +1432,15 @@ def install(options, env, fstore, statestore):
                     "server, assuming the time is in sync.")
             (krb_fd, krb_name) = tempfile.mkstemp()
             os.close(krb_fd)
-            if configure_krb5_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server, cli_kdc, dnsok, options, krb_name, client_domain):
+            if configure_krb5_conf(
+                    cli_realm=cli_realm,
+                    cli_domain=cli_domain,
+                    cli_server=cli_server,
+                    cli_kdc=cli_kdc,
+                    dnsok=False,
+                    options=options,
+                    filename=krb_name,
+                    client_domain=client_domain):
                 root_logger.error("Test kerberos configuration failed")
                 return CLIENT_INSTALL_ERROR
             env['KRB5_CONFIG'] = krb_name
@@ -1514,9 +1523,25 @@ def install(options, env, fstore, statestore):
                 subject_base = subject_base.strip()
                 subject_base = DN(subject_base)
 
-        finally:
             if options.principal is not None:
-                (stderr, stdout, returncode) = run(["kdestroy"], raiseonerr=False, env=env)
+                stderr, stdout, returncode = run(
+                        ["kdestroy"], raiseonerr=False, env=env)
+
+            # Obtain the TGT. We do it with the temporary krb5.conf, so that
+            # only the KDC we're installing under is contacted.
+            # Other KDCs might not have replicated the principal yet.
+            # Once we have the TGT, it's usable on any server.
+            env['KRB5CCNAME'] = os.environ['KRB5CCNAME'] = CCACHE_FILE
+            try:
+                run(['/usr/bin/kinit', '-k', '-t', '/etc/krb5.keytab',
+                        'host/%s@%s' % (hostname, cli_realm)], env=env)
+            except CalledProcessError, e:
+                root_logger.error("Failed to obtain host TGT.")
+                # failure to get ticket makes it impossible to login and bind
+                # from sssd to LDAP, abort installation and rollback changes
+                return CLIENT_INSTALL_ERROR
+
+        finally:
             try:
                 os.remove(krb_name)
             except OSError:
@@ -1555,22 +1580,21 @@ def install(options, env, fstore, statestore):
     if not options.on_master:
         # Configure krb5.conf
         fstore.backup_file("/etc/krb5.conf")
-        if configure_krb5_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server, cli_kdc, dnsok, options, "/etc/krb5.conf", client_domain):
+        if configure_krb5_conf(
+                cli_realm=cli_realm,
+                cli_domain=cli_domain,
+                cli_server=cli_server,
+                cli_kdc=cli_kdc,
+                dnsok=dnsok,
+                options=options,
+                filename="/etc/krb5.conf",
+                client_domain=client_domain):
             return CLIENT_INSTALL_ERROR
 
         root_logger.info(
             "Configured /etc/krb5.conf for IPA realm %s", cli_realm)
 
-    os.environ['KRB5CCNAME'] = CCACHE_FILE
-    try:
-        ipautil.run(['/usr/bin/kinit', '-k', '-t', '/etc/krb5.keytab', 'host/%s@%s' % (hostname, cli_realm)])
-    except CalledProcessError, e:
-        root_logger.error("Failed to obtain host TGT.")
-        # fail to obtain ticket makes it impossible to login and bind from sssd to LDAP,
-        # abort installation and rollback changes
-        return CLIENT_INSTALL_ERROR
-
-    # Now, we have a TGT, lets try to connect to the server's XML-RPC interface
+    # Now, let's try to connect to the server's XML-RPC interface
     try:
         api.Backend.xmlclient.connect()
     except errors.KerberosError, e:
-- 
1.7.11.4

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to