This commit adds a thread safe MEMORY keytab implementation
authorJeffrey Altman <jaltman@secure-endpoints.com>
Tue, 30 Jan 2007 17:21:56 +0000 (17:21 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Tue, 30 Jan 2007 17:21:56 +0000 (17:21 +0000)
that is compatible with Heimdal 0.7.  Each successful resolve
returns a handle to a keytab and increases the internal
reference count.  Each close invalidates the handle and
decreases the reference count.  When the reference count hits
zero, the keytab is destroyed.

When a kt_destroy function is added, the automatic destruction
after close behavior will be removed.

ticket: 5411

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

src/lib/krb5/keytab/Makefile.in
src/lib/krb5/keytab/kt-int.h
src/lib/krb5/keytab/kt_memory.c [new file with mode: 0644]
src/lib/krb5/keytab/ktbase.c
src/lib/krb5/keytab/ktfr_entry.c

index 2fcfbaa0683e6d15792856b1da9db649451f4668..806719053f4801a6a56579b80120e2f8dc34b4d0 100644 (file)
@@ -16,6 +16,7 @@ STLIBOBJS= \
        ktremove.o      \
        ktfns.o         \
        kt_file.o       \
+       kt_memory.o     \
        kt_srvtab.o     \
        read_servi.o
 
@@ -27,6 +28,7 @@ OBJS= \
        $(OUTPRE)ktremove.$(OBJEXT)     \
        $(OUTPRE)ktfns.$(OBJEXT)        \
        $(OUTPRE)kt_file.$(OBJEXT)      \
+       $(OUTPRE)kt_memory.$(OBJEXT)    \
        $(OUTPRE)kt_srvtab.$(OBJEXT)    \
        $(OUTPRE)read_servi.$(OBJEXT)
 
@@ -38,6 +40,7 @@ SRCS= \
        $(srcdir)/ktremove.c    \
        $(srcdir)/ktfns.c       \
        $(srcdir)/kt_file.c     \
+       $(srcdir)/kt_memory.c   \
        $(srcdir)/kt_srvtab.c   \
        $(srcdir)/read_servi.c
 
@@ -121,6 +124,14 @@ 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_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 \
index 23bbc5505792ac329ee7111e2b8cc38ee4be4943..e62b2d3f1bbefcb8e6b2e4b52b8b63a436ee18af 100644 (file)
@@ -36,4 +36,7 @@ int krb5int_kt_initialize(void);
 
 void krb5int_kt_finalize(void);
 
+int krb5int_mkt_initialize(void);
+
+void krb5int_mkt_finalize(void);
 #endif /* __KRB5_KEYTAB_INT_H__ */
diff --git a/src/lib/krb5/keytab/kt_memory.c b/src/lib/krb5/keytab/kt_memory.c
new file mode 100644 (file)
index 0000000..76aa31c
--- /dev/null
@@ -0,0 +1,654 @@
+/*\r
+ * lib/krb5/keytab/kt_memory.c\r
+ *\r
+ * Copyright 2007 by Secure Endpoints Inc.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person\r
+ * obtaining a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ */\r
+\r
+#include "k5-int.h"\r
+#include <stdio.h>\r
+\r
+#define HEIMDAL_COMPATIBLE\r
+\r
+/*\r
+ * Information needed by internal routines of the file-based ticket\r
+ * cache implementation.\r
+ */\r
+\r
+\r
+/*\r
+ * Constants\r
+ */\r
+#define IGNORE_VNO 0\r
+#define IGNORE_ENCTYPE 0\r
+\r
+/* \r
+ * Types\r
+ */\r
+/* From krb5.h: \r
+ * typedef struct krb5_keytab_entry_st {\r
+ *    krb5_magic magic;\r
+ *    krb5_principal principal;    principal of this key\r
+ *    krb5_timestamp timestamp;    time entry written to keytable \r
+ *    krb5_kvno vno;               key version number \r
+ *    krb5_keyblock key;           the secret key\r
+ *} krb5_keytab_entry;\r
+ */\r
+\r
+/* Individual key entries within a table, in a linked list */\r
+typedef struct _krb5_mkt_link {\r
+    struct _krb5_mkt_link *next;\r
+    krb5_keytab_entry *entry;\r
+} krb5_mkt_link, *krb5_mkt_cursor;\r
+\r
+/* Per-keytab data header */\r
+typedef struct _krb5_mkt_data {\r
+    char              *name;           /* Name of the keytab */\r
+    k5_mutex_t                 lock;           /* Thread-safety - all but link */\r
+    krb5_int32         refcount;       \r
+    krb5_mkt_cursor    link;\r
+} krb5_mkt_data;\r
+\r
+/* List of memory key tables */\r
+typedef struct _krb5_mkt_list_node {\r
+    struct _krb5_mkt_list_node *next;\r
+    krb5_keytab keytab;\r
+} krb5_mkt_list_node;\r
+\r
+/* Iterator over memory key tables */\r
+typedef struct _krb5_mkt_ptcursor_data {\r
+    struct _krb5_mkt_list_node *cur;\r
+} krb5_mkt_ptcursor_data;\r
+\r
+/* \r
+ * Globals \r
+ */\r
+static krb5_mkt_list_node * krb5int_mkt_list = NULL;\r
+static k5_mutex_t krb5int_mkt_mutex = K5_MUTEX_PARTIAL_INITIALIZER;\r
+\r
+/*\r
+ * Macros\r
+ */\r
+#define KTLOCK(id) k5_mutex_lock(&(((krb5_mkt_data *)(id)->data)->lock))\r
+#define KTUNLOCK(id) k5_mutex_unlock(&(((krb5_mkt_data *)(id)->data)->lock))\r
+#define KTCHECKLOCK(id) k5_mutex_assert_locked(&(((krb5_mkt_data *)(id)->data)->lock))\r
+\r
+#define KTGLOCK k5_mutex_lock(&krb5int_mkt_mutex)\r
+#define KTGUNLOCK k5_mutex_unlock(&krb5int_mkt_mutex)\r
+#define KTGCHECKLOCK k5_mutex_assert_locked(&krb5int_mkt_mutex)\r
+\r
+#define KTLINK(id) (((krb5_mkt_data *)(id)->data)->link)\r
+#define KTREFCNT(id) (((krb5_mkt_data *)(id)->data)->refcount)\r
+#define KTNAME(id) (((krb5_mkt_data *)(id)->data)->name)\r
+\r
+extern const struct _krb5_kt_ops krb5_mkt_ops;\r
+\r
+krb5_error_code KRB5_CALLCONV krb5_mkt_resolve \r
+       (krb5_context,\r
+                  const char *,\r
+                  krb5_keytab *);\r
+\r
+krb5_error_code KRB5_CALLCONV krb5_mkt_get_name \r
+       (krb5_context,\r
+                  krb5_keytab,\r
+                  char *,\r
+                  unsigned int);\r
+\r
+krb5_error_code KRB5_CALLCONV krb5_mkt_close \r
+       (krb5_context,\r
+                  krb5_keytab);\r
+\r
+krb5_error_code KRB5_CALLCONV krb5_mkt_get_entry \r
+       (krb5_context,\r
+                  krb5_keytab,\r
+                  krb5_const_principal,\r
+                  krb5_kvno,\r
+                  krb5_enctype,\r
+                  krb5_keytab_entry *);\r
+\r
+krb5_error_code KRB5_CALLCONV krb5_mkt_start_seq_get \r
+       (krb5_context,\r
+                  krb5_keytab,\r
+                  krb5_kt_cursor *);\r
+\r
+krb5_error_code KRB5_CALLCONV krb5_mkt_get_next \r
+       (krb5_context,\r
+                  krb5_keytab,\r
+                  krb5_keytab_entry *,\r
+                  krb5_kt_cursor *);\r
+\r
+krb5_error_code KRB5_CALLCONV krb5_mkt_end_get \r
+       (krb5_context,\r
+                  krb5_keytab,\r
+                  krb5_kt_cursor *);\r
+\r
+/* routines to be included on extended version (write routines) */\r
+krb5_error_code KRB5_CALLCONV krb5_mkt_add \r
+       (krb5_context,\r
+                  krb5_keytab,\r
+                  krb5_keytab_entry *);\r
+\r
+krb5_error_code KRB5_CALLCONV krb5_mkt_remove \r
+       (krb5_context,\r
+                  krb5_keytab,\r
+                  krb5_keytab_entry *);\r
+\r
+int krb5int_mkt_initialize(void) {\r
+    return k5_mutex_finish_init(&krb5int_mkt_mutex);\r
+}\r
+\r
+void krb5int_mkt_finalize(void) {\r
+    krb5_mkt_list_node *node, *next_node;\r
+    krb5_mkt_cursor cursor, next_cursor;\r
+\r
+    k5_mutex_destroy(&krb5int_mkt_mutex);\r
+\r
+    for (node = krb5int_mkt_list; node; node = next_node) {\r
+       next_node = node->next;\r
+\r
+       /* destroy the contents of node->keytab */\r
+       krb5_xfree(KTNAME(node->keytab));\r
+\r
+       /* free the keytab entries */\r
+       for (cursor = KTLINK(node->keytab); cursor; cursor = next_cursor) {\r
+           next_cursor = cursor->next;\r
+           /* the call to krb5_kt_free_entry uses a NULL in place of the\r
+            * krb5_context since we know that the context isn't used by\r
+            * krb5_kt_free_entry or krb5_free_principal. */\r
+           krb5_kt_free_entry(NULL, cursor->entry);\r
+           krb5_xfree(cursor);\r
+       }\r
+\r
+       /* destroy the lock */\r
+       k5_mutex_destroy(&(((krb5_mkt_data *)node->keytab->data)->lock));\r
+\r
+       /* free the private data */\r
+       krb5_xfree(node->keytab->data);\r
+\r
+       /* and the keytab */\r
+       krb5_xfree(node->keytab);\r
+\r
+       /* and finally the node */\r
+       krb5_xfree(node);\r
+    }\r
+}\r
+/*\r
+ * This is an implementation specific resolver.  It returns a keytab \r
+ * initialized with memory keytab routines.\r
+ */\r
+\r
+krb5_error_code KRB5_CALLCONV \r
+krb5_mkt_resolve(krb5_context context, const char *name, krb5_keytab *id)\r
+{\r
+    krb5_mkt_data *data;\r
+    krb5_mkt_list_node *list;\r
+    krb5_error_code err = 0;\r
+\r
+    /* First determine if a memory keytab of this name already exists */\r
+    err = KTGLOCK;\r
+    if (err)\r
+       return(err);\r
+\r
+    for (list = krb5int_mkt_list; list; list = list->next)\r
+    {\r
+       if (strcmp(name,KTNAME(list->keytab)) == 0) {\r
+           /* Found */\r
+           *id = list->keytab;\r
+           goto done;\r
+       }\r
+    }\r
+\r
+    /* We will now create the new key table with the specified name.\r
+     * We do not drop the global lock, therefore the name will indeed\r
+     * be unique when we add it.\r
+     */\r
+\r
+    if ((list = (krb5_mkt_list_node *)malloc(sizeof(krb5_mkt_list_node))) == NULL) {\r
+       err = ENOMEM;\r
+       goto done;\r
+    }\r
+\r
+    if ((list->keytab = (krb5_keytab)malloc(sizeof(struct _krb5_kt))) == NULL) {\r
+       krb5_xfree(list);\r
+       err = ENOMEM;\r
+       goto done;      \r
+    }\r
+\r
+    list->keytab->ops = &krb5_mkt_ops;\r
+    if ((data = (krb5_mkt_data *)malloc(sizeof(krb5_mkt_data))) == NULL) {\r
+       krb5_xfree(list->keytab);\r
+       krb5_xfree(list);\r
+       err = ENOMEM;\r
+       goto done;\r
+    }\r
+\r
+    err = k5_mutex_init(&data->lock);\r
+    if (err) {\r
+       krb5_xfree(data);\r
+       krb5_xfree(list->keytab);\r
+       krb5_xfree(list);\r
+       goto done;\r
+    }\r
+\r
+    if ((data->name = (char *)calloc(strlen(name) + 1, sizeof(char))) == NULL) {\r
+       k5_mutex_destroy(&data->lock);\r
+       krb5_xfree(data);\r
+       krb5_xfree(list->keytab);\r
+       krb5_xfree(list);\r
+       err = ENOMEM;\r
+       goto done;\r
+    }\r
+\r
+    (void) strcpy(data->name, name);\r
+\r
+    data->link = NULL;\r
+    data->refcount = 0;\r
+    list->keytab->data = (krb5_pointer)data;\r
+    list->keytab->magic = KV5M_KEYTAB;\r
+\r
+    list->next = krb5int_mkt_list;\r
+    krb5int_mkt_list = list;\r
+\r
+    *id = list->keytab;\r
+\r
+  done:\r
+    err = KTLOCK(*id);\r
+    if (err) {\r
+       k5_mutex_destroy(&data->lock);\r
+       krb5_xfree(data->name);\r
+       krb5_xfree(data);\r
+       krb5_xfree(list->keytab);\r
+       krb5_xfree(list);\r
+    } else {\r
+       KTREFCNT(*id)++;\r
+       KTUNLOCK(*id);\r
+    }\r
+\r
+    KTGUNLOCK;\r
+    return(err);\r
+}\r
+\r
+\r
+/*\r
+ * "Close" a memory-based keytab.  This is effectively a no-op.\r
+ * We check to see if the keytab exists and that is about it.\r
+ * Closing a file keytab does not destroy the contents.  Closing\r
+ * a memory keytab shouldn't either.\r
+ */\r
+\r
+krb5_error_code KRB5_CALLCONV \r
+krb5_mkt_close(krb5_context context, krb5_keytab id)\r
+{\r
+    krb5_mkt_list_node **listp;\r
+#ifdef HEIMDAL_COMPATIBLE\r
+    krb5_mkt_list_node *node;\r
+    krb5_mkt_data * data;\r
+#endif\r
+    krb5_error_code err = 0;\r
+\r
+    /* First determine if a memory keytab of this name already exists */\r
+    err = KTGLOCK;\r
+    if (err)\r
+       return(err);\r
+    \r
+    for (listp = &krb5int_mkt_list; *listp; listp = &((*listp)->next))\r
+    {\r
+       if (id == (*listp)->keytab) {\r
+           /* Found */\r
+           break;\r
+       }\r
+    }\r
+\r
+    if (*listp == NULL) {\r
+       /* The specified keytab could not be found */\r
+       err = KRB5_KT_NOTFOUND;\r
+       goto done;\r
+    }\r
+\r
+    /* reduce the refcount and return */\r
+    err = KTLOCK(id);\r
+    if (err)\r
+       goto done;\r
+\r
+    KTREFCNT(id)--;\r
+    KTUNLOCK(id);\r
+\r
+#ifdef HEIMDAL_COMPATIBLE\r
+    /* In Heimdal if the refcount hits 0, the MEMORY keytab is \r
+     * destroyed since there is no krb5_kt_destroy function.\r
+     * There is no need to lock the entry while performing \r
+     * these operations as the refcount will be 0 and we are\r
+     * holding the global lock.\r
+     */\r
+    data = (krb5_mkt_data *)id->data;\r
+    if (data->refcount == 0) {\r
+       krb5_mkt_cursor cursor, next_cursor;\r
+\r
+       node = *listp;\r
+       *listp = node->next;\r
+\r
+       /* destroy the contents of node->keytab (aka id) */\r
+       krb5_xfree(data->name);\r
+\r
+       /* free the keytab entries */\r
+       for (cursor = KTLINK(node->keytab); cursor; cursor = next_cursor) {\r
+           next_cursor = cursor->next;\r
+\r
+           krb5_kt_free_entry(context, cursor->entry);\r
+           krb5_xfree(cursor);\r
+       }\r
+\r
+       /* destroy the lock */\r
+       k5_mutex_destroy(&(data->lock));\r
+\r
+       /* free the private data */\r
+       krb5_xfree(data);\r
+\r
+       /* and the keytab */\r
+       krb5_xfree(node->keytab);\r
+\r
+       /* and finally the node */\r
+       krb5_xfree(node);\r
+    }\r
+#endif /* HEIMDAL_COMPATIBLE */\r
+\r
+  done:\r
+    KTGUNLOCK;\r
+    return(err);\r
+}\r
+\r
+/*\r
+ * This is the get_entry routine for the memory based keytab implementation.\r
+ * It either retrieves the entry or returns an error.\r
+ */\r
+\r
+krb5_error_code KRB5_CALLCONV\r
+krb5_mkt_get_entry(krb5_context context, krb5_keytab id,\r
+                     krb5_const_principal principal, krb5_kvno kvno,\r
+                     krb5_enctype enctype, krb5_keytab_entry *out_entry)\r
+{\r
+    krb5_mkt_cursor   cursor;\r
+    krb5_keytab_entry *entry, *match = NULL;\r
+    krb5_error_code err = 0;\r
+    int found_wrong_kvno = 0;\r
+    krb5_boolean similar = 0;\r
+\r
+    err = KTLOCK(id);\r
+    if (err)\r
+       return err;\r
+\r
+    for (cursor = KTLINK(id); cursor && cursor->entry; cursor = cursor->next) {\r
+       entry = cursor->entry;\r
+\r
+       /* if the principal isn't the one requested, free new_entry\r
+          and continue to the next. */\r
+\r
+       if (!krb5_principal_compare(context, principal, entry->principal))\r
+           continue;\r
+\r
+       /* if the enctype is not ignored and doesn't match, free new_entry\r
+          and continue to the next */\r
+       if (enctype != IGNORE_ENCTYPE) {\r
+           if ((err = krb5_c_enctype_compare(context, enctype, \r
+                                             entry->key.enctype,\r
+                                              &similar))) {\r
+               /* we can't determine the enctype of the entry */\r
+               continue;\r
+           }\r
+\r
+           if (!similar)\r
+               continue;\r
+       }\r
+\r
+       if (kvno == IGNORE_VNO) {\r
+           if (match == NULL)\r
+               match = entry;\r
+           else if (entry->vno > match->vno)\r
+               match = entry;\r
+       } else {\r
+           if (entry->vno == kvno) {\r
+               match = entry;\r
+               break;\r
+           } else {\r
+               found_wrong_kvno++;\r
+           }\r
+       }\r
+    }\r
+\r
+    /* if we found an entry that matches, ... */\r
+    if (match) { \r
+       out_entry->magic = entry->magic;\r
+       out_entry->timestamp = entry->timestamp;\r
+       out_entry->vno = entry->vno;\r
+       out_entry->key = entry->key; \r
+       /*\r
+        * Coerce the enctype of the output keyblock in case we\r
+        * got an inexact match on the enctype.\r
+        */\r
+       out_entry->key.enctype = enctype;\r
+       err = krb5_copy_principal(context, entry->principal, &(out_entry->principal));\r
+    } else {\r
+       if (!err)\r
+           err = found_wrong_kvno ? KRB5_KT_KVNONOTFOUND : KRB5_KT_NOTFOUND;\r
+    }\r
+\r
+    KTUNLOCK(id);\r
+    return(err);\r
+}\r
+\r
+/*\r
+ * Get the name of the memory-based keytab.\r
+ */\r
+\r
+krb5_error_code KRB5_CALLCONV\r
+krb5_mkt_get_name(krb5_context context, krb5_keytab id, char *name, unsigned int len)\r
+{\r
+    memset(name, 0, len);\r
+\r
+    if (len < strlen(id->ops->prefix)+2)\r
+       return(KRB5_KT_NAME_TOOLONG);\r
+    strcpy(name, id->ops->prefix);\r
+    name += strlen(id->ops->prefix);\r
+    name[0] = ':';\r
+    name++;\r
+    len -= strlen(id->ops->prefix)+1;\r
+\r
+    if (len < strlen(KTNAME(id)+1))\r
+       return(KRB5_KT_NAME_TOOLONG);\r
+    strcpy(name, KTNAME(id));\r
+    /* strcpy will NUL-terminate the destination */\r
+\r
+    return(0);\r
+}\r
+\r
+/*\r
+ * krb5_mkt_start_seq_get()\r
+ */\r
+\r
+krb5_error_code KRB5_CALLCONV\r
+krb5_mkt_start_seq_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursorp)\r
+{\r
+    krb5_error_code err = 0;\r
+\r
+    err = KTLOCK(id);\r
+    if (err)\r
+       return(err);\r
+\r
+    *cursorp = (krb5_kt_cursor)KTLINK(id);\r
+    KTUNLOCK(id);\r
+\r
+    return(0);\r
+}\r
+\r
+/*\r
+ * krb5_mkt_get_next()\r
+ */\r
+\r
+krb5_error_code KRB5_CALLCONV \r
+krb5_mkt_get_next(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry, krb5_kt_cursor *cursor)\r
+{\r
+    krb5_mkt_cursor mkt_cursor = (krb5_mkt_cursor)*cursor;\r
+    krb5_error_code err = 0;\r
+\r
+    err = KTLOCK(id);\r
+    if (err)\r
+       return err;\r
+\r
+    if (mkt_cursor == NULL) {\r
+       KTUNLOCK(id);\r
+       return KRB5_KT_END;\r
+    }\r
+\r
+    entry->magic = mkt_cursor->entry->magic;\r
+    entry->timestamp = mkt_cursor->entry->timestamp;\r
+    entry->vno = mkt_cursor->entry->vno;\r
+    entry->key = mkt_cursor->entry->key; \r
+    err = krb5_copy_principal(context, mkt_cursor->entry->principal, &(entry->principal));\r
+    if (!err)\r
+       *cursor = (krb5_kt_cursor *)mkt_cursor->next;\r
+    KTUNLOCK(id);\r
+    return(err);\r
+}\r
+\r
+/*\r
+ * krb5_mkt_end_get()\r
+ */\r
+\r
+krb5_error_code KRB5_CALLCONV \r
+krb5_mkt_end_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursor)\r
+{\r
+    *cursor = NULL;\r
+    return(0);\r
+}\r
+\r
+\r
+/*\r
+ * krb5_mkt_add()\r
+ */\r
+\r
+krb5_error_code KRB5_CALLCONV \r
+krb5_mkt_add(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry)\r
+{\r
+    krb5_error_code err = 0;\r
+    krb5_mkt_cursor cursor;\r
+\r
+    err = KTLOCK(id);\r
+    if (err)\r
+       return err;\r
+\r
+    cursor = (krb5_mkt_cursor)malloc(sizeof(krb5_mkt_link));\r
+    if (cursor == NULL) {\r
+       err = ENOMEM;\r
+       goto done;\r
+    }\r
+    cursor->entry = (krb5_keytab_entry *)malloc(sizeof(krb5_keytab_entry));\r
+    if (cursor->entry == NULL) {\r
+       krb5_xfree(cursor);\r
+       err = ENOMEM;\r
+       goto done;\r
+    }\r
+    cursor->entry->magic = entry->magic;\r
+    cursor->entry->timestamp = entry->timestamp;\r
+    cursor->entry->vno = entry->vno;\r
+    cursor->entry->key = entry->key; \r
+    err = krb5_copy_principal(context, entry->principal, &(cursor->entry->principal));\r
+    if (err) {\r
+       krb5_xfree(cursor->entry);\r
+       krb5_xfree(cursor);\r
+       goto done;\r
+    }\r
+\r
+    if (KTLINK(id) == NULL) {\r
+       cursor->next = NULL;\r
+       KTLINK(id) = cursor;\r
+    } else {\r
+       cursor->next = KTLINK(id);\r
+       KTLINK(id) = cursor;\r
+    }\r
+\r
+  done:\r
+    KTUNLOCK(id);\r
+    return err;\r
+}\r
+\r
+/*\r
+ * krb5_mkt_remove()\r
+ */\r
+\r
+krb5_error_code KRB5_CALLCONV \r
+krb5_mkt_remove(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry)\r
+{\r
+    krb5_mkt_cursor *pcursor, next;\r
+    krb5_error_code err = 0;\r
+\r
+    err = KTLOCK(id);\r
+    if (err)\r
+       return err;\r
+\r
+    if ( KTLINK(id) == NULL ) {\r
+       err = KRB5_KT_NOTFOUND;\r
+       goto done;\r
+    }\r
+       \r
+    for ( pcursor = &KTLINK(id); *pcursor; pcursor = &(*pcursor)->next ) {\r
+       if ( (*pcursor)->entry->vno == entry->vno &&\r
+            (*pcursor)->entry->key.enctype == entry->key.enctype &&\r
+            krb5_principal_compare(context, (*pcursor)->entry->principal, entry->principal))\r
+            break;\r
+    }\r
+\r
+    if (!*pcursor) {\r
+       err = KRB5_KT_NOTFOUND;\r
+       goto done;\r
+    }\r
+\r
+    krb5_kt_free_entry(context, (*pcursor)->entry);\r
+    krb5_xfree((*pcursor)->entry);\r
+    next = (*pcursor)->next;\r
+    krb5_xfree(*pcursor);\r
+    (*pcursor) = next;\r
+\r
+  done:\r
+    KTUNLOCK(id);\r
+    return err;\r
+}\r
+\r
+\r
+/*\r
+ * krb5_mkt_ops\r
+ */\r
+\r
+const struct _krb5_kt_ops krb5_mkt_ops = {\r
+    0,\r
+    "MEMORY",  /* Prefix -- this string should not appear anywhere else! */\r
+    krb5_mkt_resolve,\r
+    krb5_mkt_get_name, \r
+    krb5_mkt_close,\r
+    krb5_mkt_get_entry,\r
+    krb5_mkt_start_seq_get,\r
+    krb5_mkt_get_next,\r
+    krb5_mkt_end_get,\r
+    krb5_mkt_add,\r
+    krb5_mkt_remove,\r
+    NULL\r
+};\r
+\r
index 79c9151efdc897f9616ffe2b1ffe5a9766da8b21..3e4f6a6be615789743231f4ccc6c9350f91cbeb5 100644 (file)
  * or implied warranty.
  * 
  *
+ * Copyright 2007 by Secure Endpoints Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
  * Registration functions for keytab.
  */
 
 extern const krb5_kt_ops krb5_ktf_ops;
 extern const krb5_kt_ops krb5_ktf_writable_ops;
 extern const krb5_kt_ops krb5_kts_ops;
+extern const krb5_kt_ops krb5_mkt_ops;
 
 struct krb5_kt_typelist {
     const krb5_kt_ops *ops;
     const struct krb5_kt_typelist *next;
 };
+const static struct krb5_kt_typelist krb5_kt_typelist_srvtab = {
+    &krb5_kts_ops,
+    NULL
+};
+const static struct krb5_kt_typelist krb5_kt_typelist_memory = {
+    &krb5_mkt_ops,
+    &krb5_kt_typelist_srvtab
+};
 const static struct krb5_kt_typelist krb5_kt_typelist_wrfile  = {
     &krb5_ktf_writable_ops,
-    0
+    &krb5_kt_typelist_memory
 };
 const static struct krb5_kt_typelist krb5_kt_typelist_file  = {
     &krb5_ktf_ops,
     &krb5_kt_typelist_wrfile
 };
-const static struct krb5_kt_typelist krb5_kt_typelist_srvtab = {
-    &krb5_kts_ops,
-    &krb5_kt_typelist_file
-};
-static const struct krb5_kt_typelist *kt_typehead = &krb5_kt_typelist_srvtab;
+
+static const struct krb5_kt_typelist *kt_typehead = &krb5_kt_typelist_file;
 /* Lock for protecting the type list.  */
 static k5_mutex_t kt_typehead_lock = K5_MUTEX_PARTIAL_INITIALIZER;
 
 int krb5int_kt_initialize(void)
 {
-    return k5_mutex_finish_init(&kt_typehead_lock);
+    int err;
+
+    err = k5_mutex_finish_init(&kt_typehead_lock);
+    if (err)
+       goto done;
+    err = krb5int_mkt_initialize();
+    if (err)
+       goto done;
+
+  done:
+    return(err);
 }
 
 void
 krb5int_kt_finalize(void)
 {
-    struct krb5_kt_typelist *t, *t_next;
+    const struct krb5_kt_typelist *t, *t_next;
+
     k5_mutex_destroy(&kt_typehead_lock);
-    for (t = kt_typehead; t != &krb5_kt_typelist_srvtab; t = t_next) {
+    for (t = kt_typehead; t != &krb5_kt_typelist_file; t = t_next) {
        t_next = t->next;
-       free(t);
+       free((struct krb5_kt_typelist *)t);
     }
+
+    krb5int_mkt_finalize();
 }
 
 
index a86b38bc2d36e0ce866994eb9e26a67e7da15c38..b4305e21afe563a2c6e5c112255e8b6718bb21cc 100644 (file)
@@ -37,7 +37,7 @@ krb5_free_keytab_entry_contents (krb5_context context, krb5_keytab_entry *entry)
     
     krb5_free_principal(context, entry->principal);
     if (entry->key.contents) {
-       memset((char *)entry->key.contents, 0, entry->key.length);
+       zap((char *)entry->key.contents, entry->key.length);
        krb5_xfree(entry->key.contents);
     }
     return 0;