summaryrefslogtreecommitdiff
path: root/ckcapi-session.c
diff options
context:
space:
mode:
Diffstat (limited to 'ckcapi-session.c')
-rw-r--r--ckcapi-session.c204
1 files changed, 127 insertions, 77 deletions
diff --git a/ckcapi-session.c b/ckcapi-session.c
index 0e9316f..0d71fe2 100644
--- a/ckcapi-session.c
+++ b/ckcapi-session.c
@@ -21,13 +21,7 @@
#include "ckcapi.h"
-typedef struct _SessionList {
- CkCapiSession **list;
- size_t lmax;
-} SessionList;
-
-/* These are protected by global_mutex */
-static SessionList the_sessions = { NULL, 0 };
+static CkCapiArray* all_sessions = NULL;
static void
object_data_release(CkCapiObjectData* objdata)
@@ -37,34 +31,58 @@ object_data_release(CkCapiObjectData* objdata)
(objdata->data_funcs->release)(objdata);
}
-CkCapiSession*
-ckcapi_session_create(void)
+CK_RV
+ckcapi_session_create(CK_SLOT_ID slot, CkCapiSession** ret)
{
- CkCapiSession* sess = calloc(1, sizeof(CkCapiSession));
+ CkCapiSession* sess;
+ DWORD err;
+
+ sess = calloc(1, sizeof(CkCapiSession));
if(!sess)
- return NULL;
+ return CKR_HOST_MEMORY;
sess->object_data = ckcapi_hash_new();
if(!sess->object_data) {
free(sess);
- return NULL;
+ return CKR_HOST_MEMORY;
}
sess->mutex = CreateMutex(NULL, FALSE, NULL);
if(!sess->mutex) {
ckcapi_hash_free(sess->object_data, NULL);
free(sess);
- return NULL;
+ return CKR_HOST_MEMORY;
+ }
+
+ sess->store = CertOpenSystemStore((HCRYPTPROV)NULL,
+ ckcapi_token_get_store_name(slot));
+ if(sess->store == NULL)
+ {
+ err = GetLastError();
+
+ /* Store not found, we don't care */
+ if(err != ERROR_FILE_NOT_FOUND)
+ {
+ ckcapi_hash_free(sess->object_data, NULL);
+ CloseHandle(sess->mutex);
+ free(sess);
+ return ckcapi_winerr_to_ckr(err);
+ }
}
+ sess->slot = slot;
+
DBGS(sess, "created");
- return sess;
+
+ *ret = sess;
+ return CKR_OK;
}
CK_RV
ckcapi_session_register(CkCapiSession* sess)
{
- CK_ULONG id = 0;
+ CkCapiSession* blank = NULL;
+ CK_SESSION_HANDLE id = 0;
CK_RV ret = CKR_OK;
size_t i;
@@ -78,6 +96,22 @@ ckcapi_session_register(CkCapiSession* sess)
/* Find a nice session identifier */
while(id == 0) {
+ /* Allocate sessions properly */
+ if(!all_sessions)
+ {
+ all_sessions = ckcapi_array_new(0, 1, sizeof(CkCapiSession*));
+ if(!all_sessions)
+ {
+ ret = CKR_HOST_MEMORY;
+ break;
+ }
+
+ /* A blank entry for '0' */
+ ckcapi_array_append(all_sessions, blank);
+
+ DBG(("allocated new session list"));
+ }
+
/*
* PKCS#11 GRAY AREA: We're assuming we can reuse session
* handles. PKCS#11 spec says they're like file handles,
@@ -85,53 +119,32 @@ ckcapi_session_register(CkCapiSession* sess)
*/
/* Note we never put anything in array position '0' */
- for(i = 1; i < the_sessions.lmax; ++i)
+ for(i = 1; i < all_sessions->len; ++i)
{
/* Any empty position will do */
- if(!the_sessions.list[i])
+ if(!ckcapi_array_index(all_sessions, CkCapiSession*, i))
{
id = i;
break;
}
}
- /* Couldn't find a handle, reallocate */
- if(id == 0)
+ /* Couldn't find a handle, append a handle */
+ if(id == 0)
{
- CkCapiSession** buf;
- size_t oldmax, newmax;
-
- oldmax = the_sessions.lmax;
- newmax = oldmax + 16;
-
- buf = realloc(the_sessions.list, newmax * sizeof(CkCapiSession*));
- if(!buf)
- {
- DBGS(sess, ("couldn't allocate session list, out of memory"));
- ret = CKR_HOST_MEMORY;
- break;
- }
-
- /* Choose the first of the new block as the id */
- id = oldmax;
-
- /* Clear new memory */
- the_sessions.list = buf;
- for( ; oldmax < newmax; ++oldmax)
- buf[oldmax] = NULL;
- the_sessions.lmax = newmax;
-
- DBG(("allocated new session list: %d max", newmax));
+ id = all_sessions->len;
+ ckcapi_array_append(all_sessions, blank);
}
}
if(ret == CKR_OK)
{
- ASSERT(id > 0 && id < the_sessions.lmax);
- ASSERT(the_sessions.list[id] == NULL);
+ ASSERT(id > 0 && id < all_sessions->len);
+ ASSERT(!ckcapi_array_index(all_sessions, CkCapiSession*, id));
+
/* And assign it to the session handle */
- the_sessions.list[id] = sess;
+ ckcapi_array_index(all_sessions, CkCapiSession*, i) = sess;
sess->id = id;
/* The session list reference */
@@ -163,6 +176,9 @@ ckcapi_session_destroy(CkCapiSession* sess)
ASSERT(sess->operation_data == NULL);
ASSERT(sess->operation_cancel == NULL);
+ if(sess->store)
+ CertCloseStore(sess->store, 0);
+
/* Make all the object adat go away */
ASSERT(sess->object_data != NULL);
ckcapi_hash_free(sess->object_data, object_data_release);
@@ -176,7 +192,7 @@ ckcapi_session_destroy(CkCapiSession* sess)
}
static CK_RV
-lock_ref_internal(SessionList* sessions, CK_SESSION_HANDLE id,
+lock_ref_internal(CkCapiArray* sessions, CK_SESSION_HANDLE id,
int remove, CkCapiSession** sess_ret)
{
CkCapiSession *sess;
@@ -185,15 +201,15 @@ lock_ref_internal(SessionList* sessions, CK_SESSION_HANDLE id,
ASSERT(sessions);
ASSERT(sess_ret);
- if(id >= sessions->lmax)
+ if(id >= sessions->len)
{
DBG(("invalid session id: %d", id));
return CKR_SESSION_HANDLE_INVALID;
}
/* A seemingly valid id */
- ASSERT(sessions->list);
- sess = sessions->list[id];
+ ASSERT(sessions);
+ sess = ckcapi_array_index(sessions, CkCapiSession*, id);
if(!sess)
{
@@ -241,7 +257,7 @@ lock_ref_internal(SessionList* sessions, CK_SESSION_HANDLE id,
/* And remove it if necessary */
if(remove)
{
- sessions->list[id] = NULL;
+ ckcapi_array_index(sessions, CkCapiSession*, id) = NULL;
/* The session list reference */
sess->refs--;
@@ -276,7 +292,7 @@ ckcapi_session_get_lock_ref(CK_ULONG id, int remove, CkCapiSession **sess)
ckcapi_lock_global();
- ret = lock_ref_internal (&the_sessions, id, remove, sess);
+ ret = lock_ref_internal (all_sessions, id, remove, sess);
ckcapi_unlock_global();
@@ -313,15 +329,15 @@ ckcapi_session_unref_unlock(CkCapiSession* sess)
ckcapi_session_destroy(sess);
}
-void
-ckcapi_session_close_all()
+CK_RV
+ckcapi_session_close_all(CK_SLOT_ID slot)
{
/* This must be called without any locks held */
- SessionList sessions;
+ CkCapiArray* sessions;
CkCapiSession *sess;
size_t i;
- CK_RV ret;
+ CK_RV ret = CKR_OK;
/*
* PKCS#11 GRAY AREA: What happens when this gets called
@@ -329,37 +345,71 @@ ckcapi_session_close_all()
* because by the time it returns, all sessions should be closed.
*/
+ DBG(("closing all sessions for: %d", slot));
+
ckcapi_lock_global();
+ sessions = ckcapi_array_sized_new(0, 1, sizeof(CkCapiSession*),
+ all_sessions->len);
+ if(!sessions)
+ ret = CKR_HOST_MEMORY;
+
/* Steal all the session data */
- sessions.list = the_sessions.list;
- the_sessions.list = NULL;
- sessions.lmax = the_sessions.lmax;
- the_sessions.lmax = 0;
-
- if(sessions.list || sessions.lmax)
- DBG(("closing all sessions"));
+ if(ret == CKR_OK)
+ {
+ for(i = 0; i < all_sessions->len; ++i)
+ {
+ sess = ckcapi_array_index(all_sessions, CkCapiSession*, i);
+ if(sess && (slot == ((CK_SLOT_ID)-1) || sess->slot == slot))
+ {
+ /* Steal this session */
+ ckcapi_array_index(all_sessions, CkCapiSession*, i) = NULL;
+ }
+ else
+ {
+ /* Not a session we're interested in */
+ sess = NULL;
+ }
+
+ /* Both null and normal sessions are set to preserve indexes */
+ ckcapi_array_append(sessions, sess);
+ }
+
+ ASSERT(sessions->len == all_sessions->len);
+ }
ckcapi_unlock_global();
+ if(ret != CKR_OK)
+ return ret;
+
/* Close each session in turn */
- for(i = 1; i < sessions.lmax; ++i)
+ for(i = 0; i < sessions->len; ++i)
{
- if(!sessions.list[i])
+ if(!ckcapi_array_index(sessions, CkCapiSession*, i))
continue;
-
- ret = lock_ref_internal (&sessions, i, 1, &sess);
- ASSERT(ret == CKR_OK);
- ckcapi_session_unref_unlock(sess);
+ /* We need any calls in other threads to finish, so wait here */
+ if(lock_ref_internal(sessions, i, 1, &sess) == CKR_OK)
+ ckcapi_session_unref_unlock(sess);
}
/* We stole the memory above, free it now */
- if(sessions.list)
- {
- free(sessions.list);
- DBG(("freed session list"));
- }
+ ckcapi_array_free(sessions, 1);
+ return CKR_OK;
+}
+
+void
+ckcapi_session_cleanup_all()
+{
+ ckcapi_session_close_all((CK_SLOT_ID)-1);
+
+ ckcapi_lock_global();
+
+ ckcapi_array_free(all_sessions, 1);
+ all_sessions = NULL;
+
+ ckcapi_unlock_global();
}
/* ----------------------------------------------------------------------------
@@ -430,14 +480,14 @@ ckcapi_session_enum_object_data(CkCapiSession* sess,
ASSERT(sess->object_data);
ASSERT(enum_func);
- max = ckcapi_object_get_max_handle();
+ max = ckcapi_token_get_max_handle();
for(i = 0; i < max; ++i)
{
objdata = (CkCapiObjectData*)ckcapi_hash_get(sess->object_data, &i, sizeof(i));
if(!objdata)
continue;
- obj = ckcapi_object_lookup (sess, i);
+ obj = ckcapi_token_lookup_object(sess->slot, i);
if(!obj)
continue;
@@ -451,7 +501,7 @@ ckcapi_session_get_object_data_for(CkCapiSession* sess, CK_OBJECT_HANDLE hand,
{
CkCapiObject* obj;
- obj = ckcapi_object_lookup(sess, hand);
+ obj = ckcapi_token_lookup_object(sess->slot, hand);
if(!obj)
return CKR_OBJECT_HANDLE_INVALID;