summaryrefslogtreecommitdiff
path: root/p11-kit/filter.c
diff options
context:
space:
mode:
Diffstat (limited to 'p11-kit/filter.c')
-rw-r--r--p11-kit/filter.c420
1 files changed, 420 insertions, 0 deletions
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);
+}