On Thu 07 Mar 2013 11:01:33 PM CET, Rob Crittenden wrote:
Petr Viktorin wrote:
On 03/07/2013 04:27 PM, Tomas Babej wrote:
On 03/07/2013 04:12 PM, Petr Viktorin wrote:
Thanks! I just have two more very minor nitpicks.

On 03/06/2013 01:04 PM, Tomas Babej wrote:
On 03/05/2013 02:10 PM, Petr Viktorin wrote:
Thanks! The mechanism works, but see below.

This is a RFE so it needs a design document.

http://freeipa.org/page/V3/Client_install_using_keytab

Please also add the link to the commit message.


I think you answered PetrĀ²'s security questions adequately.
Petr, note that this is a client-side change; if the keytab is
compromised the attacker can do all this manually anyway.

diff --git a/ipa-client/ipa-install/ipa-client-install
b/ipa-client/ipa-install/ipa-client-install
index
308c3f8d0ec39e1e7f048d37a34738bf6a4853e2..a16a6b2d7cddbf7085b27c3835a4676919a8a15b


100755
--- a/ipa-client/ipa-install/ipa-client-install
+++ b/ipa-client/ipa-install/ipa-client-install
@@ -104,6 +104,8 @@ def parse_options():
[...]
@@ -1691,8 +1693,12 @@ def install(options, env, fstore, statestore):
          except ipaclient.ntpconf.NTPConfigurationError:
              pass

-    if options.unattended and (options.password is None and
options.principal is None and options.prompt_password is False) and
not options.on_master:
-        root_logger.error("One of password and principal are
required.")
+    if options.unattended and ((options.password is None and
+                                options.principal is None and
+                                options.keytab is None and
+                                options.prompt_password is False)\
+                                and not options.on_master):

Please also remove the inner parentheses and the backslash.

Both fixed, updated patch attached.

Tomas

ACK, thanks!


This needs related man page updates before we can push it.


Man pages updated:

[tbabej@thinkpad7 freeipa]$ git diff
diff --git a/ipa-client/man/ipa-client-install.1 b/ipa-client/man/ipa-client-ins
[...]
+\fB\-k\fR, \fB\-\-keytab\fR
+Path to backed up host keytab from previous enrollment.
+.TP
[...]
diff --git a/ipa-client/man/ipa-join.1 b/ipa-client/man/ipa-join.1
[...]
+\fB\-f,\-\-force\fR
+Force enrolling the host even if host entry exists.
+.TP

Can you update the design to specifically include that the old
certificate needs to be revoked, not just that a new certificate be
issued (sort of implied, and it worked in my testing)?

I updated the design page accordingly. However, shouldn't be this handled by server side automatically?

rob

Updated patch attached.
>From 73f533075321520fb94218641e1d45533cdfa9f3 Mon Sep 17 00:00:00 2001
From: Tomas Babej <tba...@redhat.com>
Date: Tue, 26 Feb 2013 13:20:13 +0100
Subject: [PATCH] Add support for re-enrolling hosts using keytab

A host that has been recreated  and does not have its
host entry disabled or removed, can be re-enrolled using
a previously backed up keytab file.

A new option --keytab has been added to ipa-client-install. This
can be used to specify path to the keytab and can be used instead
of -p or -w options.

A new option -f has been added to ipa-join. It forces client to
join even if the host entry already exits. A new certificate,
ssh keys are generated, ipaUniqueID stays the same.

Design page: http://freeipa.org/page/V3/Client_install_using_keytab

https://fedorahosted.org/freeipa/ticket/3374
---
 ipa-client/ipa-install/ipa-client-install | 40 +++++++++++++++++++++++++++----
 ipa-client/ipa-join.c                     | 14 +++++++----
 ipa-client/man/ipa-client-install.1       |  3 +++
 ipa-client/man/ipa-join.1                 |  3 +++
 4 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install
index 308c3f8d0ec39e1e7f048d37a34738bf6a4853e2..bd458ed09856dfccd161b1dc96f4b1e0ec7f7e40 100755
--- a/ipa-client/ipa-install/ipa-client-install
+++ b/ipa-client/ipa-install/ipa-client-install
@@ -104,6 +104,8 @@ def parse_options():
                       help="principal to use to join the IPA realm"),
     basic_group.add_option("-w", "--password", dest="password", sensitive=True,
                       help="password to join the IPA realm (assumes bulk password unless principal is also set)"),
+    basic_group.add_option("-k", "--keytab", dest="keytab",
+                      help="path to backed up keytab from previous enrollment"),
     basic_group.add_option("-W", dest="prompt_password", action="store_true",
                       default=False,
                       help="Prompt for a password to join the IPA realm"),
@@ -1691,8 +1693,12 @@ def install(options, env, fstore, statestore):
         except ipaclient.ntpconf.NTPConfigurationError:
             pass
 
-    if options.unattended and (options.password is None and options.principal is None and options.prompt_password is False) and not options.on_master:
-        root_logger.error("One of password and principal are required.")
+    if options.unattended and (options.password is None and
+                               options.principal is None and
+                               options.keytab is None and
+                               options.prompt_password is False and
+                               not options.on_master):
+        root_logger.error("One of password / principal / keytab is required.")
         return CLIENT_INSTALL_ERROR
 
     if options.hostname:
@@ -1910,8 +1916,10 @@ def install(options, env, fstore, statestore):
         ipaservices.backup_and_replace_hostname(fstore, statestore, options.hostname)
 
     if not options.unattended:
-        if options.principal is None and options.password is None and options.prompt_password is False:
-            options.principal = user_input("User authorized to enroll computers", allow_empty=False)
+        if (options.principal is None and options.password is None and
+                options.prompt_password is False and options.keytab is None):
+            options.principal = user_input("User authorized to enroll "
+                                           "computers", allow_empty=False)
             root_logger.debug(
                 "will use principal provided as option: %s", options.principal)
 
@@ -1985,12 +1993,34 @@ def install(options, env, fstore, statestore):
                         else:
                             stdin = sys.stdin.readline()
 
-                (stderr, stdout, returncode) = run(["kinit", principal], raiseonerr=False, stdin=stdin, env=env)
+                (stderr, stdout, returncode) = run(["kinit", principal],
+                                                    raiseonerr=False,
+                                                    stdin=stdin,
+                                                    env=env)
                 if returncode != 0:
                     root_logger.error("Kerberos authentication failed")
                     root_logger.info("%s", stdout)
                     print_port_conf_info()
                     return CLIENT_INSTALL_ERROR
+            elif options.keytab:
+                join_args.append("-f")
+                if os.path.exists(options.keytab):
+                    (stderr, stdout, returncode) = run(
+                        ['/usr/bin/kinit','-k', '-t', options.keytab,
+                            'host/%s@%s' % (hostname, cli_realm)],
+                        env=env,
+                        raiseonerr=False)
+
+                    if returncode != 0:
+                        root_logger.error("Kerberos authentication failed "
+                                          "using keytab: %s", options.keytab)
+                        root_logger.info("%s", stdout)
+                        print_port_conf_info()
+                        return CLIENT_INSTALL_ERROR
+                else:
+                    root_logger.error("Keytab file could not be found: %s"
+                                      % options.keytab)
+                    return CLIENT_INSTALL_ERROR
             elif options.password:
                 nolog = (options.password,)
                 join_args.append("-w")
diff --git a/ipa-client/ipa-join.c b/ipa-client/ipa-join.c
index 8369e360f90dfc4ade1db792745b660da50677ca..df33d3b08cf69a37ae9de76266a071825a95871f 100644
--- a/ipa-client/ipa-join.c
+++ b/ipa-client/ipa-join.c
@@ -558,7 +558,7 @@ done:
 }
 
 static int
-join_krb5(const char *ipaserver, char *hostname, char **hostdn, const char **princ, const char **subject, int quiet) {
+join_krb5(const char *ipaserver, char *hostname, char **hostdn, const char **princ, const char **subject, int force, int quiet) {
     xmlrpc_env env;
     xmlrpc_value * argArrayP = NULL;
     xmlrpc_value * paramArrayP = NULL;
@@ -663,7 +663,7 @@ join_krb5(const char *ipaserver, char *hostname, char **hostdn, const char **pri
         goto cleanup;
     }
     xmlrpc_struct_find_value(&env, structP, "krblastpwdchange", &krblastpwdchangeP);
-    if (krblastpwdchangeP) {
+    if (krblastpwdchangeP && !force) {
         xmlrpc_value * singleprincP = NULL;
 
         /* FIXME: all values are returned as lists currently. Once this is
@@ -929,7 +929,7 @@ cleanup:
 
 
 static int
-join(const char *server, const char *hostname, const char *bindpw, const char *basedn, const char *keytab, int quiet)
+join(const char *server, const char *hostname, const char *bindpw, const char *basedn, const char *keytab, int force, int quiet)
 {
     int rval = 0;
     pid_t childpid = 0;
@@ -1003,7 +1003,8 @@ join(const char *server, const char *hostname, const char *bindpw, const char *b
             rval = 6;
             goto cleanup;
         }
-        rval = join_krb5(ipaserver, host, &hostdn, &princ, &subject, quiet);
+        rval = join_krb5(ipaserver, host, &hostdn, &princ, &subject, force,
+                         quiet);
     }
 
     if (rval) goto cleanup;
@@ -1100,6 +1101,7 @@ main(int argc, const char **argv) {
     static const char *basedn = NULL;
     int quiet = 0;
     int unenroll = 0;
+    int force = 0;
     struct poptOption options[] = {
         { "debug", 'd', POPT_ARG_NONE, &debug, 0,
           _("Print the raw XML-RPC output in GSSAPI mode"), NULL },
@@ -1113,6 +1115,8 @@ main(int argc, const char **argv) {
           _("IPA Server to use"), _("hostname") },
         { "keytab", 'k', POPT_ARG_STRING, &keytab, 0,
           _("Specifies where to store keytab information."), _("filename") },
+        { "force", 'f', POPT_ARG_NONE, &force, 0,
+          _("Force the host join. Rejoin even if already joined."), NULL },
         { "bindpw", 'w', POPT_ARG_STRING, &bindpw, 0,
           _("LDAP password (if not using Kerberos)"), _("password") },
         { "basedn", 'b', POPT_ARG_STRING, &basedn, 0,
@@ -1149,7 +1153,7 @@ main(int argc, const char **argv) {
     } else {
         ret = check_perms(keytab);
         if (ret == 0)
-            ret = join(server, hostname, bindpw, basedn, keytab, quiet);
+            ret = join(server, hostname, bindpw, basedn, keytab, force, quiet);
     }
 
     exit(ret);
diff --git a/ipa-client/man/ipa-client-install.1 b/ipa-client/man/ipa-client-install.1
index 2990b6694de9acc0780d3afe21ae7766c57d0b41..8a77a113a58556c39f401f9079cff35d273c1e4a 100644
--- a/ipa-client/man/ipa-client-install.1
+++ b/ipa-client/man/ipa-client-install.1
@@ -76,6 +76,9 @@ Password for joining a machine to the IPA realm. Assumes bulk password unless pr
 \fB\-W\fR
 Prompt for the password for joining a machine to the IPA realm.
 .TP
+\fB\-k\fR, \fB\-\-keytab\fR
+Path to backed up host keytab from previous enrollment.
+.TP
 \fB\-\-mkhomedir\fR
 Configure PAM to create a users home directory if it does not exist.
 .TP
diff --git a/ipa-client/man/ipa-join.1 b/ipa-client/man/ipa-join.1
index bd33b16cc7cdd12173875b18b78c75d5f71a3069..5dd4004b36c096bbccf1cd966e3f189fa2e356ca 100644
--- a/ipa-client/man/ipa-join.1
+++ b/ipa-client/man/ipa-join.1
@@ -64,6 +64,9 @@ The password to use if not using Kerberos to authenticate. Use a password of thi
 \fB\-b,\-\-basedn basedn\fR
 The basedn of the IPA server (of the form dc=example,dc=com). This is only needed when not using Kerberos to authenticate and anonymous binds are disallowed in the IPA LDAP server.
 .TP
+\fB\-f,\-\-force\fR
+Force enrolling the host even if host entry exists.
+.TP
 \fB\-u,\-\-unenroll\fR
 Unenroll this host from the IPA server. No keytab entry is removed in the process
 (see
-- 
1.7.11.7

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

Reply via email to