#include "k5-int.h"
#include "autoconf.h"
#include <stdio.h>
#include <errno.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
int debug=0;
extern const krb5_kt_ops krb5_ktf_writable_ops;
#define KRB5_OK 0
#define CHECK(kret,msg) \
if (kret != KRB5_OK) {\
com_err(msg, kret, ""); \
fflush(stderr);\
exit(1);\
} else if(debug) printf("%s went ok\n", msg);
#define CHECK_STR(str,msg) \
if (str == 0) {\
com_err(msg, kret, "");\
exit(1);\
} else if(debug) printf("%s went ok\n", msg);
static void test_misc(krb5_context context)
{
krb5_error_code kret;
krb5_keytab ktid;
char defname[BUFSIZ];
char *name;
fprintf(stderr, "Testing miscellaneous error conditions\n");
kret = krb5_kt_resolve(context, "unknown_method_ep:/tmp/name", &ktid);
if (kret != KRB5_KT_UNKNOWN_TYPE) {
CHECK(kret, "resolve unknown type");
}
kret = krb5_kt_default_name(context, defname, sizeof(defname));
CHECK(kret, "krb5_kt_default_name error");
name = malloc(strlen(defname));
if(!name) {
fprintf(stderr, "Out of memory in testing\n");
exit(1);
}
kret = krb5_kt_default_name(context, name, strlen(defname));
free(name);
if (kret != KRB5_CONFIG_NOTENUFSPACE) {
CHECK(kret, "krb5_kt_default_name limited");
}
}
static void kt_test(krb5_context context, const char *name)
{
krb5_error_code kret;
krb5_keytab kt;
const char *type;
char buf[BUFSIZ];
char *p;
krb5_keytab_entry kent, kent2;
krb5_principal princ;
krb5_kt_cursor cursor, cursor2;
int cnt;
kret = krb5_kt_resolve(context, name, &kt);
CHECK(kret, "resolve");
type = krb5_kt_get_type(context, kt);
CHECK_STR(type, "getting kt type");
printf(" Type is: %s\n", type);
kret = krb5_kt_get_name(context, kt, buf, sizeof(buf));
CHECK(kret, "get_name");
printf(" Name is: %s\n", buf);
p = malloc(strlen(buf));
kret = krb5_kt_get_name(context, kt, p, 1);
if(kret != KRB5_KT_NAME_TOOLONG) {
CHECK(kret, "get_name - size 1");
}
kret = krb5_kt_get_name(context, kt, p, strlen(buf));
if(kret != KRB5_KT_NAME_TOOLONG) {
CHECK(kret, "get_name");
}
free(p);
kret = krb5_parse_name(context, "test/test2@TEST.MIT.EDU", &princ);
CHECK(kret, "parsing principal");
kret = krb5_kt_get_entry(context, kt, princ, 0, 0, &kent);
if((kret != KRB5_KT_NOTFOUND) && (kret != ENOENT)) {
CHECK(kret, "Getting non-existant entry");
}
memset(&kent, 0, sizeof(kent));
kent.magic = KV5M_KEYTAB_ENTRY;
kent.principal = princ;
kent.timestamp = 327689;
kent.vno = 1;
kent.key.magic = KV5M_KEYBLOCK;
kent.key.enctype = 1;
kent.key.length = 1;
kent.key.contents = (krb5_octet *) "1";
kret = krb5_kt_add_entry(context, kt, &kent);
CHECK(kret, "Adding initial entry");
kent.key.enctype = 2;
kret = krb5_kt_add_entry(context, kt, &kent);
CHECK(kret, "Adding second entry");
kent.key.enctype = 1;
kent.vno = 2;
kent.key.contents = (krb5_octet *) "2";
kret = krb5_kt_add_entry(context, kt, &kent);
CHECK(kret, "Adding third entry");
krb5_free_principal(context, princ);
kret = krb5_kt_start_seq_get(context, kt, &cursor);
CHECK(kret, "Start sequence get");
memset(&kent, 0, sizeof(kent));
cnt = 0;
while((kret = krb5_kt_next_entry(context, kt, &kent, &cursor)) == 0) {
if(((kent.vno != 1) && (kent.vno != 2)) ||
((kent.key.enctype != 1) && (kent.key.enctype != 2)) ||
(kent.key.length != 1) ||
(kent.key.contents[0] != kent.vno +'0')) {
fprintf(stderr, "Error in read contents\n");
exit(1);
}
if((kent.magic != KV5M_KEYTAB_ENTRY) ||
(kent.key.magic != KV5M_KEYBLOCK)) {
fprintf(stderr, "Magic number in sequence not proper\n");
exit(1);
}
cnt++;
krb5_free_keytab_entry_contents(context, &kent);
}
if (kret != KRB5_KT_END) {
CHECK(kret, "getting next entry");
}
if(cnt != 3) {
fprintf(stderr, "Mismatch in number of entries in keytab");
}
kret = krb5_kt_end_seq_get(context, kt, &cursor);
CHECK(kret, "End sequence get");
kret = krb5_parse_name(context, "test3/test2@TEST.MIT.EDU", &princ);
CHECK(kret, "parsing principal");
kret = krb5_kt_get_entry(context, kt, princ, 0, 0, &kent);
if((kret != KRB5_KT_NOTFOUND)) {
CHECK(kret, "Getting non-existant entry");
}
krb5_free_principal(context, princ);
kret = krb5_parse_name(context, "test/test2@TEST.MIT.EDU", &princ);
CHECK(kret, "parsing principal");
kret = krb5_kt_get_entry(context, kt, princ, 0, 0, &kent);
CHECK(kret, "looking up principal");
if (!krb5_principal_compare(context, princ, kent.principal) ||
((kent.vno != 1) && (kent.vno != 2)) ||
((kent.key.enctype != 1) && (kent.key.enctype != 2)) ||
(kent.key.length != 1) ||
(kent.key.contents[0] != kent.vno +'0')) {
fprintf(stderr, "Retrieved principal does not check\n");
exit(1);
}
krb5_free_keytab_entry_contents(context, &kent);
kret = krb5_kt_get_entry(context, kt, princ, 0, 1, &kent);
CHECK(kret, "looking up principal");
if (!krb5_principal_compare(context, princ, kent.principal) ||
(kent.vno != 2) || (kent.key.enctype != 1) ||
(kent.key.length != 1) ||
(kent.key.contents[0] != kent.vno +'0')) {
fprintf(stderr, "Retrieved principal does not check\n");
exit(1);
}
krb5_free_keytab_entry_contents(context, &kent);
kret = krb5_kt_get_entry(context, kt, princ, 2, 0, &kent);
CHECK(kret, "looking up principal");
if (!krb5_principal_compare(context, princ, kent.principal) ||
(kent.vno != 2) || (kent.key.enctype != 1) ||
(kent.key.length != 1) ||
(kent.key.contents[0] != kent.vno +'0')) {
fprintf(stderr, "Retrieved principal does not check\n");
exit(1);
}
krb5_free_keytab_entry_contents(context, &kent);
kret = krb5_kt_get_entry(context, kt, princ, 1, 1, &kent);
CHECK(kret, "looking up principal");
if (!krb5_principal_compare(context, princ, kent.principal) ||
(kent.vno != 1) || (kent.key.enctype != 1) ||
(kent.key.length != 1) ||
(kent.key.contents[0] != kent.vno +'0')) {
fprintf(stderr, "Retrieved principal does not check\n");
exit(1);
}
krb5_free_keytab_entry_contents(context, &kent);
kret = krb5_kt_start_seq_get(context, kt, &cursor);
CHECK(kret, "Start sequence get(2)");
kret = krb5_kt_start_seq_get(context, kt, &cursor2);
CHECK(kret, "Start sequence get(3)");
kret = krb5_kt_next_entry(context, kt, &kent, &cursor);
CHECK(kret, "getting next entry(2)");
krb5_free_keytab_entry_contents(context, &kent);
kret = krb5_kt_next_entry(context, kt, &kent, &cursor);
CHECK(kret, "getting next entry(3)");
kret = krb5_kt_next_entry(context, kt, &kent2, &cursor2);
CHECK(kret, "getting next entry(4)");
krb5_free_keytab_entry_contents(context, &kent2);
kret = krb5_kt_get_entry(context, kt, kent.principal, 0, 0, &kent2);
CHECK(kret, "looking up principal(2)");
krb5_free_keytab_entry_contents(context, &kent2);
kret = krb5_kt_next_entry(context, kt, &kent2, &cursor2);
CHECK(kret, "getting next entry(5)");
if (!krb5_principal_compare(context, kent.principal, kent2.principal)) {
fprintf(stderr, "iterators not in sync\n");
exit(1);
}
krb5_free_keytab_entry_contents(context, &kent);
krb5_free_keytab_entry_contents(context, &kent2);
kret = krb5_kt_next_entry(context, kt, &kent, &cursor);
CHECK(kret, "getting next entry(6)");
kret = krb5_kt_next_entry(context, kt, &kent2, &cursor2);
CHECK(kret, "getting next entry(7)");
krb5_free_keytab_entry_contents(context, &kent);
krb5_free_keytab_entry_contents(context, &kent2);
kret = krb5_kt_end_seq_get(context, kt, &cursor);
CHECK(kret, "ending sequence get(1)");
kret = krb5_kt_end_seq_get(context, kt, &cursor2);
CHECK(kret, "ending sequence get(2)");
kret = krb5_kt_get_entry(context, kt, princ, 3, 1, &kent);
if(kret != KRB5_KT_KVNONOTFOUND) {
CHECK(kret, "looking up specific principal, kvno, enctype");
}
krb5_free_principal(context, princ);
kret = krb5_parse_name(context, "test/test2@TEST.MIT.EDU", &princ);
CHECK(kret, "parsing principal");
kret = krb5_kt_get_entry(context, kt, princ, 0, 1, &kent);
CHECK(kret, "looking up principal");
if (!krb5_principal_compare(context, princ, kent.principal) ||
(kent.vno != 2) || (kent.key.enctype != 1) ||
(kent.key.length != 1) ||
(kent.key.contents[0] != kent.vno +'0')) {
fprintf(stderr, "Retrieved principal does not check\n");
exit(1);
}
kret = krb5_kt_remove_entry(context, kt, &kent);
CHECK(kret, "Removing entry");
krb5_free_keytab_entry_contents(context, &kent);
kret = krb5_kt_get_entry(context, kt, princ, 0, 1, &kent);
CHECK(kret, "looking up principal");
if (!krb5_principal_compare(context, princ, kent.principal) ||
(kent.vno != 1) || (kent.key.enctype != 1) ||
(kent.key.length != 1) ||
(kent.key.contents[0] != kent.vno +'0')) {
fprintf(stderr, "Delete principal check failed\n");
exit(1);
}
krb5_free_keytab_entry_contents(context, &kent);
krb5_free_principal(context, princ);
kret = krb5_kt_close(context, kt);
CHECK(kret, "close");
}
static void do_test(krb5_context context, const char *prefix,
krb5_boolean delete)
{
char *name, *filename;
if (asprintf(&filename, "/tmp/kttest.%ld", (long) getpid()) < 0) {
perror("asprintf");
exit(1);
}
if (asprintf(&name, "%s%s", prefix, filename) < 0) {
perror("asprintf");
exit(1);
}
printf("Starting test on %s\n", name);
kt_test(context, name);
printf("Test on %s passed\n", name);
if(delete)
unlink(filename);
free(filename);
free(name);
}
int
main (void)
{
krb5_context context;
krb5_error_code kret;
if ((kret = krb5_init_context(&context))) {
printf("Couldn't initialize krb5 library: %s\n",
error_message(kret));
exit(1);
}
kret = krb5_kt_register(context, &krb5_ktf_writable_ops);
if(kret && kret != KRB5_KT_TYPE_EXISTS) {
CHECK(kret, "register ktf_writable");
}
test_misc(context);
do_test(context, "WRFILE:", FALSE);
do_test(context, "MEMORY:", TRUE);
krb5_free_context(context);
return 0;
}
#if 0
krb5_error_code KRB5_CALLCONV krb5_kt_remove_entry
(krb5_context,
krb5_keytab,
krb5_keytab_entry * );
#endif