Add a new program to perform various tests on the WRFILE: and MEMORY: keytabs
authorEzra Peisach <epeisach@mit.edu>
Sun, 4 Feb 2007 03:08:47 +0000 (03:08 +0000)
committerEzra Peisach <epeisach@mit.edu>
Sun, 4 Feb 2007 03:08:47 +0000 (03:08 +0000)
I developed this program to test functionality of the MEMORY keytab - which
resulted in the numerous fixes that have been committed recently.

Tests all functioanlity of keytabs except for krb5_kt_default() and
krb5_kt_read_service_key() - although essential functionality tested.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@19142 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/keytab/Makefile.in
src/lib/krb5/keytab/t_keytab.c [new file with mode: 0644]

index 806719053f4801a6a56579b80120e2f8dc34b4d0..0a375c954c9613b537616039a8d8629781a5c2b9 100644 (file)
@@ -4,6 +4,10 @@ mydir=lib/krb5/keytab
 BUILDTOP=$(REL)..$(S)..$(S)..
 DEFS=
 
+RUN_SETUP = @KRB5_RUN_ENV@
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
 ##DOS##BUILDTOP = ..\..\..
 ##DOS##PREFIXDIR=keytab
 ##DOS##OBJFILE=..\$(OUTPRE)$(PREFIXDIR).lst
@@ -44,6 +48,9 @@ SRCS= \
        $(srcdir)/kt_srvtab.c   \
        $(srcdir)/read_servi.c
 
+EXTRADEPSRCS= \
+       $(srcdir)/t_keytab.c 
+
 all-windows:: $(OBJFILE)
 
 ##DOS$(OBJFILE): $(OBJS)
@@ -53,6 +60,17 @@ all-windows:: $(OBJFILE)
 all-unix:: all-libobjs
 clean-unix:: clean-libobjs
 
+check-unix:: t_keytab
+       KRB5_CONFIG=$(srcdir)/t_krb5.conf ; export KRB5_CONFIG ;\
+       $(RUN_SETUP) $(VALGRIND) ./t_keytab
+
+T_KEYTAB_OBJS = t_keytab.o
+t_keytab: $(T_KEYTAB_OBJS) $(KRB5_BASE_DEPLIBS)
+       $(CC_LINK) -o $@ $(T_KEYTAB_OBJS) $(KRB5_BASE_LIBS)
+
+clean-unix::
+       $(RM) t_keytab t_keytab.o
+
 clean-windows::
        @echo Making clean in krb5\keytab
        $(RM) $(OBJFILE)
@@ -124,14 +142,15 @@ kt_file.so kt_file.po $(OUTPRE)kt_file.$(OBJEXT): $(BUILDTOP)/include/autoconf.h
   $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
   $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
   $(SRCTOP)/include/socket-utils.h kt_file.c
-kt_memory.so kt_memory.po $(OUTPRE)kt_memory.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
-  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
-  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h \
-  $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
-  $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
-  $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
-  $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
-  $(SRCTOP)/include/socket-utils.h kt_memory.c
+kt_memory.so kt_memory.po $(OUTPRE)kt_memory.$(OBJEXT): \
+  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
+  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \
+  $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \
+  $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  kt_memory.c
 kt_srvtab.so kt_srvtab.po $(OUTPRE)kt_srvtab.$(OBJEXT): \
   $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
   $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
@@ -150,3 +169,12 @@ read_servi.so read_servi.po $(OUTPRE)read_servi.$(OBJEXT): \
   $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \
   $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
   read_servi.c
+t_keytab.so t_keytab.po $(OUTPRE)t_keytab.$(OBJEXT): \
+  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
+  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \
+  $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \
+  $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  t_keytab.c
diff --git a/src/lib/krb5/keytab/t_keytab.c b/src/lib/krb5/keytab/t_keytab.c
new file mode 100644 (file)
index 0000000..63e4689
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ * lib/krb5/keytab/t_keytab.c
+ *
+ * Copyright (C) 2007 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * 
+ *
+ * A set of tests for the keytab interface
+ */
+
+
+#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)
+{
+  /* Tests for certain error returns */
+  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");
+  }
+
+  /* Test length limits on krb5_kt_default_name */
+  kret = krb5_kt_default_name(context, defname, sizeof(defname));
+  CHECK(kret, "krb5_kt_default_name error");
+
+  /* Now allocate space - without the null... */
+  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;
+     char *type;
+     char buf[BUFSIZ];
+     char *p;
+     krb5_keytab_entry kent;
+     krb5_principal princ;
+     krb5_kt_cursor cursor;
+     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);
+
+     /* Check that length checks fail */
+     /* The buffer is allocated too small - to allow for valgrind test of
+       overflows
+     */
+     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);
+
+     /* Try to lookup unknown principal - when keytab does not exist*/
+     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");
+     }
+
+
+     /* ===================   Add entries to keytab ================= */
+     /*
+      * Add the following for this principal
+      * enctype 1, kvno 1, key = "1"
+      * enctype 2, kvno 1, key = "1"
+      * enctype 1, kvno 2, key = "2"
+      */
+     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");
+     
+     /* Free memory */
+     krb5_free_principal(context, princ);
+
+     /* ==============   Test iterating over contents of keytab ========= */
+
+     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");
+
+
+     /* ==========================   get_entry tests ============== */
+
+     /* Try to lookup unknown principal  - now that keytab exists*/
+     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);
+
+     /* Try to lookup known principal */
+     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");
+
+     /* Ensure a valid answer  - we did not specify an enctype or kvno */
+     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);
+
+     /* Try to lookup a specific enctype - but unspecified kvno - should give
+      * max kvno 
+      */
+     kret = krb5_kt_get_entry(context, kt, princ, 0, 1, &kent);
+     CHECK(kret, "looking up principal");
+
+     /* Ensure a valid answer  - we did specified an enctype */
+     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);
+
+     /* Try to lookup unspecified enctype, but a specified kvno */
+
+     kret = krb5_kt_get_entry(context, kt, princ, 2, 0, &kent);
+     CHECK(kret, "looking up principal");
+
+     /* Ensure a valid answer  - we did not specify a kvno */
+     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);
+
+
+
+     /* Try to lookup specified enctype and kvno */
+
+     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);
+
+
+     /* Try to lookup specified enctype and kvno  - that does not exist*/
+
+     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);
+
+     /* =========================   krb5_kt_remove_entry =========== */
+     /* Lookup the keytab entry w/ 2 kvno - and delete version 2 - 
+       ensure gone */
+     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");
+
+     /* Ensure a valid answer  - we are looking for max(kvno) and enc=1 */
+     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);
+
+     }
+
+     /* Delete it */
+     kret = krb5_kt_remove_entry(context, kt, &kent);
+     CHECK(kret, "Removing entry");
+
+     krb5_free_keytab_entry_contents(context, &kent);
+     /* And ensure gone */
+
+     kret = krb5_kt_get_entry(context, kt, princ, 0, 1, &kent);
+     CHECK(kret, "looking up principal");
+
+     /* Ensure a valid answer - kvno should now be 1 - we deleted 2 */
+     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);
+     
+     /* =======================  Finally close =======================  */
+
+     kret = krb5_kt_close(context, kt);
+     CHECK(kret, "close");
+
+}
+
+static void do_test(krb5_context context, const char *prefix, 
+                   krb5_boolean delete)
+{
+  char name[300], filename[300];
+
+  sprintf(filename, "/tmp/kttest.%ld", (long) getpid());
+  sprintf(name, "%s%s", prefix, filename);
+  printf("Starting test on %s\n", name);
+  kt_test(context, name);
+  printf("Test on %s passed\n", name);
+  if(delete)
+         unlink(filename);
+
+}
+
+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);
+       }
+
+       /* All keytab types are registered by default -- test for 
+          redundant error */
+       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
+/* remove and add are functions, so that they can return NOWRITE
+   if not a writable keytab */
+krb5_error_code KRB5_CALLCONV krb5_kt_remove_entry
+       (krb5_context,
+               krb5_keytab,
+               krb5_keytab_entry * );
+
+
+
+#endif