--- krb5-1.4.3-kwc/src/aclocal.m4 | 8 krb5-1.4.3-kwc/src/configure.in | 2 krb5-1.4.3-kwc/src/include/krb5/autoconf.h.in | 9 krb5-1.4.3-kwc/src/lib/krb5/ccache/Makefile.in | 12 krb5-1.4.3-kwc/src/lib/krb5/ccache/ccbase.c | 18 krb5-1.4.3-kwc/src/lib/krb5/os/ccdefname.c | 4 --- diff -puN src/aclocal.m4~add_keyring_ccache_20060822 src/aclocal.m4 --- krb5-1.4.4/src/aclocal.m4~add_keyring_ccache_20060822 2006-08-25 12:37:34.000000000 -0400 +++ krb5-1.4.4-andros/src/aclocal.m4 2006-08-25 12:37:34.000000000 -0400 @@ -82,6 +82,7 @@ KRB5_AC_PRAGMA_WEAK_REF KRB5_LIB_PARAMS KRB5_AC_INITFINI KRB5_AC_ENABLE_THREADS +KRB5_AC_LIBKEYUTILS ])dnl dnl Maintainer mode, akin to what automake provides, 'cept we don't @@ -1746,3 +1747,10 @@ AC_DEFUN([KRB5_AC_LIBUTIL], UTIL_LIB=-lutil])dnl AC_SUBST(UTIL_LIB) ]) +dnl +dnl +dnl On Linux, if libkeyutils exists we want to include it +AC_DEFUN([KRB5_AC_LIBKEYUTILS], + [AC_CHECK_LIB(keyutils, add_key) +]) + diff -puN src/configure.in~add_keyring_ccache_20060822 src/configure.in --- krb5-1.4.4/src/configure.in~add_keyring_ccache_20060822 2006-08-25 12:37:34.000000000 -0400 +++ krb5-1.4.4-andros/src/configure.in 2006-08-25 12:37:34.000000000 -0400 @@ -64,7 +64,7 @@ LIBUTIL=-lutil ]) AC_SUBST(LIBUTIL) dnl for kdc -AC_CHECK_HEADERS(syslog.h stdarg.h sys/select.h sys/sockio.h ifaddrs.h unistd.h) +AC_CHECK_HEADERS(syslog.h stdarg.h sys/select.h sys/sockio.h ifaddrs.h unistd.h keyutils.h) AC_CHECK_FUNCS(openlog syslog closelog strftime vsprintf) KRB5_NEED_PROTO([#include #ifdef HAVE_UNISTD_H diff -puN src/include/krb5/autoconf.h.in~add_keyring_ccache_20060822 src/include/krb5/autoconf.h.in --- krb5-1.4.4/src/include/krb5/autoconf.h.in~add_keyring_ccache_20060822 2006-08-25 12:37:34.000000000 -0400 +++ krb5-1.4.4-andros/src/include/krb5/autoconf.h.in 2006-08-25 12:37:34.000000000 -0400 @@ -108,6 +108,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the `keyutils' library (-lkeyutils). */ +#undef HAVE_LIBKEYUTILS + /* Define to 1 if you have the `nsl' library (-lnsl). */ #undef HAVE_LIBNSL diff -puN src/lib/krb5/ccache/ccbase.c~add_keyring_ccache_20060822 src/lib/krb5/ccache/ccbase.c --- krb5-1.4.4/src/lib/krb5/ccache/ccbase.c~add_keyring_ccache_20060822 2006-08-25 12:37:34.000000000 -0400 +++ krb5-1.4.4-andros/src/lib/krb5/ccache/ccbase.c 2006-08-25 12:37:34.000000000 -0400 @@ -38,6 +38,9 @@ struct krb5_cc_typelist { struct krb5_cc_typelist *next; }; extern const krb5_cc_ops krb5_mcc_ops; +#ifdef HAVE_LIBKEYUTILS +extern const krb5_cc_ops krb5_krcc_ops; +#endif #ifdef _WIN32 extern const krb5_cc_ops krb5_lcc_ops; @@ -45,12 +48,21 @@ static struct krb5_cc_typelist cc_lcc_en static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, &cc_lcc_entry }; #else static struct krb5_cc_typelist cc_mcc_entry = { &krb5_mcc_ops, NULL }; +#ifdef HAVE_LIBKEYUTILS +static struct krb5_cc_typelist cc_file_entry = { &krb5_cc_file_ops, + &cc_mcc_entry }; +static struct krb5_cc_typelist cc_krcc_entry = { &krb5_krcc_ops, + &cc_file_entry }; +#endif /* HAVE_LIBKEYUTILS */ #endif static struct krb5_cc_typelist cc_fcc_entry = { &krb5_cc_file_ops, &cc_mcc_entry }; - +#ifdef HAVE_LIBKEYUTILS +static struct krb5_cc_typelist *cc_typehead = &cc_krcc_entry; +#else static struct krb5_cc_typelist *cc_typehead = &cc_fcc_entry; +#endif static k5_mutex_t cc_typelist_lock = K5_MUTEX_PARTIAL_INITIALIZER; int @@ -73,14 +85,18 @@ krb5int_cc_initialize(void) void krb5int_cc_finalize(void) { +#ifndef HAVE_LIBKEYUTILS struct krb5_cc_typelist *t, *t_next; +#endif k5_mutex_destroy(&cc_typelist_lock); k5_mutex_destroy(&krb5int_cc_file_mutex); k5_mutex_destroy(&krb5int_mcc_mutex); +#ifndef HAVE_LIBKEYUTILS for (t = cc_typehead; t != &cc_fcc_entry; t = t_next) { t_next = t->next; free(t); } +#endif } diff -puN /dev/null src/lib/krb5/ccache/cc_keyring.c --- /dev/null 2006-05-22 10:25:23.000000000 -0400 +++ krb5-1.4.4-andros/src/lib/krb5/ccache/cc_keyring.c 2006-08-25 12:37:34.000000000 -0400 @@ -0,0 +1,2042 @@ +/* + * lib/krb5/ccache/cc_keyring.c + * + * Copyright (c) 2006 + * The Regents of the University of Michigan + * ALL RIGHTS RESERVED + * + * Permission is granted to use, copy, create derivative works + * and redistribute this software and such derivative works + * for any purpose, so long as the name of The University of + * Michigan is not used in any advertising or publicity + * pertaining to the use of distribution of this software + * without specific, written prior authorization. If the + * above copyright notice or any other identification of the + * University of Michigan is included in any copy of any + * portion of this software, then the disclaimer below must + * also be included. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION + * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY + * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF + * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING + * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE + * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING + * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + * + * Implementation of a credentials cache stored in the Linux keyring facility + * + * Some assumptions: + * + * - A credentials cache "file" == a keyring with separate keys + * for the information in the ccache (see below) + * - A credentials cache keyring will contain only keys, + * not other keyrings + * - Each Kerberos ticket will have its own key within the ccache keyring + * - The principal information for the ccache is stored in a + * special key, which is not counted in the 'numkeys' count + */ +#include "k5-int.h" +#include +#include + +#if 0 +#define KRCC_DEBUG 1 +#define KRCC_EXTRA_DEBUG 1 /* Extra debugging -- should be removed */ +#endif + +#if KRCC_DEBUG +void debug_print(char *fmt, ...); /* prototype to silence warning */ +#include +#define DEBUG_PRINT(x) debug_print x +void +debug_print(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); +#ifdef DEBUG_STDERR + vfprintf(stderr, fmt, ap); +#else + vsyslog(LOG_ERR, fmt, ap); +#endif + va_end(ap); +} +#else +#define DEBUG_PRINT(x) +#endif + +/* + * We always use "user" key type + */ +#define KRCC_KEY_TYPE_USER "user" + +/* + * We create ccaches as separate keyrings + */ +#define KRCC_KEY_TYPE_KEYRING "keyring" + +/* + * Special name of the key within a ccache keyring + * holding principal information + */ +#define KRCC_SPEC_PRINC_KEYNAME "__krb5_princ__" + +/* XXX The following two belong in some library header since outside + * programs will need to use these same names... + */ +/* + * Special name for key to communicate key serial numbers + * This is used by the Linux gssd process to pass the + * user's keyring values it gets on an request upcall. + * The format of the contents should be + * :: + */ +#define KRCC_SPEC_IDS_KEYNAME "_gssd_keyring_ids_" + +/* + * Special name for the key to communicate the name(s) + * of credentials caches to be used for requests. + * This should currently contain a single name, but + * in the future may contain a list that may be + * intelligently chosen from. + */ +#define KRCC_SPEC_CCACHE_SET_KEYNAME "__krb5_cc_set__" + +#define KRB5_OK 0 + +/* Hopefully big enough to hold a serialized credential */ +#define GUESS_CRED_SIZE 2048 + +#define ALLOC(NUM,TYPE) \ + (((NUM) <= (((size_t)0-1)/ sizeof(TYPE))) \ + ? (TYPE *) calloc((NUM), sizeof(TYPE)) \ + : (errno = ENOMEM,(TYPE *) 0)) + +#define CHECK_N_GO(ret, errdest) if (ret != KRB5_OK) goto errdest +#define CHECK(ret) if (ret != KRB5_OK) goto errout +#define CHECK_OUT(ret) if (ret != KRB5_OK) return ret + +typedef struct krb5_krcc_ring_ids { + key_serial_t session; + key_serial_t process; + key_serial_t thread; +} krb5_krcc_ring_ids_t; + +typedef struct _krb5_krcc_cursor +{ + int numkeys; + int currkey; + key_serial_t princ_id; + key_serial_t *keys; +} *krb5_krcc_cursor; + +/* + * This represents a credentials cache "file" + * where ring_id is the keyring serial number for + * this credentials cache "file". Each key + * in the keyring contains a separate key. + */ +typedef struct _krb5_krcc_data +{ + char *name; /* Name for this credentials cache */ + k5_mutex_t lock; /* synchronization */ + key_serial_t ring_id; /* keyring representing ccache */ + key_serial_t princ_id; /* key holding principal info */ + int numkeys; /* # of keys in this ring + * (does NOT include principal info) */ +} krb5_krcc_data; + +/* Passed internally to assure we don't go past the bounds of our buffer */ +typedef struct _krb5_krcc_buffer_cursor +{ + char *bpp; + char *endp; +} krb5_krcc_bc; + +/* + * Internal functions (exported via the krb5_krcc_ops) + */ + +extern const krb5_cc_ops krb5_krcc_ops; + +static const char *KRB5_CALLCONV krb5_krcc_get_name + (krb5_context, krb5_ccache id); + +static krb5_error_code KRB5_CALLCONV krb5_krcc_resolve + (krb5_context, krb5_ccache * id, const char *residual); + +static krb5_error_code KRB5_CALLCONV krb5_krcc_generate_new + (krb5_context, krb5_ccache * id); + +static krb5_error_code KRB5_CALLCONV krb5_krcc_initialize + (krb5_context, krb5_ccache id, krb5_principal princ); + +static krb5_error_code KRB5_CALLCONV krb5_krcc_destroy + (krb5_context, krb5_ccache id); + +static krb5_error_code KRB5_CALLCONV krb5_krcc_close + (krb5_context, krb5_ccache id); + +static krb5_error_code KRB5_CALLCONV krb5_krcc_store + (krb5_context, krb5_ccache id, krb5_creds * creds); + +static krb5_error_code KRB5_CALLCONV krb5_krcc_retrieve + (krb5_context, krb5_ccache id, krb5_flags whichfields, + krb5_creds * mcreds, krb5_creds * creds); + +static krb5_error_code KRB5_CALLCONV krb5_krcc_get_principal + (krb5_context, krb5_ccache id, krb5_principal * princ); + +static krb5_error_code KRB5_CALLCONV krb5_krcc_start_seq_get + (krb5_context, krb5_ccache id, krb5_cc_cursor * cursor); + +static krb5_error_code KRB5_CALLCONV krb5_krcc_next_cred + (krb5_context, krb5_ccache id, krb5_cc_cursor * cursor, + krb5_creds * creds); + +static krb5_error_code KRB5_CALLCONV krb5_krcc_end_seq_get + (krb5_context, krb5_ccache id, krb5_cc_cursor * cursor); + +static krb5_error_code KRB5_CALLCONV krb5_krcc_remove_cred + (krb5_context context, krb5_ccache cache, krb5_flags flags, + krb5_creds * creds); + +static krb5_error_code KRB5_CALLCONV krb5_krcc_set_flags + (krb5_context, krb5_ccache id, krb5_flags flags); + +#ifdef HAVE_GET_FLAGS +static krb5_error_code KRB5_CALLCONV krb5_krcc_get_flags + (krb5_context context, krb5_ccache id, krb5_flags * flags); +#endif + +/* + * Internal utility functions + */ + +static krb5_error_code krb5_krcc_clearcache + (krb5_context context, krb5_ccache id); + +static krb5_error_code krb5_krcc_new_data(const char *, krb5_krcc_data **); + +static krb5_error_code krb5_krcc_save_principal + (krb5_context context, krb5_ccache id, krb5_principal princ); + +static krb5_error_code krb5_krcc_retrieve_principal + (krb5_context context, krb5_ccache id, krb5_principal * princ); + +static int krb5_krcc_get_ring_ids(krb5_krcc_ring_ids_t *p); + +/* Routines to parse a key from a keyring into a cred structure */ +static krb5_error_code krb5_krcc_parse + (krb5_context, krb5_ccache id, krb5_pointer buf, unsigned int len, + krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_parse_cred + (krb5_context context, krb5_ccache id, krb5_creds * creds, + char *payload, int psize); +static krb5_error_code krb5_krcc_parse_principal + (krb5_context context, krb5_ccache id, krb5_principal * princ, + krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_parse_keyblock + (krb5_context context, krb5_ccache id, krb5_keyblock * keyblock, + krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_parse_times + (krb5_context context, krb5_ccache id, krb5_ticket_times * t, + krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_parse_krb5data + (krb5_context context, krb5_ccache id, krb5_data * data, + krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_parse_int32 + (krb5_context context, krb5_ccache id, krb5_int32 * i, krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_parse_octet + (krb5_context context, krb5_ccache id, krb5_octet * octet, + krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_parse_addrs + (krb5_context context, krb5_ccache id, krb5_address *** a, + krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_parse_addr + (krb5_context context, krb5_ccache id, krb5_address * a, + krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_parse_authdata + (krb5_context context, krb5_ccache id, krb5_authdata *** ad, + krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_parse_authdatum + (krb5_context context, krb5_ccache id, krb5_authdata * ad, + krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_parse_ui_2 + (krb5_context, krb5_ccache id, krb5_ui_2 * i, krb5_krcc_bc * bc); + +/* Routines to unparse a cred structure into keyring key */ +static krb5_error_code krb5_krcc_unparse + (krb5_context, krb5_ccache id, krb5_pointer buf, unsigned int len, + krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_unparse_cred + (krb5_context context, krb5_ccache id, krb5_creds * creds, + char **datapp, unsigned int *lenptr); +static krb5_error_code krb5_krcc_unparse_principal + (krb5_context, krb5_ccache id, krb5_principal princ, krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_unparse_keyblock + (krb5_context, krb5_ccache id, krb5_keyblock * keyblock, + krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_unparse_times + (krb5_context, krb5_ccache id, krb5_ticket_times * t, krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_unparse_krb5data + (krb5_context, krb5_ccache id, krb5_data * data, krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_unparse_int32 + (krb5_context, krb5_ccache id, krb5_int32 i, krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_unparse_octet + (krb5_context, krb5_ccache id, krb5_int32 i, krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_unparse_addrs + (krb5_context, krb5_ccache, krb5_address ** a, krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_unparse_addr + (krb5_context, krb5_ccache, krb5_address * a, krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_unparse_authdata + (krb5_context, krb5_ccache, krb5_authdata ** ad, krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_unparse_authdatum + (krb5_context, krb5_ccache, krb5_authdata * ad, krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_unparse_ui_4 + (krb5_context, krb5_ccache id, krb5_ui_4 i, krb5_krcc_bc * bc); +static krb5_error_code krb5_krcc_unparse_ui_2 + (krb5_context, krb5_ccache id, krb5_int32 i, krb5_krcc_bc * bc); + +/* Note the following is a stub function for Linux */ +extern krb5_error_code krb5_change_cache(void); + +/* + * Modifies: + * id + * + * Effects: + * Creates/refreshes the cred cache id. If the cache exists, its + * contents are destroyed. + * + * Errors: + * system errors + * permission errors + */ + +static krb5_error_code KRB5_CALLCONV +krb5_krcc_initialize(krb5_context context, krb5_ccache id, + krb5_principal princ) +{ + krb5_error_code kret; + + DEBUG_PRINT(("krb5_krcc_initialize: entered\n")); + + kret = k5_mutex_lock(&((krb5_krcc_data *) id->data)->lock); + if (kret) + return kret; + + kret = krb5_krcc_clearcache(context, id); + if (kret != KRB5_OK) + goto out; + + kret = krb5_krcc_save_principal(context, id, princ); + if (kret == KRB5_OK) + krb5_change_cache(); + +out: + k5_mutex_unlock(&((krb5_krcc_data *) id->data)->lock); + return kret; +} + +/* + * Modifies: + * id + * + * Effects: + * Closes the file cache, invalidates the id, and frees any resources + * associated with the cache. + */ +static krb5_error_code KRB5_CALLCONV +krb5_krcc_close(krb5_context context, krb5_ccache id) +{ + DEBUG_PRINT(("krb5_krcc_close: entered\n")); + + krb5_xfree(id); + return KRB5_OK; +} + +/* + * Modifies: + * id + * + * Effects: + * Clears out a ccache keyring, unlinking all keys within it + * + * Requires: + * Must be called with mutex locked. + * + * Errors: + * system errors + */ + +static krb5_error_code +krb5_krcc_clearcache(krb5_context context, krb5_ccache id) +{ + krb5_krcc_data *d; + key_serial_t *keys; + unsigned int size; + int res; + int i; + + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); + + d = (krb5_krcc_data *) id->data; + + DEBUG_PRINT(("krb5_krcc_clearcache: ring_id %d, princ_id %d, " + "numkeys is %d\n", d->ring_id, d->princ_id, d->numkeys)); + if (d->numkeys > 0) { + + size = (d->numkeys + 1) * sizeof(key_serial_t); /* +1 for princ key */ + keys = malloc(size); + reread: + if (!keys) + return KRB5_CC_NOMEM; + + res = keyctl_read(d->ring_id, (char *) keys, size); + if (res < 0) { + free(keys); + return errno; + } + if (res != size) { /* are there more keys than we thought? */ + DEBUG_PRINT(("krb5_krcc_clearcache: numkeys %d, res %d, " + "size %d reallocing key array\n", + d->numkeys, res, size)); + size = res; + keys = realloc(keys, (unsigned int) res); + goto reread; + } + + for (i = 0; i < (size / sizeof(key_serial_t)); i++) { + res = keyctl_unlink(keys[i], d->ring_id); + if (res < 0) { + com_err("krb5_krcc_clearcache", errno, "unlinking key"); + DEBUG_PRINT(("krb5_krcc_clearcache: error unlinking " + "key %d, res == %d\n", keys[i], res)); + } + } + free(keys); + d->numkeys = 0; + d->princ_id = 0; + } + return KRB5_OK; +} + +/* + * Effects: + * Destroys the contents of id. + * + * Errors: + * none + */ +static krb5_error_code KRB5_CALLCONV +krb5_krcc_destroy(krb5_context context, krb5_ccache id) +{ + krb5_error_code kret; + krb5_krcc_data *d; + int res; + + DEBUG_PRINT(("krb5_krcc_destroy: entered\n")); + + d = (krb5_krcc_data *) id->data; + + kret = k5_mutex_lock(&d->lock); + if (kret) + return kret; + + krb5_krcc_clearcache(context, id); + krb5_xfree(d->name); + res = keyctl_unlink(d->ring_id, KEY_SPEC_SESSION_KEYRING); + if (res < 0) { + kret = errno; + com_err("krb5_krcc_clearcache", errno, "unlinking key"); + k5_mutex_unlock(&d->lock); + return kret; + } + k5_mutex_destroy(&d->lock); + krb5_xfree(d); + krb5_xfree(id); + + krb5_change_cache(); + + return KRB5_OK; +} + + +/* + * Requires: + * residual is a legal path name, and a null-terminated string + * + * Modifies: + * id + * + * Effects: + * creates a cred cache that will reside in the keyring with + * a name of . + * + * Returns: + * A filled in krb5_ccache structure "id". + * + * Errors: + * KRB5_CC_NOMEM - there was insufficient memory to allocate the + * krb5_ccache. id is undefined. + * permission errors + */ + +static krb5_error_code KRB5_CALLCONV +krb5_krcc_resolve(krb5_context context, krb5_ccache * id, const char *full_residual) +{ + krb5_ccache lid; + krb5_error_code kret; + krb5_krcc_data *d; + key_serial_t key; + key_serial_t pkey = 0; + int nkeys = 0; + int res; + krb5_krcc_ring_ids_t ids; + key_serial_t ring_id; + const char *residual; + + DEBUG_PRINT(("krb5_krcc_resolve: entered with name '%s'\n", + full_residual)); + + res = krb5_krcc_get_ring_ids(&ids); + if (res) { + kret = EINVAL; /* XXX */ + DEBUG_PRINT(("krb5_krcc_resolve: Error getting ring id values!\n")); + return kret; + } + + if (strncmp(full_residual, "thread:", 7) == 0) { + residual = full_residual + 7; + ring_id = ids.thread; + } else if (strncmp(full_residual, "process:", 8) == 0) { + residual = full_residual + 8; + ring_id = ids.process; + } else { + residual = full_residual; + ring_id = ids.session; + } + +#ifdef KRCC_EXTRA_DEBUG + DEBUG_PRINT(("krb5_krcc_resolve: searching ring %d for residual '%s'\n", + ring_id, residual)); /* XXX */ +#endif + +#if 0 + /* This looks in the default order of thread, process, session */ + key = request_key(KRCC_KEY_TYPE_KEYRING, residual, NULL, 0); +#else + /* + * Use keyctl_search instead of request_key. If we're supposed + * to be looking for a process ccache, we shouldn't find a + * thread ccache. + * XXX But should we look for a session one if there isn't + * a process one? Same goes for thread. Should we look in + * process and session if not found in thread? + * + */ + key = keyctl_search(ring_id, KRCC_KEY_TYPE_KEYRING, residual, 0); +#endif + if (key < 0) { /* XXX May need to check return codes here */ +#ifdef KRCC_EXTRA_DEBUG + DEBUG_PRINT(("krb5_krcc_resolve: adding new keyring named '%s' " + "to keyring %d\n", residual, ring_id)); /* XXX */ +#endif + key = add_key(KRCC_KEY_TYPE_KEYRING, residual, NULL, 0, ring_id); + if (key < 0) { + kret = errno; + DEBUG_PRINT(("Error adding new keyring '%s': %s\n", + residual, strerror(errno))); + return kret; + } +#ifdef KRCC_EXTRA_DEBUG + DEBUG_PRINT(("krb5_krcc_resolve: new keyring '%s' is " + "key %d\n", residual, key)); /* XXX */ +#endif + } else { + /* Determine key containing principal information */ + pkey = keyctl_search(key, KRCC_KEY_TYPE_USER, KRCC_SPEC_PRINC_KEYNAME, 0); +#ifdef KRCC_EXTRA_DEBUG + DEBUG_PRINT(("keyctl_search for %s returned key %d\n", + KRCC_SPEC_PRINC_KEYNAME, pkey)); /* XXX */ +#endif + if (pkey < 0) { + DEBUG_PRINT(("Error locating principal info for existing " + "ccache in ring %d: %s\n", key, strerror(errno))); + pkey = 0; + } + /* Determine how many keys exist */ + res = keyctl_read(key, NULL, 0); + if (res > 0) + nkeys = (res / sizeof(key_serial_t)) - 1; + else + nkeys = 0; + } + + lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache)); + if (lid == NULL) + return KRB5_CC_NOMEM; + + kret = krb5_krcc_new_data(residual, &d); + if (kret) { + free(lid); + return kret; + } + + lid->ops = &krb5_krcc_ops; + + DEBUG_PRINT(("krb5_krcc_resolve: ring_id %d, princ_id %d, " + "nkeys %d\n", key, pkey, nkeys)); + d->ring_id = key; + d->princ_id = pkey; + d->numkeys = nkeys; + lid->data = d; + lid->magic = KV5M_CCACHE; + *id = lid; + return KRB5_OK; +} + +/* + * Effects: + * Prepares for a sequential search of the credentials cache. + * Returns a krb5_cc_cursor to be used with krb5_krcc_next_cred and + * krb5_krcc_end_seq_get. + * + * If the cache is modified between the time of this call and the time + * of the final krb5_krcc_end_seq_get, the results are undefined. + * + * Errors: + * KRB5_CC_NOMEM + * system errors + */ +static krb5_error_code KRB5_CALLCONV +krb5_krcc_start_seq_get(krb5_context context, krb5_ccache id, + krb5_cc_cursor * cursor) +{ + krb5_krcc_cursor krcursor; + krb5_error_code kret; + krb5_krcc_data *d; + unsigned int size; + int res; + + DEBUG_PRINT(("krb5_krcc_start_seq_get: entered\n")); + + d = id->data; + kret = k5_mutex_lock(&d->lock); + if (kret) + return kret; + + size = sizeof(*krcursor) + ((d->numkeys + 1) * sizeof(key_serial_t)); + + krcursor = (krb5_krcc_cursor) malloc(size); + if (krcursor == NULL) { + k5_mutex_unlock(&d->lock); + return KRB5_CC_NOMEM; + } + + krcursor->keys = (key_serial_t *) ((char *) krcursor + sizeof(*krcursor)); + res = keyctl_read(d->ring_id, (char *) krcursor->keys, + ((d->numkeys + 1) * sizeof(key_serial_t))); + if (res < 0 || res > ((d->numkeys + 1) * sizeof(key_serial_t))) { + DEBUG_PRINT(("Read %d bytes from keyring, numkeys %d: %s\n", + res, d->numkeys, strerror(errno))); + free(krcursor); + k5_mutex_unlock(&d->lock); + return KRB5_CC_IO; + } + + krcursor->numkeys = d->numkeys; + krcursor->currkey = 0; + krcursor->princ_id = d->princ_id; + + k5_mutex_unlock(&d->lock); + *cursor = (krb5_cc_cursor) krcursor; + return KRB5_OK; +} + +/* + * Requires: + * cursor is a krb5_cc_cursor originally obtained from + * krb5_krcc_start_seq_get. + * + * Modifes: + * cursor, creds + * + * Effects: + * Fills in creds with the "next" credentals structure from the cache + * id. The actual order the creds are returned in is arbitrary. + * Space is allocated for the variable length fields in the + * credentials structure, so the object returned must be passed to + * krb5_destroy_credential. + * + * The cursor is updated for the next call to krb5_krcc_next_cred. + * + * Errors: + * system errors + */ +static krb5_error_code KRB5_CALLCONV +krb5_krcc_next_cred(krb5_context context, krb5_ccache id, + krb5_cc_cursor * cursor, krb5_creds * creds) +{ + krb5_krcc_cursor krcursor; + krb5_error_code kret; + int psize; + void *payload; + + DEBUG_PRINT(("krb5_krcc_next_cred: entered\n")); + + /* + * Once the node in the linked list is created, it's never + * modified, so we don't need to worry about locking here. + * (Note that we don't support _remove_cred.) + */ + krcursor = (krb5_krcc_cursor) * cursor; + if (krcursor == NULL) + return KRB5_CC_END; + memset(creds, 0, sizeof(krb5_creds)); + + /* If we're pointing at the entry with the principal, skip it */ + if (krcursor->keys[krcursor->currkey] == krcursor->princ_id) + krcursor->currkey++; + + /* If we're pointing past the end of the keys array, there are no more */ + if (krcursor->currkey > krcursor->numkeys) + return KRB5_CC_END; + + /* Read the key, the right size buffer will ba allocated and returned */ + psize = keyctl_read_alloc(krcursor->keys[krcursor->currkey], &payload); + if (psize == -1) { + DEBUG_PRINT(("Error reading key %d: %s\n", + krcursor->keys[krcursor->currkey], + strerror(errno))); + kret = KRB5_CC_IO; + goto freepayload; + } + krcursor->currkey++; + + kret = krb5_krcc_parse_cred(context, id, creds, payload, psize); + + freepayload: + free(payload); + return kret; +} + +/* + * Requires: + * cursor is a krb5_cc_cursor originally obtained from + * krb5_krcc_start_seq_get. + * + * Modifies: + * id, cursor + * + * Effects: + * Finishes sequential processing of the keyring credentials ccache id, + * and invalidates the cursor (it must never be used after this call). + */ +/* ARGSUSED */ +static krb5_error_code KRB5_CALLCONV +krb5_krcc_end_seq_get(krb5_context context, krb5_ccache id, + krb5_cc_cursor * cursor) +{ + DEBUG_PRINT(("krb5_krcc_end_seq_get: entered\n")); + + free(*cursor); + *cursor = 0L; + return KRB5_OK; +} + +/* Utility routine: Creates the back-end data for a keyring cache. + + Call with the global list lock held. */ +static krb5_error_code +krb5_krcc_new_data(const char *name, krb5_krcc_data ** datapp) +{ + krb5_error_code kret; + krb5_krcc_data *d; + + d = malloc(sizeof(krb5_krcc_data)); + if (d == NULL) + return KRB5_CC_NOMEM; + + kret = k5_mutex_init(&d->lock); + if (kret) { + krb5_xfree(d); + return kret; + } + + d->name = strdup(name); + if (d->name == NULL) { + k5_mutex_destroy(&d->lock); + krb5_xfree(d); + return KRB5_CC_NOMEM; + } + d->princ_id = 0; + + *datapp = d; + return 0; +} + +/* + * Effects: + * Creates a new keyring cred cache whose name is guaranteed to be + * unique. + * + * Returns: + * The filled in krb5_ccache id. + * + * Errors: + * KRB5_CC_NOMEM - there was insufficient memory to allocate the + * krb5_ccache. id is undefined. + */ +static krb5_error_code KRB5_CALLCONV +krb5_krcc_generate_new(krb5_context context, krb5_ccache * id) +{ + krb5_ccache lid; + char scratch[6 + 1]; /* 6 for the scratch part, +1 for NUL */ + krb5_error_code kret; + krb5_krcc_data *d; + + DEBUG_PRINT(("krb5_krcc_generate_new: entered\n")); + + /* Allocate memory */ + lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache)); + if (lid == NULL) + return KRB5_CC_NOMEM; + + /* XXX incorporate lxs's patch to the memory ccache code here XXX */ + lid->ops = &krb5_krcc_ops; + + (void) strcpy(scratch, "XXXXXX"); + mktemp(scratch); + + kret = krb5_krcc_new_data(scratch, &d); + if (kret) { + krb5_xfree(lid); + return kret; + } + lid->data = d; + krb5_change_cache(); + return KRB5_OK; +} + +/* + * Requires: + * id is a keyring credential cache + * + * Returns: + * The name of the keyring cred cache id. + */ +static const char *KRB5_CALLCONV +krb5_krcc_get_name(krb5_context context, krb5_ccache id) +{ + DEBUG_PRINT(("krb5_krcc_get_name: entered\n")); + return (char *) ((krb5_krcc_data *) id->data)->name; +} + +/* + * Modifies: + * id, princ + * + * Effects: + * Retrieves the primary principal from id, as set with + * krb5_krcc_initialize. The principal is returned is allocated + * storage that must be freed by the caller via krb5_free_principal. + * + * Errors: + * system errors + * KRB5_CC_NOMEM + */ +static krb5_error_code KRB5_CALLCONV +krb5_krcc_get_principal(krb5_context context, krb5_ccache id, + krb5_principal * princ) +{ + DEBUG_PRINT(("krb5_krcc_get_principal: entered\n")); + + return krb5_krcc_retrieve_principal(context, id, princ); +} + +static krb5_error_code KRB5_CALLCONV +krb5_krcc_retrieve(krb5_context context, krb5_ccache id, + krb5_flags whichfields, krb5_creds * mcreds, + krb5_creds * creds) +{ + DEBUG_PRINT(("krb5_krcc_retrieve: entered\n")); + + return krb5_cc_retrieve_cred_default(context, id, whichfields, + mcreds, creds); +} + +/* + * Non-functional stub implementation for krb5_krcc_remove + * + * Errors: + * KRB5_CC_NOSUPP - not implemented + */ +static krb5_error_code KRB5_CALLCONV +krb5_krcc_remove_cred(krb5_context context, krb5_ccache cache, + krb5_flags flags, krb5_creds * creds) +{ + DEBUG_PRINT(("krb5_krcc_remove_cred: entered (returning KRB5_CC_NOSUPP)\n")); + + return KRB5_CC_NOSUPP; +} + +/* + * Requires: + * id is a cred cache returned by krb5_krcc_resolve or + * krb5_krcc_generate_new, but has not been opened by krb5_krcc_initialize. + * + * Modifies: + * id + * + * Effects: + * Sets the operational flags of id to flags. + */ +static krb5_error_code KRB5_CALLCONV +krb5_krcc_set_flags(krb5_context context, krb5_ccache id, krb5_flags flags) +{ + DEBUG_PRINT(("krb5_krcc_set_flags: entered\n")); + + return KRB5_OK; +} + +#ifdef HAVE_GET_FLAGS /* Not included in the 1.4 release? */ +static krb5_error_code KRB5_CALLCONV +krb5_krcc_get_flags(krb5_context context, krb5_ccache id, krb5_flags * flags) +{ + DEBUG_PRINT(("krb5_krcc_get_flags: entered\n")); + + *flags = 0; + return KRB5_OK; +} +#endif + +/* store: Save away creds in the ccache keyring. */ +static krb5_error_code KRB5_CALLCONV +krb5_krcc_store(krb5_context context, krb5_ccache id, krb5_creds * creds) +{ + krb5_error_code kret; + krb5_krcc_data *d = (krb5_krcc_data *) id->data; + char *payload = NULL; + unsigned int payloadlen; + key_serial_t newkey; + char *keyname = NULL; + + DEBUG_PRINT(("krb5_krcc_store: entered\n")); + + kret = k5_mutex_lock(&d->lock); + if (kret) + return kret; + + /* Get the service principal name and use it as the key name */ + kret = krb5_unparse_name(context, creds->server, &keyname); + if (kret) { + DEBUG_PRINT(("Error unparsing service principal name!\n")); + goto errout; + } + + /* Serialize credential into memory */ + kret = krb5_krcc_unparse_cred(context, id, creds, &payload, &payloadlen); + if (kret != KRB5_OK) + goto errout; + + /* Add new key (credentials) into keyring */ + DEBUG_PRINT(("krb5_krcc_store: adding new key '%s' to keyring %d\n", + keyname, d->ring_id)); /* XXX */ + newkey = add_key(KRCC_KEY_TYPE_USER, keyname, payload, payloadlen, d->ring_id); + if (newkey < 0) { + kret = errno; + DEBUG_PRINT(("Error adding user key '%s': %s\n", + keyname, strerror(kret))); + } else { + d->numkeys++; + kret = KRB5_OK; + } + + errout: + if (keyname) + krb5_free_unparsed_name(context, keyname); + if (payload) + free(payload); + + k5_mutex_unlock(&d->lock); + return kret; +} + +static krb5_error_code +krb5_krcc_save_principal(krb5_context context, krb5_ccache id, + krb5_principal princ) +{ + krb5_krcc_data *d; + krb5_error_code kret; + char *payload; + key_serial_t newkey; + unsigned int payloadsize; + krb5_krcc_bc bc; + + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); + + d = (krb5_krcc_data *) id->data; + + payload = malloc(GUESS_CRED_SIZE); + if (payload == NULL) + return KRB5_CC_NOMEM; + + bc.bpp = payload; + bc.endp = payload + GUESS_CRED_SIZE; + + kret = krb5_krcc_unparse_principal(context, id, princ, &bc); + CHECK_N_GO(kret, errout); + + /* Add new key into keyring */ + payloadsize = bc.bpp - payload; + DEBUG_PRINT(("krb5_krcc_save_principal: adding new key '%s' " + "to keyring %d\n", + KRCC_SPEC_PRINC_KEYNAME, d->ring_id)); /* XXX */ + newkey = add_key(KRCC_KEY_TYPE_USER, KRCC_SPEC_PRINC_KEYNAME, payload, + payloadsize, d->ring_id); + if (newkey < 0) { + kret = errno; + DEBUG_PRINT(("Error adding key for principal: %s\n", + strerror(kret))); + } else { + d->princ_id = newkey; + kret = KRB5_OK; + } + + errout: + free(payload); + return kret; +} + +static krb5_error_code +krb5_krcc_retrieve_principal(krb5_context context, krb5_ccache id, + krb5_principal * princ) +{ + krb5_krcc_data *d = (krb5_krcc_data *) id->data; + krb5_error_code kret; + void *payload = NULL; + int psize; + krb5_krcc_bc bc; + + kret = k5_mutex_lock(&d->lock); + if (kret) + return kret; + + if (!d->princ_id) { + princ = 0L; + kret = KRB5_FCC_NOFILE; + goto errout; + } + + psize = keyctl_read_alloc(d->princ_id, &payload); + if (psize == -1) { + DEBUG_PRINT(("Reading principal key %d: %s\n", + d->princ_id, strerror(errno))); + kret = KRB5_CC_IO; + goto errout; + } + bc.bpp = payload; + bc.endp = (char *)payload + psize; + kret = krb5_krcc_parse_principal(context, id, princ, &bc); + + errout: + if (payload) + free(payload); + k5_mutex_unlock(&d->lock); + return kret; +} + +static int +krb5_krcc_get_ring_ids(krb5_krcc_ring_ids_t *p) +{ + key_serial_t ids_key; + char ids_buf[128]; + key_serial_t session, process, thread; + long val; + + DEBUG_PRINT(("krb5_krcc_get_ring_ids: entered\n")); + + if (!p) + return EINVAL; + + /* Use the defaults in case we find no ids key */ + p->session = KEY_SPEC_SESSION_KEYRING; + p->process = KEY_SPEC_PROCESS_KEYRING; + p->thread = KEY_SPEC_THREAD_KEYRING; + + /* + * Note that in the "normal" case, this will not be found. + * The Linux gssd creates this key to communicate the + * user's key serial numbers. + */ + DEBUG_PRINT(("krb5_krcc_get_ring_ids: requesting key type '%s' name '%s'\n", + KRCC_KEY_TYPE_USER, KRCC_SPEC_IDS_KEYNAME)); + ids_key = request_key(KRCC_KEY_TYPE_USER, KRCC_SPEC_IDS_KEYNAME, NULL, 0); + if (ids_key < 0) + goto out; + + DEBUG_PRINT(("krb5_krcc_get_ring_ids: processing key %d\n", ids_key)); + /* + * Read and parse the ids file + */ + /* XXX + * This should also carry the "active" ccache name? + * Or better yet, we should call krb5_cc_set_default_name + * with the context to be used so we get the right one. + * This part should be done in krb5int_cc_default()??? + * XXX + */ + memset(ids_buf, '\0', sizeof(ids_buf)); + val = keyctl_read(ids_key, ids_buf, sizeof(ids_buf)); + if (val > sizeof(ids_buf)) + goto out; + +#ifdef KRCC_EXTRA_DEBUG + DEBUG_PRINT(("krb5_krcc_get_ring_ids: read %d bytes ('%s') " + "from key %d\n", val, ids_buf, ids_key)); +#endif + /* Note that a format of "%i:%i:%i" does not work here */ + val = sscanf(ids_buf, "%d:%d:%d", &session, &process, &thread); + if (val != 3) + goto out; + +#ifdef KRCC_EXTRA_DEBUG + DEBUG_PRINT(("krb5_krcc_get_ring_ids: parsed %d values: %d:%d:%d\n", + val, session, process, thread)); +#endif + p->session = session; + p->process = process; + p->thread = thread; + + out: + DEBUG_PRINT(("krb5_krcc_get_ring_ids: returning %d:%d:%d\n", + p->session, p->process, p->thread)); + return 0; +} + +/* + * =============================================================== + * INTERNAL functions to parse a credential from a key payload + * (Borrowed heavily from krb5_fcc_{read|store}_ funtions.) + * =============================================================== + */ + +/* + * Effects: + * Copies len bytes from the key payload buffer into buf. + * Updates payload pointer and returns KRB5_CC_END if we + * try to read past the end of the payload buffer's data. + * + * Requires: + * Must be called with mutex locked. + * + * Errors: + * KRB5_CC_END - there were not len bytes available + */ +static krb5_error_code +krb5_krcc_parse(krb5_context context, krb5_ccache id, krb5_pointer buf, + unsigned int len, krb5_krcc_bc * bc) +{ +#ifdef NEED_LOCK_ASSERTIONS + krb5_krcc_data *data = (krb5_krcc_data *) id->data; + + k5_assert_locked(&data->lock); +#endif + DEBUG_PRINT(("krb5_krcc_parse: entered\n")); + + if ((bc->endp == bc->bpp) || (bc->endp - bc->bpp) < len) + return KRB5_CC_END; + + memcpy(buf, bc->bpp, len); + bc->bpp += len; + + return KRB5_OK; +} + +/* + * Take a key (credential) read from a keyring entry + * and parse it into a credential structure. + */ +static krb5_error_code +krb5_krcc_parse_cred(krb5_context context, krb5_ccache id, krb5_creds * creds, + char *payload, int psize) +{ + krb5_error_code kret; + krb5_octet octet; + krb5_int32 int32; + krb5_krcc_bc bc; + + /* Parse the pieces of the credential */ + bc.bpp = payload; + bc.endp = bc.bpp + psize; + kret = krb5_krcc_parse_principal(context, id, &creds->client, &bc); + CHECK_N_GO(kret, out); + + kret = krb5_krcc_parse_principal(context, id, &creds->server, &bc); + CHECK_N_GO(kret, cleanclient); + + kret = krb5_krcc_parse_keyblock(context, id, &creds->keyblock, &bc); + CHECK_N_GO(kret, cleanserver); + + kret = krb5_krcc_parse_times(context, id, &creds->times, &bc); + CHECK_N_GO(kret, cleanserver); + + kret = krb5_krcc_parse_octet(context, id, &octet, &bc); + CHECK_N_GO(kret, cleanserver); + creds->is_skey = octet; + + kret = krb5_krcc_parse_int32(context, id, &int32, &bc); + CHECK_N_GO(kret, cleanserver); + creds->ticket_flags = int32; + + kret = krb5_krcc_parse_addrs(context, id, &creds->addresses, &bc); + CHECK_N_GO(kret, cleanblock); + + kret = krb5_krcc_parse_authdata(context, id, &creds->authdata, &bc); + CHECK_N_GO(kret, cleanaddrs); + + kret = krb5_krcc_parse_krb5data(context, id, &creds->ticket, &bc); + CHECK_N_GO(kret, cleanauthdata); + + kret = krb5_krcc_parse_krb5data(context, id, &creds->second_ticket, &bc); + CHECK_N_GO(kret, cleanticket); + + kret = KRB5_OK; + goto out; + + cleanticket: + memset(creds->ticket.data, 0, (unsigned) creds->ticket.length); + krb5_xfree(creds->ticket.data); + cleanauthdata: + /* XXX ??? */ + cleanaddrs: + krb5_free_addresses(context, creds->addresses); + cleanblock: + krb5_xfree(creds->keyblock.contents); + cleanserver: + krb5_free_principal(context, creds->server); + cleanclient: + krb5_free_principal(context, creds->client); + + out: + return kret; +} + +static krb5_error_code +krb5_krcc_parse_principal(krb5_context context, krb5_ccache id, + krb5_principal * princ, krb5_krcc_bc * bc) +{ + krb5_error_code kret; + register krb5_principal tmpprinc; + krb5_int32 length, type; + int i; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + /* Read principal type */ + kret = krb5_krcc_parse_int32(context, id, &type, bc); + if (kret != KRB5_OK) + return kret; + + /* Read the number of components */ + kret = krb5_krcc_parse_int32(context, id, &length, bc); + if (kret != KRB5_OK) + return kret; + + if (length < 0) + return KRB5_CC_NOMEM; + + tmpprinc = (krb5_principal) malloc(sizeof(krb5_principal_data)); + if (tmpprinc == NULL) + return KRB5_CC_NOMEM; + if (length) { + size_t msize = length; + if (msize != length) { + free(tmpprinc); + return KRB5_CC_NOMEM; + } + tmpprinc->data = ALLOC(msize, krb5_data); + if (tmpprinc->data == 0) { + free((char *) tmpprinc); + return KRB5_CC_NOMEM; + } + } else + tmpprinc->data = 0; + tmpprinc->magic = KV5M_PRINCIPAL; + tmpprinc->length = length; + tmpprinc->type = type; + + kret = krb5_krcc_parse_krb5data(context, id, + krb5_princ_realm(context, tmpprinc), bc); + i = 0; + CHECK(kret); + + for (i = 0; i < length; i++) { + kret = krb5_krcc_parse_krb5data(context, id, + krb5_princ_component(context, tmpprinc, + i), bc); + CHECK(kret); + } + *princ = tmpprinc; + return KRB5_OK; + + errout: + while (--i >= 0) + free(krb5_princ_component(context, tmpprinc, i)->data); + free((char *) tmpprinc->data); + free((char *) tmpprinc); + return kret; +} + +static krb5_error_code +krb5_krcc_parse_keyblock(krb5_context context, krb5_ccache id, + krb5_keyblock * keyblock, krb5_krcc_bc * bc) +{ + krb5_error_code kret; + krb5_ui_2 ui2; + krb5_int32 int32; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + keyblock->magic = KV5M_KEYBLOCK; + keyblock->contents = 0; + + kret = krb5_krcc_parse_ui_2(context, id, &ui2, bc); + CHECK(kret); + keyblock->enctype = ui2; + + kret = krb5_krcc_parse_int32(context, id, &int32, bc); + CHECK(kret); + if (int32 < 0) + return KRB5_CC_NOMEM; + keyblock->length = int32; + /* Overflow check. */ + if (keyblock->length != int32) + return KRB5_CC_NOMEM; + if (keyblock->length == 0) + return KRB5_OK; + keyblock->contents = ALLOC(keyblock->length, krb5_octet); + if (keyblock->contents == NULL) + return KRB5_CC_NOMEM; + + kret = krb5_krcc_parse(context, id, keyblock->contents, + keyblock->length, bc); + CHECK(kret); + + return KRB5_OK; + errout: + if (keyblock->contents) + krb5_xfree(keyblock->contents); + return kret; +} + +static krb5_error_code +krb5_krcc_parse_times(krb5_context context, krb5_ccache id, + krb5_ticket_times * t, krb5_krcc_bc * bc) +{ + krb5_error_code kret; + krb5_int32 i; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + kret = krb5_krcc_parse_int32(context, id, &i, bc); + CHECK(kret); + t->authtime = i; + + kret = krb5_krcc_parse_int32(context, id, &i, bc); + CHECK(kret); + t->starttime = i; + + kret = krb5_krcc_parse_int32(context, id, &i, bc); + CHECK(kret); + t->endtime = i; + + kret = krb5_krcc_parse_int32(context, id, &i, bc); + CHECK(kret); + t->renew_till = i; + + return 0; + errout: + return kret; +} + +static krb5_error_code +krb5_krcc_parse_krb5data(krb5_context context, krb5_ccache id, + krb5_data * data, krb5_krcc_bc * bc) +{ + krb5_error_code kret; + krb5_int32 len; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + data->magic = KV5M_DATA; + data->data = 0; + + kret = krb5_krcc_parse_int32(context, id, &len, bc); + CHECK(kret); + if (len < 0) + return KRB5_CC_NOMEM; + data->length = len; + if (data->length != len || data->length + 1 == 0) + return KRB5_CC_NOMEM; + + if (data->length == 0) { + data->data = 0; + return KRB5_OK; + } + + data->data = (char *) malloc(data->length + 1); + if (data->data == NULL) + return KRB5_CC_NOMEM; + + kret = krb5_krcc_parse(context, id, data->data, (unsigned) data->length, + bc); + CHECK(kret); + + data->data[data->length] = 0; /* Null terminate, just in case.... */ + return KRB5_OK; + errout: + if (data->data) + krb5_xfree(data->data); + return kret; +} + +static krb5_error_code +krb5_krcc_parse_int32(krb5_context context, krb5_ccache id, krb5_int32 * i, + krb5_krcc_bc * bc) +{ + krb5_error_code kret; + unsigned char buf[4]; + krb5_int32 val; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + kret = krb5_krcc_parse(context, id, buf, 4, bc); + if (kret) + return kret; + val = buf[0]; + val = (val << 8) | buf[1]; + val = (val << 8) | buf[2]; + val = (val << 8) | buf[3]; + *i = val; + return 0; +} + +static krb5_error_code +krb5_krcc_parse_octet(krb5_context context, krb5_ccache id, krb5_octet * i, + krb5_krcc_bc * bc) +{ +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + return krb5_krcc_parse(context, id, (krb5_pointer) i, 1, bc); +} + +static krb5_error_code +krb5_krcc_parse_addrs(krb5_context context, krb5_ccache id, + krb5_address *** addrs, krb5_krcc_bc * bc) +{ + krb5_error_code kret; + krb5_int32 length; + size_t msize; + int i; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + *addrs = 0; + + /* Read the number of components */ + kret = krb5_krcc_parse_int32(context, id, &length, bc); + CHECK(kret); + + /* + * Make *addrs able to hold length pointers to krb5_address structs + * Add one extra for a null-terminated list + */ + msize = length; + msize += 1; + if (msize == 0 || msize - 1 != length || length < 0) + return KRB5_CC_NOMEM; + *addrs = ALLOC(msize, krb5_address *); + if (*addrs == NULL) + return KRB5_CC_NOMEM; + + for (i = 0; i < length; i++) { + (*addrs)[i] = (krb5_address *) malloc(sizeof(krb5_address)); + if ((*addrs)[i] == NULL) { + krb5_free_addresses(context, *addrs); + return KRB5_CC_NOMEM; + } + kret = krb5_krcc_parse_addr(context, id, (*addrs)[i], bc); + CHECK(kret); + } + + return KRB5_OK; + errout: + if (*addrs) + krb5_free_addresses(context, *addrs); + return kret; +} + +static krb5_error_code +krb5_krcc_parse_addr(krb5_context context, krb5_ccache id, krb5_address * addr, + krb5_krcc_bc * bc) +{ + krb5_error_code kret; + krb5_ui_2 ui2; + krb5_int32 int32; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + addr->magic = KV5M_ADDRESS; + addr->contents = 0; + + kret = krb5_krcc_parse_ui_2(context, id, &ui2, bc); + CHECK(kret); + addr->addrtype = ui2; + + kret = krb5_krcc_parse_int32(context, id, &int32, bc); + CHECK(kret); + if ((int32 & VALID_INT_BITS) != int32) /* Overflow int??? */ + return KRB5_CC_NOMEM; + addr->length = int32; + /* + * Length field is "unsigned int", which may be smaller + * than 32 bits. + */ + if (addr->length != int32) + return KRB5_CC_NOMEM; /* XXX */ + + if (addr->length == 0) + return KRB5_OK; + + addr->contents = (krb5_octet *) malloc(addr->length); + if (addr->contents == NULL) + return KRB5_CC_NOMEM; + + kret = krb5_krcc_parse(context, id, addr->contents, addr->length, bc); + CHECK(kret); + + return KRB5_OK; + errout: + if (addr->contents) + krb5_xfree(addr->contents); + return kret; +} + +static krb5_error_code +krb5_krcc_parse_authdata(krb5_context context, krb5_ccache id, + krb5_authdata *** a, krb5_krcc_bc * bc) +{ + krb5_error_code kret; + krb5_int32 length; + size_t msize; + int i; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + *a = 0; + + /* Read the number of components */ + kret = krb5_krcc_parse_int32(context, id, &length, bc); + CHECK(kret); + + if (length == 0) + return KRB5_OK; + + /* + * Make *a able to hold length pointers to krb5_authdata structs + * Add one extra for a null-terminated list + */ + msize = length; + msize += 1; + if (msize == 0 || msize - 1 != length || length < 0) + return KRB5_CC_NOMEM; + *a = ALLOC(msize, krb5_authdata *); + if (*a == NULL) + return KRB5_CC_NOMEM; + + for (i = 0; i < length; i++) { + (*a)[i] = (krb5_authdata *) malloc(sizeof(krb5_authdata)); + if ((*a)[i] == NULL) { + krb5_free_authdata(context, *a); + return KRB5_CC_NOMEM; + } + kret = krb5_krcc_parse_authdatum(context, id, (*a)[i], bc); + CHECK(kret); + } + + return KRB5_OK; + errout: + if (*a) + krb5_free_authdata(context, *a); + return kret; +} + +static krb5_error_code +krb5_krcc_parse_authdatum(krb5_context context, krb5_ccache id, + krb5_authdata * a, krb5_krcc_bc * bc) +{ + krb5_error_code kret; + krb5_int32 int32; + krb5_ui_2 ui2; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + a->magic = KV5M_AUTHDATA; + a->contents = NULL; + + kret = krb5_krcc_parse_ui_2(context, id, &ui2, bc); + CHECK(kret); + a->ad_type = (krb5_authdatatype) ui2; + kret = krb5_krcc_parse_int32(context, id, &int32, bc); + CHECK(kret); + if ((int32 & VALID_INT_BITS) != int32) /* Overflow int??? */ + return KRB5_CC_NOMEM; + a->length = int32; + /* + * Value could have gotten truncated if int is + * smaller than 32 bits. + */ + if (a->length != int32) + return KRB5_CC_NOMEM; /* XXX */ + + if (a->length == 0) + return KRB5_OK; + + a->contents = (krb5_octet *) malloc(a->length); + if (a->contents == NULL) + return KRB5_CC_NOMEM; + + kret = krb5_krcc_parse(context, id, a->contents, a->length, bc); + CHECK(kret); + + return KRB5_OK; + errout: + if (a->contents) + krb5_xfree(a->contents); + return kret; + +} + +static krb5_error_code +krb5_krcc_parse_ui_2(krb5_context context, krb5_ccache id, krb5_ui_2 * i, + krb5_krcc_bc * bc) +{ + krb5_error_code kret; + unsigned char buf[2]; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + kret = krb5_krcc_parse(context, id, buf, 2, bc); + if (kret) + return kret; + *i = (buf[0] << 8) + buf[1]; + return 0; +} + +/* + * Requires: + * locked mutex + * + * Effects: + * Copies len bytes from buf into the payload buffer (bc->bpp). + * Detects attempts to write past end of the payload buffer. + * Updates payload buffer pointer accordingly. + * + * Errors: + * system errors + */ +static krb5_error_code +krb5_krcc_unparse(krb5_context context, krb5_ccache id, krb5_pointer buf, + unsigned int len, krb5_krcc_bc * bc) +{ +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + if (bc->bpp + len > bc->endp) + return KRB5_CC_WRITE; + + memcpy(bc->bpp, buf, len); + bc->bpp += len; + + return KRB5_OK; +} + +static krb5_error_code +krb5_krcc_unparse_principal(krb5_context context, krb5_ccache id, + krb5_principal princ, krb5_krcc_bc * bc) +{ + krb5_error_code kret; + krb5_int32 i, length, tmp, type; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + type = krb5_princ_type(context, princ); + tmp = length = krb5_princ_size(context, princ); + + kret = krb5_krcc_unparse_int32(context, id, type, bc); + CHECK_OUT(kret); + + kret = krb5_krcc_unparse_int32(context, id, tmp, bc); + CHECK_OUT(kret); + + kret = krb5_krcc_unparse_krb5data(context, id, + krb5_princ_realm(context, princ), bc); + CHECK_OUT(kret); + + for (i = 0; i < length; i++) { + kret = krb5_krcc_unparse_krb5data(context, id, + krb5_princ_component(context, princ, + i), bc); + CHECK_OUT(kret); + } + + return KRB5_OK; +} + +static krb5_error_code +krb5_krcc_unparse_keyblock(krb5_context context, krb5_ccache id, + krb5_keyblock * keyblock, krb5_krcc_bc * bc) +{ + krb5_error_code kret; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + kret = krb5_krcc_unparse_ui_2(context, id, keyblock->enctype, bc); + CHECK_OUT(kret); + kret = krb5_krcc_unparse_ui_4(context, id, keyblock->length, bc); + CHECK_OUT(kret); + return krb5_krcc_unparse(context, id, (char *) keyblock->contents, + keyblock->length, bc); +} + +static krb5_error_code +krb5_krcc_unparse_times(krb5_context context, krb5_ccache id, + krb5_ticket_times * t, krb5_krcc_bc * bc) +{ + krb5_error_code kret; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + kret = krb5_krcc_unparse_int32(context, id, t->authtime, bc); + CHECK_OUT(kret); + kret = krb5_krcc_unparse_int32(context, id, t->starttime, bc); + CHECK_OUT(kret); + kret = krb5_krcc_unparse_int32(context, id, t->endtime, bc); + CHECK_OUT(kret); + kret = krb5_krcc_unparse_int32(context, id, t->renew_till, bc); + CHECK_OUT(kret); + return 0; +} + +static krb5_error_code +krb5_krcc_unparse_krb5data(krb5_context context, krb5_ccache id, + krb5_data * data, krb5_krcc_bc * bc) +{ + krb5_error_code kret; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + kret = krb5_krcc_unparse_ui_4(context, id, data->length, bc); + CHECK_OUT(kret); + return krb5_krcc_unparse(context, id, data->data, data->length, bc); +} + +static krb5_error_code +krb5_krcc_unparse_int32(krb5_context context, krb5_ccache id, krb5_int32 i, + krb5_krcc_bc * bc) +{ + unsigned char buf[4]; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + buf[3] = (unsigned char) (i & 0xFF); + i >>= 8; + buf[2] = (unsigned char) (i & 0xFF); + i >>= 8; + buf[1] = (unsigned char) (i & 0xFF); + i >>= 8; + buf[0] = (unsigned char) (i & 0xFF); + return krb5_krcc_unparse(context, id, buf, 4, bc); +} + +static krb5_error_code +krb5_krcc_unparse_octet(krb5_context context, krb5_ccache id, krb5_int32 i, + krb5_krcc_bc * bc) +{ + krb5_octet ibuf; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + ibuf = (krb5_octet) i; + return krb5_krcc_unparse(context, id, (char *) &ibuf, 1, bc); +} + +static krb5_error_code +krb5_krcc_unparse_addrs(krb5_context context, krb5_ccache id, + krb5_address ** addrs, krb5_krcc_bc * bc) +{ + krb5_error_code kret; + krb5_address **temp; + krb5_int32 i, length = 0; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + /* Count the number of components */ + if (addrs) { + temp = addrs; + while (*temp++) + length += 1; + } + + kret = krb5_krcc_unparse_int32(context, id, length, bc); + CHECK_OUT(kret); + for (i = 0; i < length; i++) { + kret = krb5_krcc_unparse_addr(context, id, addrs[i], bc); + CHECK_OUT(kret); + } + + return KRB5_OK; +} + +static krb5_error_code +krb5_krcc_unparse_addr(krb5_context context, krb5_ccache id, + krb5_address * addr, krb5_krcc_bc * bc) +{ + krb5_error_code kret; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + kret = krb5_krcc_unparse_ui_2(context, id, addr->addrtype, bc); + CHECK_OUT(kret); + kret = krb5_krcc_unparse_ui_4(context, id, addr->length, bc); + CHECK_OUT(kret); + return krb5_krcc_unparse(context, id, (char *) addr->contents, + addr->length, bc); +} + +static krb5_error_code +krb5_krcc_unparse_authdata(krb5_context context, krb5_ccache id, + krb5_authdata ** a, krb5_krcc_bc * bc) +{ + krb5_error_code kret; + krb5_authdata **temp; + krb5_int32 i, length = 0; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + if (a != NULL) { + for (temp = a; *temp; temp++) + length++; + } + + kret = krb5_krcc_unparse_int32(context, id, length, bc); + CHECK_OUT(kret); + for (i = 0; i < length; i++) { + kret = krb5_krcc_unparse_authdatum(context, id, a[i], bc); + CHECK_OUT(kret); + } + return KRB5_OK; +} + +static krb5_error_code +krb5_krcc_unparse_authdatum(krb5_context context, krb5_ccache id, + krb5_authdata * a, krb5_krcc_bc * bc) +{ + krb5_error_code kret; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + kret = krb5_krcc_unparse_ui_2(context, id, a->ad_type, bc); + CHECK_OUT(kret); + kret = krb5_krcc_unparse_ui_4(context, id, a->length, bc); + CHECK_OUT(kret); + return krb5_krcc_unparse(context, id, (krb5_pointer) a->contents, + a->length, bc); +} + +static krb5_error_code +krb5_krcc_unparse_ui_4(krb5_context context, krb5_ccache id, krb5_ui_4 i, + krb5_krcc_bc * bc) +{ + unsigned char buf[4]; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + buf[3] = (unsigned char) (i & 0xFF); + i >>= 8; + buf[2] = (unsigned char) (i & 0xFF); + i >>= 8; + buf[1] = (unsigned char) (i & 0xFF); + i >>= 8; + buf[0] = (unsigned char) (i & 0xFF); + return krb5_krcc_unparse(context, id, buf, 4, bc); +} + +static krb5_error_code +krb5_krcc_unparse_ui_2(krb5_context context, krb5_ccache id, krb5_int32 i, + krb5_krcc_bc * bc) +{ + unsigned char buf[2]; + +#ifdef NEED_LOCK_ASSERTIONS + k5_assert_locked(&((krb5_krcc_data *) id->data)->lock); +#endif + + buf[1] = (unsigned char) (i & 0xFF); + i >>= 8; + buf[0] = (unsigned char) (i & 0xFF); + return krb5_krcc_unparse(context, id, buf, 2, bc); +} + +/* + * =============================================================== + * INTERNAL functions to unparse a credential into a key payload + * (Borrowed heavily from krb5_fcc_{read|store}_ funtions.) + * =============================================================== + */ + +/* + * Take a credential structure and unparse it (serialize) + * for storage into a keyring key entry. + * Caller is responsible for freeing returned buffer. + */ +static krb5_error_code +krb5_krcc_unparse_cred(krb5_context context, krb5_ccache id, + krb5_creds * creds, char **datapp, unsigned int *lenptr) +{ + krb5_error_code kret; + char *buf; + krb5_krcc_bc bc; + + if (!creds || !datapp || !lenptr) + return EINVAL; + + *datapp = NULL; + *lenptr = 0; + + buf = malloc(GUESS_CRED_SIZE); + if (buf == NULL) + return KRB5_CC_NOMEM; + + bc.bpp = buf; + bc.endp = buf + GUESS_CRED_SIZE; + + kret = krb5_krcc_unparse_principal(context, id, creds->client, &bc); + CHECK_N_GO(kret, errout); + + kret = krb5_krcc_unparse_principal(context, id, creds->server, &bc); + CHECK_N_GO(kret, errout); + + kret = krb5_krcc_unparse_keyblock(context, id, &creds->keyblock, &bc); + CHECK_N_GO(kret, errout); + + kret = krb5_krcc_unparse_times(context, id, &creds->times, &bc); + CHECK_N_GO(kret, errout); + + kret = krb5_krcc_unparse_octet(context, id, (krb5_int32) creds->is_skey, + &bc); + CHECK_N_GO(kret, errout); + + kret = krb5_krcc_unparse_int32(context, id, creds->ticket_flags, &bc); + CHECK_N_GO(kret, errout); + + kret = krb5_krcc_unparse_addrs(context, id, creds->addresses, &bc); + CHECK_N_GO(kret, errout); + + kret = krb5_krcc_unparse_authdata(context, id, creds->authdata, &bc); + CHECK_N_GO(kret, errout); + + kret = krb5_krcc_unparse_krb5data(context, id, &creds->ticket, &bc); + CHECK_N_GO(kret, errout); + + kret = krb5_krcc_unparse_krb5data(context, id, &creds->second_ticket, &bc); + CHECK_N_GO(kret, errout); + + /* Success! */ + *datapp = buf; + *lenptr = bc.bpp - buf; + kret = KRB5_OK; + + errout: + return kret; +} + +/* + * ccache implementation storing credentials in the Linux keyring facility + * The default is to put them at the session keyring level. + * If "KEYRING:process:" or "KEYRING:thread:" is specified, then they will + * be stored at the process or thread level respectively. + */ +const krb5_cc_ops krb5_krcc_ops = { + 0, + "KEYRING", + krb5_krcc_get_name, + krb5_krcc_resolve, + krb5_krcc_generate_new, + krb5_krcc_initialize, + krb5_krcc_destroy, + krb5_krcc_close, + krb5_krcc_store, + krb5_krcc_retrieve, + krb5_krcc_get_principal, + krb5_krcc_start_seq_get, + krb5_krcc_next_cred, + krb5_krcc_end_seq_get, + krb5_krcc_remove_cred, + krb5_krcc_set_flags, +#ifdef HAVE_GET_FLAGS + krb5_krcc_get_flags /* added after 1.4 release */ +#endif +}; diff -puN src/lib/krb5/ccache/Makefile.in~add_keyring_ccache_20060822 src/lib/krb5/ccache/Makefile.in --- krb5-1.4.4/src/lib/krb5/ccache/Makefile.in~add_keyring_ccache_20060822 2006-08-25 12:37:34.000000000 -0400 +++ krb5-1.4.4-andros/src/lib/krb5/ccache/Makefile.in 2006-08-25 12:37:34.000000000 -0400 @@ -25,7 +25,9 @@ STLIBOBJS= \ ccdefault.o \ ccdefops.o \ cc_retr.o \ - cc_file.o cc_memory.o \ + cc_file.o \ + cc_memory.o \ + cc_keyring.o \ ccfns.o \ ser_cc.o @@ -36,6 +38,7 @@ OBJS= $(OUTPRE)ccbase.$(OBJEXT) \ $(OUTPRE)cc_retr.$(OBJEXT) \ $(OUTPRE)cc_file.$(OBJEXT) \ $(OUTPRE)cc_memory.$(OBJEXT) \ + $(OUTPRE)cc_keyring.$(OBJEXT) \ $(OUTPRE)ccfns.$(OBJEXT) \ $(OUTPRE)ser_cc.$(OBJEXT) $(MSLSA_OBJ) @@ -46,6 +49,7 @@ SRCS= $(srcdir)/ccbase.c \ $(srcdir)/cc_retr.c \ $(srcdir)/cc_file.c \ $(srcdir)/cc_memory.c \ + $(srcdir)/cc_keyring.c \ $(srcdir)/ccfns.c \ $(srcdir)/ser_cc.c $(MSLSA_SRC) @@ -142,6 +146,12 @@ cc_memory.so cc_memory.po $(OUTPRE)cc_me $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \ $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ $(SRCTOP)/include/krb5/kdb.h +cc_keyring.so cc_keyring.po $(OUTPRE)cc_keyring.$(OBJEXT): cc_keyring.c $(SRCTOP)/include/k5-int.h \ + $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \ + $(BUILDTOP)/include/krb5.h $(COM_ERR_DEPS) $(BUILDTOP)/include/profile.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/include/krb5/kdb.h ccfns.so ccfns.po $(OUTPRE)ccfns.$(OBJEXT): ccfns.c $(SRCTOP)/include/k5-int.h \ $(BUILDTOP)/include/krb5/osconf.h $(BUILDTOP)/include/krb5/autoconf.h \ $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-thread.h \ diff -puN src/lib/krb5/os/ccdefname.c~add_keyring_ccache_20060822 src/lib/krb5/os/ccdefname.c --- krb5-1.4.4/src/lib/krb5/os/ccdefname.c~add_keyring_ccache_20060822 2006-08-25 12:37:34.000000000 -0400 +++ krb5-1.4.4-andros/src/lib/krb5/os/ccdefname.c 2006-08-25 12:37:34.000000000 -0400 @@ -224,7 +224,11 @@ cleanup: #if !(defined(_WIN32)) static krb5_error_code get_from_os(char *name_buf, int name_size) { +#ifdef HAVE_LIBKEYUTILS + snprintf(name_buf, (unsigned) name_size, "KEYRING:krb5cc"); +#else sprintf(name_buf, "FILE:/tmp/krb5cc_%ld", (long) getuid()); +#endif return 0; } #endif _