81715b1776
- pull in fix to store KDC time offsets in keyring credential caches (RT#7768, #1030607)
312 lines
10 KiB
Diff
312 lines
10 KiB
Diff
commit fb4817a32d0c369049e0868468dd2eb75487630d
|
|
Author: Simo Sorce <simo@redhat.com>
|
|
Date: Thu Nov 14 17:23:59 2013 -0500
|
|
|
|
Add support to store time offsets in cc_keyring
|
|
|
|
The code follows the same model used for the memory ccache type. Time
|
|
offsets are stored in each credential cache in a special key just like
|
|
the principal name. Legacy session caches do not store timestamps as
|
|
legacy code would fail when iterating over the new offset key.
|
|
|
|
[ghudson@mit.edu: minor formatting changes; note legacy session
|
|
exception in commit message]
|
|
|
|
ticket: 7768 (new)
|
|
target_version: 1.12
|
|
tags: pullup
|
|
|
|
diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c
|
|
index a07a0dc..2192fa5 100644
|
|
--- a/src/lib/krb5/ccache/cc_keyring.c
|
|
+++ b/src/lib/krb5/ccache/cc_keyring.c
|
|
@@ -189,6 +189,11 @@ debug_print(char *fmt, ...)
|
|
#define KRCC_PERSISTENT_KEYRING_NAME "_krb"
|
|
|
|
/*
|
|
+ * Name of the key holding time offsets for the individual cache
|
|
+ */
|
|
+#define KRCC_TIME_OFFSETS "__krb5_time_offsets__"
|
|
+
|
|
+/*
|
|
* Keyring name prefix and length of random name part
|
|
*/
|
|
#define KRCC_NAME_PREFIX "krb_ccache_"
|
|
@@ -217,6 +222,7 @@ typedef struct _krb5_krcc_cursor
|
|
int numkeys;
|
|
int currkey;
|
|
key_serial_t princ_id;
|
|
+ key_serial_t offsets_id;
|
|
key_serial_t *keys;
|
|
} *krb5_krcc_cursor;
|
|
|
|
@@ -340,6 +346,12 @@ static krb5_error_code krb5_krcc_save_principal
|
|
|
|
static krb5_error_code krb5_krcc_retrieve_principal
|
|
(krb5_context context, krb5_ccache id, krb5_principal * princ);
|
|
+static krb5_error_code krb5_krcc_save_time_offsets
|
|
+(krb5_context context, krb5_ccache id, krb5_int32 time_offset,
|
|
+ krb5_int32 usec_offset);
|
|
+static krb5_error_code krb5_krcc_get_time_offsets
|
|
+(krb5_context context, krb5_ccache id, krb5_int32 *time_offset,
|
|
+ krb5_int32 *usec_offset);
|
|
|
|
/* Routines to parse a key from a keyring into a cred structure */
|
|
static krb5_error_code krb5_krcc_parse
|
|
@@ -410,6 +422,12 @@ krb5_krcc_parse_index(krb5_context context, krb5_int32 *version,
|
|
static krb5_error_code
|
|
krb5_krcc_unparse_index(krb5_context context, krb5_int32 version,
|
|
const char *primary, void **datapp, int *lenptr);
|
|
+static krb5_error_code
|
|
+krb5_krcc_parse_offsets(krb5_context context, krb5_int32 *time_offset,
|
|
+ krb5_int32 *usec_offset, void *payload, int psize);
|
|
+static krb5_error_code
|
|
+krb5_krcc_unparse_offsets(krb5_context context, krb5_int32 time_offset,
|
|
+ krb5_int32 usec_offset, void **datapp, int *lenptr);
|
|
|
|
/* Note the following is a stub function for Linux */
|
|
extern krb5_error_code krb5_change_cache(void);
|
|
@@ -835,6 +853,7 @@ krb5_krcc_initialize(krb5_context context, krb5_ccache id,
|
|
krb5_principal princ)
|
|
{
|
|
krb5_krcc_data *data = (krb5_krcc_data *)id->data;
|
|
+ krb5_os_context os_ctx = &context->os_context;
|
|
krb5_error_code kret;
|
|
const char *cache_name, *p;
|
|
|
|
@@ -863,6 +882,15 @@ krb5_krcc_initialize(krb5_context context, krb5_ccache id,
|
|
(void)keyctl_link(data->cache_id, KEY_SPEC_SESSION_KEYRING);
|
|
|
|
kret = krb5_krcc_save_principal(context, id, princ);
|
|
+
|
|
+ /* Save time offset if it is valid and this is not a legacy cache. Legacy
|
|
+ * applications would fail to parse the new key in the cache keyring. */
|
|
+ if (!is_legacy_cache_name(data->name) &&
|
|
+ (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID)) {
|
|
+ kret = krb5_krcc_save_time_offsets(context, id, os_ctx->time_offset,
|
|
+ os_ctx->usec_offset);
|
|
+ }
|
|
+
|
|
if (kret == KRB5_OK)
|
|
krb5_change_cache();
|
|
|
|
@@ -1039,6 +1067,7 @@ make_cache(key_serial_t collection_id, key_serial_t cache_id,
|
|
static krb5_error_code KRB5_CALLCONV
|
|
krb5_krcc_resolve(krb5_context context, krb5_ccache *id, const char *residual)
|
|
{
|
|
+ krb5_os_context os_ctx = &context->os_context;
|
|
krb5_error_code ret;
|
|
key_serial_t collection_id, cache_id;
|
|
char *anchor_name = NULL, *collection_name = NULL, *subsidiary_name = NULL;
|
|
@@ -1067,6 +1096,19 @@ krb5_krcc_resolve(krb5_context context, krb5_ccache *id, const char *residual)
|
|
|
|
ret = make_cache(collection_id, cache_id, anchor_name, collection_name,
|
|
subsidiary_name, id);
|
|
+ if (ret)
|
|
+ goto cleanup;
|
|
+
|
|
+ /* Lookup time offsets if necessary. */
|
|
+ if ((context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) &&
|
|
+ !(os_ctx->os_flags & KRB5_OS_TOFFSET_VALID)) {
|
|
+ if (krb5_krcc_get_time_offsets(context, *id,
|
|
+ &os_ctx->time_offset,
|
|
+ &os_ctx->usec_offset) == 0) {
|
|
+ os_ctx->os_flags &= ~KRB5_OS_TOFFSET_TIME;
|
|
+ os_ctx->os_flags |= KRB5_OS_TOFFSET_VALID;
|
|
+ }
|
|
+ }
|
|
|
|
cleanup:
|
|
free(anchor_name);
|
|
@@ -1122,6 +1164,8 @@ krb5_krcc_start_seq_get(krb5_context context, krb5_ccache id,
|
|
}
|
|
|
|
krcursor->princ_id = d->princ_id;
|
|
+ krcursor->offsets_id = keyctl_search(d->cache_id, KRCC_KEY_TYPE_USER,
|
|
+ KRCC_TIME_OFFSETS, 0);
|
|
krcursor->numkeys = size / sizeof(key_serial_t);
|
|
krcursor->keys = keys;
|
|
|
|
@@ -1174,8 +1218,10 @@ krb5_krcc_next_cred(krb5_context context, krb5_ccache id,
|
|
if (krcursor->currkey >= krcursor->numkeys)
|
|
return KRB5_CC_END;
|
|
|
|
- /* If we're pointing at the entry with the principal, skip it */
|
|
- if (krcursor->keys[krcursor->currkey] == krcursor->princ_id) {
|
|
+ /* If we're pointing at the entry with the principal, or at the key
|
|
+ * with the time offsets, skip it. */
|
|
+ while (krcursor->keys[krcursor->currkey] == krcursor->princ_id ||
|
|
+ krcursor->keys[krcursor->currkey] == krcursor->offsets_id) {
|
|
krcursor->currkey++;
|
|
/* Check if we have now reached the end */
|
|
if (krcursor->currkey >= krcursor->numkeys)
|
|
@@ -1621,6 +1667,84 @@ errout:
|
|
return kret;
|
|
}
|
|
|
|
+static krb5_error_code
|
|
+krb5_krcc_save_time_offsets(krb5_context context, krb5_ccache id,
|
|
+ krb5_int32 time_offset, krb5_int32 usec_offset)
|
|
+{
|
|
+ krb5_krcc_data *d = (krb5_krcc_data *)id->data;
|
|
+ krb5_error_code kret;
|
|
+ key_serial_t newkey;
|
|
+ void *payload = NULL;
|
|
+ int psize;
|
|
+
|
|
+ k5_cc_mutex_assert_locked(context, &d->lock);
|
|
+
|
|
+ /* Prepare the payload. */
|
|
+ kret = krb5_krcc_unparse_offsets(context, time_offset, usec_offset,
|
|
+ &payload, &psize);
|
|
+ CHECK_N_GO(kret, errout);
|
|
+
|
|
+ /* Add new key into keyring. */
|
|
+ newkey = add_key(KRCC_KEY_TYPE_USER, KRCC_TIME_OFFSETS, payload, psize,
|
|
+ d->cache_id);
|
|
+ if (newkey == -1) {
|
|
+ kret = errno;
|
|
+ DEBUG_PRINT(("Error adding time offsets key: %s\n", strerror(kret)));
|
|
+ } else {
|
|
+ kret = KRB5_OK;
|
|
+ krb5_krcc_update_change_time(d);
|
|
+ }
|
|
+
|
|
+errout:
|
|
+ free(payload);
|
|
+ return kret;
|
|
+}
|
|
+
|
|
+static krb5_error_code
|
|
+krb5_krcc_get_time_offsets(krb5_context context, krb5_ccache id,
|
|
+ krb5_int32 *time_offset, krb5_int32 *usec_offset)
|
|
+{
|
|
+ krb5_krcc_data *d = (krb5_krcc_data *)id->data;
|
|
+ krb5_error_code kret;
|
|
+ key_serial_t key;
|
|
+ krb5_int32 t, u;
|
|
+ void *payload = NULL;
|
|
+ int psize;
|
|
+
|
|
+ k5_cc_mutex_lock(context, &d->lock);
|
|
+
|
|
+ if (!d->cache_id) {
|
|
+ kret = KRB5_FCC_NOFILE;
|
|
+ goto errout;
|
|
+ }
|
|
+
|
|
+ key = keyctl_search(d->cache_id, KRCC_KEY_TYPE_USER, KRCC_TIME_OFFSETS, 0);
|
|
+ if (key == -1) {
|
|
+ kret = ENOENT;
|
|
+ goto errout;
|
|
+ }
|
|
+
|
|
+ psize = keyctl_read_alloc(key, &payload);
|
|
+ if (psize == -1) {
|
|
+ DEBUG_PRINT(("Reading time offsets key %d: %s\n",
|
|
+ key, strerror(errno)));
|
|
+ kret = KRB5_CC_IO;
|
|
+ goto errout;
|
|
+ }
|
|
+
|
|
+ kret = krb5_krcc_parse_offsets(context, &t, &u, payload, psize);
|
|
+ if (kret)
|
|
+ goto errout;
|
|
+
|
|
+ *time_offset = t;
|
|
+ *usec_offset = u;
|
|
+
|
|
+errout:
|
|
+ free(payload);
|
|
+ k5_cc_mutex_unlock(context, &d->lock);
|
|
+ return kret;
|
|
+}
|
|
+
|
|
struct krcc_ptcursor_data {
|
|
key_serial_t collection_id;
|
|
char *anchor_name;
|
|
@@ -2656,6 +2780,83 @@ errout:
|
|
return kret;
|
|
}
|
|
|
|
+static krb5_error_code
|
|
+krb5_krcc_parse_offsets(krb5_context context, krb5_int32 *time_offset,
|
|
+ krb5_int32 *usec_offset, void *payload, int psize)
|
|
+{
|
|
+ krb5_error_code kret;
|
|
+ krb5_krcc_bc bc;
|
|
+
|
|
+ bc.bpp = payload;
|
|
+ bc.endp = bc.bpp + psize;
|
|
+
|
|
+ kret = krb5_krcc_parse_int32(context, time_offset, &bc);
|
|
+ CHECK_OUT(kret);
|
|
+
|
|
+ kret = krb5_krcc_parse_int32(context, usec_offset, &bc);
|
|
+ CHECK_OUT(kret);
|
|
+
|
|
+ return KRB5_OK;
|
|
+}
|
|
+
|
|
+static krb5_error_code
|
|
+krb5_krcc_unparse_offsets_internal(krb5_context context,
|
|
+ krb5_int32 time_offset,
|
|
+ krb5_int32 usec_offset,
|
|
+ krb5_krcc_bc *bc)
|
|
+{
|
|
+ krb5_error_code kret;
|
|
+
|
|
+ kret = krb5_krcc_unparse_int32(context, time_offset, bc);
|
|
+ CHECK_OUT(kret);
|
|
+
|
|
+ kret = krb5_krcc_unparse_int32(context, usec_offset, bc);
|
|
+ CHECK_OUT(kret);
|
|
+
|
|
+ return KRB5_OK;
|
|
+}
|
|
+
|
|
+static krb5_error_code
|
|
+krb5_krcc_unparse_offsets(krb5_context context, krb5_int32 time_offset,
|
|
+ krb5_int32 usec_offset, void **datapp, int *lenptr)
|
|
+{
|
|
+ krb5_error_code kret;
|
|
+ krb5_krcc_bc bc;
|
|
+ char *buf;
|
|
+
|
|
+ if (!datapp || !lenptr)
|
|
+ return EINVAL;
|
|
+
|
|
+ *datapp = NULL;
|
|
+ *lenptr = 0;
|
|
+
|
|
+ /* Do a dry run first to calculate the size. */
|
|
+ bc.bpp = bc.endp = NULL;
|
|
+ bc.size = 0;
|
|
+ kret = krb5_krcc_unparse_offsets_internal(context, time_offset,
|
|
+ usec_offset, &bc);
|
|
+ CHECK_OUT(kret);
|
|
+
|
|
+ buf = malloc(bc.size);
|
|
+ if (buf == NULL)
|
|
+ return ENOMEM;
|
|
+
|
|
+ bc.bpp = buf;
|
|
+ bc.endp = buf + bc.size;
|
|
+ kret = krb5_krcc_unparse_offsets_internal(context, time_offset,
|
|
+ usec_offset, &bc);
|
|
+ CHECK(kret);
|
|
+
|
|
+ /* Success! */
|
|
+ *datapp = buf;
|
|
+ *lenptr = bc.bpp - buf;
|
|
+ kret = KRB5_OK;
|
|
+
|
|
+errout:
|
|
+ if (kret)
|
|
+ free(buf);
|
|
+ return kret;
|
|
+}
|
|
/*
|
|
* Utility routine: called by krb5_krcc_* functions to keep
|
|
* result of krb5_krcc_last_change_time up to date.
|