Unenroll a host when a client is uninstalled. This means we bind using the host credentials and disable our own keytab. This will let the client be re-enrolled without requiring admin input (used to have to either delete the host or disable the keytab as admin).

I also did some other cleanup in ipa-join and added a fair bit of info to the ipa-getkeytab and ipa-join man pages.

rob
>From 1f4e07bc8665a2e02aaee726c86658d6b2f3f9a2 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Fri, 17 Sep 2010 21:37:32 -0400
Subject: [PATCH] Unenroll the client from the IPA server on uninstall.

Unenrollment means that the host keytab is disabled on the server making
it possible to re-install on the client. This host principal is how we
distinguish an enrolled vs an unenrolled client machine on the server.

I added a --unroll option to ipa-join that binds using the host credentials
and disables its own keytab.

I fixed a couple of other unrelated problems in ipa-join at the same time.

I also documented all the possible return values of ipa-getkeytab and
ipa-join. There is so much overlap because ipa-join calls ipa-getkeytab
and it returns whatever value ipa-getkeytab returned on failure.

ticket 242
---
 install/share/default-aci.ldif            |    3 +-
 ipa-client/ipa-install/ipa-client-install |   10 +-
 ipa-client/ipa-join.c                     |  256 ++++++++++++++++++++++++++---
 ipa-client/man/ipa-client-install.1       |   46 +++---
 ipa-client/man/ipa-getkeytab.1            |   48 ++++--
 ipa-client/man/ipa-join.1                 |   69 +++++++--
 6 files changed, 358 insertions(+), 74 deletions(-)

diff --git a/install/share/default-aci.ldif b/install/share/default-aci.ldif
index ecdf98d..a18245f 100644
--- a/install/share/default-aci.ldif
+++ b/install/share/default-aci.ldif
@@ -46,8 +46,9 @@ add: aci
 aci: (targetattr="userCertificate || krbPrincipalKey")(version 3.0; aci "Hosts can manage service Certificates and kerberos keys"; allow(write) userattr = "parent[0,1].managedby#USERDN";)
 
 # Allow hosts to update their own certificate in host/
+# krbLastPwdChange lets a host unenroll itself
 dn: cn=computers,cn=accounts,$SUFFIX
 changetype: modify
 add: aci
-aci: (targetattr="userCertificate")(version 3.0; aci "Hosts can modify service userCertificate"; allow(write) userdn = "ldap:///self";;)
+aci: (targetattr="userCertificate || krbLastPwdChange")(version 3.0; aci "Hosts can modify service userCertificate"; allow(write) userdn = "ldap:///self";;)
 
diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install
index 7e52b75..bded567 100755
--- a/ipa-client/ipa-install/ipa-client-install
+++ b/ipa-client/ipa-install/ipa-client-install
@@ -173,7 +173,7 @@ def chkconfig(name, status):
 
     return
 
-def uninstall(options):
+def uninstall(options, env):
 
     if not fstore.has_files() and not options.force:
         print "IPA client is not configured on this system."
@@ -211,6 +211,12 @@ def uninstall(options):
     except:
         print "Failed to disable automatic startup of the certmonger daemon"
 
+    print "Unenrolling client from IPA server"
+    join_args = ["/usr/sbin/ipa-join", "--unenroll"]
+    (stdout, stderr, returncode) = run(join_args, raiseonerr=False, env=env)
+    if returncode != 0:
+        print "Unenrolling host failed: %s" % stderr
+
     print "Removing Kerberos service principals from /etc/krb5.keytab"
     try:
         parser = RawConfigParser()
@@ -498,7 +504,7 @@ def main():
     fstore = sysrestore.FileStore('/var/lib/ipa-client/sysrestore')
 
     if options.uninstall:
-        return uninstall(options)
+        return uninstall(options, env)
 
     if fstore.has_files() and not options.force:
         print "IPA client is already configured on this system."
diff --git a/ipa-client/ipa-join.c b/ipa-client/ipa-join.c
index d18461f..c8bf421 100644
--- a/ipa-client/ipa-join.c
+++ b/ipa-client/ipa-join.c
@@ -288,8 +288,7 @@ get_subject(const char *ipaserver, char *ldap_base, const char **subject)
                             NULL, NULL, NULL, 0, &res);
 
     if (ret != LDAP_SUCCESS) {
-        fprintf(stderr, "Search for ipaCertificateSubjectBase failed with error %d",
-                attrs[0], ret);
+        fprintf(stderr, "Search for ipaCertificateSubjectBase failed with error %d", ret);
         rval = 14;
         goto done;
     }
@@ -334,7 +333,7 @@ done:
  * the state of the entry.
  */
 static int
-join_ldap(const char *ipaserver, const char *hostname, const char ** binddn, const char *bindpw, const char **princ, const char **subject, int quiet)
+join_ldap(const char *ipaserver, char *hostname, const char ** binddn, const char *bindpw, const char **princ, const char **subject, int quiet)
 {
     LDAP *ld;
     char *filter = NULL;
@@ -353,19 +352,22 @@ join_ldap(const char *ipaserver, const char *hostname, const char ** binddn, con
     *binddn = NULL;
 
     if (get_root_dn(ipaserver, &ldap_base) != 0) {
-        fprintf(stderr, "Unable to determine root DN of %s\n", ipaserver);
+        if (!quiet)
+            fprintf(stderr, "Unable to determine root DN of %s\n", ipaserver);
         rval = 14;
         goto done;
     }
 
     if (get_subject(ipaserver, ldap_base, subject) != 0) {
-        fprintf(stderr, "Unable to determine certificate subject of %s\n", ipaserver);
+        if (!quiet)
+            fprintf(stderr, "Unable to determine certificate subject of %s\n", ipaserver);
         /* Not a critical failure */
     }
 
     ld = connect_ldap(ipaserver, NULL, NULL);
     if (!ld) {
-        fprintf(stderr, "Unable to make an LDAP connection to %s\n", ipaserver);
+        if (!quiet)
+            fprintf(stderr, "Unable to make an LDAP connection to %s\n", ipaserver);
         rval = 14;
         goto done;
     }
@@ -378,18 +380,21 @@ join_ldap(const char *ipaserver, const char *hostname, const char ** binddn, con
     if ((ret = ldap_search_ext_s(ld, ldap_base, LDAP_SCOPE_SUB,
          filter, attrs, 0, NULL, NULL, LDAP_NO_LIMIT,
          LDAP_NO_LIMIT, &result)) != LDAP_SUCCESS) {
-        fprintf(stderr, "ldap_search_ext_s: %s\n", ldap_err2string(ret));
+        if (!quiet)
+            fprintf(stderr, "ldap_search_ext_s: %s\n", ldap_err2string(ret));
         rval = 14;
         goto ldap_done;
     }
     e = ldap_first_entry(ld, result);
     if (!e) {
-        fprintf(stderr, "Unable to find host '%s'\n", hostname);
+        if (!quiet)
+            fprintf(stderr, "Unable to find host '%s'\n", hostname);
         rval = 14;
         goto ldap_done;
     }
     if ((*binddn = ldap_get_dn(ld, e)) == NULL) {
-        fprintf(stderr, "Unable to get binddn for host '%s'\n", hostname);
+        if (!quiet)
+            fprintf(stderr, "Unable to get binddn for host '%s'\n", hostname);
         rval = 14;
         goto ldap_done;
     }
@@ -414,10 +419,12 @@ join_ldap(const char *ipaserver, const char *hostname, const char ** binddn, con
     ld = connect_ldap(ipaserver, *binddn, bindpw);
     if (!ld) {
         if (has_principal) {
-            fprintf(stderr, "Host is already joined.\n");
+            if (!quiet)
+                fprintf(stderr, "Host is already joined.\n");
             rval = 13;
         } else {
-            fprintf(stderr, "Incorrect password.\n");
+            if (!quiet)
+                fprintf(stderr, "Incorrect password.\n");
             rval = 15;
         }
         goto done;
@@ -427,9 +434,10 @@ join_ldap(const char *ipaserver, const char *hostname, const char ** binddn, con
     valrequest.bv_len = strlen(hostname);
 
     if ((rc = ldap_extended_operation_s(ld, JOIN_OID, &valrequest, NULL, NULL, &oidresult, &valresult)) != LDAP_SUCCESS) {
-        fprintf(stderr, "principal not found in host entry\n");
+        if (!quiet)
+            fprintf(stderr, "principal not found in host entry\n");
         if (debug) ldap_perror(ld, "ldap_extended_operation_s");
-        rval = 12;
+        rval = 18;
         goto ldap_done;
     }
 
@@ -452,7 +460,7 @@ done:
 }
 
 static int
-join_krb5(const char *ipaserver, const char *hostname, const char **hostdn, const char **princ, const char **subject, int quiet) {
+join_krb5(const char *ipaserver, char *hostname, const char **hostdn, const char **princ, const char **subject, int quiet) {
     xmlrpc_env env;
     xmlrpc_value * argArrayP = NULL;
     xmlrpc_value * paramArrayP = NULL;
@@ -509,7 +517,7 @@ join_krb5(const char *ipaserver, const char *hostname, const char **hostdn, cons
 
     callRPC(&env, serverInfoP, "join", paramArrayP, &resultP);
     if (handle_fault(&env)) {
-        rval = 1;
+        rval = 17;
         goto cleanup_xmlrpc;
     }
 
@@ -533,7 +541,8 @@ join_krb5(const char *ipaserver, const char *hostname, const char **hostdn, cons
         xmlrpc_DECREF(princP);
         xmlrpc_DECREF(singleprincP);
     } else {
-        fprintf(stderr, "principal not found in XML-RPC response\n");
+        if (!quiet)
+            fprintf(stderr, "principal not found in XML-RPC response\n");
         rval = 12;
         goto cleanup;
     }
@@ -547,7 +556,8 @@ join_krb5(const char *ipaserver, const char *hostname, const char **hostdn, cons
         xmlrpc_array_read_item(&env, krblastpwdchangeP, 0, &singleprincP);
         xmlrpc_read_string(&env, singleprincP, &krblastpwdchange);
         xmlrpc_DECREF(krblastpwdchangeP);
-        fprintf(stderr, "Host is already joined.\n");
+        if (!quiet)
+            fprintf(stderr, "Host is already joined.\n");
         rval = 13;
         goto cleanup;
     }
@@ -581,13 +591,196 @@ cleanup_xmlrpc:
 }
 
 static int
+unenroll_host(const char *server, const char *hostname, const char *ktname, int quiet)
+{
+    int rval = 0;
+    char *ipaserver = NULL;
+    char *host = NULL;
+    struct utsname uinfo;
+    char *principal = NULL;
+    char *realm = NULL;
+
+    krb5_context krbctx = NULL;
+    krb5_keytab keytab;
+    krb5_ccache ccache = NULL;
+    krb5_principal princ = NULL;
+    krb5_error_code krberr;
+    krb5_creds creds;
+    krb5_get_init_creds_opt gicopts;
+    char tgs[LINE_MAX];
+
+    xmlrpc_env env;
+    xmlrpc_value * argArrayP = NULL;
+    xmlrpc_value * paramArrayP = NULL;
+    xmlrpc_value * paramP = NULL;
+    xmlrpc_value * resultP = NULL;
+    xmlrpc_server_info * serverInfoP = NULL;
+    xmlrpc_value *princP = NULL;
+    char * url = NULL;
+
+    if (server) {
+        ipaserver = strdup(server);
+    } else {
+        char * conf_data = read_config_file(IPA_CONFIG);
+        if ((ipaserver = getIPAserver(conf_data)) == NULL) {
+            if (!quiet)
+                fprintf(stderr, "Unable to determine IPA server from %s\n", IPA_CONFIG);
+            exit(1);
+        }
+        free(conf_data);
+    }
+
+    if (NULL == hostname) {
+        uname(&uinfo);
+        host = strdup(uinfo.nodename);
+    } else {
+        host = strdup(hostname);
+    }
+
+    if (NULL == strstr(host, ".")) {
+        if (!quiet)
+            fprintf(stderr, "The hostname must be fully-qualified: %s\n", host);
+        rval = 16;
+        goto cleanup;
+    }
+
+    krberr = krb5_init_context(&krbctx);
+    if (krberr) {
+        if (!quiet)
+            fprintf(stderr, "Unable to join host: Kerberos context initialization failed\n");
+        rval = 1;
+        goto cleanup;
+    }
+    krberr = krb5_kt_resolve(krbctx, ktname, &keytab);
+    if (krberr != 0) {
+        if (!quiet)
+            fprintf(stderr, "Error resolving keytab: %s.\n",
+                error_message(krberr));
+            rval = 7;
+            goto cleanup;
+    }
+    krb5_get_default_realm(krbctx, &realm);
+    asprintf(&principal, "host/%...@%s", host,  realm);
+    krberr = krb5_parse_name(krbctx, principal, &princ);
+    if (krberr != 0) {
+        if (!quiet)
+            fprintf(stderr, "Error parsing \"%s\": %s.\n", principal,
+                    error_message(krberr));
+        return krberr;
+    }
+    strcpy(tgs, KRB5_TGS_NAME);
+    snprintf(tgs + strlen(tgs), sizeof(tgs) - strlen(tgs), "/%.*s",
+             (krb5_princ_realm(krbctx, princ))->length,
+             (krb5_princ_realm(krbctx, princ))->data);
+    snprintf(tgs + strlen(tgs), sizeof(tgs) - strlen(tgs), "@%.*s",
+             (krb5_princ_realm(krbctx, princ))->length,
+             (krb5_princ_realm(krbctx, princ))->data);
+    memset(&creds, 0, sizeof(creds));
+    krb5_get_init_creds_opt_init(&gicopts);
+    krb5_get_init_creds_opt_set_forwardable(&gicopts, 1);
+    krberr = krb5_get_init_creds_keytab(krbctx, &creds, princ, keytab,
+                                      0, tgs, &gicopts);
+    if (krberr != 0) {
+        if (!quiet)
+            fprintf(stderr, "Error obtaining initial credentials: %s.\n",
+                    error_message(krberr));
+        return krberr;
+    }
+
+    krberr = krb5_cc_resolve(krbctx, "MEMORY:ipa-join", &ccache);
+    if (krberr == 0) {
+        krberr = krb5_cc_initialize(krbctx, ccache, creds.client);
+    } else {
+        if (!quiet)
+            fprintf(stderr, "Unable to generate Kerberos Credential Cache\n");
+        rval = 19;
+        goto cleanup;
+    }
+    krberr = krb5_cc_store_cred(krbctx, ccache, &creds);
+    if (krberr != 0) {
+        if (!quiet)
+            fprintf(stderr, "Error storing creds in credential cache: %s.\n",
+                    error_message(krberr));
+        return krberr;
+    }
+    krb5_cc_close(krbctx, ccache);
+    ccache = NULL;
+    putenv("KRB5CCNAME=MEMORY:ipa-join");
+
+    /* Start up our XML-RPC client library. */
+    xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION);
+
+    xmlrpc_env_init(&env);
+
+    xmlrpc_client_setup_global_const(&env);
+
+#if 1
+    asprintf(&url, "https://%s:443/ipa/xml";, ipaserver);
+#else
+    asprintf(&url, "http://%s:8888/";, ipaserver);
+#endif
+    serverInfoP = xmlrpc_server_info_new(&env, url);
+
+    argArrayP = xmlrpc_array_new(&env);
+    paramArrayP = xmlrpc_array_new(&env);
+
+    paramP = xmlrpc_string_new(&env, host);
+    xmlrpc_array_append_item(&env, argArrayP, paramP);
+    xmlrpc_array_append_item(&env, paramArrayP, argArrayP);
+    xmlrpc_DECREF(paramP);
+
+    callRPC(&env, serverInfoP, "host_disable", paramArrayP, &resultP);
+    if (handle_fault(&env)) {
+        rval = 17;
+        goto cleanup;
+    }
+
+    xmlrpc_struct_find_value(&env, resultP, "result", &princP);
+    if (princP) {
+        xmlrpc_bool result;
+
+        xmlrpc_read_bool(&env, princP, &result);
+        if (result == 1) {
+            if (!quiet)
+                fprintf(stderr, "Unenrollment successful.\n");
+        } else {
+            if (!quiet)
+                fprintf(stderr, "Unenrollment failed.\n");
+        }
+
+        xmlrpc_DECREF(princP);
+    } else {
+        fprintf(stderr, "result not found in XML-RPC response\n");
+        rval = 20;
+        goto cleanup;
+    }
+
+cleanup:
+
+    krb5_kt_close(krbctx, keytab);
+    free((char *)principal);
+    free((char *)ipaserver);
+    if (princ) krb5_free_principal(krbctx, princ);
+    if (ccache) krb5_cc_close(krbctx, ccache);
+    if (krbctx) krb5_free_context(krbctx);
+
+    free(url);
+    xmlrpc_env_clean(&env);
+    xmlrpc_client_cleanup();
+
+    return rval;
+}
+
+
+static int
 join(const char *server, const char *hostname, const char *bindpw, const char *keytab, int quiet)
 {
-    int rval;
+    int rval = 0;
     pid_t childpid = 0;
     int status = 0;
     char *ipaserver = NULL;
     char *iparealm = NULL;
+    char * host = NULL;
     const char * princ = NULL;
     const char * subject = NULL;
     const char * hostdn = NULL;
@@ -611,17 +804,19 @@ join(const char *server, const char *hostname, const char *bindpw, const char *k
 
     if (NULL == hostname) {
         uname(&uinfo);
-        hostname = strdup(uinfo.nodename);
+        host = strdup(uinfo.nodename);
+    } else {
+        host = strdup(hostname);
     }
 
-    if (NULL == strstr(hostname, ".")) {
-        fprintf(stderr, "The hostname must be fully-qualified: %s\n", hostname);
+    if (NULL == strstr(host, ".")) {
+        fprintf(stderr, "The hostname must be fully-qualified: %s\n", host);
         rval = 16;
         goto cleanup;
     }
 
     if (bindpw)
-        rval = join_ldap(ipaserver, hostname, &hostdn, bindpw, &princ, &subject, quiet);
+        rval = join_ldap(ipaserver, host, &hostdn, bindpw, &princ, &subject, quiet);
     else {
         krberr = krb5_init_context(&krbctx);
         if (krberr) {
@@ -635,14 +830,14 @@ join(const char *server, const char *hostname, const char *bindpw, const char *k
             rval = 5;
             goto cleanup;
         }
-
+        
         krberr = krb5_cc_get_principal(krbctx, ccache, &uprinc);
         if (krberr) {
             fprintf(stderr, "Unable to join host: Kerberos User Principal not found and host password not provided.\n");
             rval = 6;
             goto cleanup;
         }
-        rval = join_krb5(ipaserver, hostname, &hostdn, &princ, &subject, quiet);
+        rval = join_krb5(ipaserver, host, &hostdn, &princ, &subject, quiet);
     }
 
     if (rval) goto cleanup;
@@ -733,9 +928,11 @@ main(int argc, char **argv) {
     static const char *keytab = NULL;
     static const char *bindpw = NULL;
     int quiet = 0;
+    int unenroll = 0;
     struct poptOption options[] = {
             { "debug", 'd', POPT_ARG_NONE, &debug, 0, "Print the raw XML-RPC output", "XML-RPC debugging Output"},
             { "quiet", 'q', POPT_ARG_NONE, &quiet, 0, "Print as little as possible", "Output only on errors"},
+            { "unenroll", 'u', POPT_ARG_NONE, &unenroll, 0, "Unenroll this host", "Unenroll this host from IPA server" },
             { "hostname", 'h', POPT_ARG_STRING, &hostname, 0, "Use this hostname instead of the node name", "Host Name" },
             { "server", 's', POPT_ARG_STRING, &server, 0, "IPA Server to use", "IPA Server Name" },
             { "keytab", 'k', POPT_ARG_STRING, &keytab, 0, "File were to store the keytab information", "Keytab File Name" },
@@ -758,12 +955,17 @@ main(int argc, char **argv) {
     if (debug)
         setenv("XMLRPC_TRACE_XML", "1", 1);
 
+
     if (!keytab)
         keytab = "/etc/krb5.keytab";
 
-    ret = check_perms(keytab);
-    if (ret == 0)
-        ret = join(server, hostname, bindpw, keytab, quiet);
+    if (unenroll) {
+        ret = unenroll_host(server, hostname, keytab, quiet);
+    } else {
+        ret = check_perms(keytab);
+        if (ret == 0)
+            ret = join(server, hostname, bindpw, keytab, quiet);
+    }
 
     exit(ret);
 }
diff --git a/ipa-client/man/ipa-client-install.1 b/ipa-client/man/ipa-client-install.1
index 4cdc921..7047044 100644
--- a/ipa-client/man/ipa-client-install.1
+++ b/ipa-client/man/ipa-client-install.1
@@ -1,21 +1,21 @@
 .\" A man page for ipa-client-install
 .\" Copyright (C) 2008 Red Hat, Inc.
-.\" 
+.\"
 .\" This is free software; you can redistribute it and/or modify it under
 .\" the terms of the GNU Library General Public License as published by
 .\" the Free Software Foundation; version 2 only
-.\" 
+.\"
 .\" This program is distributed in the hope that it will be useful, but
 .\" WITHOUT ANY WARRANTY; without even the implied warranty of
 .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 .\" General Public License for more details.
-.\" 
+.\"
 .\" You should have received a copy of the GNU Library General Public
 .\" License along with this program; if not, write to the Free Software
 .\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-.\" 
+.\"
 .\" Author: Rob Crittenden <rcrit...@redhat.com>
-.\" 
+.\"
 .TH "ipa-client-install" "1" "Mar 14 2008" "freeipa" ""
 .SH "NAME"
 ipa\-client\-install \- Configure an IPA client
@@ -26,31 +26,33 @@ Configures a client machine to use IPA for authentication and identity services.
 
 By default this configures SSSD to connect to an IPA server for authentication and authorization. Optionally one can instead configure PAM and NSS (Name Switching Service) to work with an IPA server over Kerberos and LDAP.
 
-An authorized user is required to join a client machine to IPA. This can take the form of a kerberos principal or a one-time password associated with the machine.
+An authorized user is required to join a client machine to IPA. This can take the form of a kerberos principal or a one\-time password associated with the machine.
+
+This same tool is used to unconfigure IPA and attemps to return the machine to its previous state. Part of this process is to unenroll the host from the IPA server. Unenrollment consists of disabling the prinicipal key on the IPA server so that it may be re\-enrolled. The machine principal in /etc/krb5.keytab (host/<fqdn>@REALM) is used to authenticate to the IPA server to unenroll itself. If this principal does not exist then unenrollment will fail and an administrator will need to disable the host principal (ipa host\-disable <fqdn>).
 .SH "OPTIONS"
-.TP 
+.TP
 \fB\-\-domain\fR=\fIDOMAIN\fR
 Set the domain name to DOMAIN
-.TP 
+.TP
 \fB\-\-server\fR=\fISERVER\fR
 Set the IPA server to connect to
-.TP 
+.TP
 \fB\-\-realm\fR=\fIREALM_NAME\fR
 Set the IPA realm name to REALM_NAME
-.TP 
+.TP
 \fB\-f\fR, \fB\-\-force\fR
 Force the settings even if errors occur
-.TP 
+.TP
 \fB\-d\fR, \fB\-\-debug\fR
 Print debugging information to stdout
-.TP 
+.TP
 \fB\-U\fR, \fB\-\-unattended\fR
 Unattended installation. The user will not be prompted.
-.TP 
+.TP
 \fB\-N\fR, \fB\-\-no\-ntp\fR
 Do not configure or enable NTP.
-.TP 
-\fB\-\-ntp-server\fR=\fINTP_SERVER\fR
+.TP
+\fB\-\-ntp\-server\fR=\fINTP_SERVER\fR
 Configure ntpd to use this NTP server.
 Do not configure or enable NTP.
 .TP
@@ -59,24 +61,24 @@ Do not configure the client to use SSSD for authentication, use nss_ldap instead
 .TP
 \fB\-\-on\-master\fB
 The client is being configured on an IPA server.
-.TP 
+.TP
 \fB\-w\fR \fIPASSWORD\fR, \fB\-\-password\fR=\fIPASSWORD\fR
 Password for joining a machine to the IPA realm. Assumes bulk password unless principal is also set.
-.TP 
+.TP
 \fB\-W\fR
 Prompt for the password for joining a machine to the IPA realm.
-.TP 
+.TP
 \fB\-p\fR, \fB\-\-principal\fR
 Authorized kerberos principal to use to join the IPA realm.
-.TP 
+.TP
 \fB\-\-permit\fR
-Configure SSSD to permit all access. Otherwise the machine will be controlled by the Host-based Access Controls (HBAC) on the IPA server.
-.TP 
+Configure SSSD to permit all access. Otherwise the machine will be controlled by the Host\-based Access Controls (HBAC) on the IPA server.
+.TP
 \fB\-\-mkhomedir\fR
 Configure pam to create a users home directory if it does not exist.
 .TP
 \fB\-\-uninstall\fR
-Remove the IPA client software and restore the configuration to the pre-IPA state.
+Remove the IPA client software and restore the configuration to the pre\-IPA state.
 .SH "EXIT STATUS"
 0 if the installation was successful
 
diff --git a/ipa-client/man/ipa-getkeytab.1 b/ipa-client/man/ipa-getkeytab.1
index 5533d98..cb4c184 100644
--- a/ipa-client/man/ipa-getkeytab.1
+++ b/ipa-client/man/ipa-getkeytab.1
@@ -1,22 +1,22 @@
 .\" A man page for ipa-getkeytab
 .\" Copyright (C) 2007 Red Hat, Inc.
-.\" 
+.\"
 .\" This is free software; you can redistribute it and/or modify it under
 .\" the terms of the GNU Library General Public License as published by
 .\" the Free Software Foundation; version 2 only
-.\" 
+.\"
 .\" This program is distributed in the hope that it will be useful, but
 .\" WITHOUT ANY WARRANTY; without even the implied warranty of
 .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 .\" General Public License for more details.
-.\" 
+.\"
 .\" You should have received a copy of the GNU Library General Public
 .\" License along with this program; if not, write to the Free Software
 .\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-.\" 
+.\"
 .\" Author: Karl MacMillan <kmacm...@redhat.com>
 .\" Author: Simo Sorce <sso...@redhat.com>
-.\" 
+.\"
 .TH "ipa-getkeytab" "1" "Oct 10 2007" "freeipa" ""
 .SH "NAME"
 ipa\-getkeytab \- Get a keytab for a kerberos principal
@@ -47,17 +47,17 @@ example above).
 \fBWARNING:\fR retrieving the keytab resets the secret for the Kerberos principal.
 This renders all other keytabs for that principal invalid.
 .SH "OPTIONS"
-.TP 
+.TP
 \fB\-s ipaserver\fR
 The IPA server to retrieve the keytab from (FQDN).
-.TP 
+.TP
 \fB\-p principal\-name\fR
 The non\-realm part of the full principal name.
-.TP 
+.TP
 \fB\-k keytab\-file\fR
 The keytab file where to append the new key (will be
 created if it does not exist).
-.TP 
+.TP
 \fB\-e encryption\-types\fR
 The list of encryption types to use to generate keys.
 ipa\-getkeytab will use local client defaults if not provided.
@@ -70,10 +70,10 @@ arcfour\-hmac
 des\-hmac\-sha1
 des\-cbc\-md5
 des\-cbc\-crc
-.TP 
+.TP
 \fB\-q\fR
 Quiet mode. Only errors are displayed.
-.TP 
+.TP
 \fB\-\-permitted\-enctypes\fR
 This options returns a description of the permitted encryption types, like this:
 Supported encryption types:
@@ -99,3 +99,29 @@ the host foo.example.com and save it in the file /tmp/ldap.keytab.
 
 .SH "EXIT STATUS"
 The exit status is 0 on success, nonzero on error.
+
+0 Success
+
+1 Kerberos context initialization failed
+
+2 Incorrect usage
+
+3 Out of memory
+
+4 Invalid service principal name
+
+5 No Kerberos credentials cache
+
+6 No Kerberos principal and no bind DN and password
+
+7 Failed to open keytab
+
+8 Failed to create key material
+
+9 Setting keytab failed
+
+10 Bind password required when using a bind DN
+
+11 Failed to add key to keytab
+
+12 Failed to close keytab
diff --git a/ipa-client/man/ipa-join.1 b/ipa-client/man/ipa-join.1
index 672cd6b..6ca19d6 100644
--- a/ipa-client/man/ipa-join.1
+++ b/ipa-client/man/ipa-join.1
@@ -20,16 +20,16 @@
 .SH "NAME"
 ipa\-join \- Join a machine to an IPA realm and get a keytab for the host service principal
 .SH "SYNOPSIS"
-ipa\-join [ \fB\-h\fR hostname ] [ \fB\-k\fR keytab\-file ] [ \fB\-s\fR server ] [ \fB\-w\fR bulk\-bind\-password ] [ \fB\-d\fR ] [ \fB\-q\fR ]
+ipa\-join [ \fB\-h\fR hostname ] [ \fB\-k\fR keytab\-file ] [ \fB\-s\fR server ] [ \fB\-w\fR bulk\-bind\-password ] [\fB\-u\fR] [ \fB\-d\fR ] [ \fB\-q\fR ]
 
 .SH "DESCRIPTION"
-Joins a host to an IPA realm and retrieves a kerberos \fIkeytab\fR for the host service principal.
+Joins a host to an IPA realm and retrieves a kerberos \fIkeytab\fR for the host service principal, or unenrolls an enrolled host from an IPA server.
 
 Kerberos keytabs are used for services (like sshd) to perform kerberos authentication. A keytab is a file with one or more secrets (or keys) for a kerberos principal.
 
 The ipa\-join command will create and retrieve a service principal for host/foo.example....@example.com and place it by default into /etc/krb5.keytab. The location can be overridden with the \-k option.
 
-The IPA server to contact is set in /etc/ipa/default.conf by default and can be overridden using the -s,--server option.
+The IPA server to contact is set in /etc/ipa/default.conf by default and can be overridden using the \-s,\-\-server option.
 
 In order to join the machine needs to be authenticated. This can happen in one of two ways:
 
@@ -37,27 +37,32 @@ In order to join the machine needs to be authenticated. This can happen in one o
 
 * Provide a password to authenticate with
 
-If a client host has already been joined to the IPA realm the ipa-join command will fail. The host will need to be removed from the server using `ipa host-del FQDN` in order to join the client to the realm.
+If a client host has already been joined to the IPA realm the ipa\-join command will fail. The host will need to be removed from the server using `ipa host\-del FQDN` in order to join the client to the realm.
 
-This command is normally executed by the ipa-client-install command as part of the enrollment process.
+This command is normally executed by the ipa\-client\-install command as part of the enrollment process.
+
+The reverse is unenrollment. Unenrolling a host removes the Kerberos key on the IPA server. This prepares the host to be re\-enrolled. This uses the host principal stored in /etc/krb5.conf to authenticate to the IPA server to perform the unenrollment.
 .SH "OPTIONS"
 .TP
-\fB\-h,--hostname hostname\fR
+\fB\-h,\-\-hostname hostname\fR
 The hostname of this server (FQDN). By default of nodename from uname(2) is used.
 .TP
-\fB\-s,--server server\fR
+\fB\-s,\-\-server server\fR
 The hostname of this server (FQDN). By default of nodename from uname(2) is used.
 .TP
-\fB\-k,--keytab keytab\-file\fR
+\fB\-k,\-\-keytab keytab\-file\fR
 The keytab file where to append the new key (will be created if it does not exist). Default: /etc/krb5.keytab
 .TP
-\fB\-w,--bindpw password\fR
+\fB\-w,\-\-bindpw password\fR
 The password to use if not using kerberos to authenticate
 .TP
-\fB\-q,--quiet\fR
+\fB\-u,\-\-unenroll\fR
+Unenroll this host from the IPA server
+.TP
+\fB\-q,\-\-quiet\fR
 Quiet mode. Only errors are displayed.
 .TP
-\fB\-d,--debug\fR
+\fB\-d,\-\-debug\fR
 Debug mode.
 .SH "EXAMPLES"
 Join IPA domain and retrieve a keytab with kerberos credentials.
@@ -74,3 +79,45 @@ Join IPA domain and save the keytab in another location.
   # ipa\-join \-k /tmp/host.keytab
 .SH "EXIT STATUS"
 The exit status is 0 on success, nonzero on error.
+
+0 Success
+
+1 Kerberos context initialization failed
+
+2 Incorrect usage
+
+3 Out of memory
+
+4 Invalid service principal name
+
+5 No Kerberos credentials cache
+
+6 No Kerberos principal and no bind DN and password
+
+7 Failed to open keytab
+
+8 Failed to create key material
+
+9 Setting keytab failed
+
+10 Bind password required when using a bind DN
+
+11 Failed to add key to keytab
+
+12 Failed to close keytab
+
+13 Host is already enrolled
+
+14 LDAP failure
+
+15 Incorrect bulk password
+
+16 Host name must be fully\-qualified
+
+17 XML\-RPC fault
+
+18 Principal not found in host entry
+
+19 Unable to generate Kerberos credentials cache
+
+20 Unenrollment result not in XML\-RPC response
-- 
1.7.2.1

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

Reply via email to