#include <krb5.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
static krb5_context ctx;
static void
check(krb5_error_code code)
{
const char *errmsg;
if (code != 0) {
errmsg = krb5_get_error_message(ctx, code);
fprintf(stderr, "%s\n", errmsg);
krb5_free_error_message(ctx, errmsg);
}
assert(code == 0);
}
static void
get_collection_names(char ***list_out, size_t *count_out)
{
krb5_cccol_cursor cursor;
krb5_ccache cache;
char **list = NULL;
size_t count = 0;
char *name;
check(krb5_cccol_cursor_new(ctx, &cursor));
while (1) {
check(krb5_cccol_cursor_next(ctx, cursor, &cache));
if (cache == NULL)
break;
check(krb5_cc_get_full_name(ctx, cache, &name));
krb5_cc_close(ctx, cache);
list = realloc(list, (count + 1) * sizeof(*list));
assert(list != NULL);
list[count++] = name;
}
krb5_cccol_cursor_free(ctx, &cursor);
*list_out = list;
*count_out = count;
}
static krb5_boolean
in_list(char **list, size_t count, const char *name)
{
size_t i;
for (i = 0; i < count; i++) {
if (strcmp(list[i], name) == 0)
return TRUE;
}
return FALSE;
}
static void
free_list(char **list, size_t count)
{
size_t i;
for (i = 0; i < count; i++)
krb5_free_string(ctx, list[i]);
free(list);
}
static void
check_collection(const char *first, size_t others, ...)
{
va_list ap;
char **list;
size_t count, i;
const char *name;
get_collection_names(&list, &count);
if (first != NULL) {
assert(strcmp(first, list[0]) == 0);
assert(count == others + 1);
} else {
assert(count == others);
}
va_start(ap, others);
for (i = 0; i < others; i++) {
name = va_arg(ap, const char *);
assert(in_list(list, count, name));
}
va_end(ap);
free_list(list, count);
}
static void
check_name(krb5_ccache cache, const char *expected_name)
{
char *name;
check(krb5_cc_get_full_name(ctx, cache, &name));
assert(strcmp(name, expected_name) == 0);
krb5_free_string(ctx, name);
}
static void
check_primary_name(const char *collection_name, const char *expected_name)
{
krb5_ccache cache;
check(krb5_cc_resolve(ctx, collection_name, &cache));
check_name(cache, expected_name);
krb5_cc_close(ctx, cache);
}
static void
check_princ(const char *name, krb5_principal expected_princ)
{
krb5_ccache cache;
krb5_principal princ;
check(krb5_cc_resolve(ctx, name, &cache));
if (expected_princ != NULL) {
check(krb5_cc_get_principal(ctx, cache, &princ));
assert(krb5_principal_compare(ctx, princ, expected_princ));
krb5_free_principal(ctx, princ);
} else {
assert(krb5_cc_get_principal(ctx, cache, &princ) != 0);
}
krb5_cc_close(ctx, cache);
}
static void
check_match(krb5_principal princ, const char *expected_name)
{
krb5_ccache cache;
if (expected_name != NULL) {
check(krb5_cc_cache_match(ctx, princ, &cache));
check_name(cache, expected_name);
krb5_cc_close(ctx, cache);
} else {
assert(krb5_cc_cache_match(ctx, princ, &cache) != 0);
}
}
int
main(int argc, char **argv)
{
krb5_ccache ccinitial, ccu1, ccu2;
krb5_principal princ1, princ2, princ3;
const char *collection_name, *typename;
char *initial_primary_name, *unique1_name, *unique2_name;
assert(argc == 2);
collection_name = argv[1];
check(krb5_init_context(&ctx));
check(krb5_cc_set_default_name(ctx, collection_name));
check(krb5_cc_resolve(ctx, collection_name, &ccinitial));
check(krb5_cc_get_full_name(ctx, ccinitial, &initial_primary_name));
assert(strcmp(initial_primary_name, collection_name) != 0);
check_primary_name(collection_name, initial_primary_name);
check_collection(NULL, 0);
check_princ(collection_name, NULL);
check_princ(initial_primary_name, NULL);
typename = krb5_cc_get_type(ctx, ccinitial);
check(krb5_cc_new_unique(ctx, typename, NULL, &ccu1));
check(krb5_cc_get_full_name(ctx, ccu1, &unique1_name));
check(krb5_parse_name(ctx, "princ1@X", &princ1));
check(krb5_cc_initialize(ctx, ccu1, princ1));
check_princ(unique1_name, princ1);
check_match(princ1, unique1_name);
check_collection(NULL, 1, unique1_name);
check(krb5_cc_new_unique(ctx, typename, NULL, &ccu2));
check(krb5_cc_get_full_name(ctx, ccu2, &unique2_name));
check(krb5_parse_name(ctx, "princ2@X", &princ2));
check(krb5_cc_initialize(ctx, ccu2, princ2));
check_princ(unique2_name, princ2);
check_match(princ1, unique1_name);
check_match(princ2, unique2_name);
check_collection(NULL, 2, unique1_name, unique2_name);
assert(strcmp(unique1_name, initial_primary_name) != 0);
assert(strcmp(unique1_name, collection_name) != 0);
assert(strcmp(unique2_name, initial_primary_name) != 0);
assert(strcmp(unique2_name, collection_name) != 0);
assert(strcmp(unique2_name, unique1_name) != 0);
check_primary_name(collection_name, initial_primary_name);
check(krb5_parse_name(ctx, "princ3@X", &princ3));
check(krb5_cc_initialize(ctx, ccinitial, princ3));
check_name(ccinitial, initial_primary_name);
check_princ(initial_primary_name, princ3);
check_princ(collection_name, princ3);
check_match(princ3, initial_primary_name);
check_collection(initial_primary_name, 2, unique1_name, unique2_name);
check(krb5_cc_switch(ctx, ccu1));
check_primary_name(collection_name, unique1_name);
check_princ(collection_name, princ1);
check_collection(unique1_name, 2, initial_primary_name, unique2_name);
check(krb5_cc_switch(ctx, ccu2));
check_primary_name(collection_name, unique2_name);
check_princ(collection_name, princ2);
check_collection(unique2_name, 2, initial_primary_name, unique1_name);
check(krb5_cc_switch(ctx, ccinitial));
check_primary_name(collection_name, initial_primary_name);
check_princ(collection_name, princ3);
check_collection(initial_primary_name, 2, unique1_name, unique2_name);
check(krb5_cc_set_default_name(ctx, unique1_name));
check_collection(unique1_name, 0);
check(krb5_cc_set_default_name(ctx, collection_name));
check(krb5_cc_destroy(ctx, ccinitial));
check_princ(initial_primary_name, NULL);
check_princ(collection_name, NULL);
check_primary_name(collection_name, initial_primary_name);
check_match(princ1, unique1_name);
check_match(princ2, unique2_name);
check_match(princ3, NULL);
check_collection(NULL, 2, unique1_name, unique2_name);
check(krb5_cc_switch(ctx, ccu1));
check_primary_name(collection_name, unique1_name);
check_princ(collection_name, princ1);
check_collection(unique1_name, 1, unique2_name);
check(krb5_cc_destroy(ctx, ccu2));
check_princ(unique2_name, NULL);
check_match(princ2, NULL);
check_collection(unique1_name, 0);
check_primary_name(collection_name, unique1_name);
check_match(princ1, unique1_name);
check_princ(collection_name, princ1);
check(krb5_cc_destroy(ctx, ccu1));
check_princ(unique1_name, NULL);
check_princ(collection_name, NULL);
check_primary_name(collection_name, unique1_name);
check_match(princ1, NULL);
check_collection(NULL, 0);
krb5_free_string(ctx, initial_primary_name);
krb5_free_string(ctx, unique1_name);
krb5_free_string(ctx, unique2_name);
krb5_free_principal(ctx, princ1);
krb5_free_principal(ctx, princ2);
krb5_free_principal(ctx, princ3);
krb5_free_context(ctx);
return 0;
}