summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2009-12-04 16:29:09 -0500
committerRob Crittenden <rcritten@redhat.com>2009-12-04 16:29:09 -0500
commit62d40286ac67faa6b009e121035f92afa1372cf3 (patch)
tree1c9bfa065b4398aa529a65bd28ff5606858e626e
parent8ecb5897c111b6243c5325dadf2af0e6cb1e4c33 (diff)
downloadfreeipa-62d40286ac67faa6b009e121035f92afa1372cf3.tar.gz
freeipa-62d40286ac67faa6b009e121035f92afa1372cf3.tar.xz
freeipa-62d40286ac67faa6b009e121035f92afa1372cf3.zip
A utility for removing principals from a keytab.
When we un-enroll a client we'll do a bit of cleanup including removing any principals for the IPA realm from /etc/krb5.keytab. This removes principals in 2 ways: - By principal, only entries matching the full principal are removed - By realm. Any principal for that realm is removed This does not change the KDC at all, just removes entries from a file on the client machine.
-rw-r--r--ipa-client/Makefile.am10
-rw-r--r--ipa-client/ipa-rmkeytab.c218
-rw-r--r--ipa-client/man/Makefile.am1
-rw-r--r--ipa-client/man/ipa-rmkeytab.190
-rw-r--r--ipa.spec.in5
5 files changed, 324 insertions, 0 deletions
diff --git a/ipa-client/Makefile.am b/ipa-client/Makefile.am
index 9a8b5f690..3f3c13b1a 100644
--- a/ipa-client/Makefile.am
+++ b/ipa-client/Makefile.am
@@ -22,6 +22,7 @@ INCLUDES = \
sbin_PROGRAMS = \
ipa-getkeytab \
+ ipa-rmkeytab \
ipa-join \
$(NULL)
@@ -37,6 +38,15 @@ ipa_getkeytab_LDADD = \
$(POPT_LIBS) \
$(NULL)
+ipa_rmkeytab_SOURCES = \
+ ipa-rmkeytab.c \
+ $(NULL)
+
+ipa_rmkeytab_LDADD = \
+ $(KRB5_LIBS) \
+ $(POPT_LIBS) \
+ $(NULL)
+
ipa_join_SOURCES = \
config.c \
ipa-join.c \
diff --git a/ipa-client/ipa-rmkeytab.c b/ipa-client/ipa-rmkeytab.c
new file mode 100644
index 000000000..d3f1ded37
--- /dev/null
+++ b/ipa-client/ipa-rmkeytab.c
@@ -0,0 +1,218 @@
+/* Authors: Rob Crittenden <rcritten@redhat.com>
+ *
+ * Copyright (C) 2009 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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 General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <krb5.h>
+#include <popt.h>
+#include <errno.h>
+
+int
+remove_principal(krb5_context context, krb5_keytab ktid, const char *principal, int debug)
+{
+ krb5_error_code krberr;
+ krb5_keytab_entry entry, entry2;
+ int rval = 0;
+ int removed = 0;
+
+ memset(&entry, 0, sizeof(entry));
+ krberr = krb5_parse_name(context, principal, &entry.principal);
+ if (krberr) {
+ fprintf(stderr, "Unable to parse principal name\n");
+ if (debug)
+ fprintf(stderr, "krb5_parse_name %d: %s\n", krberr, error_message(krberr));
+ rval = 4;
+ goto done;
+ }
+
+ /* Loop through the keytab and remove all entries with this principal name
+ * irrespective of the encryption type. A failure to find one after the
+ * first means we're done.
+ */
+ fprintf(stderr, "Removing principal %s\n", principal);
+ while (1) {
+ memset(&entry2, 0, sizeof(entry2));
+ krberr = krb5_kt_get_entry(context, ktid,
+ entry.principal,
+ 0,
+ 0,
+ &entry2);
+ if (krberr) {
+ if (removed > 0)
+ /* not found but we've removed some, we're done */
+ break;
+ if (krberr == ENOENT) {
+ fprintf(stderr, "Failed to open keytab\n");
+ rval = 3;
+ goto done;
+ }
+ fprintf(stderr, "principal not found\n");
+ if (debug)
+ fprintf(stderr, "krb5_kt_get_entry %d: %s\n", krberr, error_message(krberr));
+ rval = 5;
+ break;
+ }
+
+ krberr = krb5_kt_remove_entry(context, ktid, &entry2);
+ if (krberr) {
+ fprintf(stderr, "Unable to remove entry\n");
+ if (debug) {
+ fprintf(stdout, "kvno %d\n", entry2.vno);
+ fprintf(stderr, "krb5_kt_remove_entry %d: %s\n", krberr, error_message(krberr));
+ }
+ rval = 6;
+ break;
+ }
+
+ krb5_free_keytab_entry_contents(context, &entry2);
+ removed++;
+ }
+
+ if (entry2.principal)
+ krb5_free_keytab_entry_contents(context, &entry2);
+
+done:
+
+ return rval;
+}
+
+int
+remove_realm(krb5_context context, krb5_keytab ktid, const char *realm, int debug)
+{
+ krb5_error_code krberr;
+ krb5_keytab_entry entry;
+ krb5_kt_cursor kt_cursor;
+ char * entry_princ_s = NULL;
+ int rval = 0;
+
+ krberr = krb5_kt_start_seq_get(context, ktid, &kt_cursor);
+ memset(&entry, 0, sizeof(entry));
+ while (krb5_kt_next_entry(context, ktid, &entry, &kt_cursor) == 0) {
+ krberr = krb5_unparse_name(context, entry.principal, &entry_princ_s);
+ if (krberr) {
+ fprintf(stderr, "Unable to parse principal\n");
+ if (debug) {
+ fprintf(stderr, "krb5_unparse_name %d: %s\n", krberr, error_message(krberr));
+ }
+ rval = 4;
+ goto done;
+ }
+
+ if (strstr(entry_princ_s, realm) != NULL) {
+ rval = remove_principal(context, ktid, entry_princ_s, debug);
+ if (rval != 0)
+ goto done;
+ /* Have to reset the cursor */
+ krberr = krb5_kt_start_seq_get(context, ktid, &kt_cursor);
+ }
+ }
+
+done:
+
+ return rval;
+}
+
+int
+main(int argc, char **argv)
+{
+ krb5_context context;
+ krb5_error_code krberr;
+ krb5_keytab ktid;
+ char * ktname;
+ char * atrealm;
+ poptContext pc;
+ static const char *keytab = NULL;
+ static const char *principal = NULL;
+ static const char *realm = NULL;
+ int debug = 0;
+ int ret, rval;
+ struct poptOption options[] = {
+ { "debug", 'd', POPT_ARG_NONE, &debug, 0, "Print debugging information", "Debugging output" },
+ { "principal", 'p', POPT_ARG_STRING, &principal, 0, "The principal to get a keytab for (ex: ftp/ftp.example.com@EXAMPLE.COM)", "Kerberos Service Principal Name" },
+ { "keytab", 'k', POPT_ARG_STRING, &keytab, 0, "File were to store the keytab information", "Keytab File Name" },
+ { "realm", 'r', POPT_ARG_STRING, &realm, 0, "Remove all principals in this realm", "Realm name" },
+{ NULL, 0, POPT_ARG_NONE, NULL, 0, NULL, NULL }
+ };
+
+ memset(&ktid, 0, sizeof(ktid));
+
+ krberr = krb5_init_context(&context);
+ if (krberr) {
+ fprintf(stderr, "Kerberos context initialization failed\n");
+ exit(1);
+ }
+
+ pc = poptGetContext("ipa-rmkeytab", argc, (const char **)argv, options, 0);
+ ret = poptGetNextOpt(pc);
+ if (ret != -1 || (!principal && !realm) || !keytab) {
+ poptPrintUsage(pc, stderr, 0);
+ rval = 1;
+ goto cleanup;
+ }
+
+ ret = asprintf(&ktname, "WRFILE:%s", keytab);
+ if (ret == -1) {
+ rval = 2;
+ goto cleanup;
+ }
+
+ /* The remove_realm function just does a substring match. Ensure that
+ * the string we pass in looks like a realm.
+ */
+ if (realm) {
+ if (realm[0] != '@')
+ ret = asprintf(&atrealm, "@%s", realm);
+ if (ret == -1) {
+ rval = 2;
+ goto cleanup;
+ }
+ else
+ atrealm = strcpy(atrealm, realm);
+ }
+
+ krberr = krb5_kt_resolve(context, ktname, &ktid);
+ if (krberr) {
+ fprintf(stderr, "Failed to open keytab '%s'\n", keytab);
+ rval = 3;
+ goto cleanup;
+ }
+
+ if (principal)
+ rval = remove_principal(context, ktid, principal, debug);
+ else if (realm)
+ rval = remove_realm(context, ktid, atrealm, debug);
+
+cleanup:
+ if (rval == 0 || rval > 3) {
+ krberr = krb5_kt_close(context, ktid);
+ if (krberr) {
+ fprintf(stderr, "Closing keytab failed\n");
+ if (debug)
+ fprintf(stderr, "krb5_kt_close %d: %s\n", krberr, error_message(krberr));
+ }
+ }
+
+ krb5_free_context(context);
+
+ poptFreeContext(pc);
+
+ return rval;
+}
diff --git a/ipa-client/man/Makefile.am b/ipa-client/man/Makefile.am
index eee7144c1..bf11e39a8 100644
--- a/ipa-client/man/Makefile.am
+++ b/ipa-client/man/Makefile.am
@@ -6,6 +6,7 @@ NULL =
man_MANS = \
ipa-getkeytab.1 \
+ ipa-rmkeytab.1 \
ipa-client-install.1 \
ipa-join.1
diff --git a/ipa-client/man/ipa-rmkeytab.1 b/ipa-client/man/ipa-rmkeytab.1
new file mode 100644
index 000000000..a60f45cf9
--- /dev/null
+++ b/ipa-client/man/ipa-rmkeytab.1
@@ -0,0 +1,90 @@
+.\" A man page for ipa-rmkeytab
+.\" Copyright (C) 2009 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 <rcritten@redhat.com>
+.\"
+.\"
+.TH "ipa-rmkeytab" "1" "Oct 30 2009" "freeipa" ""
+.SH "NAME"
+ipa\-rmkeytab \- Remove a kerberos principal from a keytab
+.SH "SYNOPSIS"
+ipa\-rmkeytab [ \fB\-p\fR principal\-name ] [ \fB\-k\fR keytab\-file ] [ \fB\-r\fR realm ] [ \fB\-d\fR ]
+
+.SH "DESCRIPTION"
+Removes a kerberos principal from a \fIkeytab\fR.
+
+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.
+
+A kerberos service principal is a kerberos identity
+that can be used for authentication. Service principals
+contain the name of the service, the hostname of the
+server, and the realm name.
+
+ipa\-rmkeytab provides two ways to remove principals.
+A specific principal can be removed or all principals for all
+principals for a given realm can be removed.
+
+All encryption types and versions of a principal are removed.
+
+The realm may be included when removing a specific principal but
+it is not required.
+
+\fBNOTE:\fR removing a principal from the keytab does not affect
+the Kerberos principal stored in the IPA server. It merely removes
+the entry from the local keytab.
+.SH "OPTIONS"
+.TP
+\fB\-p principal\-name\fR
+The non\-realm part of the full principal name.
+.TP
+\fB\-k keytab\-file\fR
+The keytab file where to append the new key (will be
+created if it does not exist).
+.TP
+\fB\-r realm\fR
+A realm to remove all principals for.
+.TP
+\fB\-d\fR
+Debug mode. Additional information is displayed.
+.SH "EXAMPLES"
+Remove the NFS service principal on the host foo.example.com from /tmp/nfs.keytab.
+
+ # ipa\-rmkeytab \-p nfs/foo.example.com \-k /tmp/nfs.keytab
+
+Remove the ldap service principal onthe host foo.example.com from /etc/krb5.keytab.
+
+ # ipa\-rmkeytab \-p ldap/foo.example.com \-k /tmp/ldap.keytab
+
+Remove all principals for the realm EXAMPLE.COM.
+
+ # ipa\-rmkeytab \-r EXAMPLE.COM \-k /tmp/ldap.keytab
+.SH "EXIT STATUS"
+The exit status is 0 on success, nonzero on error.
+
+1 Kerberos initialization failed
+
+2 Memory allocation error
+
+3 Unable to open keytab
+
+4 Unable to parse the principal name
+
+5 Principal name not found in keytab
+
+6 Unable to remove principal from keytab
diff --git a/ipa.spec.in b/ipa.spec.in
index 76f9e57c1..84884a5cd 100644
--- a/ipa.spec.in
+++ b/ipa.spec.in
@@ -425,6 +425,7 @@ fi
%doc LICENSE README
%{_sbindir}/ipa-client-install
%{_sbindir}/ipa-getkeytab
+%{_sbindir}/ipa-rmkeytab
%{_sbindir}/ipa-join
%dir %{_usr}/share/ipa
%dir %{_usr}/share/ipa/ipaclient
@@ -435,6 +436,7 @@ fi
%dir %{python_sitelib}/ipaclient
%{python_sitelib}/ipaclient/*.py*
%{_mandir}/man1/ipa-getkeytab.1.gz
+%{_mandir}/man1/ipa-rmkeytab.1.gz
%{_mandir}/man1/ipa-client-install.1.gz
%{_mandir}/man1/ipa-join.1.gz
@@ -482,6 +484,9 @@ fi
%endif
%changelog
+* Fri Dec 4 2009 Rob Crittenden <rcritten@redhat.com> - 1.99-13
+- Add ipa-rmkeytab tool
+
* Tue Dec 1 2009 Rob Crittenden <rcritten@redhat.com> - 1.99-12
- Set minimum of python-pyasn1 to 0.0.9a so we have support for the ASN.1
Any type