#include <CoreFoundation/CoreFoundation.h>
#include <Kerberos/Kerberos.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
const char *program = NULL;
int quiet = 0;
int all = 0;
const char *cacheName = NULL;
const char *principalName = NULL;
int destroy_tickets (void);
static int options (int argc, char * const *argv);
static int usage (void);
static void printiferr (errcode_t err, const char *format, ...);
static void printerr (const char *format, ...);
static void vprinterr (const char *format, va_list args);
int main (int argc, char * const *argv)
{
int err = 0;
program = strrchr (argv[0], '/') ? strrchr (argv[0], '/') + 1 : argv[0];
err = options (argc, argv);
if (!err) {
err = destroy_tickets ();
}
return err;
}
int destroy_tickets (void)
{
krb5_error_code err = 0;
if (cacheName != NULL) {
krb5_context kcontext = NULL;
krb5_ccache ccache = NULL;
const char *name = NULL;
const char *type = NULL;
err = krb5_init_context (&kcontext);
printiferr (err, "while initializing Kerberos 5");
if (!err) {
err = krb5_cc_resolve (kcontext, cacheName, &ccache);
printiferr (err, "while locating credentials cache '%s'", cacheName);
}
if (!err) {
name = krb5_cc_get_name (kcontext, ccache);
if (name == NULL) { err = EINVAL; }
printiferr (err, "while getting the credentials cache name");
}
if (!err) {
type = krb5_cc_get_type (kcontext, ccache);
if (type == NULL) { err = EINVAL; }
printiferr (err, "while getting the credentials cache type");
}
if (!err) {
if (strcmp (type, "API") == 0) {
cc_context_t cc_context = NULL;
cc_ccache_t cc_ccache = NULL;
err = cc_initialize (&cc_context, ccapi_version_4, NULL, NULL);
printiferr (err, "while initializing credentials cache");
if (!err) {
err = cc_context_open_ccache (cc_context, name, &cc_ccache);
printiferr (err, "while opening credentials cache '%s'", cacheName);
}
if (!err) {
err = cc_ccache_destroy (cc_ccache);
if (!err) { cc_ccache = NULL; }
printiferr (err, "while destroying credentials cache '%s'", cacheName);
}
if (cc_ccache != NULL) { cc_ccache_release (cc_ccache); }
if (cc_context != NULL) { cc_context_release (cc_context); }
} else {
err = krb5_cc_destroy (kcontext, ccache);
printiferr (err, "while destroying credentials cache '%s'", cacheName);
}
}
if (kcontext != NULL) { krb5_free_context (kcontext); }
} else if (all) {
while (!err) {
err = KLDestroyTickets (NULL);
}
err = 0;
} else {
KLPrincipal principal = NULL;
if (principalName != NULL) {
err = KLCreatePrincipalFromString (principalName, kerberosVersion_V5, &principal);
printiferr (err, "while creating principal for '%s'", principalName);
}
if (!err) {
err = KLDestroyTickets (principal);
if ((err == klPrincipalDoesNotExistErr) ||
(err == klCacheDoesNotExistErr) ||
(err == klSystemDefaultDoesNotExistErr)) {
if (principal != NULL && principalName != NULL) {
printerr ("No credentials cache for principal '%s'\n", principalName);
} else {
printerr ("No default credentials cache\n");
}
} else {
printiferr (err, "while destroying tickets");
}
}
if (principal != NULL) { KLDisposePrincipal (principal); }
}
return err ? 1 : 0;
}
static int options (int argc, char * const *argv)
{
int option;
while ((option = getopt (argc, argv, "qaAc:p:")) != -1) {
switch (option) {
case 'q':
quiet = 1;
break;
case 'a':
case 'A':
all = 1;
break;
case 'c':
if (cacheName != NULL) {
printerr ("Only one -c option allowed\n");
return usage ();
}
cacheName = optarg;
break;
case 'p':
if (principalName != NULL) {
printerr ("Only one -p option allowed\n");
return usage ();
}
principalName = optarg;
break;
default:
return usage ();
}
}
if (cacheName != NULL && principalName != NULL) {
printerr ("Only one of -c or -p allowed\n");
return usage ();
}
if (all && (cacheName != NULL || principalName != NULL)) {
printerr ("-a cannot be combined with -c or -p\n");
return usage ();
}
return 0;
}
static int usage (void)
{
fprintf (stderr, "Usage: %s [-q] [-[a|A] | -c cache_name | -p principal]\n", program);
fprintf (stderr, "\t-q quiet mode\n");
fprintf (stderr, "\t-[a|A] destroy all caches\n");
fprintf (stderr, "\t-c specify name of credentials cache\n");
fprintf (stderr, "\t-p specify name of principal (Kerberos 5 format)\n");
return 2;
}
static void printiferr (errcode_t err, const char *format, ...)
{
if (err && (err != ccIteratorEnd) && (err != KRB5_CC_END)) {
va_list pvar;
va_start (pvar, format);
com_err_va (program, err, format, pvar);
va_end (pvar);
}
}
static void printerr (const char *format, ...)
{
va_list pvar;
va_start (pvar, format);
vprinterr (format, pvar);
va_end (pvar);
}
static void vprinterr (const char *format, va_list args)
{
if (!quiet) {
fprintf (stderr, "%s: ", program);
vfprintf (stderr, format, args);
}
}