summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaiki Ueno <dueno@redhat.com>2016-12-13 18:24:16 +0100
committerDaiki Ueno <ueno@gnu.org>2017-02-08 16:34:28 +0100
commitfd9b5c19485e2b88150696b523d889df2ed41cba (patch)
treea1112f7ad04a5db8e73d37a9693581530c3af654
parent3d54011b0d0bf1b31fbab8d7025b7201722d61c3 (diff)
filter: New virtual wrapper for access control
-rw-r--r--doc/manual/Makefile.am1
-rw-r--r--p11-kit/Makefile.am5
-rw-r--r--p11-kit/filter.c420
-rw-r--r--p11-kit/filter.h55
-rw-r--r--p11-kit/test-filter.c143
5 files changed, 624 insertions, 0 deletions
diff --git a/doc/manual/Makefile.am b/doc/manual/Makefile.am
index ae59530..7108977 100644
--- a/doc/manual/Makefile.am
+++ b/doc/manual/Makefile.am
@@ -52,6 +52,7 @@ IGNORE_HFILES= \
conf.h \
debug.h \
dict.h \
+ filter.h \
log.h \
mock.h \
modules.h \
diff --git a/p11-kit/Makefile.am b/p11-kit/Makefile.am
index c55746a..d51c052 100644
--- a/p11-kit/Makefile.am
+++ b/p11-kit/Makefile.am
@@ -13,6 +13,7 @@ MODULE_SRCS = \
p11-kit/conf.c p11-kit/conf.h \
p11-kit/iter.c \
p11-kit/log.c p11-kit/log.h \
+ p11-kit/filter.c p11-kit/filter.h \
p11-kit/modules.c p11-kit/modules.h \
p11-kit/pkcs11.h \
p11-kit/pin.c \
@@ -217,12 +218,16 @@ CHECK_PROGS += \
test-virtual \
test-managed \
test-log \
+ test-filter \
test-transport \
$(NULL)
test_log_SOURCES = p11-kit/test-log.c
test_log_LDADD = $(p11_kit_LIBS)
+test_filter_SOURCES = p11-kit/test-filter.c
+test_filter_LDADD = $(p11_kit_LIBS)
+
test_managed_SOURCES = p11-kit/test-managed.c
test_managed_LDADD = $(p11_kit_LIBS)
diff --git a/p11-kit/filter.c b/p11-kit/filter.c
new file mode 100644
index 0000000..09e1a45
--- /dev/null
+++ b/p11-kit/filter.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2016, Red Hat Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ *
+ * CONTRIBUTORS
+ * Daiki Ueno
+ */
+
+#include "config.h"
+
+#include "attrs.h"
+#include "buffer.h"
+#include "constants.h"
+#include "debug.h"
+#include "filter.h"
+#include "iter.h"
+#include "message.h"
+#include "p11-kit.h"
+#include "virtual.h"
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+
+typedef struct {
+ p11_virtual virt;
+ CK_X_FUNCTION_LIST *lower;
+ p11_destroyer destroyer;
+ p11_array *entries;
+ bool allowed;
+ bool initialized;
+ CK_SLOT_ID *slots;
+ CK_ULONG n_slots;
+ CK_ULONG max_slots;
+} FilterData;
+
+extern int p11_match_uri_token_info (CK_TOKEN_INFO_PTR one,
+ CK_TOKEN_INFO_PTR two);
+
+static bool
+filter_match_token (FilterData *filter, CK_TOKEN_INFO *token)
+{
+ unsigned int i;
+
+ for (i = 0; i < filter->entries->num; i++) {
+ CK_TOKEN_INFO *entry = filter->entries->elem[i];
+ bool matched = p11_match_uri_token_info (entry, token);
+
+ if ((filter->allowed && matched) ||
+ (!filter->allowed && !matched))
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+filter_add_slot (FilterData *filter, CK_SLOT_ID slot)
+{
+ if (filter->n_slots >= filter->max_slots) {
+ filter->max_slots = filter->max_slots * 2 + 1;
+ filter->slots = realloc (filter->slots,
+ filter->max_slots * sizeof (CK_SLOT_ID));
+ if (filter->slots == NULL)
+ return false;
+ }
+ filter->slots[filter->n_slots++] = slot;
+ return true;
+}
+
+static CK_RV
+filter_ensure (FilterData *filter)
+{
+ CK_FUNCTION_LIST *lower = NULL;
+ P11KitIter *iter = NULL;
+ CK_RV rv = CKR_OK;
+
+ if (filter->slots != NULL) {
+ free (filter->slots);
+ filter->slots = NULL;
+ }
+ filter->n_slots = 0;
+ filter->max_slots = 0;
+
+ iter = p11_kit_iter_new (NULL,
+ P11_KIT_ITER_WITH_TOKENS |
+ P11_KIT_ITER_WITHOUT_OBJECTS);
+ if (iter == NULL) {
+ rv = CKR_HOST_MEMORY;
+ goto out;
+ }
+
+ lower = p11_virtual_wrap (filter->virt.lower_module, NULL);
+ if (lower == NULL) {
+ rv = CKR_HOST_MEMORY;
+ goto out;
+ }
+
+ p11_kit_iter_begin_with (iter, lower, 0, CK_INVALID_HANDLE);
+ while (p11_kit_iter_next (iter) == CKR_OK) {
+ CK_TOKEN_INFO *token;
+
+ token = p11_kit_iter_get_token (iter);
+ if (filter_match_token (filter, token)) {
+ CK_SLOT_ID slot;
+
+ slot = p11_kit_iter_get_slot (iter);
+ if (!filter_add_slot (filter, slot)) {
+ rv = CKR_HOST_MEMORY;
+ goto out;
+ }
+ }
+ }
+
+ rv = CKR_OK;
+ out:
+ p11_kit_iter_free (iter);
+ if (lower)
+ p11_virtual_unwrap (lower);
+ return rv;
+}
+
+static void
+filter_reinit (FilterData *filter)
+{
+ CK_RV rv;
+
+ rv = filter_ensure (filter);
+ if (rv == CKR_OK)
+ filter->initialized = true;
+ else {
+ filter->initialized = false;
+ p11_message ("filter cannot be initialized");
+ }
+}
+
+static CK_RV
+filter_C_Initialize (CK_X_FUNCTION_LIST *self,
+ CK_VOID_PTR pInitArgs)
+{
+ FilterData *filter = (FilterData *)self;
+ CK_RV rv;
+
+ rv = filter->lower->C_Initialize (filter->lower, pInitArgs);
+ if (rv == CKR_OK)
+ filter_reinit (filter);
+ return rv;
+}
+
+static CK_RV
+filter_C_Finalize (CK_X_FUNCTION_LIST *self,
+ CK_VOID_PTR pReserved)
+{
+ FilterData *filter = (FilterData *)self;
+
+ free (filter->slots);
+ filter->n_slots = 0;
+ p11_array_clear (filter->entries);
+ filter->initialized = false;
+ filter->allowed = false;
+
+ return filter->lower->C_Finalize (filter->lower, pReserved);
+}
+
+static CK_RV
+filter_C_GetSlotList (CK_X_FUNCTION_LIST *self,
+ CK_BBOOL tokenPresent,
+ CK_SLOT_ID_PTR pSlotList,
+ CK_ULONG_PTR pulCount)
+{
+ FilterData *filter = (FilterData *)self;
+ CK_ULONG count;
+
+ if (pulCount == NULL)
+ return CKR_ARGUMENTS_BAD;
+
+ count = *pulCount;
+ *pulCount = filter->n_slots;
+
+ if (pSlotList == NULL)
+ return CKR_OK;
+
+ if (filter->n_slots > count)
+ return CKR_BUFFER_TOO_SMALL;
+
+ for (count = 0; count < filter->n_slots; count++)
+ pSlotList[count] = count;
+ *pulCount = filter->n_slots;
+ return CKR_OK;
+}
+
+static CK_RV
+filter_C_GetSlotInfo (CK_X_FUNCTION_LIST *self,
+ CK_SLOT_ID slotID,
+ CK_SLOT_INFO_PTR pInfo)
+{
+ FilterData *filter = (FilterData *)self;
+
+ if (slotID >= filter->n_slots)
+ return CKR_SLOT_ID_INVALID;
+
+ return filter->lower->C_GetSlotInfo (filter->lower, filter->slots[slotID], pInfo);
+}
+
+static CK_RV
+filter_C_GetTokenInfo (CK_X_FUNCTION_LIST *self,
+ CK_SLOT_ID slotID,
+ CK_TOKEN_INFO_PTR pInfo)
+{
+ FilterData *filter = (FilterData *)self;
+
+ if (slotID >= filter->n_slots)
+ return CKR_SLOT_ID_INVALID;
+
+ return filter->lower->C_GetTokenInfo (filter->lower, filter->slots[slotID], pInfo);
+}
+
+static CK_RV
+filter_C_GetMechanismList (CK_X_FUNCTION_LIST *self,
+ CK_SLOT_ID slotID,
+ CK_MECHANISM_TYPE_PTR pMechanismList,
+ CK_ULONG_PTR pulCount)
+{
+ FilterData *filter = (FilterData *)self;
+
+ if (slotID >= filter->n_slots)
+ return CKR_SLOT_ID_INVALID;
+
+ return filter->lower->C_GetMechanismList (filter->lower,
+ filter->slots[slotID],
+ pMechanismList,
+ pulCount);
+}
+
+static CK_RV
+filter_C_GetMechanismInfo (CK_X_FUNCTION_LIST *self,
+ CK_SLOT_ID slotID,
+ CK_MECHANISM_TYPE type,
+ CK_MECHANISM_INFO_PTR pInfo)
+{
+ FilterData *filter = (FilterData *)self;
+
+ if (slotID >= filter->n_slots)
+ return CKR_SLOT_ID_INVALID;
+
+ return filter->lower->C_GetMechanismInfo (filter->lower,
+ filter->slots[slotID],
+ type,
+ pInfo);
+}
+
+static CK_RV
+filter_C_InitToken (CK_X_FUNCTION_LIST *self,
+ CK_SLOT_ID slotID,
+ CK_UTF8CHAR_PTR pPin,
+ CK_ULONG ulPinLen,
+ CK_UTF8CHAR_PTR pLabel)
+{
+ FilterData *filter = (FilterData *)self;
+
+ if (slotID >= filter->n_slots)
+ return CKR_SLOT_ID_INVALID;
+
+ return filter->lower->C_InitToken (filter->lower, filter->slots[slotID],
+ pPin, ulPinLen, pLabel);
+}
+
+static CK_RV
+filter_C_WaitForSlotEvent (CK_X_FUNCTION_LIST *self,
+ CK_FLAGS flags,
+ CK_SLOT_ID_PTR pSlot,
+ CK_VOID_PTR pReserved)
+{
+ return CKR_FUNCTION_NOT_SUPPORTED;
+}
+
+static CK_RV
+filter_C_OpenSession (CK_X_FUNCTION_LIST *self,
+ CK_SLOT_ID slotID,
+ CK_FLAGS flags,
+ CK_VOID_PTR pApplication,
+ CK_NOTIFY Notify,
+ CK_SESSION_HANDLE_PTR phSession)
+{
+ FilterData *filter = (FilterData *)self;
+
+ if (slotID >= filter->n_slots)
+ return CKR_SLOT_ID_INVALID;
+
+ return filter->lower->C_OpenSession (filter->lower,
+ filter->slots[slotID], flags,
+ pApplication, Notify,
+ phSession);
+}
+
+static CK_RV
+filter_C_CloseAllSessions (CK_X_FUNCTION_LIST *self,
+ CK_SLOT_ID slotID)
+{
+ FilterData *filter = (FilterData *)self;
+
+ if (slotID >= filter->n_slots)
+ return CKR_SLOT_ID_INVALID;
+
+ return filter->lower->C_CloseAllSessions (filter->lower,
+ filter->slots[slotID]);
+}
+
+void
+p11_filter_release (void *data)
+{
+ FilterData *filter = (FilterData *)data;
+
+ return_if_fail (data != NULL);
+ p11_virtual_uninit (&filter->virt);
+ p11_array_free (filter->entries);
+ free (filter);
+}
+
+p11_virtual *
+p11_filter_subclass (p11_virtual *lower,
+ p11_destroyer destroyer)
+{
+ FilterData *filter;
+ CK_X_FUNCTION_LIST functions;
+
+ filter = calloc (1, sizeof (FilterData));
+ return_val_if_fail (filter != NULL, NULL);
+
+ memcpy (&functions, &p11_virtual_stack, sizeof (CK_X_FUNCTION_LIST));
+ functions.C_Initialize = filter_C_Initialize;
+ functions.C_Finalize = filter_C_Finalize;
+ functions.C_GetSlotList = filter_C_GetSlotList;
+ functions.C_GetSlotInfo = filter_C_GetSlotInfo;
+ functions.C_GetTokenInfo = filter_C_GetTokenInfo;
+ functions.C_GetMechanismList = filter_C_GetMechanismList;
+ functions.C_GetMechanismInfo = filter_C_GetMechanismInfo;
+ functions.C_InitToken = filter_C_InitToken;
+ functions.C_WaitForSlotEvent = filter_C_WaitForSlotEvent;
+ functions.C_OpenSession = filter_C_OpenSession;
+ functions.C_CloseAllSessions = filter_C_CloseAllSessions;
+
+ p11_virtual_init (&filter->virt, &functions, lower, destroyer);
+ filter->lower = &lower->funcs;
+ filter->entries = p11_array_new ((p11_destroyer)free);
+ return &filter->virt;
+}
+
+void
+p11_filter_allow_token (p11_virtual *virt,
+ CK_TOKEN_INFO *token)
+{
+ FilterData *filter = (FilterData *)virt;
+ CK_TOKEN_INFO *token_copy;
+
+ return_if_fail (filter->allowed || filter->entries->num == 0);
+ filter->allowed = true;
+
+ token_copy = memdup (token, sizeof (CK_TOKEN_INFO));
+ return_if_fail (token_copy != NULL);
+
+ if (!p11_array_push (filter->entries, token_copy))
+ return_if_reached ();
+
+ if (filter->initialized)
+ filter_reinit (filter);
+}
+
+void
+p11_filter_deny_token (p11_virtual *virt,
+ CK_TOKEN_INFO *token)
+{
+ FilterData *filter = (FilterData *)virt;
+ CK_TOKEN_INFO *token_copy;
+
+ return_if_fail (!filter->allowed || filter->entries->num == 0);
+ filter->allowed = false;
+
+ token_copy = memdup (token, sizeof (CK_TOKEN_INFO));
+ return_if_fail (token_copy != NULL);
+
+ if (!p11_array_push (filter->entries, token_copy))
+ return_if_reached ();
+
+ if (filter->initialized)
+ filter_reinit (filter);
+}
diff --git a/p11-kit/filter.h b/p11-kit/filter.h
new file mode 100644
index 0000000..90cdb12
--- /dev/null
+++ b/p11-kit/filter.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016, Red Hat Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ *
+ * CONTRIBUTORS
+ * Daiki Ueno
+ */
+
+#ifndef P11_FILTER_H_
+#define P11_FILTER_H_
+
+#include "virtual.h"
+
+p11_virtual *p11_filter_subclass (p11_virtual *lower,
+ p11_destroyer destroyer);
+
+void p11_filter_release (void *filterger);
+
+void p11_filter_allow_token (p11_virtual *virt,
+ CK_TOKEN_INFO *token);
+
+void p11_filter_deny_token (p11_virtual *virt,
+ CK_TOKEN_INFO *token);
+
+#endif /* P11_FILTER_H_ */
diff --git a/p11-kit/test-filter.c b/p11-kit/test-filter.c
new file mode 100644
index 0000000..72272db
--- /dev/null
+++ b/p11-kit/test-filter.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2016 Red Hat Inc
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Daiki Ueno
+ */
+
+#include "config.h"
+#include "test.h"
+
+#include "dict.h"
+#include "library.h"
+#include "filter.h"
+#include "mock.h"
+#include "modules.h"
+#include "p11-kit.h"
+#include "virtual.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+static CK_TOKEN_INFO TOKEN_ONE = {
+ "TEST LABEL ",
+ "TEST MANUFACTURER ",
+ "TEST MODEL ",
+ "TEST SERIAL ",
+ CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED | CKF_CLOCK_ON_TOKEN | CKF_TOKEN_INITIALIZED,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ { 75, 175 },
+ { 85, 185 },
+ { '1', '9', '9', '9', '0', '5', '2', '5', '0', '9', '1', '9', '5', '9', '0', '0' }
+};
+
+static void
+test_allowed (void)
+{
+ CK_FUNCTION_LIST_PTR module;
+ p11_virtual virt;
+ p11_virtual *filter;
+ CK_ULONG count;
+ CK_RV rv;
+
+ p11_virtual_init (&virt, &p11_virtual_base, &mock_module, NULL);
+ filter = p11_filter_subclass (&virt, NULL);
+ module = p11_virtual_wrap (filter, (p11_destroyer)p11_virtual_uninit);
+ assert_ptr_not_null (module);
+
+ p11_filter_allow_token (filter, &TOKEN_ONE);
+
+ rv = (module->C_Initialize) (NULL);
+ assert_num_eq (CKR_OK, rv);
+
+ rv = (module->C_GetSlotList) (CK_TRUE, NULL, &count);
+ assert_num_eq (CKR_OK, rv);
+ assert_num_eq (count, 1);
+
+ rv = (module->C_Finalize) (NULL);
+ assert_num_eq (CKR_OK, rv);
+
+ p11_virtual_unwrap (module);
+ p11_filter_release (filter);
+}
+
+static void
+test_denied (void)
+{
+ CK_FUNCTION_LIST_PTR module;
+ p11_virtual virt;
+ p11_virtual *filter;
+ CK_ULONG count;
+ CK_RV rv;
+
+ p11_virtual_init (&virt, &p11_virtual_base, &mock_module, NULL);
+ filter = p11_filter_subclass (&virt, NULL);
+ module = p11_virtual_wrap (filter, (p11_destroyer)p11_virtual_uninit);
+ assert_ptr_not_null (module);
+
+ p11_filter_deny_token (filter, &TOKEN_ONE);
+
+ rv = (module->C_Initialize) (NULL);
+ assert_num_eq (CKR_OK, rv);
+
+ rv = (module->C_GetSlotList) (CK_TRUE, NULL, &count);
+ assert_num_eq (CKR_OK, rv);
+ assert_num_eq (count, 0);
+
+ rv = (module->C_Finalize) (NULL);
+ assert_num_eq (CKR_OK, rv);
+
+ p11_virtual_unwrap (module);
+ p11_filter_release (filter);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ p11_library_init ();
+ mock_module_init ();
+
+ p11_test (test_allowed, "/filter/test_allowed");
+ p11_test (test_denied, "/filter/test_denied");
+
+ return p11_test_run (argc, argv);
+}