Skip to content
Snippets Groups Projects
Commit bcb78df5 authored by Fredrik Thulin's avatar Fredrik Thulin
Browse files

rpc_C_CloseAllSessions: Only close sessions opened by this thread.

Threads on pkcs11-proxy map to applications rather than threads in the
PKCS#11 (v2.2) specification. It is therefor important to not close
sessions opened by other threads in C_CloseAllSessions.
parent d6d75c72
No related branches found
No related tags found
No related merge requests found
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
# define DEBUG_OUTPUT 0 // change to 1 to enable debugging # define DEBUG_OUTPUT 0 // change to 1 to enable debugging
# define PKCS11PROXY_LISTEN_BACKLOG 128 # define PKCS11PROXY_LISTEN_BACKLOG 128
# define PKCS11PROXY_MAX_SESSION_COUNT 256
#ifdef __MINGW32__ #ifdef __MINGW32__
......
...@@ -59,6 +59,11 @@ static CK_FUNCTION_LIST_PTR pkcs11_module = NULL; ...@@ -59,6 +59,11 @@ static CK_FUNCTION_LIST_PTR pkcs11_module = NULL;
#define PARSE_ERROR CKR_DEVICE_ERROR #define PARSE_ERROR CKR_DEVICE_ERROR
#define PREP_ERROR CKR_DEVICE_MEMORY #define PREP_ERROR CKR_DEVICE_MEMORY
typedef struct {
CK_SESSION_HANDLE id;
CK_SLOT_ID slot;
} SessionState;
typedef struct _CallState { typedef struct _CallState {
GckRpcMessage *req; GckRpcMessage *req;
GckRpcMessage *resp; GckRpcMessage *resp;
...@@ -70,6 +75,10 @@ typedef struct _CallState { ...@@ -70,6 +75,10 @@ typedef struct _CallState {
int (*write)(int, unsigned char *,size_t); int (*write)(int, unsigned char *,size_t);
struct sockaddr_storage addr; struct sockaddr_storage addr;
socklen_t addrlen; socklen_t addrlen;
/* XXX Maybe sessions should be a linked list instead, to remove the hard
* upper limit and reduce typical memory use.
*/
SessionState sessions[PKCS11PROXY_MAX_SESSION_COUNT];
} CallState; } CallState;
typedef struct _DispatchState { typedef struct _DispatchState {
...@@ -872,9 +881,7 @@ static CK_RV rpc_C_Initialize(CallState * cs) ...@@ -872,9 +881,7 @@ static CK_RV rpc_C_Initialize(CallState * cs)
static CK_RV rpc_C_Finalize(CallState * cs) static CK_RV rpc_C_Finalize(CallState * cs)
{ {
CK_SLOT_ID_PTR slots; CK_ULONG i;
CK_ULONG n_slots, i;
CK_SLOT_ID appartment;
CK_RV ret; CK_RV ret;
DispatchState *ds, *next; DispatchState *ds, *next;
...@@ -888,27 +895,17 @@ static CK_RV rpc_C_Finalize(CallState * cs) ...@@ -888,27 +895,17 @@ static CK_RV rpc_C_Finalize(CallState * cs)
* We don't actually C_Finalize lower layers, since this would finalize * We don't actually C_Finalize lower layers, since this would finalize
* for all appartments, client applications. Anyway this is done by * for all appartments, client applications. Anyway this is done by
* the code that loaded us. * the code that loaded us.
*
* But we do need to cleanup resources used by this client, so instead
* we call C_CloseAllSessions for each appartment for this client.
*/ */
ret = (pkcs11_module->C_GetSlotList) (TRUE, NULL, &n_slots); /* Close all sessions that have been opened by this thread, regardless of slot */
if (ret == CKR_OK) { for (i = 0; i < PKCS11PROXY_MAX_SESSION_COUNT; i++) {
slots = calloc(n_slots, sizeof(CK_SLOT_ID)); if (cs->sessions[i].id) {
if (slots == NULL) { gck_rpc_log("Closing session %li on position %i", cs->sessions[i].id, i);
ret = CKR_DEVICE_MEMORY;
} else { ret = (pkcs11_module->C_CloseSession) (cs->sessions[i].id);
ret = if (ret != CKR_OK)
(pkcs11_module->C_GetSlotList) (TRUE, slots, break;
&n_slots); cs->sessions[i].id = 0;
for (i = 0; ret == CKR_OK && i < n_slots; ++i) {
appartment = slots[i];
ret =
(pkcs11_module->
C_CloseAllSessions) (appartment);
}
free(slots);
} }
} }
...@@ -1067,6 +1064,21 @@ static CK_RV rpc_C_OpenSession(CallState * cs) ...@@ -1067,6 +1064,21 @@ static CK_RV rpc_C_OpenSession(CallState * cs)
IN_ULONG(slot_id); IN_ULONG(slot_id);
IN_ULONG(flags); IN_ULONG(flags);
PROCESS_CALL((slot_id, flags, NULL, NULL, &session)); PROCESS_CALL((slot_id, flags, NULL, NULL, &session));
if (_ret == CKR_OK) {
int i;
/* Remember this thread opened this session. Needed for C_CloseAllSessions. */
for (i = 0; i < PKCS11PROXY_MAX_SESSION_COUNT; i++) {
if (! cs->sessions[i].id) {
cs->sessions[i].id = session;
cs->sessions[i].slot = slot_id;
gck_rpc_log("Session %li stored in position %i", session, i);
break;
}
}
if (i == PKCS11PROXY_MAX_SESSION_COUNT) {
_ret = CKR_SESSION_COUNT; goto _cleanup;
}
}
OUT_ULONG(session); OUT_ULONG(session);
END_CALL; END_CALL;
} }
...@@ -1078,18 +1090,61 @@ static CK_RV rpc_C_CloseSession(CallState * cs) ...@@ -1078,18 +1090,61 @@ static CK_RV rpc_C_CloseSession(CallState * cs)
BEGIN_CALL(C_CloseSession); BEGIN_CALL(C_CloseSession);
IN_ULONG(session); IN_ULONG(session);
PROCESS_CALL((session)); PROCESS_CALL((session));
if (_ret == CKR_OK) {
int i;
/* Remove this session from this threads list */
for (i = 0; i < PKCS11PROXY_MAX_SESSION_COUNT; i++) {
if (cs->sessions[i].id == session) {
gck_rpc_log("Session %li removed from position %i", session, i);
cs->sessions[i].id = 0;
break;
}
}
if (i == PKCS11PROXY_MAX_SESSION_COUNT) {
/* Ignore errors, like with close() */
gck_rpc_log("C_CloseSession on unknown session");
}
}
END_CALL; END_CALL;
} }
static CK_RV rpc_C_CloseAllSessions(CallState * cs) static CK_RV rpc_C_CloseAllSessions(CallState * cs)
{ {
CK_SLOT_ID slot_id; CK_SLOT_ID slot_id;
CK_SLOT_INFO slotInfo;
int i;
/* Slot id becomes appartment so lower layers can tell clients apart. */ /* Close all sessions that have been opened by this thread. PKCS#11 (v2.2) says
* C_CloseAllSessions closes all the sessions opened by one application, leaving
* sessions opened by other applications alone even if the sessions share slot.
*
* Each application on the client side of pkcs11-proxy will mean different thread
* on the server side, so we should close all sessions for a slot opened in this
* thread.
*/
BEGIN_CALL(C_CloseAllSessions); BEGIN_CALL(C_CloseAllSessions);
IN_ULONG(slot_id); IN_ULONG(slot_id);
PROCESS_CALL((slot_id));
/* To emulate real C_CloseAllSessions (well, the SoftHSM one) we check if slot_id is valid. */
_ret = pkcs11_module->C_GetSlotInfo(slot_id, &slotInfo);
if (_ret != CKR_OK)
goto _cleanup;
for (i = 0; i < PKCS11PROXY_MAX_SESSION_COUNT; i++) {
if (cs->sessions[i].id && (cs->sessions[i].slot == slot_id)) {
gck_rpc_log("Closing session %li on position %i with slot %i", cs->sessions[i].id, i, slot_id);
_ret = (pkcs11_module->C_CloseSession) (cs->sessions[i].id);
if (_ret == CKR_OK ||
_ret == CKR_SESSION_CLOSED ||
_ret == CKR_SESSION_HANDLE_INVALID) {
cs->sessions[i].id = 0;
}
if (_ret != CKR_OK)
goto _cleanup;
}
}
END_CALL; END_CALL;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment