Skip to content

Commit

Permalink
iter: Enable iteration over slots/tokens/modules
Browse files Browse the repository at this point in the history
While PKCS#11 URI can identify slots/tokens/modules, P11KitIter is only
capable of iterating over objects.

This patch adds new behaviors to P11KitIter to support iterations over
slots/tokens/modules, using the C coroutine trick as described in:
http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
  • Loading branch information
ueno committed Jan 2, 2017
1 parent 794385d commit 4e05b6d
Show file tree
Hide file tree
Showing 4 changed files with 297 additions and 27 deletions.
2 changes: 2 additions & 0 deletions doc/manual/p11-kit-sections.txt
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ p11_kit_iter_callback
p11_kit_iter_begin
p11_kit_iter_begin_with
p11_kit_iter_next
p11_kit_iter_get_kind
p11_kit_iter_get_module
p11_kit_iter_get_slot
p11_kit_iter_get_slot_info
Expand All @@ -130,6 +131,7 @@ p11_kit_iter_get_attributes
p11_kit_iter_load_attributes
p11_kit_iter_destroy_object
p11_kit_iter_free
P11KitIterKind
P11KitIterBehavior
p11_kit_remote_serve_module
</SECTION>
Expand Down
149 changes: 124 additions & 25 deletions p11-kit/iter.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013 Red Hat Inc.
* Copyright (C) 2013,2016 Red Hat Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
Expand Down Expand Up @@ -55,7 +55,7 @@ typedef struct _Callback {
/**
* P11KitIter:
*
* Used to iterate over PKCS\#11 objects.
* Used to iterate over PKCS\#11 objects, tokens, slots, and modules.
*/
struct p11_kit_iter {

Expand All @@ -82,12 +82,15 @@ struct p11_kit_iter {
CK_ULONG saw_objects;

/* The current iteration */
P11KitIterKind kind;
CK_FUNCTION_LIST_PTR module;
CK_SLOT_ID slot;
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE object;
CK_SLOT_INFO slot_info;
CK_TOKEN_INFO token_info;
int move_next_session_state;
int iter_next_state;

/* And various flags */
unsigned int searching : 1;
Expand All @@ -97,14 +100,33 @@ struct p11_kit_iter {
unsigned int keep_session : 1;
unsigned int preload_results : 1;
unsigned int want_writable : 1;
unsigned int with_modules : 1;
unsigned int with_slots : 1;
unsigned int with_tokens : 1;
unsigned int with_objects : 1;
};

/**
* P11KitIterKind:
* @P11_KIT_ITER_KIND_MODULE: The iterator is pointing to a module.
* @P11_KIT_ITER_KIND_SLOT: The iterator is pointing to a slot.
* @P11_KIT_ITER_KIND_TOKEN: The iterator is pointing to a token.
* @P11_KIT_ITER_KIND_OBJECT: The iterator is pointing to an object.
* @P11_KIT_ITER_KIND_UNKNOWN: The iterator doesn't point to anything.
*
* The kind of the current match.
*/

/**
* P11KitIterBehavior:
* @P11_KIT_ITER_BUSY_SESSIONS: Allow the iterator's sessions to be
* in a busy state when the iterator returns an object.
* @P11_KIT_ITER_WANT_WRITABLE: Try to open read-write sessions when
* iterating over obojects.
* iterating over objects.
* @P11_KIT_ITER_WITH_MODULES: Stop at each module while iterating.
* @P11_KIT_ITER_WITH_SLOTS: Stop at each slot while iterating.
* @P11_KIT_ITER_WITH_TOKENS: Stop at each token while iterating.
* @P11_KIT_ITER_WITHOUT_OBJECTS: Ignore objects while iterating.
*
* Various flags controlling the behavior of the iterator.
*/
Expand Down Expand Up @@ -139,6 +161,10 @@ p11_kit_iter_new (P11KitUri *uri,

iter->want_writable = !!(behavior & P11_KIT_ITER_WANT_WRITABLE);
iter->preload_results = !(behavior & P11_KIT_ITER_BUSY_SESSIONS);
iter->with_modules = !!(behavior & P11_KIT_ITER_WITH_MODULES);
iter->with_slots = !!(behavior & P11_KIT_ITER_WITH_SLOTS);
iter->with_tokens = !!(behavior & P11_KIT_ITER_WITH_TOKENS);
iter->with_objects = !(behavior & P11_KIT_ITER_WITHOUT_OBJECTS);

p11_kit_iter_set_uri (iter, uri);
return iter;
Expand Down Expand Up @@ -334,6 +360,9 @@ finish_iterating (P11KitIter *iter,
p11_array_clear (iter->modules);

iter->iterating = 0;
iter->move_next_session_state = 0;
iter->iter_next_state = 0;
iter->kind = P11_KIT_ITER_KIND_UNKNOWN;
return rv;
}

Expand Down Expand Up @@ -470,6 +499,10 @@ call_all_filters (P11KitIter *iter,
return CKR_OK;
}

#define COROUTINE_BEGIN(name) switch (iter->name ## _state) { case 0:
#define COROUTINE_RETURN(name,i,x) do { iter->name ## _state = i; return x; case i:; } while (0)
#define COROUTINE_END(name) }

static CK_RV
move_next_session (P11KitIter *iter)
{
Expand All @@ -478,6 +511,8 @@ move_next_session (P11KitIter *iter)
CK_INFO minfo;
CK_RV rv;

COROUTINE_BEGIN (move_next_session);

finish_slot (iter);

/* If we have no more slots, then move to next module */
Expand All @@ -497,23 +532,31 @@ move_next_session (P11KitIter *iter)
if (rv != CKR_OK || !p11_match_uri_module_info (&iter->match_module, &minfo))
continue;

rv = (iter->module->C_GetSlotList) (CK_TRUE, NULL, &num_slots);
if (rv != CKR_OK)
return finish_iterating (iter, rv);
if (iter->with_modules) {
iter->kind = P11_KIT_ITER_KIND_MODULE;
COROUTINE_RETURN (move_next_session, 1, CKR_OK);
}

if (iter->with_slots || iter->with_tokens || iter->with_objects) {
rv = (iter->module->C_GetSlotList) (CK_TRUE, NULL, &num_slots);
if (rv != CKR_OK)
return finish_iterating (iter, rv);

iter->slots = realloc (iter->slots, sizeof (CK_SLOT_ID) * (num_slots + 1));
return_val_if_fail (iter->slots != NULL, CKR_HOST_MEMORY);
iter->slots = realloc (iter->slots, sizeof (CK_SLOT_ID) * (num_slots + 1));
return_val_if_fail (iter->slots != NULL, CKR_HOST_MEMORY);

rv = (iter->module->C_GetSlotList) (CK_TRUE, iter->slots, &num_slots);
if (rv != CKR_OK)
return finish_iterating (iter, rv);
rv = (iter->module->C_GetSlotList) (CK_TRUE, iter->slots, &num_slots);
if (rv != CKR_OK)
return finish_iterating (iter, rv);

iter->num_slots = num_slots;
assert (iter->saw_slots == 0);
iter->num_slots = num_slots;
assert (iter->saw_slots == 0);
}
}

/* Move to the next slot, and open a session on it */
while (iter->saw_slots < iter->num_slots) {
while ((iter->with_slots || iter->with_tokens || iter->with_objects) &&
iter->saw_slots < iter->num_slots) {
iter->slot = iter->slots[iter->saw_slots++];

assert (iter->module != NULL);
Expand All @@ -522,9 +565,17 @@ move_next_session (P11KitIter *iter)
rv = (iter->module->C_GetSlotInfo) (iter->slot, &iter->slot_info);
if (rv != CKR_OK || !p11_match_uri_slot_info (&iter->match_slot, &iter->slot_info))
continue;
if (iter->with_slots) {
iter->kind = P11_KIT_ITER_KIND_SLOT;
COROUTINE_RETURN (move_next_session, 2, CKR_OK);
}
rv = (iter->module->C_GetTokenInfo) (iter->slot, &iter->token_info);
if (rv != CKR_OK || !p11_match_uri_token_info (&iter->match_token, &iter->token_info))
continue;
if (iter->with_tokens) {
iter->kind = P11_KIT_ITER_KIND_TOKEN;
COROUTINE_RETURN (move_next_session, 3, CKR_OK);
}

session_flags = CKF_SERIAL_SESSION;

Expand All @@ -537,11 +588,17 @@ move_next_session (P11KitIter *iter)
if (rv != CKR_OK)
return finish_iterating (iter, rv);

if (iter->session != 0)
if (iter->session != 0) {
iter->move_next_session_state = 0;
iter->kind = P11_KIT_ITER_KIND_UNKNOWN;
return CKR_OK;
}
}

COROUTINE_END (move_next_session);

/* Otherwise try again */
iter->move_next_session_state = 0;
return move_next_session (iter);
}

Expand Down Expand Up @@ -572,36 +629,54 @@ p11_kit_iter_next (P11KitIter *iter)

return_val_if_fail (iter->iterating, CKR_OPERATION_NOT_INITIALIZED);

COROUTINE_BEGIN (iter_next);

iter->object = 0;

if (iter->match_nothing)
return finish_iterating (iter, CKR_CANCEL);

if (!(iter->with_modules || iter->with_slots || iter->with_tokens || iter->with_objects))
return finish_iterating (iter, CKR_CANCEL);

/*
* If we have outstanding objects, then iterate one through those
* Note that we pass each object through the filters, and only
* assume it's iterated if it matches
*/
while (iter->saw_objects < iter->num_objects) {
while (iter->with_objects && iter->saw_objects < iter->num_objects) {
iter->object = iter->objects[iter->saw_objects++];

rv = call_all_filters (iter, &matches);
if (rv != CKR_OK)
return finish_iterating (iter, rv);

if (matches)
return CKR_OK;
if (matches && iter->with_objects) {
iter->kind = P11_KIT_ITER_KIND_OBJECT;
COROUTINE_RETURN (iter_next, 1, CKR_OK);
}
}

/* If we have finished searching then move to next session */
if (iter->searched) {
rv = move_next_session (iter);
if (rv != CKR_OK)
return finish_iterating (iter, rv);
/* Move to next session, if we have finished searching
* objects, or we are looking for modules/slots/tokens */
if ((iter->with_objects && iter->searched) ||
(!iter->with_objects &&
(iter->with_modules || iter->with_slots || iter->with_tokens))) {
/* Use iter->kind as the sentinel to detect the case where
* any match (except object) is successful in
* move_next_session() */
do {
iter->kind = P11_KIT_ITER_KIND_UNKNOWN;
rv = move_next_session (iter);
if (rv != CKR_OK)
return finish_iterating (iter, rv);
if (iter->kind != P11_KIT_ITER_KIND_UNKNOWN)
COROUTINE_RETURN (iter_next, 2, CKR_OK);
} while (iter->move_next_session_state > 0);
}

/* Ready to start searching */
if (!iter->searching && !iter->searched) {
if (iter->with_objects && !iter->searching && !iter->searched) {
count = p11_attrs_count (iter->match_attrs);
rv = (iter->module->C_FindObjectsInit) (iter->session, iter->match_attrs, count);
if (rv != CKR_OK)
Expand All @@ -611,7 +686,7 @@ p11_kit_iter_next (P11KitIter *iter)
}

/* If we have searched on this session then try to continue */
if (iter->searching) {
if (iter->with_objects && iter->searching) {
assert (iter->module != NULL);
assert (iter->session != 0);
iter->num_objects = 0;
Expand Down Expand Up @@ -650,10 +725,34 @@ p11_kit_iter_next (P11KitIter *iter)
}
}

COROUTINE_END (iter_next);

/* Try again */
iter->iter_next_state = 0;
iter->move_next_session_state = 0;
iter->kind = P11_KIT_ITER_KIND_UNKNOWN;
return p11_kit_iter_next (iter);
}

/**
* p11_kit_iter_get_kind:
* @iter: the iterator
*
* Get the kind of the current match (a module, slot, token, or an
* object).
*
* This can only be called after p11_kit_iter_next() succeeds.
*
* Returns: a #P11KitIterKind value
*/
P11KitIterKind
p11_kit_iter_get_kind (P11KitIter *iter)
{
return_val_if_fail (iter != NULL, P11_KIT_ITER_KIND_UNKNOWN);
return_val_if_fail (iter->iterating, P11_KIT_ITER_KIND_UNKNOWN);
return iter->kind;
}

/**
* p11_kit_iter_get_module:
* @iter: the iterator
Expand Down
16 changes: 15 additions & 1 deletion p11-kit/iter.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013 Red Hat, Inc
* Copyright (c) 2013,2016 Red Hat, Inc
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
Expand Down Expand Up @@ -48,9 +48,21 @@ extern "C" {
typedef struct p11_kit_iter P11KitIter;
typedef P11KitIter p11_kit_iter;

typedef enum {
P11_KIT_ITER_KIND_MODULE,
P11_KIT_ITER_KIND_SLOT,
P11_KIT_ITER_KIND_TOKEN,
P11_KIT_ITER_KIND_OBJECT,
P11_KIT_ITER_KIND_UNKNOWN = -1,
} P11KitIterKind;

typedef enum {
P11_KIT_ITER_BUSY_SESSIONS = 1 << 1,
P11_KIT_ITER_WANT_WRITABLE = 1 << 2,
P11_KIT_ITER_WITH_MODULES = 1 << 3,
P11_KIT_ITER_WITH_SLOTS = 1 << 4,
P11_KIT_ITER_WITH_TOKENS = 1 << 5,
P11_KIT_ITER_WITHOUT_OBJECTS = 1 << 6,
} P11KitIterBehavior;

typedef CK_RV (* p11_kit_iter_callback) (P11KitIter *iter,
Expand Down Expand Up @@ -84,6 +96,8 @@ void p11_kit_iter_begin_with (P11KitIter *iter,

CK_RV p11_kit_iter_next (P11KitIter *iter);

P11KitIterKind p11_kit_iter_get_kind (P11KitIter *iter);

CK_FUNCTION_LIST_PTR p11_kit_iter_get_module (P11KitIter *iter);

CK_SLOT_ID p11_kit_iter_get_slot (P11KitIter *iter);
Expand Down
Loading

0 comments on commit 4e05b6d

Please sign in to comment.