Hi,

please, review the attached patch which adds --ssh-update to ipa-client-
install.

Ticket: https://fedorahosted.org/freeipa/ticket/2655

---
Martin

From 4974a57f48a0cd48b83724297ae2af572bc530eb Mon Sep 17 00:00:00 2001
From: Martin Stefany <martin stefany eu>
Date: Mon, 22 Feb 2016 20:58:13 +0000
Subject: [PATCH] Add new parameter --ssh-update to ipa-client-install

Add a new parameter '--ssh-update' which can be used later after freeipa
client is installed to update SSH hostkeys and SSHFP DNS records for
host.

https://fedorahosted.org/freeipa/ticket/2655
---
 ipa-client/ipa-install/ipa-client-install | 102
+++++++++++++++++++++++++++++-
 1 file changed, 99 insertions(+), 3 deletions(-)

diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-
install/ipa-client-install
index
789ff591591673744ee3b922e5c0181233ad553c..97adfb6b449fb441bddada89a3b151
33e398ca50 100755
--- a/ipa-client/ipa-install/ipa-client-install
+++ b/ipa-client/ipa-install/ipa-client-install
@@ -71,6 +71,7 @@ CLIENT_INSTALL_ERROR = 1
 CLIENT_NOT_CONFIGURED = 2
 CLIENT_ALREADY_CONFIGURED = 3
 CLIENT_UNINSTALL_ERROR = 4 # error after restoring files/state
+CLIENT_SSHUPDATE_ERROR = 5 # error during update of SSH public keys
 
 def parse_options():
     def validate_ca_cert_file_option(option, opt, value, parser):
@@ -215,6 +216,12 @@ def parse_options():
                                           "be run with --unattended
option")
     parser.add_option_group(uninstall_group)
 
+    sshupdate_group = OptionGroup(parser, "SSH key update options")
+    sshupdate_group.add_option("--ssh-update", dest="ssh_update",
+                      action="store_true", default=False,
+                      help="update local host's SSH public keys in host
entry and DNS.")
+    parser.add_option_group(sshupdate_group)
+
     options, args = parser.parse_args()
     safe_opts = parser.get_safe_opts(options)
 
@@ -840,6 +847,92 @@ def uninstall(options, env):
 
     return rv
 
+def sshupdate(options, env):
+    if not is_ipa_client_installed():
+        root_logger.error("IPA client is not configured on this
system.")
+        return CLIENT_NOT_CONFIGURED
+
+    api.bootstrap(context='cli_installer', debug=options.debug)
+    api.finalize()
+    if 'config_loaded' not in api.env:
+        root_logger.error("Failed to initialize IPA API.")
+        return CLIENT_SSHUPDATE_ERROR
+
+    # Now, let's try to connect to the server's RPC interface
+    connected = False
+    try:
+        api.Backend.rpcclient.connect()
+        connected = True
+        root_logger.debug("Try RPC connection")
+        api.Backend.rpcclient.forward('ping')
+    except errors.KerberosError as e:
+        if connected:
+            api.Backend.rpcclient.disconnect()
+        root_logger.info(
+            "Cannot connect to the server due to Kerberos error: %s. "
+            "Trying with delegate=True", e)
+        try:
+            api.Backend.rpcclient.connect(delegate=True)
+            root_logger.debug("Try RPC connection")
+            api.Backend.rpcclient.forward('ping')
+
+            root_logger.info("Connection with delegate=True
successful")
+
+            # The remote server is not capable of Kerberos S4U2Proxy
+            # delegation. This features is implemented in IPA server
+            # version 2.2 and higher
+            root_logger.warning(
+                "Target IPA server has a lower version than the
enrolled "
+                "client")
+            root_logger.warning(
+                "Some capabilities including the ipa command capability
"
+                "may not be available")
+        except errors.PublicError as e2:
+            root_logger.warning(
+                "Second connect with delegate=True also failed: %s",
e2)
+            root_logger.error(
+                "Cannot connect to the IPA server RPC interface: %s",
e2)
+            return CLIENT_SSHUPDATE_ERROR
+    except errors.PublicError as e:
+        root_logger.error(
+            "Cannot connect to the server due to generic error: %s", e)
+        return CLIENT_SSHUPDATE_ERROR
+
+    # We need to pull IPA server address from default.conf
+    try:
+        parser = RawConfigParser()
+        parser.read(paths.IPA_DEFAULT_CONF)
+        cli_realm = parser.get('global', 'realm')
+        hostname = parser.get('global', 'host')
+    # TODO: consult with review team
+    # except ConfigParser.NoSectionError as e:
+    #     pass
+    # except ConfigParser.ParsingError as e:
+    #     pass
+    finally:
+        pass
+
+    host_principal = 'host/%s@%s' % (hostname, cli_realm)
+    # 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.
+    try:
+        ipautil.kinit_keytab(host_principal, paths.KRB5_KEYTAB,
+                             CCACHE_FILE,
+                             # config=krb_name,
+                             attempts=options.kinit_attempts)
+        env['KRB5CCNAME'] = os.environ['KRB5CCNAME'] = CCACHE_FILE
+    except Krb5Error as e:
+        print_port_conf_info()
+        root_logger.error("Failed to obtain host TGT: %s" % e)
+        # failure to get ticket makes it impossible to login and bind
+        # from sssd to LDAP, abort installation and rollback changes
+        return CLIENT_INSTALL_ERROR
+
+    # passing server parameter seems unneccessary, thus passing only ""
+    update_ssh_keys("", hostname,
services.knownservices.sshd.get_config_dir(), options.create_sshfp)
+
 def configure_ipa_conf(fstore, cli_basedn, cli_realm, cli_domain,
cli_server, hostname):
     ipaconf = ipaclient.ipachangeconf.IPAChangeConf("IPA Installer")
     ipaconf.setOptionAssignment(" = ")
@@ -2797,7 +2890,7 @@ def install(options, env, fstore, statestore):
             connected = True
             root_logger.debug("Try RPC connection")
             api.Backend.rpcclient.forward('ping')
-        except errors.KerberosError, e:
+        except errors.KerberosError as e:
             if connected:
                 api.Backend.rpcclient.disconnect()
             root_logger.info(
@@ -2820,13 +2913,13 @@ def install(options, env, fstore, statestore):
                 root_logger.warning(
                     "Some capabilities including the ipa command
capability "
                     "may not be available")
-            except errors.PublicError, e2:
+            except errors.PublicError as e2:
                 root_logger.warning(
                     "Second connect with delegate=True also failed:
%s", e2)
                 root_logger.error(
                     "Cannot connect to the IPA server RPC interface:
%s", e2)
                 return CLIENT_INSTALL_ERROR
-        except errors.PublicError, e:
+        except errors.PublicError as e:
             root_logger.error(
                 "Cannot connect to the server due to generic error:
%s", e)
             return CLIENT_INSTALL_ERROR
@@ -3088,6 +3181,9 @@ def main():
     if options.uninstall:
         return uninstall(options, env)
 
+    if options.ssh_update:
+        return sshupdate(options, env)
+
     if is_ipa_client_installed(on_master=options.on_master):
         root_logger.error("IPA client is already configured on this
system.")
         root_logger.info(
-- 
1.8.3.1

Attachment: signature.asc
Description: This is a digitally signed message part

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to