]> granicus.if.org Git - p11-kit/commitdiff
Manage C_CloseAllSessions function for multiple callers
authorStef Walter <stefw@gnome.org>
Tue, 19 Feb 2013 12:51:32 +0000 (13:51 +0100)
committerStef Walter <stefw@gnome.org>
Tue, 21 May 2013 08:47:53 +0000 (10:47 +0200)
Make C_CloseAllSessions work for different callers. Track the sessions
that each caller opens and close just those when C_CloseAllSessiosn is
called.

common/mock.c
doc/manual/p11-kit-sharing.xml
p11-kit/modules.c
p11-kit/tests/test-init.c
p11-kit/tests/test-managed.c

index 1a6657c8dcc882fd1cf00445ab221ed86214aa42..f1d1c03e3731aebe81d7bc085a7dc049cdf0ea48 100644 (file)
@@ -1048,7 +1048,7 @@ mock_C_GetSessionInfo (CK_SESSION_HANDLE session,
        return_val_if_fail (info != NULL, CKR_ARGUMENTS_BAD);
 
        sess = p11_dict_get (the_sessions, handle_to_pointer (session));
-       if (!session)
+       if (!sess)
                return CKR_SESSION_HANDLE_INVALID;
 
        if (logged_in) {
index 01b3c8b84cd327e5b7fe85bd6fd02a4e285b4331..0989923f88ba076d555cfcc732121dad1d4c1f22 100644 (file)
                        function concurrently from different threads and <literal>p11-kit</literal>
                        will guarantee that this managed in a thread-safe manner.</para>
                </listitem>
+               <listitem>
+                       <para>Call to <literal>C_CloseAllSessions</literal> only close the
+                       sessions that the caller of the managed module has opened. This allows the
+                       <literal>C_CloseAllSessions</literal> function to be used without closing
+                       sessions for other callers of the same PKCS#11 module.</para>
+               </listitem>
                </itemizedlist>
        </section>
 </chapter>
index 20475f25d2f883f3eccc45dc2af160099bb1a0f0..b124e0e59d28ff58e77c9038ec1534fe1258fafb 100644 (file)
@@ -170,6 +170,8 @@ typedef struct _Module {
 typedef struct {
        p11_virtual virt;
        Module *mod;
+       bool initialized;
+       p11_dict *sessions;
 } Managed;
 
 /*
@@ -1408,13 +1410,31 @@ static CK_RV
 managed_C_Initialize (CK_X_FUNCTION_LIST *self,
                       CK_VOID_PTR init_args)
 {
-       Module *mod = ((Managed *)self)->mod;
+       Managed *managed = ((Managed *)self);
+       p11_dict *sessions;
        CK_RV rv;
 
        p11_debug ("in");
        p11_lock ();
 
-       rv = initialize_module_inlock_reentrant (mod);
+       if (managed->initialized) {
+               rv = CKR_CRYPTOKI_ALREADY_INITIALIZED;
+
+       } else {
+               sessions = p11_dict_new (p11_dict_ulongptr_hash,
+                                        p11_dict_ulongptr_equal,
+                                        free, free);
+               if (!sessions)
+                       rv = CKR_HOST_MEMORY;
+               else
+                       rv = initialize_module_inlock_reentrant (managed->mod);
+               if (rv == CKR_OK) {
+                       managed->sessions = sessions;
+                       managed->initialized = true;
+               } else {
+                       p11_dict_free (sessions);
+               }
+       }
 
        p11_unlock ();
        p11_debug ("out: %lu", rv);
@@ -1422,17 +1442,125 @@ managed_C_Initialize (CK_X_FUNCTION_LIST *self,
        return rv;
 }
 
+static CK_RV
+managed_track_session_inlock (p11_dict *sessions,
+                              CK_SLOT_ID slot_id,
+                              CK_SESSION_HANDLE session)
+{
+       void *key;
+       void *value;
+
+       key = memdup (&session, sizeof (CK_SESSION_HANDLE));
+       return_val_if_fail (key != NULL, CKR_HOST_MEMORY);
+
+       value = memdup (&slot_id, sizeof (CK_SESSION_HANDLE));
+       return_val_if_fail (value != NULL, CKR_HOST_MEMORY);
+
+       if (!p11_dict_set (sessions, key, value))
+               return_val_if_reached (CKR_HOST_MEMORY);
+
+       return CKR_OK;
+}
+
+static void
+managed_untrack_session_inlock (p11_dict *sessions,
+                                CK_SESSION_HANDLE session)
+{
+       p11_dict_remove (sessions, &session);
+}
+
+static CK_SESSION_HANDLE *
+managed_steal_sessions_inlock (p11_dict *sessions,
+                        bool matching_slot_id,
+                        CK_SLOT_ID slot_id,
+                        int *count)
+{
+       CK_SESSION_HANDLE *stolen;
+       CK_SESSION_HANDLE *key;
+       CK_SLOT_ID *value;
+       p11_dictiter iter;
+       int at, i;
+
+       assert (sessions != NULL);
+       assert (count != NULL);
+
+       stolen = calloc (p11_dict_size (sessions), sizeof (CK_SESSION_HANDLE));
+       return_val_if_fail (stolen != NULL, NULL);
+
+       at = 0;
+       p11_dict_iterate (sessions, &iter);
+       while (p11_dict_next (&iter, (void **)&key, (void **)&value)) {
+               if (!matching_slot_id || slot_id == *value)
+                       stolen[at++] = *key;
+       }
+
+       /* Removed them all, clear the whole array */
+       if (at == p11_dict_size (sessions)) {
+               p11_dict_clear (sessions);
+
+       /* Only removed some, go through and remove those */
+       } else {
+               for (i = 0; i < at; i++) {
+                       if (!p11_dict_remove (sessions, stolen + at))
+                               assert_not_reached ();
+               }
+       }
+
+       *count = at;
+       return stolen;
+}
+
+static void
+managed_close_sessions (CK_X_FUNCTION_LIST *funcs,
+                        CK_SESSION_HANDLE *stolen,
+                        int count)
+{
+       CK_RV rv;
+       int i;
+
+       for (i = 0; i < count; i++) {
+               rv = funcs->C_CloseSession (funcs, stolen[i]);
+               if (rv != CKR_OK)
+                       p11_message ("couldn't close session: %s", p11_kit_strerror (rv));
+       }
+}
+
 static CK_RV
 managed_C_Finalize (CK_X_FUNCTION_LIST *self,
                     CK_VOID_PTR reserved)
 {
-       Module *mod = ((Managed *)self)->mod;
+       Managed *managed = ((Managed *)self);
+       CK_SESSION_HANDLE *sessions;
+       int count;
        CK_RV rv;
 
        p11_debug ("in");
        p11_lock ();
 
-       rv = finalize_module_inlock_reentrant (mod);
+       if (!managed->initialized) {
+               rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       } else {
+               sessions = managed_steal_sessions_inlock (managed->sessions, false, 0, &count);
+
+               if (sessions && count) {
+                       /* WARNING: reentrancy can occur here */
+                       p11_unlock ();
+                       managed_close_sessions (&managed->mod->virt.funcs, sessions, count);
+                       p11_lock ();
+               }
+
+               free (sessions);
+
+               /* WARNING: reentrancy can occur here */
+               rv = finalize_module_inlock_reentrant (managed->mod);
+
+               if (rv == CKR_OK) {
+                       managed->initialized = false;
+                       p11_dict_free (managed->sessions);
+                       managed->sessions = NULL;
+               }
+       }
 
        p11_unlock ();
        p11_debug ("out: %lu", rv);
@@ -1440,6 +1568,69 @@ managed_C_Finalize (CK_X_FUNCTION_LIST *self,
        return rv;
 }
 
+static CK_RV
+managed_C_OpenSession (CK_X_FUNCTION_LIST *self,
+                       CK_SLOT_ID slot_id,
+                       CK_FLAGS flags,
+                       CK_VOID_PTR application,
+                       CK_NOTIFY notify,
+                       CK_SESSION_HANDLE_PTR session)
+{
+       Managed *managed = ((Managed *)self);
+       CK_RV rv;
+
+       return_val_if_fail (session != NULL, CKR_ARGUMENTS_BAD);
+
+       self = &managed->mod->virt.funcs;
+       rv = self->C_OpenSession (self, slot_id, flags, application, notify, session);
+
+       if (rv == CKR_OK) {
+               p11_lock ();
+               rv = managed_track_session_inlock (managed->sessions, slot_id, *session);
+               p11_unlock ();
+       }
+
+       return rv;
+}
+
+static CK_RV
+managed_C_CloseSession (CK_X_FUNCTION_LIST *self,
+                        CK_SESSION_HANDLE session)
+{
+       Managed *managed = ((Managed *)self);
+       CK_RV rv;
+
+       self = &managed->mod->virt.funcs;
+       rv = self->C_CloseSession (self, session);
+
+       if (rv == CKR_OK) {
+               p11_lock ();
+               managed_untrack_session_inlock (managed->sessions, session);
+               p11_unlock ();
+       }
+
+       return rv;
+}
+
+static CK_RV
+managed_C_CloseAllSessions (CK_X_FUNCTION_LIST *self,
+                            CK_SLOT_ID slot_id)
+{
+       Managed *managed = ((Managed *)self);
+       CK_SESSION_HANDLE *stolen;
+       int count;
+
+       p11_lock ();
+       stolen = managed_steal_sessions_inlock (managed->sessions, true, slot_id, &count);
+       p11_unlock ();
+
+       self = &managed->mod->virt.funcs;
+       managed_close_sessions (self, stolen, count);
+       free (stolen);
+
+       return stolen ? CKR_OK : CKR_GENERAL_ERROR;
+}
+
 static void
 managed_free_inlock (void *data)
 {
@@ -1460,6 +1651,9 @@ managed_create_inlock (Module *mod)
                          &mod->virt, NULL);
        managed->virt.funcs.C_Initialize = managed_C_Initialize;
        managed->virt.funcs.C_Finalize = managed_C_Finalize;
+       managed->virt.funcs.C_CloseAllSessions = managed_C_CloseAllSessions;
+       managed->virt.funcs.C_CloseSession = managed_C_CloseSession;
+       managed->virt.funcs.C_OpenSession = managed_C_OpenSession;
        managed->mod = mod;
        mod->ref_count++;
 
index f2347c8a04f657c9d03b000540578bb092509532..dbeab468b1bfeacb9089c82da8e4624238458434 100644 (file)
@@ -152,7 +152,14 @@ test_recursive_initialization (CuTest *tc)
        p11_unlock ();
 
        rv = p11_kit_module_initialize (recursive_managed);
-       CuAssertTrue (tc, rv == CKR_FUNCTION_FAILED);
+       CuAssertIntEquals (tc, CKR_FUNCTION_FAILED, rv);
+
+       p11_lock ();
+
+       rv = p11_module_release_inlock_reentrant (recursive_managed);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       p11_unlock ();
 
        p11_kit_be_loud ();
 }
index 8a6a1e858c1320e16c5d33262d72ecbaf026ce3d..6184c44c0ff499f171057c0ad2b2a678db248266 100644 (file)
@@ -105,15 +105,33 @@ test_initialize_finalize (CuTest *tc)
        CK_FUNCTION_LIST_PTR module;
        CK_RV rv;
 
-       module = setup_mock_module (tc, NULL);
+       p11_lock ();
+
+       rv = p11_module_load_inlock_reentrant (&mock_module, 0, &module);
+       CuAssertTrue (tc, rv == CKR_OK);
+       CuAssertPtrNotNull (tc, module);
+       CuAssertTrue (tc, p11_virtual_is_wrapper (module));
+
+       p11_unlock ();
 
        rv = module->C_Initialize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 
+       rv = module->C_Initialize (NULL);
+       CuAssertTrue (tc, rv == CKR_CRYPTOKI_ALREADY_INITIALIZED);
+
        rv = module->C_Finalize (NULL);
        CuAssertTrue (tc, rv == CKR_OK);
 
-       teardown_mock_module (tc, module);
+       rv = module->C_Finalize (NULL);
+       CuAssertTrue (tc, rv == CKR_CRYPTOKI_NOT_INITIALIZED);
+
+       p11_lock ();
+
+       rv = p11_module_release_inlock_reentrant (module);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       p11_unlock ();
 }
 
 static void
@@ -137,6 +155,47 @@ test_initialize_fail (CuTest *tc)
        CuAssertTrue (tc, rv == CKR_FUNCTION_FAILED);
 }
 
+static void
+test_separate_close_all_sessions (CuTest *tc)
+{
+       CK_FUNCTION_LIST *first;
+       CK_FUNCTION_LIST *second;
+       CK_SESSION_HANDLE s1;
+       CK_SESSION_HANDLE s2;
+       CK_SESSION_INFO info;
+       CK_RV rv;
+
+       first = setup_mock_module (tc, &s1);
+       second = setup_mock_module (tc, &s2);
+
+       rv = first->C_GetSessionInfo (s1, &info);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = second->C_GetSessionInfo (s2, &info);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       first->C_CloseAllSessions (MOCK_SLOT_ONE_ID);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = first->C_GetSessionInfo (s1, &info);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = second->C_GetSessionInfo (s2, &info);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       second->C_CloseAllSessions (MOCK_SLOT_ONE_ID);
+       CuAssertTrue (tc, rv == CKR_OK);
+
+       rv = first->C_GetSessionInfo (s1, &info);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       rv = second->C_GetSessionInfo (s2, &info);
+       CuAssertTrue (tc, rv == CKR_SESSION_HANDLE_INVALID);
+
+       teardown_mock_module (tc, first);
+       teardown_mock_module (tc, second);
+}
+
 /* Bring in all the mock module tests */
 #include "test-mock.c"
 
@@ -153,6 +212,7 @@ main (void)
 
        SUITE_ADD_TEST (suite, test_initialize_finalize);
        SUITE_ADD_TEST (suite, test_initialize_fail);
+       SUITE_ADD_TEST (suite, test_separate_close_all_sessions);
        test_mock_add_tests (suite);
 
        p11_kit_be_quiet ();