2009-12-04 15:29:09 -06:00
|
|
|
/* 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>
|
|
|
|
|
2010-10-11 17:36:43 -05:00
|
|
|
#include "config.h"
|
|
|
|
#include <libintl.h>
|
|
|
|
#define _(STRING) gettext(STRING)
|
|
|
|
|
|
|
|
|
2009-12-04 15:29:09 -06:00
|
|
|
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) {
|
2010-10-11 17:36:43 -05:00
|
|
|
fprintf(stderr, _("Unable to parse principal name\n"));
|
2009-12-04 15:29:09 -06:00
|
|
|
if (debug)
|
2010-10-11 17:36:43 -05:00
|
|
|
fprintf(stderr, _("krb5_parse_name %d: %s\n"),
|
|
|
|
krberr, error_message(krberr));
|
2009-12-04 15:29:09 -06:00
|
|
|
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.
|
|
|
|
*/
|
2010-10-11 17:36:43 -05:00
|
|
|
fprintf(stderr, _("Removing principal %s\n"), principal);
|
2009-12-04 15:29:09 -06:00
|
|
|
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) {
|
2010-10-11 17:36:43 -05:00
|
|
|
fprintf(stderr, _("Failed to open keytab\n"));
|
2009-12-04 15:29:09 -06:00
|
|
|
rval = 3;
|
|
|
|
goto done;
|
|
|
|
}
|
2010-10-11 17:36:43 -05:00
|
|
|
fprintf(stderr, _("principal not found\n"));
|
2009-12-04 15:29:09 -06:00
|
|
|
if (debug)
|
2010-10-11 17:36:43 -05:00
|
|
|
fprintf(stderr, _("krb5_kt_get_entry %d: %s\n"),
|
|
|
|
krberr, error_message(krberr));
|
2009-12-04 15:29:09 -06:00
|
|
|
rval = 5;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
krberr = krb5_kt_remove_entry(context, ktid, &entry2);
|
|
|
|
if (krberr) {
|
2010-10-11 17:36:43 -05:00
|
|
|
fprintf(stderr, _("Unable to remove entry\n"));
|
2009-12-04 15:29:09 -06:00
|
|
|
if (debug) {
|
2010-10-11 17:36:43 -05:00
|
|
|
fprintf(stdout, _("kvno %d\n"), entry2.vno);
|
|
|
|
fprintf(stderr, _("krb5_kt_remove_entry %d: %s\n"),
|
|
|
|
krberr, error_message(krberr));
|
2009-12-04 15:29:09 -06:00
|
|
|
}
|
|
|
|
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) {
|
2010-10-11 17:36:43 -05:00
|
|
|
fprintf(stderr, _("Unable to parse principal\n"));
|
2009-12-04 15:29:09 -06:00
|
|
|
if (debug) {
|
2010-10-11 17:36:43 -05:00
|
|
|
fprintf(stderr, _("krb5_unparse_name %d: %s\n"),
|
|
|
|
krberr, error_message(krberr));
|
2009-12-04 15:29:09 -06:00
|
|
|
}
|
|
|
|
rval = 4;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2009-12-17 13:29:54 -06:00
|
|
|
/* keytab entries are locked when looping. Temporarily suspend
|
|
|
|
* the looping. */
|
|
|
|
krb5_kt_end_seq_get(context, ktid, &kt_cursor);
|
|
|
|
|
2009-12-04 15:29:09 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-10-11 17:36:43 -05:00
|
|
|
int init_gettext(void)
|
|
|
|
{
|
|
|
|
char *c;
|
|
|
|
|
|
|
|
c = setlocale(LC_ALL, "");
|
|
|
|
if (!c) {
|
|
|
|
return EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
c = bindtextdomain(PACKAGE, LOCALEDIR);
|
|
|
|
if (c == NULL) {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
c = textdomain(PACKAGE);
|
|
|
|
if (c == NULL) {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-12-04 15:29:09 -06:00
|
|
|
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[] = {
|
2010-10-11 17:36:43 -05:00
|
|
|
{ "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") },
|
2010-02-24 10:41:34 -06:00
|
|
|
POPT_AUTOHELP
|
|
|
|
POPT_TABLEEND
|
2009-12-04 15:29:09 -06:00
|
|
|
};
|
|
|
|
|
2010-10-11 17:36:43 -05:00
|
|
|
ret = init_gettext();
|
|
|
|
if (ret) {
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2009-12-04 15:29:09 -06:00
|
|
|
memset(&ktid, 0, sizeof(ktid));
|
|
|
|
|
|
|
|
krberr = krb5_init_context(&context);
|
|
|
|
if (krberr) {
|
2010-10-11 17:36:43 -05:00
|
|
|
fprintf(stderr, _("Kerberos context initialization failed\n"));
|
2009-12-04 15:29:09 -06:00
|
|
|
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) {
|
2010-10-11 17:36:43 -05:00
|
|
|
fprintf(stderr, _("Failed to open keytab '%s'\n"), keytab);
|
2009-12-04 15:29:09 -06:00
|
|
|
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) {
|
2010-10-11 17:36:43 -05:00
|
|
|
fprintf(stderr, _("Closing keytab failed\n"));
|
2009-12-04 15:29:09 -06:00
|
|
|
if (debug)
|
2010-10-11 17:36:43 -05:00
|
|
|
fprintf(stderr, _("krb5_kt_close %d: %s\n"),
|
|
|
|
krberr, error_message(krberr));
|
2009-12-04 15:29:09 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
krb5_free_context(context);
|
|
|
|
|
|
|
|
poptFreeContext(pc);
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
}
|