From 4711fe7c1cd4761c893c371b84757d6bfcda82e8 Mon Sep 17 00:00:00 2001 From: Ken Raeburn Date: Tue, 19 Jun 2007 23:45:48 +0000 Subject: [PATCH] set eol-style and mime-type properties git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@19594 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/krb5/keytab/kt_memory.c | 1354 +++++++++++++++---------------- 1 file changed, 677 insertions(+), 677 deletions(-) diff --git a/src/lib/krb5/keytab/kt_memory.c b/src/lib/krb5/keytab/kt_memory.c index e103e7685..ae232801a 100644 --- a/src/lib/krb5/keytab/kt_memory.c +++ b/src/lib/krb5/keytab/kt_memory.c @@ -1,677 +1,677 @@ -/* - * lib/krb5/keytab/kt_memory.c - * - * 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. - */ - -#include "k5-int.h" -#include "kt-int.h" -#include - -#define HEIMDAL_COMPATIBLE - -/* - * Information needed by internal routines of the file-based ticket - * cache implementation. - */ - - -/* - * Constants - */ -#define IGNORE_VNO 0 -#define IGNORE_ENCTYPE 0 - -/* - * Types - */ -/* From krb5.h: - * typedef struct krb5_keytab_entry_st { - * krb5_magic magic; - * krb5_principal principal; principal of this key - * krb5_timestamp timestamp; time entry written to keytable - * krb5_kvno vno; key version number - * krb5_keyblock key; the secret key - *} krb5_keytab_entry; - */ - -/* Individual key entries within a table, in a linked list */ -typedef struct _krb5_mkt_link { - struct _krb5_mkt_link *next; - krb5_keytab_entry *entry; -} krb5_mkt_link, *krb5_mkt_cursor; - -/* Per-keytab data header */ -typedef struct _krb5_mkt_data { - char *name; /* Name of the keytab */ - k5_mutex_t lock; /* Thread-safety - all but link */ - krb5_int32 refcount; - krb5_mkt_cursor link; -} krb5_mkt_data; - -/* List of memory key tables */ -typedef struct _krb5_mkt_list_node { - struct _krb5_mkt_list_node *next; - krb5_keytab keytab; -} krb5_mkt_list_node; - -/* Iterator over memory key tables */ -typedef struct _krb5_mkt_ptcursor_data { - struct _krb5_mkt_list_node *cur; -} krb5_mkt_ptcursor_data; - -/* - * Globals - */ -static krb5_mkt_list_node * krb5int_mkt_list = NULL; -static k5_mutex_t krb5int_mkt_mutex = K5_MUTEX_PARTIAL_INITIALIZER; - -/* - * Macros - */ -#define KTLOCK(id) k5_mutex_lock(&(((krb5_mkt_data *)(id)->data)->lock)) -#define KTUNLOCK(id) k5_mutex_unlock(&(((krb5_mkt_data *)(id)->data)->lock)) -#define KTCHECKLOCK(id) k5_mutex_assert_locked(&(((krb5_mkt_data *)(id)->data)->lock)) - -#define KTGLOCK k5_mutex_lock(&krb5int_mkt_mutex) -#define KTGUNLOCK k5_mutex_unlock(&krb5int_mkt_mutex) -#define KTGCHECKLOCK k5_mutex_assert_locked(&krb5int_mkt_mutex) - -#define KTLINK(id) (((krb5_mkt_data *)(id)->data)->link) -#define KTREFCNT(id) (((krb5_mkt_data *)(id)->data)->refcount) -#define KTNAME(id) (((krb5_mkt_data *)(id)->data)->name) - -extern const struct _krb5_kt_ops krb5_mkt_ops; - -krb5_error_code KRB5_CALLCONV krb5_mkt_resolve - (krb5_context, - const char *, - krb5_keytab *); - -krb5_error_code KRB5_CALLCONV krb5_mkt_get_name - (krb5_context, - krb5_keytab, - char *, - unsigned int); - -krb5_error_code KRB5_CALLCONV krb5_mkt_close - (krb5_context, - krb5_keytab); - -krb5_error_code KRB5_CALLCONV krb5_mkt_get_entry - (krb5_context, - krb5_keytab, - krb5_const_principal, - krb5_kvno, - krb5_enctype, - krb5_keytab_entry *); - -krb5_error_code KRB5_CALLCONV krb5_mkt_start_seq_get - (krb5_context, - krb5_keytab, - krb5_kt_cursor *); - -krb5_error_code KRB5_CALLCONV krb5_mkt_get_next - (krb5_context, - krb5_keytab, - krb5_keytab_entry *, - krb5_kt_cursor *); - -krb5_error_code KRB5_CALLCONV krb5_mkt_end_get - (krb5_context, - krb5_keytab, - krb5_kt_cursor *); - -/* routines to be included on extended version (write routines) */ -krb5_error_code KRB5_CALLCONV krb5_mkt_add - (krb5_context, - krb5_keytab, - krb5_keytab_entry *); - -krb5_error_code KRB5_CALLCONV krb5_mkt_remove - (krb5_context, - krb5_keytab, - krb5_keytab_entry *); - -int krb5int_mkt_initialize(void) { - return k5_mutex_finish_init(&krb5int_mkt_mutex); -} - -void krb5int_mkt_finalize(void) { - krb5_mkt_list_node *node, *next_node; - krb5_mkt_cursor cursor, next_cursor; - - k5_mutex_destroy(&krb5int_mkt_mutex); - - for (node = krb5int_mkt_list; node; node = next_node) { - next_node = node->next; - - /* destroy the contents of node->keytab */ - krb5_xfree(KTNAME(node->keytab)); - - /* free the keytab entries */ - for (cursor = KTLINK(node->keytab); cursor; cursor = next_cursor) { - next_cursor = cursor->next; - /* the call to krb5_kt_free_entry uses a NULL in place of the - * krb5_context since we know that the context isn't used by - * krb5_kt_free_entry or krb5_free_principal. */ - krb5_kt_free_entry(NULL, cursor->entry); - krb5_xfree(cursor->entry); - krb5_xfree(cursor); - } - - /* destroy the lock */ - k5_mutex_destroy(&(((krb5_mkt_data *)node->keytab->data)->lock)); - - /* free the private data */ - krb5_xfree(node->keytab->data); - - /* and the keytab */ - krb5_xfree(node->keytab); - - /* and finally the node */ - krb5_xfree(node); - } -} -/* - * This is an implementation specific resolver. It returns a keytab - * initialized with memory keytab routines. - */ - -krb5_error_code KRB5_CALLCONV -krb5_mkt_resolve(krb5_context context, const char *name, krb5_keytab *id) -{ - krb5_mkt_data *data = 0; - krb5_mkt_list_node *list; - krb5_error_code err = 0; - - /* First determine if a memory keytab of this name already exists */ - err = KTGLOCK; - if (err) - return(err); - - for (list = krb5int_mkt_list; list; list = list->next) - { - if (strcmp(name,KTNAME(list->keytab)) == 0) { - /* Found */ - *id = list->keytab; - goto done; - } - } - - /* We will now create the new key table with the specified name. - * We do not drop the global lock, therefore the name will indeed - * be unique when we add it. - */ - - if ((list = (krb5_mkt_list_node *)malloc(sizeof(krb5_mkt_list_node))) == NULL) { - err = ENOMEM; - goto done; - } - - if ((list->keytab = (krb5_keytab)malloc(sizeof(struct _krb5_kt))) == NULL) { - krb5_xfree(list); - err = ENOMEM; - goto done; - } - - list->keytab->ops = &krb5_mkt_ops; - if ((data = (krb5_mkt_data *)malloc(sizeof(krb5_mkt_data))) == NULL) { - krb5_xfree(list->keytab); - krb5_xfree(list); - err = ENOMEM; - goto done; - } - - err = k5_mutex_init(&data->lock); - if (err) { - krb5_xfree(data); - krb5_xfree(list->keytab); - krb5_xfree(list); - goto done; - } - - if ((data->name = (char *)calloc(strlen(name) + 1, sizeof(char))) == NULL) { - k5_mutex_destroy(&data->lock); - krb5_xfree(data); - krb5_xfree(list->keytab); - krb5_xfree(list); - err = ENOMEM; - goto done; - } - - (void) strcpy(data->name, name); - - data->link = NULL; - data->refcount = 0; - list->keytab->data = (krb5_pointer)data; - list->keytab->magic = KV5M_KEYTAB; - - list->next = krb5int_mkt_list; - krb5int_mkt_list = list; - - *id = list->keytab; - - done: - err = KTLOCK(*id); - if (err) { - k5_mutex_destroy(&data->lock); - if (data && data->name) - krb5_xfree(data->name); - krb5_xfree(data); - if (list && list->keytab) - krb5_xfree(list->keytab); - krb5_xfree(list); - } else { - KTREFCNT(*id)++; - KTUNLOCK(*id); - } - - KTGUNLOCK; - return(err); -} - - -/* - * "Close" a memory-based keytab. This is effectively a no-op. - * We check to see if the keytab exists and that is about it. - * Closing a file keytab does not destroy the contents. Closing - * a memory keytab shouldn't either. - */ - -krb5_error_code KRB5_CALLCONV -krb5_mkt_close(krb5_context context, krb5_keytab id) -{ - krb5_mkt_list_node **listp; -#ifdef HEIMDAL_COMPATIBLE - krb5_mkt_list_node *node; - krb5_mkt_data * data; -#endif - krb5_error_code err = 0; - - /* First determine if a memory keytab of this name already exists */ - err = KTGLOCK; - if (err) - return(err); - - for (listp = &krb5int_mkt_list; *listp; listp = &((*listp)->next)) - { - if (id == (*listp)->keytab) { - /* Found */ - break; - } - } - - if (*listp == NULL) { - /* The specified keytab could not be found */ - err = KRB5_KT_NOTFOUND; - goto done; - } - - /* reduce the refcount and return */ - err = KTLOCK(id); - if (err) - goto done; - - KTREFCNT(id)--; - KTUNLOCK(id); - -#ifdef HEIMDAL_COMPATIBLE - /* In Heimdal if the refcount hits 0, the MEMORY keytab is - * destroyed since there is no krb5_kt_destroy function. - * There is no need to lock the entry while performing - * these operations as the refcount will be 0 and we are - * holding the global lock. - */ - data = (krb5_mkt_data *)id->data; - if (data->refcount == 0) { - krb5_mkt_cursor cursor, next_cursor; - - node = *listp; - *listp = node->next; - - /* destroy the contents of node->keytab (aka id) */ - krb5_xfree(data->name); - - /* free the keytab entries */ - for (cursor = KTLINK(node->keytab); cursor; cursor = next_cursor) { - next_cursor = cursor->next; - - krb5_kt_free_entry(context, cursor->entry); - krb5_xfree(cursor->entry); - krb5_xfree(cursor); - } - - /* destroy the lock */ - k5_mutex_destroy(&(data->lock)); - - /* free the private data */ - krb5_xfree(data); - - /* and the keytab */ - krb5_xfree(node->keytab); - - /* and finally the node */ - krb5_xfree(node); - } -#endif /* HEIMDAL_COMPATIBLE */ - - done: - KTGUNLOCK; - return(err); -} - -/* - * This is the get_entry routine for the memory based keytab implementation. - * It either retrieves the entry or returns an error. - */ - -krb5_error_code KRB5_CALLCONV -krb5_mkt_get_entry(krb5_context context, krb5_keytab id, - krb5_const_principal principal, krb5_kvno kvno, - krb5_enctype enctype, krb5_keytab_entry *out_entry) -{ - krb5_mkt_cursor cursor; - krb5_keytab_entry *entry, *match = NULL; - krb5_error_code err = 0; - int found_wrong_kvno = 0; - krb5_boolean similar = 0; - - err = KTLOCK(id); - if (err) - return err; - - for (cursor = KTLINK(id); cursor && cursor->entry; cursor = cursor->next) { - entry = cursor->entry; - - /* if the principal isn't the one requested, continue to the next. */ - - if (!krb5_principal_compare(context, principal, entry->principal)) - continue; - - /* if the enctype is not ignored and doesn't match, - and continue to the next */ - if (enctype != IGNORE_ENCTYPE) { - if ((err = krb5_c_enctype_compare(context, enctype, - entry->key.enctype, - &similar))) { - /* we can't determine the enctype of the entry */ - continue; - } - - if (!similar) - continue; - } - - if (kvno == IGNORE_VNO) { - if (match == NULL) - match = entry; - else if (entry->vno > match->vno) - match = entry; - } else { - if (entry->vno == kvno) { - match = entry; - break; - } else { - found_wrong_kvno++; - } - } - } - - /* if we found an entry that matches, ... */ - if (match) { - out_entry->magic = match->magic; - out_entry->timestamp = match->timestamp; - out_entry->vno = match->vno; - out_entry->key = match->key; - err = krb5_copy_keyblock_contents(context, &(match->key), - &(out_entry->key)); - /* - * Coerce the enctype of the output keyblock in case we - * got an inexact match on the enctype. - */ - if(enctype != IGNORE_ENCTYPE) - out_entry->key.enctype = enctype; - if(!err) { - err = krb5_copy_principal(context, - match->principal, - &(out_entry->principal)); - } - } else { - if (!err) - err = found_wrong_kvno ? KRB5_KT_KVNONOTFOUND : KRB5_KT_NOTFOUND; - } - - KTUNLOCK(id); - return(err); -} - -/* - * Get the name of the memory-based keytab. - */ - -krb5_error_code KRB5_CALLCONV -krb5_mkt_get_name(krb5_context context, krb5_keytab id, char *name, unsigned int len) -{ - memset(name, 0, len); - - if (len < strlen(id->ops->prefix)+2) - return(KRB5_KT_NAME_TOOLONG); - strcpy(name, id->ops->prefix); - name += strlen(id->ops->prefix); - name[0] = ':'; - name++; - len -= strlen(id->ops->prefix)+1; - - if (len < strlen(KTNAME(id))+1) - return(KRB5_KT_NAME_TOOLONG); - strcpy(name, KTNAME(id)); - /* strcpy will NUL-terminate the destination */ - - return(0); -} - -/* - * krb5_mkt_start_seq_get() - */ - -krb5_error_code KRB5_CALLCONV -krb5_mkt_start_seq_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursorp) -{ - krb5_error_code err = 0; - - err = KTLOCK(id); - if (err) - return(err); - - *cursorp = (krb5_kt_cursor)KTLINK(id); - KTUNLOCK(id); - - return(0); -} - -/* - * krb5_mkt_get_next() - */ - -krb5_error_code KRB5_CALLCONV -krb5_mkt_get_next(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry, krb5_kt_cursor *cursor) -{ - krb5_mkt_cursor mkt_cursor = (krb5_mkt_cursor)*cursor; - krb5_error_code err = 0; - - err = KTLOCK(id); - if (err) - return err; - - if (mkt_cursor == NULL) { - KTUNLOCK(id); - return KRB5_KT_END; - } - - entry->magic = mkt_cursor->entry->magic; - entry->timestamp = mkt_cursor->entry->timestamp; - entry->vno = mkt_cursor->entry->vno; - entry->key = mkt_cursor->entry->key; - err = krb5_copy_keyblock_contents(context, &(mkt_cursor->entry->key), - &(entry->key)); - if (!err) - err = krb5_copy_principal(context, mkt_cursor->entry->principal, - &(entry->principal)); - if (!err) - *cursor = (krb5_kt_cursor *)mkt_cursor->next; - KTUNLOCK(id); - return(err); -} - -/* - * krb5_mkt_end_get() - */ - -krb5_error_code KRB5_CALLCONV -krb5_mkt_end_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursor) -{ - *cursor = NULL; - return(0); -} - - -/* - * krb5_mkt_add() - */ - -krb5_error_code KRB5_CALLCONV -krb5_mkt_add(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry) -{ - krb5_error_code err = 0; - krb5_mkt_cursor cursor; - - err = KTLOCK(id); - if (err) - return err; - - cursor = (krb5_mkt_cursor)malloc(sizeof(krb5_mkt_link)); - if (cursor == NULL) { - err = ENOMEM; - goto done; - } - cursor->entry = (krb5_keytab_entry *)malloc(sizeof(krb5_keytab_entry)); - if (cursor->entry == NULL) { - krb5_xfree(cursor); - err = ENOMEM; - goto done; - } - cursor->entry->magic = entry->magic; - cursor->entry->timestamp = entry->timestamp; - cursor->entry->vno = entry->vno; - err = krb5_copy_keyblock_contents(context, &(entry->key), - &(cursor->entry->key)); - if (err) { - krb5_xfree(cursor->entry); - krb5_xfree(cursor); - goto done; - } - - err = krb5_copy_principal(context, entry->principal, &(cursor->entry->principal)); - if (err) { - krb5_free_keyblock_contents(context, &(cursor->entry->key)); - krb5_xfree(cursor->entry); - krb5_xfree(cursor); - goto done; - } - - if (KTLINK(id) == NULL) { - cursor->next = NULL; - KTLINK(id) = cursor; - } else { - cursor->next = KTLINK(id); - KTLINK(id) = cursor; - } - - done: - KTUNLOCK(id); - return err; -} - -/* - * krb5_mkt_remove() - */ - -krb5_error_code KRB5_CALLCONV -krb5_mkt_remove(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry) -{ - krb5_mkt_cursor *pcursor, next; - krb5_error_code err = 0; - - err = KTLOCK(id); - if (err) - return err; - - if ( KTLINK(id) == NULL ) { - err = KRB5_KT_NOTFOUND; - goto done; - } - - for ( pcursor = &KTLINK(id); *pcursor; pcursor = &(*pcursor)->next ) { - if ( (*pcursor)->entry->vno == entry->vno && - (*pcursor)->entry->key.enctype == entry->key.enctype && - krb5_principal_compare(context, (*pcursor)->entry->principal, entry->principal)) - break; - } - - if (!*pcursor) { - err = KRB5_KT_NOTFOUND; - goto done; - } - - krb5_kt_free_entry(context, (*pcursor)->entry); - krb5_xfree((*pcursor)->entry); - next = (*pcursor)->next; - krb5_xfree(*pcursor); - (*pcursor) = next; - - done: - KTUNLOCK(id); - return err; -} - - -/* - * krb5_mkt_ops - */ - -const struct _krb5_kt_ops krb5_mkt_ops = { - 0, - "MEMORY", /* Prefix -- this string should not appear anywhere else! */ - krb5_mkt_resolve, - krb5_mkt_get_name, - krb5_mkt_close, - krb5_mkt_get_entry, - krb5_mkt_start_seq_get, - krb5_mkt_get_next, - krb5_mkt_end_get, - krb5_mkt_add, - krb5_mkt_remove, - NULL -}; - +/* + * lib/krb5/keytab/kt_memory.c + * + * 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. + */ + +#include "k5-int.h" +#include "kt-int.h" +#include + +#define HEIMDAL_COMPATIBLE + +/* + * Information needed by internal routines of the file-based ticket + * cache implementation. + */ + + +/* + * Constants + */ +#define IGNORE_VNO 0 +#define IGNORE_ENCTYPE 0 + +/* + * Types + */ +/* From krb5.h: + * typedef struct krb5_keytab_entry_st { + * krb5_magic magic; + * krb5_principal principal; principal of this key + * krb5_timestamp timestamp; time entry written to keytable + * krb5_kvno vno; key version number + * krb5_keyblock key; the secret key + *} krb5_keytab_entry; + */ + +/* Individual key entries within a table, in a linked list */ +typedef struct _krb5_mkt_link { + struct _krb5_mkt_link *next; + krb5_keytab_entry *entry; +} krb5_mkt_link, *krb5_mkt_cursor; + +/* Per-keytab data header */ +typedef struct _krb5_mkt_data { + char *name; /* Name of the keytab */ + k5_mutex_t lock; /* Thread-safety - all but link */ + krb5_int32 refcount; + krb5_mkt_cursor link; +} krb5_mkt_data; + +/* List of memory key tables */ +typedef struct _krb5_mkt_list_node { + struct _krb5_mkt_list_node *next; + krb5_keytab keytab; +} krb5_mkt_list_node; + +/* Iterator over memory key tables */ +typedef struct _krb5_mkt_ptcursor_data { + struct _krb5_mkt_list_node *cur; +} krb5_mkt_ptcursor_data; + +/* + * Globals + */ +static krb5_mkt_list_node * krb5int_mkt_list = NULL; +static k5_mutex_t krb5int_mkt_mutex = K5_MUTEX_PARTIAL_INITIALIZER; + +/* + * Macros + */ +#define KTLOCK(id) k5_mutex_lock(&(((krb5_mkt_data *)(id)->data)->lock)) +#define KTUNLOCK(id) k5_mutex_unlock(&(((krb5_mkt_data *)(id)->data)->lock)) +#define KTCHECKLOCK(id) k5_mutex_assert_locked(&(((krb5_mkt_data *)(id)->data)->lock)) + +#define KTGLOCK k5_mutex_lock(&krb5int_mkt_mutex) +#define KTGUNLOCK k5_mutex_unlock(&krb5int_mkt_mutex) +#define KTGCHECKLOCK k5_mutex_assert_locked(&krb5int_mkt_mutex) + +#define KTLINK(id) (((krb5_mkt_data *)(id)->data)->link) +#define KTREFCNT(id) (((krb5_mkt_data *)(id)->data)->refcount) +#define KTNAME(id) (((krb5_mkt_data *)(id)->data)->name) + +extern const struct _krb5_kt_ops krb5_mkt_ops; + +krb5_error_code KRB5_CALLCONV krb5_mkt_resolve + (krb5_context, + const char *, + krb5_keytab *); + +krb5_error_code KRB5_CALLCONV krb5_mkt_get_name + (krb5_context, + krb5_keytab, + char *, + unsigned int); + +krb5_error_code KRB5_CALLCONV krb5_mkt_close + (krb5_context, + krb5_keytab); + +krb5_error_code KRB5_CALLCONV krb5_mkt_get_entry + (krb5_context, + krb5_keytab, + krb5_const_principal, + krb5_kvno, + krb5_enctype, + krb5_keytab_entry *); + +krb5_error_code KRB5_CALLCONV krb5_mkt_start_seq_get + (krb5_context, + krb5_keytab, + krb5_kt_cursor *); + +krb5_error_code KRB5_CALLCONV krb5_mkt_get_next + (krb5_context, + krb5_keytab, + krb5_keytab_entry *, + krb5_kt_cursor *); + +krb5_error_code KRB5_CALLCONV krb5_mkt_end_get + (krb5_context, + krb5_keytab, + krb5_kt_cursor *); + +/* routines to be included on extended version (write routines) */ +krb5_error_code KRB5_CALLCONV krb5_mkt_add + (krb5_context, + krb5_keytab, + krb5_keytab_entry *); + +krb5_error_code KRB5_CALLCONV krb5_mkt_remove + (krb5_context, + krb5_keytab, + krb5_keytab_entry *); + +int krb5int_mkt_initialize(void) { + return k5_mutex_finish_init(&krb5int_mkt_mutex); +} + +void krb5int_mkt_finalize(void) { + krb5_mkt_list_node *node, *next_node; + krb5_mkt_cursor cursor, next_cursor; + + k5_mutex_destroy(&krb5int_mkt_mutex); + + for (node = krb5int_mkt_list; node; node = next_node) { + next_node = node->next; + + /* destroy the contents of node->keytab */ + krb5_xfree(KTNAME(node->keytab)); + + /* free the keytab entries */ + for (cursor = KTLINK(node->keytab); cursor; cursor = next_cursor) { + next_cursor = cursor->next; + /* the call to krb5_kt_free_entry uses a NULL in place of the + * krb5_context since we know that the context isn't used by + * krb5_kt_free_entry or krb5_free_principal. */ + krb5_kt_free_entry(NULL, cursor->entry); + krb5_xfree(cursor->entry); + krb5_xfree(cursor); + } + + /* destroy the lock */ + k5_mutex_destroy(&(((krb5_mkt_data *)node->keytab->data)->lock)); + + /* free the private data */ + krb5_xfree(node->keytab->data); + + /* and the keytab */ + krb5_xfree(node->keytab); + + /* and finally the node */ + krb5_xfree(node); + } +} +/* + * This is an implementation specific resolver. It returns a keytab + * initialized with memory keytab routines. + */ + +krb5_error_code KRB5_CALLCONV +krb5_mkt_resolve(krb5_context context, const char *name, krb5_keytab *id) +{ + krb5_mkt_data *data = 0; + krb5_mkt_list_node *list; + krb5_error_code err = 0; + + /* First determine if a memory keytab of this name already exists */ + err = KTGLOCK; + if (err) + return(err); + + for (list = krb5int_mkt_list; list; list = list->next) + { + if (strcmp(name,KTNAME(list->keytab)) == 0) { + /* Found */ + *id = list->keytab; + goto done; + } + } + + /* We will now create the new key table with the specified name. + * We do not drop the global lock, therefore the name will indeed + * be unique when we add it. + */ + + if ((list = (krb5_mkt_list_node *)malloc(sizeof(krb5_mkt_list_node))) == NULL) { + err = ENOMEM; + goto done; + } + + if ((list->keytab = (krb5_keytab)malloc(sizeof(struct _krb5_kt))) == NULL) { + krb5_xfree(list); + err = ENOMEM; + goto done; + } + + list->keytab->ops = &krb5_mkt_ops; + if ((data = (krb5_mkt_data *)malloc(sizeof(krb5_mkt_data))) == NULL) { + krb5_xfree(list->keytab); + krb5_xfree(list); + err = ENOMEM; + goto done; + } + + err = k5_mutex_init(&data->lock); + if (err) { + krb5_xfree(data); + krb5_xfree(list->keytab); + krb5_xfree(list); + goto done; + } + + if ((data->name = (char *)calloc(strlen(name) + 1, sizeof(char))) == NULL) { + k5_mutex_destroy(&data->lock); + krb5_xfree(data); + krb5_xfree(list->keytab); + krb5_xfree(list); + err = ENOMEM; + goto done; + } + + (void) strcpy(data->name, name); + + data->link = NULL; + data->refcount = 0; + list->keytab->data = (krb5_pointer)data; + list->keytab->magic = KV5M_KEYTAB; + + list->next = krb5int_mkt_list; + krb5int_mkt_list = list; + + *id = list->keytab; + + done: + err = KTLOCK(*id); + if (err) { + k5_mutex_destroy(&data->lock); + if (data && data->name) + krb5_xfree(data->name); + krb5_xfree(data); + if (list && list->keytab) + krb5_xfree(list->keytab); + krb5_xfree(list); + } else { + KTREFCNT(*id)++; + KTUNLOCK(*id); + } + + KTGUNLOCK; + return(err); +} + + +/* + * "Close" a memory-based keytab. This is effectively a no-op. + * We check to see if the keytab exists and that is about it. + * Closing a file keytab does not destroy the contents. Closing + * a memory keytab shouldn't either. + */ + +krb5_error_code KRB5_CALLCONV +krb5_mkt_close(krb5_context context, krb5_keytab id) +{ + krb5_mkt_list_node **listp; +#ifdef HEIMDAL_COMPATIBLE + krb5_mkt_list_node *node; + krb5_mkt_data * data; +#endif + krb5_error_code err = 0; + + /* First determine if a memory keytab of this name already exists */ + err = KTGLOCK; + if (err) + return(err); + + for (listp = &krb5int_mkt_list; *listp; listp = &((*listp)->next)) + { + if (id == (*listp)->keytab) { + /* Found */ + break; + } + } + + if (*listp == NULL) { + /* The specified keytab could not be found */ + err = KRB5_KT_NOTFOUND; + goto done; + } + + /* reduce the refcount and return */ + err = KTLOCK(id); + if (err) + goto done; + + KTREFCNT(id)--; + KTUNLOCK(id); + +#ifdef HEIMDAL_COMPATIBLE + /* In Heimdal if the refcount hits 0, the MEMORY keytab is + * destroyed since there is no krb5_kt_destroy function. + * There is no need to lock the entry while performing + * these operations as the refcount will be 0 and we are + * holding the global lock. + */ + data = (krb5_mkt_data *)id->data; + if (data->refcount == 0) { + krb5_mkt_cursor cursor, next_cursor; + + node = *listp; + *listp = node->next; + + /* destroy the contents of node->keytab (aka id) */ + krb5_xfree(data->name); + + /* free the keytab entries */ + for (cursor = KTLINK(node->keytab); cursor; cursor = next_cursor) { + next_cursor = cursor->next; + + krb5_kt_free_entry(context, cursor->entry); + krb5_xfree(cursor->entry); + krb5_xfree(cursor); + } + + /* destroy the lock */ + k5_mutex_destroy(&(data->lock)); + + /* free the private data */ + krb5_xfree(data); + + /* and the keytab */ + krb5_xfree(node->keytab); + + /* and finally the node */ + krb5_xfree(node); + } +#endif /* HEIMDAL_COMPATIBLE */ + + done: + KTGUNLOCK; + return(err); +} + +/* + * This is the get_entry routine for the memory based keytab implementation. + * It either retrieves the entry or returns an error. + */ + +krb5_error_code KRB5_CALLCONV +krb5_mkt_get_entry(krb5_context context, krb5_keytab id, + krb5_const_principal principal, krb5_kvno kvno, + krb5_enctype enctype, krb5_keytab_entry *out_entry) +{ + krb5_mkt_cursor cursor; + krb5_keytab_entry *entry, *match = NULL; + krb5_error_code err = 0; + int found_wrong_kvno = 0; + krb5_boolean similar = 0; + + err = KTLOCK(id); + if (err) + return err; + + for (cursor = KTLINK(id); cursor && cursor->entry; cursor = cursor->next) { + entry = cursor->entry; + + /* if the principal isn't the one requested, continue to the next. */ + + if (!krb5_principal_compare(context, principal, entry->principal)) + continue; + + /* if the enctype is not ignored and doesn't match, + and continue to the next */ + if (enctype != IGNORE_ENCTYPE) { + if ((err = krb5_c_enctype_compare(context, enctype, + entry->key.enctype, + &similar))) { + /* we can't determine the enctype of the entry */ + continue; + } + + if (!similar) + continue; + } + + if (kvno == IGNORE_VNO) { + if (match == NULL) + match = entry; + else if (entry->vno > match->vno) + match = entry; + } else { + if (entry->vno == kvno) { + match = entry; + break; + } else { + found_wrong_kvno++; + } + } + } + + /* if we found an entry that matches, ... */ + if (match) { + out_entry->magic = match->magic; + out_entry->timestamp = match->timestamp; + out_entry->vno = match->vno; + out_entry->key = match->key; + err = krb5_copy_keyblock_contents(context, &(match->key), + &(out_entry->key)); + /* + * Coerce the enctype of the output keyblock in case we + * got an inexact match on the enctype. + */ + if(enctype != IGNORE_ENCTYPE) + out_entry->key.enctype = enctype; + if(!err) { + err = krb5_copy_principal(context, + match->principal, + &(out_entry->principal)); + } + } else { + if (!err) + err = found_wrong_kvno ? KRB5_KT_KVNONOTFOUND : KRB5_KT_NOTFOUND; + } + + KTUNLOCK(id); + return(err); +} + +/* + * Get the name of the memory-based keytab. + */ + +krb5_error_code KRB5_CALLCONV +krb5_mkt_get_name(krb5_context context, krb5_keytab id, char *name, unsigned int len) +{ + memset(name, 0, len); + + if (len < strlen(id->ops->prefix)+2) + return(KRB5_KT_NAME_TOOLONG); + strcpy(name, id->ops->prefix); + name += strlen(id->ops->prefix); + name[0] = ':'; + name++; + len -= strlen(id->ops->prefix)+1; + + if (len < strlen(KTNAME(id))+1) + return(KRB5_KT_NAME_TOOLONG); + strcpy(name, KTNAME(id)); + /* strcpy will NUL-terminate the destination */ + + return(0); +} + +/* + * krb5_mkt_start_seq_get() + */ + +krb5_error_code KRB5_CALLCONV +krb5_mkt_start_seq_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursorp) +{ + krb5_error_code err = 0; + + err = KTLOCK(id); + if (err) + return(err); + + *cursorp = (krb5_kt_cursor)KTLINK(id); + KTUNLOCK(id); + + return(0); +} + +/* + * krb5_mkt_get_next() + */ + +krb5_error_code KRB5_CALLCONV +krb5_mkt_get_next(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry, krb5_kt_cursor *cursor) +{ + krb5_mkt_cursor mkt_cursor = (krb5_mkt_cursor)*cursor; + krb5_error_code err = 0; + + err = KTLOCK(id); + if (err) + return err; + + if (mkt_cursor == NULL) { + KTUNLOCK(id); + return KRB5_KT_END; + } + + entry->magic = mkt_cursor->entry->magic; + entry->timestamp = mkt_cursor->entry->timestamp; + entry->vno = mkt_cursor->entry->vno; + entry->key = mkt_cursor->entry->key; + err = krb5_copy_keyblock_contents(context, &(mkt_cursor->entry->key), + &(entry->key)); + if (!err) + err = krb5_copy_principal(context, mkt_cursor->entry->principal, + &(entry->principal)); + if (!err) + *cursor = (krb5_kt_cursor *)mkt_cursor->next; + KTUNLOCK(id); + return(err); +} + +/* + * krb5_mkt_end_get() + */ + +krb5_error_code KRB5_CALLCONV +krb5_mkt_end_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursor) +{ + *cursor = NULL; + return(0); +} + + +/* + * krb5_mkt_add() + */ + +krb5_error_code KRB5_CALLCONV +krb5_mkt_add(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry) +{ + krb5_error_code err = 0; + krb5_mkt_cursor cursor; + + err = KTLOCK(id); + if (err) + return err; + + cursor = (krb5_mkt_cursor)malloc(sizeof(krb5_mkt_link)); + if (cursor == NULL) { + err = ENOMEM; + goto done; + } + cursor->entry = (krb5_keytab_entry *)malloc(sizeof(krb5_keytab_entry)); + if (cursor->entry == NULL) { + krb5_xfree(cursor); + err = ENOMEM; + goto done; + } + cursor->entry->magic = entry->magic; + cursor->entry->timestamp = entry->timestamp; + cursor->entry->vno = entry->vno; + err = krb5_copy_keyblock_contents(context, &(entry->key), + &(cursor->entry->key)); + if (err) { + krb5_xfree(cursor->entry); + krb5_xfree(cursor); + goto done; + } + + err = krb5_copy_principal(context, entry->principal, &(cursor->entry->principal)); + if (err) { + krb5_free_keyblock_contents(context, &(cursor->entry->key)); + krb5_xfree(cursor->entry); + krb5_xfree(cursor); + goto done; + } + + if (KTLINK(id) == NULL) { + cursor->next = NULL; + KTLINK(id) = cursor; + } else { + cursor->next = KTLINK(id); + KTLINK(id) = cursor; + } + + done: + KTUNLOCK(id); + return err; +} + +/* + * krb5_mkt_remove() + */ + +krb5_error_code KRB5_CALLCONV +krb5_mkt_remove(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry) +{ + krb5_mkt_cursor *pcursor, next; + krb5_error_code err = 0; + + err = KTLOCK(id); + if (err) + return err; + + if ( KTLINK(id) == NULL ) { + err = KRB5_KT_NOTFOUND; + goto done; + } + + for ( pcursor = &KTLINK(id); *pcursor; pcursor = &(*pcursor)->next ) { + if ( (*pcursor)->entry->vno == entry->vno && + (*pcursor)->entry->key.enctype == entry->key.enctype && + krb5_principal_compare(context, (*pcursor)->entry->principal, entry->principal)) + break; + } + + if (!*pcursor) { + err = KRB5_KT_NOTFOUND; + goto done; + } + + krb5_kt_free_entry(context, (*pcursor)->entry); + krb5_xfree((*pcursor)->entry); + next = (*pcursor)->next; + krb5_xfree(*pcursor); + (*pcursor) = next; + + done: + KTUNLOCK(id); + return err; +} + + +/* + * krb5_mkt_ops + */ + +const struct _krb5_kt_ops krb5_mkt_ops = { + 0, + "MEMORY", /* Prefix -- this string should not appear anywhere else! */ + krb5_mkt_resolve, + krb5_mkt_get_name, + krb5_mkt_close, + krb5_mkt_get_entry, + krb5_mkt_start_seq_get, + krb5_mkt_get_next, + krb5_mkt_end_get, + krb5_mkt_add, + krb5_mkt_remove, + NULL +}; + -- 2.26.2