#include "k5-int.h"
#ifdef USE_KEYRING_CCACHE
#include <errno.h>
#include <keyutils.h>
#ifdef DEBUG
#define KRCC_DEBUG 1
#endif
#if KRCC_DEBUG
void debug_print(char *fmt, ...);
#include <syslog.h>
#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
#define KRCC_KEY_TYPE_USER "user"
#define KRCC_KEY_TYPE_KEYRING "keyring"
#define KRCC_SPEC_PRINC_KEYNAME "__krb5_princ__"
#define KRCC_SPEC_IDS_KEYNAME "_gssd_keyring_ids_"
#define KRCC_SPEC_CCACHE_SET_KEYNAME "__krb5_cc_set__"
#define KRB5_OK 0
#define GUESS_CRED_SIZE 4096
#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;
typedef struct _krb5_krcc_data
{
char *name;
k5_mutex_t lock;
key_serial_t parent_id;
key_serial_t ring_id;
key_serial_t princ_id;
int numkeys;
} krb5_krcc_data;
typedef struct _krb5_krcc_buffer_cursor
{
char *bpp;
char *endp;
} krb5_krcc_bc;
k5_mutex_t krb5int_krcc_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
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);
static krb5_error_code KRB5_CALLCONV krb5_krcc_get_flags
(krb5_context context, krb5_ccache id, krb5_flags * flags);
static krb5_error_code krb5_krcc_clearcache
(krb5_context context, krb5_ccache id);
static krb5_error_code krb5_krcc_new_data
(const char *, key_serial_t ring, key_serial_t parent_ring,
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);
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);
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);
extern krb5_error_code krb5_change_cache(void);
static int KRB5_CALLCONV
krb5_krcc_getkeycount(key_serial_t cred_ring)
{
int res, nkeys;
res = keyctl_read(cred_ring, NULL, 0);
if (res > 0)
nkeys = (res / sizeof(key_serial_t)) - 1;
else
nkeys = 0;
return(nkeys);
}
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;
}
static krb5_error_code KRB5_CALLCONV
krb5_krcc_close(krb5_context context, krb5_ccache id)
{
krb5_krcc_data *d;
DEBUG_PRINT(("krb5_krcc_close: entered\n"));
d = (krb5_krcc_data *) id->data;
krb5_xfree(d->name);
k5_mutex_destroy(&d->lock);
krb5_xfree(d);
krb5_xfree(id);
return KRB5_OK;
}
static krb5_error_code
krb5_krcc_clearcache(krb5_context context, krb5_ccache id)
{
krb5_krcc_data *d;
int res;
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));
res = keyctl_clear(d->ring_id);
if (res != 0) {
return errno;
}
d->numkeys = 0;
d->princ_id = 0;
return KRB5_OK;
}
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, d->parent_id);
if (res < 0) {
kret = errno;
DEBUG_PRINT(("krb5_krcc_destroy: unlinking key %d from ring %d: %s",
d->ring_id, d->parent_id, error_message(errno)));
goto cleanup;
}
cleanup:
k5_mutex_unlock(&d->lock);
k5_mutex_destroy(&d->lock);
krb5_xfree(d);
krb5_xfree(id);
krb5_change_cache();
return KRB5_OK;
}
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;
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;
}
DEBUG_PRINT(("krb5_krcc_resolve: searching ring %d for residual '%s'\n",
ring_id, residual));
key = keyctl_search(ring_id, KRCC_KEY_TYPE_KEYRING, residual, 0);
if (key < 0) {
key = add_key(KRCC_KEY_TYPE_KEYRING, residual, NULL, 0, ring_id);
if (key < 0) {
kret = errno;
DEBUG_PRINT(("krb5_krcc_resolve: Error adding new "
"keyring '%s': %s\n", residual, strerror(errno)));
return kret;
}
DEBUG_PRINT(("krb5_krcc_resolve: new keyring '%s', "
"key %d, added to keyring %d\n",
residual, key, ring_id));
} else {
DEBUG_PRINT(("krb5_krcc_resolve: found existing "
"key %d, with name '%s' in keyring %d\n",
key, residual, ring_id));
pkey = keyctl_search(key, KRCC_KEY_TYPE_USER,
KRCC_SPEC_PRINC_KEYNAME, 0);
if (pkey < 0) {
DEBUG_PRINT(("krb5_krcc_resolve: Error locating principal "
"info for existing ccache in ring %d: %s\n",
key, strerror(errno)));
pkey = 0;
}
nkeys = krb5_krcc_getkeycount(key);
}
lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
if (lid == NULL)
return KRB5_CC_NOMEM;
kret = krb5_krcc_new_data(residual, key, ring_id, &d);
if (kret) {
free(lid);
return kret;
}
DEBUG_PRINT(("krb5_krcc_resolve: ring_id %d, princ_id %d, "
"nkeys %d\n", key, pkey, nkeys));
d->princ_id = pkey;
d->numkeys = nkeys;
lid->ops = &krb5_krcc_ops;
lid->data = d;
lid->magic = KV5M_CCACHE;
*id = lid;
return KRB5_OK;
}
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;
d->numkeys = krb5_krcc_getkeycount(d->ring_id);
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;
}
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 = NULL;
DEBUG_PRINT(("krb5_krcc_next_cred: entered\n"));
krcursor = (krb5_krcc_cursor) * cursor;
if (krcursor == NULL)
return KRB5_CC_END;
memset(creds, 0, sizeof(krb5_creds));
if (krcursor->currkey > krcursor->numkeys)
return KRB5_CC_END;
if (krcursor->keys[krcursor->currkey] == krcursor->princ_id) {
krcursor->currkey++;
if (krcursor->currkey > krcursor->numkeys)
return KRB5_CC_END;
}
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_FCC_NOFILE;
goto freepayload;
}
krcursor->currkey++;
kret = krb5_krcc_parse_cred(context, id, creds, payload, psize);
freepayload:
if (payload) free(payload);
return kret;
}
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;
}
static krb5_error_code
krb5_krcc_new_data(const char *name, key_serial_t ring,
key_serial_t parent_ring, 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;
d->ring_id = ring;
d->parent_id = parent_ring;
d->numkeys = 0;
*datapp = d;
return 0;
}
static krb5_error_code
random_string (krb5_context context, char *string, krb5_int32 length)
{
static const unsigned char charlist[] =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
krb5_error_code err = 0;
unsigned char *bytes = NULL;
size_t bytecount = length - 1;
if (!err) {
bytes = malloc (bytecount);
if (bytes == NULL) { err = ENOMEM; }
}
if (!err) {
krb5_data data;
data.length = bytecount;
data.data = (char *) bytes;
err = krb5_c_random_make_octets (context, &data);
}
if (!err) {
krb5_int32 i;
for (i = 0; i < bytecount; i++) {
string [i] = charlist[bytes[i] % (sizeof (charlist) - 1)];
}
string[length - 1] = '\0';
}
if (bytes != NULL) { free (bytes); }
return err;
}
static krb5_error_code KRB5_CALLCONV
krb5_krcc_generate_new(krb5_context context, krb5_ccache * id)
{
krb5_ccache lid;
char uniquename[8];
krb5_error_code kret;
krb5_krcc_data *d;
key_serial_t ring_id = KEY_SPEC_SESSION_KEYRING;
key_serial_t key;
DEBUG_PRINT(("krb5_krcc_generate_new: entered\n"));
lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
if (lid == NULL)
return KRB5_CC_NOMEM;
lid->ops = &krb5_krcc_ops;
kret = k5_mutex_lock(&krb5int_krcc_mutex);
if (kret) {
free(lid);
return kret;
}
#ifndef ENOKEY
#define ENOKEY 126
#endif
#ifndef EKEYEXPIRED
#define EKEYEXPIRED 127
#endif
#ifndef EKEYREVOKED
#define EKEYREVOKED 128
#endif
#ifndef EKEYREJECTED
#define EKEYREJECTED 129
#endif
while (1) {
random_string(context, uniquename, sizeof(uniquename));
DEBUG_PRINT(("krb5_krcc_generate_new: searching for name '%s'\n",
uniquename));
key = keyctl_search(ring_id, KRCC_KEY_TYPE_KEYRING, uniquename, 0);
DEBUG_PRINT(("krb5_krcc_generate_new: after searching for '%s', key = %d, errno = %d\n", uniquename, key, errno));
if (key < 0 && errno == ENOKEY) {
key = add_key(KRCC_KEY_TYPE_KEYRING, uniquename, NULL, 0, ring_id);
if (key < 0) {
kret = errno;
DEBUG_PRINT(("krb5_krcc_generate_new: '%s' trying to "
"create '%s'\n", strerror(errno), uniquename));
k5_mutex_unlock(&krb5int_krcc_mutex);
return kret;
}
break;
}
}
kret = krb5_krcc_new_data(uniquename, key, ring_id, &d);
k5_mutex_unlock(&krb5int_krcc_mutex);
if (kret) {
krb5_xfree(lid);
return kret;
}
lid->data = d;
*id = lid;
krb5_change_cache();
return KRB5_OK;
}
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;
}
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);
}
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;
}
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;
}
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;
}
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;
kret = krb5_unparse_name(context, creds->server, &keyname);
if (kret) {
DEBUG_PRINT(("Error unparsing service principal name!\n"));
goto errout;
}
kret = krb5_krcc_unparse_cred(context, id, creds, &payload, &payloadlen);
if (kret != KRB5_OK)
goto errout;
DEBUG_PRINT(("krb5_krcc_store: adding new key '%s' to keyring %d\n",
keyname, d->ring_id));
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);
payloadsize = bc.bpp - payload;
#ifdef KRCC_DEBUG
{
krb5_error_code rc;
char *princname = NULL;
rc = krb5_unparse_name(context, princ, &princname);
DEBUG_PRINT(("krb5_krcc_save_principal: adding new key '%s' "
"to keyring %d for principal '%s'\n",
KRCC_SPEC_PRINC_KEYNAME, d->ring_id,
rc ? "<unknown>" : princname));
if (rc == 0)
krb5_free_unparsed_name(context, princname);
}
#endif
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 principal key: %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;
p->session = KEY_SPEC_SESSION_KEYRING;
p->process = KEY_SPEC_PROCESS_KEYRING;
p->thread = KEY_SPEC_THREAD_KEYRING;
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 '%s' key %d\n",
KRCC_SPEC_IDS_KEYNAME, ids_key));
memset(ids_buf, '\0', sizeof(ids_buf));
val = keyctl_read(ids_key, ids_buf, sizeof(ids_buf));
if (val > sizeof(ids_buf))
goto out;
val = sscanf(ids_buf, "%d:%d:%d", &session, &process, &thread);
if (val != 3)
goto out;
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;
}
static krb5_error_code
krb5_krcc_parse(krb5_context context, krb5_ccache id, krb5_pointer buf,
unsigned int len, krb5_krcc_bc * bc)
{
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;
}
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;
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:
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;
kret = krb5_krcc_parse_int32(context, id, &type, bc);
if (kret != KRB5_OK)
return kret;
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;
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;
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;
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;
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;
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;
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)
{
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;
*addrs = 0;
kret = krb5_krcc_parse_int32(context, id, &length, bc);
CHECK(kret);
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;
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)
return KRB5_CC_NOMEM;
addr->length = int32;
if (addr->length != int32)
return KRB5_CC_NOMEM;
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;
*a = 0;
kret = krb5_krcc_parse_int32(context, id, &length, bc);
CHECK(kret);
if (length == 0)
return KRB5_OK;
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;
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)
return KRB5_CC_NOMEM;
a->length = int32;
if (a->length != int32)
return KRB5_CC_NOMEM;
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];
kret = krb5_krcc_parse(context, id, buf, 2, bc);
if (kret)
return kret;
*i = (buf[0] << 8) + buf[1];
return 0;
}
static krb5_error_code
krb5_krcc_unparse(krb5_context context, krb5_ccache id, krb5_pointer buf,
unsigned int len, krb5_krcc_bc * bc)
{
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;
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;
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;
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;
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];
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;
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;
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;
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;
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;
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];
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];
buf[1] = (unsigned char) (i & 0xFF);
i >>= 8;
buf[0] = (unsigned char) (i & 0xFF);
return krb5_krcc_unparse(context, id, buf, 2, bc);
}
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);
*datapp = buf;
*lenptr = bc.bpp - buf;
kret = KRB5_OK;
errout:
return kret;
}
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,
krb5_krcc_get_flags
};
#else
const krb5_cc_ops krb5_krcc_ops = {
0,
"KEYRING",
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
#endif