diff options
Diffstat (limited to 'ckcapi-session.c')
-rw-r--r-- | ckcapi-session.c | 204 |
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; |