summaryrefslogtreecommitdiff
path: root/trust/index.c
diff options
context:
space:
mode:
authorStef Walter <stefw@gnome.org>2013-03-12 18:03:25 +0100
committerStef Walter <stefw@gnome.org>2013-03-15 17:54:55 +0100
commitff009f8a671e6ddd02a684bb1707a2a797fe4600 (patch)
tree3f3d5162a64f0addb0ad2d1acba91eae46f8ef1e /trust/index.c
parent3fc6365093ad07b2eb5ef859093c5c5eb56ee700 (diff)
downloadp11-kit-ff009f8a671e6ddd02a684bb1707a2a797fe4600.tar.gz
trust: Refactor to include concept of the index
* The index holds PKCS#11 objects whether for the token or for the session. * The index provides hook for a builder to expand or validate objects being added to the index. * In addition theres a change hook so that a builder can maintain state between objects, such as the compat NSS trust objects. https://bugs.freedesktop.org/show_bug.cgi?id=62329
Diffstat (limited to 'trust/index.c')
-rw-r--r--trust/index.c566
1 files changed, 566 insertions, 0 deletions
diff --git a/trust/index.c b/trust/index.c
new file mode 100644
index 0000000..eb6ca7f
--- /dev/null
+++ b/trust/index.c
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2013 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: Stef Walter <stefw@redhat.com>
+ */
+
+#include "compat.h"
+
+#define P11_DEBUG_FLAG P11_DEBUG_TRUST
+
+#include "attrs.h"
+#include "debug.h"
+#include "dict.h"
+#include "index.h"
+#include "module.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+/*
+ * TODO: Eventually we want to be using a bloom filter to optimize and
+ * actually implement the index.
+ */
+
+struct _p11_index {
+ /* The list of objects */
+ p11_dict *objects;
+
+ /* Data passed to callbacks */
+ void *data;
+
+ /* Called to build an new/modified object */
+ p11_index_build_cb build;
+
+ /* Called after objects change */
+ p11_index_changed_cb changed;
+
+ /* Used for queueing changes, when in a batch */
+ p11_dict *changes;
+ bool changing;
+};
+
+struct object {
+ CK_OBJECT_HANDLE handle;
+ CK_ATTRIBUTE *attrs;
+};
+
+static void
+free_object (void *data)
+{
+ struct object *obj = data;
+ p11_attrs_free (obj->attrs);
+ free (obj);
+}
+
+p11_index *
+p11_index_new (p11_index_build_cb build,
+ p11_index_changed_cb changed,
+ void *data)
+{
+ p11_index *index;
+
+ index = calloc (1, sizeof (p11_index));
+ return_val_if_fail (index != NULL, NULL);
+
+ index->build = build;
+ index->changed = changed;
+ index->data = data;
+
+ index->objects = p11_dict_new (p11_dict_ulongptr_hash,
+ p11_dict_ulongptr_equal,
+ NULL, free_object);
+ return_val_if_fail (index->objects != NULL, NULL);
+
+ return index;
+}
+
+void
+p11_index_free (p11_index *index)
+{
+ return_if_fail (index != NULL);
+
+ p11_dict_free (index->objects);
+ p11_dict_free (index->changes);
+ free (index);
+}
+
+int
+p11_index_size (p11_index *index)
+{
+ return_val_if_fail (index != NULL, -1);
+ return p11_dict_size (index->objects);
+}
+
+static CK_RV
+index_build (p11_index *index,
+ CK_ATTRIBUTE **attrs,
+ CK_ATTRIBUTE *merge)
+{
+ if (index->build) {
+ return index->build (index->data, index, attrs, merge);
+ } else {
+ *attrs = p11_attrs_merge (*attrs, merge, true);
+ return CKR_OK;
+ }
+}
+
+static void
+call_change (p11_index *index,
+ CK_OBJECT_HANDLE handle,
+ CK_ATTRIBUTE *attrs)
+{
+ assert (index->changed);
+
+ /* When attrs is NULL, means this is a modify */
+ if (attrs == NULL) {
+ attrs = p11_index_lookup (index, handle);
+ if (attrs == NULL)
+ return;
+
+ /* Otherwise a remove operation, handle not valid anymore */
+ } else {
+ handle = 0;
+ }
+
+ index->changing = true;
+ index->changed (index->data, index, handle, attrs);
+ index->changing = false;
+}
+
+static void
+index_change (p11_index *index,
+ CK_OBJECT_HANDLE handle,
+ CK_ATTRIBUTE *removed)
+{
+ struct object *obj;
+
+ if (!index->changed || index->changing)
+ return;
+
+ if (!index->changes) {
+ call_change (index, handle, removed);
+ p11_attrs_free (removed);
+
+ } else {
+ obj = calloc (1, sizeof (struct object));
+ return_if_fail (obj != NULL);
+
+ obj->handle = handle;
+ obj->attrs = removed;
+ if (!p11_dict_set (index->changes, &obj->handle, obj))
+ return_if_reached ();
+ }
+}
+
+void
+p11_index_batch (p11_index *index)
+{
+ return_if_fail (index != NULL);
+
+ if (index->changes)
+ return;
+
+ index->changes = p11_dict_new (p11_dict_ulongptr_hash,
+ p11_dict_ulongptr_equal,
+ NULL, free_object);
+ return_if_fail (index->changes != NULL);
+}
+
+void
+p11_index_finish (p11_index *index)
+{
+ p11_dict *changes;
+ struct object *obj;
+ p11_dictiter iter;
+
+ return_if_fail (index != NULL);
+
+ if (!index->changes)
+ return;
+
+ changes = index->changes;
+ index->changes = NULL;
+
+ p11_dict_iterate (changes, &iter);
+ while (p11_dict_next (&iter, NULL, (void **)&obj))
+ call_change (index, obj->handle, obj->attrs);
+
+ p11_dict_free (changes);
+}
+
+bool
+p11_index_in_batch (p11_index *index)
+{
+ return_val_if_fail (index != NULL, false);
+ return index->changes ? true : false;
+}
+
+CK_RV
+p11_index_take (p11_index *index,
+ CK_ATTRIBUTE *attrs,
+ CK_OBJECT_HANDLE *handle)
+{
+ struct object *obj;
+ CK_RV rv;
+
+ return_val_if_fail (index != NULL, CKR_GENERAL_ERROR);
+ return_val_if_fail (attrs != NULL, CKR_GENERAL_ERROR);
+
+ obj = calloc (1, sizeof (struct object));
+ return_val_if_fail (obj != NULL, CKR_HOST_MEMORY);
+
+ rv = index_build (index, &obj->attrs, attrs);
+ if (rv != CKR_OK) {
+ p11_attrs_free (attrs);
+ return rv;
+ }
+
+ return_val_if_fail (obj->attrs != NULL, CKR_GENERAL_ERROR);
+ obj->handle = p11_module_next_id ();
+
+ if (!p11_dict_set (index->objects, &obj->handle, obj))
+ return_val_if_reached (CKR_HOST_MEMORY);
+
+ if (handle)
+ *handle = obj->handle;
+
+ index_change (index, obj->handle, NULL);
+ return CKR_OK;
+}
+
+CK_RV
+p11_index_add (p11_index *index,
+ CK_ATTRIBUTE *attrs,
+ CK_ULONG count,
+ CK_OBJECT_HANDLE *handle)
+{
+ CK_ATTRIBUTE *copy;
+
+ return_val_if_fail (index != NULL, CKR_GENERAL_ERROR);
+ return_val_if_fail (attrs == NULL || count > 0, CKR_ARGUMENTS_BAD);
+
+ copy = p11_attrs_buildn (NULL, attrs, count);
+ return_val_if_fail (copy != NULL, CKR_HOST_MEMORY);
+
+ return p11_index_take (index, copy, handle);
+}
+
+CK_RV
+p11_index_update (p11_index *index,
+ CK_OBJECT_HANDLE handle,
+ CK_ATTRIBUTE *update)
+{
+ struct object *obj;
+ CK_RV rv;
+
+ return_val_if_fail (index != NULL, CKR_GENERAL_ERROR);
+ return_val_if_fail (update != NULL, CKR_GENERAL_ERROR);
+
+ obj = p11_dict_get (index->objects, &handle);
+ if (obj == NULL) {
+ p11_attrs_free (update);
+ return CKR_OBJECT_HANDLE_INVALID;
+ }
+
+ rv = index_build (index, &obj->attrs, update);
+ if (rv != CKR_OK) {
+ p11_attrs_free (update);
+ return rv;
+ }
+
+ index_change (index, obj->handle, NULL);
+ return CKR_OK;
+}
+
+CK_RV
+p11_index_set (p11_index *index,
+ CK_OBJECT_HANDLE handle,
+ CK_ATTRIBUTE *attrs,
+ CK_ULONG count)
+{
+ CK_ATTRIBUTE *update;
+ struct object *obj;
+
+ return_val_if_fail (index != NULL, CKR_GENERAL_ERROR);
+
+ obj = p11_dict_get (index->objects, &handle);
+ if (obj == NULL)
+ return CKR_OBJECT_HANDLE_INVALID;
+
+ update = p11_attrs_buildn (NULL, attrs, count);
+ return_val_if_fail (update != NULL, CKR_HOST_MEMORY);
+
+ return p11_index_update (index, handle, update);
+}
+
+CK_RV
+p11_index_remove (p11_index *index,
+ CK_OBJECT_HANDLE handle)
+{
+ struct object *obj;
+
+ return_val_if_fail (index != NULL, CKR_GENERAL_ERROR);
+
+ if (!p11_dict_steal (index->objects, &handle, NULL, (void **)&obj))
+ return CKR_OBJECT_HANDLE_INVALID;
+
+ /* This takes ownership of the attributes */
+ index_change (index, handle, obj->attrs);
+ obj->attrs = NULL;
+ free_object (obj);
+
+ return CKR_OK;
+}
+
+static CK_RV
+index_replacev (p11_index *index,
+ CK_ATTRIBUTE *match,
+ CK_ATTRIBUTE_TYPE key,
+ CK_ATTRIBUTE **replace,
+ CK_ULONG replacen)
+{
+ CK_OBJECT_HANDLE *handles;
+ struct object *obj;
+ CK_ATTRIBUTE *attrs;
+ CK_ATTRIBUTE *attr;
+ bool handled = false;
+ CK_RV rv;
+ int i, j;
+
+ handles = p11_index_find_all (index, match);
+
+ for (i = 0; handles && handles[i] != 0; i++) {
+ obj = p11_dict_get (index->objects, handles + i);
+ if (obj == NULL)
+ continue;
+
+ handled = false;
+ attr = p11_attrs_find_valid (obj->attrs, key);
+
+ /* The match doesn't have the key, so remove it */
+ if (attr != NULL) {
+ for (j = 0; j < replacen; j++) {
+ if (!replace[j])
+ continue;
+ if (p11_attrs_matchn (replace[j], attr, 1)) {
+ attrs = NULL;
+ rv = index_build (index, &attrs, replace[j]);
+ if (rv != CKR_OK)
+ return rv;
+ p11_attrs_free (obj->attrs);
+ obj->attrs = attrs;
+ replace[j] = NULL;
+ handled = true;
+ break;
+ }
+ }
+ }
+
+ if (!handled) {
+ rv = p11_index_remove (index, handles[i]);
+ if (rv != CKR_OK)
+ return rv;
+ }
+ }
+
+ for (j = 0; j < replacen; j++) {
+ if (!replace[j])
+ continue;
+ rv = p11_index_take (index, replace[j], NULL);
+ if (rv != CKR_OK)
+ return rv;
+ replace[j] = NULL;
+ }
+
+ free (handles);
+ return CKR_OK;
+}
+
+CK_RV
+p11_index_replace (p11_index *index,
+ CK_ATTRIBUTE *match,
+ CK_ATTRIBUTE_TYPE key,
+ CK_ATTRIBUTE *replace)
+{
+ return_val_if_fail (index != NULL, CKR_GENERAL_ERROR);
+ return index_replacev (index, match, key, &replace, 1);
+}
+
+CK_RV
+p11_index_replace_all (p11_index *index,
+ CK_ATTRIBUTE *match,
+ CK_ATTRIBUTE_TYPE key,
+ p11_array *replace)
+{
+ CK_RV rv;
+ int i;
+
+ return_val_if_fail (index != NULL, CKR_GENERAL_ERROR);
+
+ rv = index_replacev (index, match, key,
+ (CK_ATTRIBUTE **)replace->elem,
+ replace->num);
+
+ for (i = 0; i < replace->num; i++) {
+ if (!replace->elem[i]) {
+ p11_array_remove (replace, i);
+ i--;
+ }
+ }
+
+ return rv;
+}
+
+CK_ATTRIBUTE *
+p11_index_lookup (p11_index *index,
+ CK_OBJECT_HANDLE handle)
+{
+ struct object *obj;
+
+ return_val_if_fail (index != NULL, NULL);
+
+ if (handle == CK_INVALID_HANDLE)
+ return NULL;
+
+ obj = p11_dict_get (index->objects, &handle);
+ return obj ? obj->attrs : NULL;
+}
+
+CK_OBJECT_HANDLE
+p11_index_find (p11_index *index,
+ CK_ATTRIBUTE *match)
+{
+ struct object *obj;
+ p11_dictiter iter;
+
+ p11_dict_iterate (index->objects, &iter);
+ while (p11_dict_next (&iter, NULL, (void *)&obj)) {
+ if (p11_attrs_match (obj->attrs, match))
+ return obj->handle;
+ }
+
+ return 0;
+}
+
+CK_OBJECT_HANDLE
+p11_index_findn (p11_index *index,
+ CK_ATTRIBUTE *match,
+ CK_ULONG count)
+{
+ struct object *obj;
+ p11_dictiter iter;
+
+ p11_dict_iterate (index->objects, &iter);
+ while (p11_dict_next (&iter, NULL, (void *)&obj)) {
+ if (p11_attrs_matchn (obj->attrs, match, count))
+ return obj->handle;
+ }
+
+ return 0;
+}
+
+CK_OBJECT_HANDLE *
+p11_index_find_all (p11_index *index,
+ CK_ATTRIBUTE *match)
+{
+ CK_OBJECT_HANDLE *handles = NULL;
+ struct object *obj;
+ p11_dictiter iter;
+ int nhandles;
+ int at = 0;
+
+ nhandles = 16;
+ handles = malloc (nhandles * sizeof (CK_OBJECT_HANDLE));
+ return_val_if_fail (handles != NULL, NULL);
+
+ p11_dict_iterate (index->objects, &iter);
+ while (p11_dict_next (&iter, NULL, (void *)&obj)) {
+ if (p11_attrs_match (obj->attrs, match)) {
+ if (at + 2 > nhandles) {
+ nhandles += 16;
+ handles = realloc (handles, nhandles * sizeof (CK_OBJECT_HANDLE));
+ return_val_if_fail (handles != NULL, NULL);
+ }
+ handles[at++] = obj->handle;
+ }
+ }
+
+ handles[at++] = 0UL;
+ return handles;
+}
+
+CK_OBJECT_HANDLE *
+p11_index_snapshot (p11_index *index,
+ p11_index *base,
+ CK_ATTRIBUTE *attrs,
+ CK_ULONG count)
+{
+ CK_OBJECT_HANDLE *snapshot;
+ CK_OBJECT_HANDLE *handle;
+ p11_dictiter iter;
+ int num;
+ int i;
+
+ /*
+ * TODO: The concept is that we use our bloom filter to provide
+ * an initial rough snapshot here of which objects match, but for
+ * now just include everything in the snapshot.
+ */
+
+ return_val_if_fail (index != NULL, NULL);
+
+ num = p11_index_size (index) + 1;
+ if (base)
+ num += p11_index_size (base);
+
+ snapshot = calloc (num, sizeof (CK_OBJECT_HANDLE));
+ return_val_if_fail (snapshot != NULL, NULL);
+
+ p11_dict_iterate (index->objects, &iter);
+ for (i = 0 ; p11_dict_next (&iter, (void *)&handle, NULL); i++) {
+ assert (i < num);
+ snapshot[i] = *handle;
+ }
+
+ if (base) {
+ p11_dict_iterate (base->objects, &iter);
+ for ( ; p11_dict_next (&iter, (void *)&handle, NULL); i++) {
+ assert (i < num);
+ snapshot[i] = *handle;
+ }
+ }
+
+ assert (i < num);
+ assert (snapshot[i] == 0UL);
+
+ return snapshot;
+}