krb5 commit: Fix KCM ccache per-type cursor
Greg Hudson
ghudson at mit.edu
Sat Aug 30 11:41:49 EDT 2014
https://github.com/krb5/krb5/commit/956cbd24e645609c94fbc836840ce0f87ba3ce79
commit 956cbd24e645609c94fbc836840ce0f87ba3ce79
Author: Greg Hudson <ghudson at mit.edu>
Date: Thu Aug 28 18:43:56 2014 -0400
Fix KCM ccache per-type cursor
The KCM per-type cursor was too simplistic and did not obey the
conventions of the other ccache types. Fix it to return a singleton
cursor when the default cache is a subsidiary and to return the
primary cache first.
For internal convenience, make_cache now accepts a context parameter
and creates a kcmio if necessary.
ticket: 8002 (new)
target_version: 1.13
src/lib/krb5/ccache/cc_kcm.c | 120 +++++++++++++++++++++++++++++++-----------
1 files changed, 89 insertions(+), 31 deletions(-)
diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c
index b763ea4..926a99c 100644
--- a/src/lib/krb5/ccache/cc_kcm.c
+++ b/src/lib/krb5/ccache/cc_kcm.c
@@ -84,8 +84,10 @@ struct kcm_cache_data {
};
struct kcm_ptcursor {
- struct uuid_list *uuids;
+ char *residual; /* primary or singleton subsidiary */
+ struct uuid_list *uuids; /* NULL for singleton subsidiary */
struct kcmio *io;
+ krb5_boolean first;
};
/* Map EINVAL or KRB5_CC_FORMAT to KRB5_KCM_MALFORMED_REPLY; pass through all
@@ -481,16 +483,24 @@ kcmreq_free(struct kcmreq *req)
free(req->reply_mem);
}
-/* Create a krb5_ccache structure. Always take ownership of io. */
+/* Create a krb5_ccache structure. If io is NULL, make a new connection for
+ * the cache. Otherwise, always take ownership of io. */
static krb5_error_code
-make_cache(const char *residual, struct kcmio *io, krb5_ccache *cache_out)
+make_cache(krb5_context context, const char *residual, struct kcmio *io,
+ krb5_ccache *cache_out)
{
+ krb5_error_code ret;
krb5_ccache cache = NULL;
struct kcm_cache_data *data = NULL;
char *residual_copy = NULL;
*cache_out = NULL;
- assert(io != NULL);
+
+ if (io == NULL) {
+ ret = kcmio_connect(context, &io);
+ if (ret)
+ return ret;
+ }
cache = malloc(sizeof(*cache));
if (cache == NULL)
@@ -605,7 +615,7 @@ kcm_resolve(krb5_context context, krb5_ccache *cache_out, const char *residual)
residual = defname;
}
- ret = make_cache(residual, io, cache_out);
+ ret = make_cache(context, residual, io, cache_out);
io = NULL;
cleanup:
@@ -634,7 +644,7 @@ kcm_gen_new(krb5_context context, krb5_ccache *cache_out)
ret = kcmreq_get_name(&req, &name);
if (ret)
goto cleanup;
- ret = make_cache(name, io, cache_out);
+ ret = make_cache(context, name, io, cache_out);
io = NULL;
cleanup:
@@ -814,14 +824,20 @@ kcm_get_flags(krb5_context context, krb5_ccache cache, krb5_flags *flags_out)
/* Construct a per-type cursor, always taking ownership of io and uuids. */
static krb5_error_code
-make_ptcursor(struct uuid_list *uuids, struct kcmio *io,
+make_ptcursor(const char *residual, struct uuid_list *uuids, struct kcmio *io,
krb5_cc_ptcursor *cursor_out)
{
krb5_cc_ptcursor cursor = NULL;
struct kcm_ptcursor *data = NULL;
+ char *residual_copy = NULL;
*cursor_out = NULL;
+ if (residual != NULL) {
+ residual_copy = strdup(residual);
+ if (residual_copy == NULL)
+ goto oom;
+ }
cursor = malloc(sizeof(*cursor));
if (cursor == NULL)
goto oom;
@@ -829,8 +845,10 @@ make_ptcursor(struct uuid_list *uuids, struct kcmio *io,
if (data == NULL)
goto oom;
+ data->residual = residual_copy;
data->uuids = uuids;
data->io = io;
+ data->first = TRUE;
cursor->ops = &krb5_kcm_ops;
cursor->data = data;
*cursor_out = cursor;
@@ -839,6 +857,7 @@ make_ptcursor(struct uuid_list *uuids, struct kcmio *io,
oom:
kcmio_close(io);
free_uuid_list(uuids);
+ free(residual_copy);
free(data);
free(cursor);
return ENOMEM;
@@ -851,7 +870,7 @@ kcm_ptcursor_new(krb5_context context, krb5_cc_ptcursor *cursor_out)
struct kcmreq req = EMPTY_KCMREQ;
struct kcmio *io = NULL;
struct uuid_list *uuids;
- const char *defname;
+ const char *defname, *primary;
*cursor_out = NULL;
@@ -859,27 +878,39 @@ kcm_ptcursor_new(krb5_context context, krb5_cc_ptcursor *cursor_out)
* name has the KCM type. */
defname = krb5_cc_default_name(context);
if (defname == NULL || strncmp(defname, "KCM:", 4) != 0)
- return make_ptcursor(NULL, NULL, cursor_out);
+ return make_ptcursor(NULL, NULL, NULL, cursor_out);
ret = kcmio_connect(context, &io);
if (ret)
- goto cleanup;
+ return ret;
+
+ /* If defname is a subsidiary cache, return a singleton cursor. */
+ if (strlen(defname) > 4)
+ return make_ptcursor(defname + 4, NULL, io, cursor_out);
kcmreq_init(&req, KCM_OP_GET_CACHE_UUID_LIST, NULL);
ret = kcmio_call(context, io, &req);
if (ret == KRB5_FCC_NOFILE) {
/* There are no accessible caches; return an empty cursor. */
- ret = make_ptcursor(NULL, NULL, cursor_out);
+ ret = make_ptcursor(NULL, NULL, NULL, cursor_out);
goto cleanup;
}
if (ret)
goto cleanup;
-
ret = kcmreq_get_uuid_list(&req, &uuids);
if (ret)
goto cleanup;
- ret = make_ptcursor(uuids, io, cursor_out);
+ kcmreq_free(&req);
+ kcmreq_init(&req, KCM_OP_GET_DEFAULT_CACHE, NULL);
+ ret = kcmio_call(context, io, &req);
+ if (ret)
+ goto cleanup;
+ ret = kcmreq_get_name(&req, &primary);
+ if (ret)
+ goto cleanup;
+
+ ret = make_ptcursor(primary, uuids, io, cursor_out);
io = NULL;
cleanup:
@@ -888,38 +919,64 @@ cleanup:
return ret;
}
+/* Return true if name is an initialized cache. */
+static krb5_boolean
+name_exists(krb5_context context, struct kcmio *io, const char *name)
+{
+ krb5_error_code ret;
+ struct kcmreq req;
+
+ kcmreq_init(&req, KCM_OP_GET_PRINCIPAL, NULL);
+ k5_buf_add_len(&req.reqbuf, name, strlen(name) + 1);
+ ret = kcmio_call(context, io, &req);
+ kcmreq_free(&req);
+ return ret == 0;
+}
+
static krb5_error_code KRB5_CALLCONV
kcm_ptcursor_next(krb5_context context, krb5_cc_ptcursor cursor,
krb5_ccache *cache_out)
{
- krb5_error_code ret;
+ krb5_error_code ret = 0;
struct kcmreq req = EMPTY_KCMREQ;
- struct kcmio *io;
struct kcm_ptcursor *data = cursor->data;
- struct uuid_list *uuids = data->uuids;
+ struct uuid_list *uuids;
+ const unsigned char *id;
const char *name;
*cache_out = NULL;
- if (uuids == NULL || uuids->pos >= uuids->count)
+ /* Return the primary or specified subsidiary cache if we haven't yet. */
+ if (data->first && data->residual != NULL) {
+ data->first = FALSE;
+ if (name_exists(context, data->io, data->residual))
+ return make_cache(context, data->residual, NULL, cache_out);
+ }
+
+ uuids = data->uuids;
+ if (uuids == NULL)
return 0;
- kcmreq_init(&req, KCM_OP_GET_CACHE_BY_UUID, NULL);
- k5_buf_add_len(&req.reqbuf, uuids->uuidbytes + (uuids->pos * KCM_UUID_LEN),
- KCM_UUID_LEN);
- uuids->pos++;
- ret = kcmio_call(context, data->io, &req);
- if (ret)
- goto cleanup;
+ while (uuids->pos < uuids->count) {
+ /* Get the name of the next cache. */
+ id = &uuids->uuidbytes[KCM_UUID_LEN * uuids->pos++];
+ kcmreq_free(&req);
+ kcmreq_init(&req, KCM_OP_GET_CACHE_BY_UUID, NULL);
+ k5_buf_add_len(&req.reqbuf, id, KCM_UUID_LEN);
+ ret = kcmio_call(context, data->io, &req);
+ if (ret)
+ goto cleanup;
+ ret = kcmreq_get_name(&req, &name);
+ if (ret)
+ goto cleanup;
- ret = kcmreq_get_name(&req, &name);
- if (ret)
- goto cleanup;
+ /* Don't yield the primary cache twice. */
+ if (strcmp(name, data->residual) == 0)
+ continue;
- ret = kcmio_connect(context, &io);
- if (ret)
- goto cleanup;
- ret = make_cache(name, io, cache_out);
+ ret = make_cache(context, name, NULL, cache_out);
+ break;
+ }
cleanup:
kcmreq_free(&req);
@@ -931,6 +988,7 @@ kcm_ptcursor_free(krb5_context context, krb5_cc_ptcursor *cursor)
{
struct kcm_ptcursor *data = (*cursor)->data;
+ free(data->residual);
free_uuid_list(data->uuids);
kcmio_close(data->io);
free(data);
More information about the cvs-krb5
mailing list