]> granicus.if.org Git - p11-kit/commitdiff
Initial implementation with new config system.
authorStef Walter <stefw@collabora.co.uk>
Tue, 25 Jan 2011 03:25:02 +0000 (21:25 -0600)
committerStef Walter <stefw@collabora.co.uk>
Tue, 25 Jan 2011 03:25:02 +0000 (21:25 -0600)
configure.ac
module/Makefile.am
module/conf.c [new file with mode: 0644]
module/conf.h [new file with mode: 0644]
module/hash.c
module/hash.h
module/p11-kit-lib.c [new file with mode: 0644]
module/p11-kit-private.h [new file with mode: 0644]
module/p11-kit-proxy.c [moved from module/p11-kit.c with 69% similarity]
module/p11-kit.h

index 52bc606bd5ca4d0a2bc5c2017069f5efed56f09c..29b50be135b2d37fb7a4f8e5b93d26772fc16124 100644 (file)
@@ -3,11 +3,12 @@ AC_CONFIG_MACRO_DIR([m4])
 
 AC_INIT([p11-kit],[0.1],[http://bugzilla.example.com])
 
-AC_CONFIG_SRCDIR([module/p11-kit.c])
+AC_CONFIG_SRCDIR([module/p11-kit-lib.c])
 AC_CONFIG_HEADERS([config.h])
 
 dnl Other initialization
 AM_INIT_AUTOMAKE
+AM_SANITY_CHECK
 AM_MAINTAINER_MODE
 m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],)
 LT_INIT
index 3be73f478d3aca60d914f174ff9ff67584933135..c3fcad24b0ed8ee47c1a76225bbb03b5c252bf11 100644 (file)
@@ -1,10 +1,14 @@
 
 INCLUDES = \
-       -DPKCS11_MODULE_PATH=\"$(PKCS11_MODULE_PATH)\"
+       -DPKCS11_CONFIG_FILE=\"$(sysconfdir)/pkcs11.conf\" \
+       -DPKCS11_CONFIG_LIBS=\"$(sysconfdir)/pkcs11/libs\"
 
 MODULE_SRCS = \
-       p11-kit.c \
-       hash.c hash.h
+       conf.c conf.h \
+       hash.c hash.h \
+       p11-kit-lib.c \
+       p11-kit-proxy.c \
+       p11-kit-private.h p11-kit.h
 
 lib_LTLIBRARIES = p11-kit.la
 
diff --git a/module/conf.c b/module/conf.c
new file mode 100644 (file)
index 0000000..a0a3917
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2005, Stefan Walter
+ * 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
+ *  Stef Walter <stef@memberwebs.com>
+ */
+
+#include "config.h"
+
+#include "conf.h"
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void
+errmsg (const char *filename, const char* msg, ...)
+{
+       #define MAX_MSGLEN  1024
+       char buf[MAX_MSGLEN];
+       va_list ap;
+
+       va_start (ap, msg);
+       vsnprintf (buf, MAX_MSGLEN, msg, ap);
+       buf[MAX_MSGLEN - 1] = 0;
+       conf_error (filename, buf);
+       va_end (ap);
+}
+
+static void
+strcln (char* data, char ch)
+{
+       char* p;
+       for (p = data; *data; data++, p++) {
+               while (*data == ch)
+                       data++;
+               *p = *data;
+       }
+
+       /* Renull terminate */
+       *p = 0;
+}
+
+static char*
+strbtrim (const char* data)
+{
+       while (*data && isspace (*data))
+               ++data;
+       return (char*)data;
+}
+
+static void
+stretrim (char* data)
+{
+       char* t = data + strlen (data);
+       while (t > data && isspace (*(t - 1))) {
+               t--;
+               *t = 0;
+       }
+}
+
+static char*
+strtrim (char* data)
+{
+       data = (char*)strbtrim (data);
+       stretrim (data);
+       return data;
+}
+
+/* -----------------------------------------------------------------------------
+ * CONFIG PARSER
+ */
+
+static char*
+read_config_file (const char* filename, int flags)
+{
+       char* config = NULL;
+       FILE* f = NULL;
+       long len;
+
+       assert (filename);
+
+       f = fopen (filename, "r");
+       if (f == NULL) {
+               if ((flags & CONF_IGNORE_MISSING) &&
+                   (errno == ENOENT || errno == ENOTDIR)) {
+                       config = strdup ("\n");
+                       if (!config)
+                               errno = ENOMEM;
+                       return config;
+               }
+               errmsg (filename, "couldn't open config file: %s", filename);
+               return NULL;
+       }
+
+       /* Figure out size */
+       if (fseek (f, 0, SEEK_END) == -1 ||
+           (len = ftell (f)) == -1 ||
+           fseek (f, 0, SEEK_SET) == -1) {
+               errmsg (filename, "couldn't seek config file: %s", filename);
+               return NULL;
+       }
+
+       if ((config = (char*)malloc (len + 2)) == NULL) {
+               errmsg (filename, "out of memory");
+               errno = ENOMEM;
+               return NULL;
+       }
+
+       /* And read in one block */
+       if (fread (config, 1, len, f) != len) {
+               errmsg (filename, "couldn't read config file: %s", filename);
+               return NULL;
+       }
+
+       fclose (f);
+
+       /* Null terminate the data */
+       config[len] = '\n';
+       config[len + 1] = 0;
+
+       /* Remove nasty dos line endings */
+       strcln (config, '\r');
+
+       return config;
+}
+
+hash_t*
+conf_parse_file (const char* filename, int flags)
+{
+       char *name;
+       char *value;
+       hash_t *ht = NULL;
+       char *config;
+       char *next;
+       char *end;
+
+       assert (filename);
+
+       /* Adds an extra newline to end of file */
+       config = read_config_file (filename, flags);
+       if (!config)
+               return NULL;
+
+       ht = hash_create (hash_string_hash, hash_string_equal, free, free);
+       next = config;
+
+       /* Go through lines and process them */
+       while ((end = strchr (next, '\n')) != NULL) {
+               *end = 0;
+               name = strbtrim (next);
+               next = end + 1;
+
+               /* Empty lines / comments at start */
+               if (!*name || *name == '#')
+                       continue;
+
+               /* Look for the break between name = value on the same line */
+               value = name + strcspn (name, ":=");
+               if (!*value) {
+                       errmsg (filename, "%s: invalid config line: %s", filename, name);
+                       errno = EINVAL;
+                       break;
+               }
+
+               /* Null terminate and split value part */
+               *value = 0;
+               value++;
+
+               name = strtrim (name);
+               value = strtrim (value);
+
+               name = strdup (name);
+               if (!name) {
+                       errno = ENOMEM;
+                       break;
+               }
+               value = strdup (value);
+               if (!value) {
+                       free (name);
+                       errno = ENOMEM;
+                       break;
+               }
+               if (!hash_set (ht, name, value)) {
+                       free (name);
+                       free (value);
+                       errno = ENOMEM;
+                       break;
+               }
+       }
+
+       /* Unsuccessful? */
+       if (end != NULL) {
+               hash_free (ht);
+               ht = NULL;
+       }
+
+       free (config);
+       return ht;
+}
diff --git a/module/conf.h b/module/conf.h
new file mode 100644 (file)
index 0000000..2a9e2f3
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2011, Collabora Ltd.
+ * Copyright (c) 2005, Stefan Walter
+ *
+ * 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@collabora.co.uk>
+ */
+
+#ifndef __CONF_H__
+#define __CONF_H__
+
+#include "hash.h"
+
+enum {
+       CONF_IGNORE_MISSING = 0x01,
+};
+
+extern void   conf_error           (const char *filename,
+                                    const char *message);
+
+hash_t*       conf_parse_file      (const char *filename,
+                                    int flags);
+
+#endif /* __CONF_H__ */
index 512a9140fd715c2dc075765356d7188e9355a1a9..84d57a277f1647d20f230c21ca9c9d73b0f6a062 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2004, Stefan Walter
- * All rights reserved.
+ * Copyright (c) 2011, Collabora Ltd.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  */
 
 #include <sys/types.h>
+
+#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
-#include "hash.h"
 
-#define KEY_DATA(he)    ((he)->key)
+#include "hash.h"
 
 /*
  * The internal form of a hash table.
  * isn't too bad given that pools have a low allocation overhead.
  */
 
-typedef struct hsh_entry_t hsh_entry_t;
+typedef struct hash_entry hash_entry_t;
 
-struct hsh_entry_t
-{
-    hsh_entry_t* next;
-    unsigned int hash;
-    const void* key;
-    size_t klen;
-    const void* val;
-};
-
-/*
- * Data structure for iterating through a hash table.
- *
- * We keep a pointer to the next hash entry here to allow the current
- * hash entry to be freed or otherwise mangled between calls to
- * hsh_next().
- */
-struct hsh_index_t
+struct hash_entry
 {
-    hsh_t* ht;
-    hsh_entry_t* ths;
-    hsh_entry_t* next;
-    unsigned int index;
+       hash_entry_t* next;
+       unsigned int hash;
+       void* key;
+       void* val;
 };
 
 /*
@@ -100,15 +85,16 @@ struct hsh_index_t
  * The count of hash entries may be greater depending on the chosen
  * collision rate.
  */
-struct hsh_t
-{
-    hsh_entry_t** array;
-    hsh_index_t iterator;    /* For hsh_first(...) */
-    unsigned int count;
-    unsigned int max;
+struct hash {
+       hash_entry_t** array;
+       unsigned int count;
+       unsigned int max;
+       hash_hash_func hash_func;
+       hash_equal_func equal_func;
+       hash_destroy_func key_destroy_func;
+       hash_destroy_func value_destroy_func;
 };
 
-
 #define INITIAL_MAX 15 /* tunable == 2^n - 1 */
 #define int_malloc malloc
 #define int_calloc calloc
@@ -118,109 +104,121 @@ struct hsh_t
  * Hash creation functions.
  */
 
-static hsh_entry_t** alloc_array(hsh_t* ht, unsigned int max)
+static hash_entry_t**
+alloc_array(hash_t* ht, unsigned int max)
 {
-    return (hsh_entry_t**)int_calloc(sizeof(*(ht->array)), (max + 1));
+       return (hash_entry_t**)int_calloc (sizeof (*(ht->array)), (max + 1));
 }
 
-hsh_t* hsh_create()
+hash_t*
+hash_create (hash_hash_func hash_func,
+             hash_equal_func equal_func,
+             hash_destroy_func key_destroy_func,
+             hash_destroy_func value_destroy_func)
 {
-    hsh_t* ht = int_malloc(sizeof(hsh_t));
-    if(ht)
-    {
-        ht->count = 0;
-        ht->max = INITIAL_MAX;
-        ht->array = alloc_array(ht, ht->max);
-        if(!ht->array)
-        {
-            int_free(ht);
-            return NULL;
-        }
-    }
-    return ht;
+       hash_t* ht;
+
+       assert (hash_func);
+       assert (equal_func);
+
+       ht = int_malloc (sizeof (hash_t));
+       if (ht) {
+               ht->count = 0;
+               ht->max = INITIAL_MAX;
+               ht->hash_func = hash_func;
+               ht->equal_func = equal_func;
+               ht->key_destroy_func = key_destroy_func;
+               ht->value_destroy_func = value_destroy_func;
+               ht->array = alloc_array (ht, ht->max);
+               if (!ht->array) {
+                       int_free (ht);
+                       return NULL;
+               }
+       }
+       return ht;
 }
 
-void hsh_free(hsh_t* ht)
+void
+hash_free (hash_t* ht)
 {
-    hsh_index_t* hi;
+       hash_iter_t hi;
+
+       if (!ht)
+               return;
 
-    for(hi = hsh_first(ht); hi; hi = hsh_next(hi))
-        int_free(hi->ths);
+       hash_iterate (ht, &hi);
+       while (hash_next (&hi, NULL, NULL)) {
+               if (ht->key_destroy_func)
+                       ht->key_destroy_func (hi.ths->key);
+               if (ht->value_destroy_func)
+                       ht->value_destroy_func (hi.ths->val);
+       }
 
-    if(ht->array)
-        int_free(ht->array);
+       if (ht->array)
+               int_free (ht->array);
 
-    int_free(ht);
+       int_free (ht);
 }
 
 /*
  * Hash iteration functions.
  */
-
-hsh_index_t* hsh_next(hsh_index_t* hi)
+int
+hash_next (hash_iter_t* hi, void **key, void **value)
 {
-    hi->ths = hi->next;
-    while(!hi->ths)
-    {
-        if(hi->index > hi->ht->max)
-            return NULL;
-
-        hi->ths = hi->ht->array[hi->index++];
-    }
-    hi->next = hi->ths->next;
-    return hi;
-}
-
-hsh_index_t* hsh_first(hsh_t* ht)
-{
-    hsh_index_t* hi = &ht->iterator;
-
-    hi->ht = ht;
-    hi->index = 0;
-    hi->ths = NULL;
-    hi->next = NULL;
-    return hsh_next(hi);
+       hi->ths = hi->next;
+       while (!hi->ths) {
+               if (hi->index > hi->ht->max)
+                       return 0;
+               hi->ths = hi->ht->array[hi->index++];
+       }
+       hi->next = hi->ths->next;
+       if (key)
+               *key = hi->ths->key;
+       if (value)
+               *value = hi->ths->val;
+       return 1;
 }
 
-void* hsh_this(hsh_index_t* hi, const void** key, size_t* klen)
+void
+hash_iterate (hash_t* ht, hash_iter_t *hi)
 {
-    if(key)
-        *key = KEY_DATA(hi->ths);
-    if(klen)
-        *klen = hi->ths->klen;
-    return (void*)hi->ths->val;
+       hi->ht = ht;
+       hi->index = 0;
+       hi->ths = NULL;
+       hi->next = NULL;
 }
 
-
 /*
  * Expanding a hash table
  */
 
-static int expand_array(hsh_t* ht)
+static int
+expand_array (hash_t* ht)
 {
-    hsh_index_t* hi;
-    hsh_entry_t** new_array;
-    unsigned int new_max;
+       hash_iter_t hi;
+       hash_entry_t** new_array;
+       unsigned int new_max;
 
-    new_max = ht->max * 2 + 1;
-    new_array = alloc_array(ht, new_max);
+       new_max = ht->max * 2 + 1;
+       new_array = alloc_array (ht, new_max);
 
-    if(!new_array)
-        return 0;
+       if(!new_array)
+               return 0;
 
-    for(hi = hsh_first(ht); hi; hi = hsh_next(hi))
-    {
-        unsigned int i = hi->ths->hash & new_max;
-        hi->ths->next = new_array[i];
-        new_array[i] = hi->ths;
-    }
+       hash_iterate (ht, &hi);
+       while (hash_next (&hi, NULL, NULL)) {
+               unsigned int i = hi.ths->hash & new_max;
+               hi.ths->next = new_array[i];
+               new_array[i] = hi.ths;
+       }
 
-    if(ht->array)
-        free(ht->array);
+       if(ht->array)
+               int_free (ht->array);
 
-    ht->array = new_array;
-    ht->max = new_max;
-    return 1;
+       ht->array = new_array;
+       ht->max = new_max;
+       return 1;
 }
 
 /*
@@ -232,151 +230,96 @@ static int expand_array(hsh_t* ht)
  * that hash entries can be removed.
  */
 
-static hsh_entry_t** find_entry(hsh_t* ht, const void* key, size_t klen, const void* val)
+static hash_entry_t**
+find_entry (hash_t* ht, const void* key, void* val)
 {
-    hsh_entry_t** hep;
-    hsh_entry_t* he;
-    const unsigned char* p;
-    unsigned int hash;
-    size_t i;
-
-    /*
-     * This is the popular `times 33' hash algorithm which is used by
-     * perl and also appears in Berkeley DB. This is one of the best
-     * known hash functions for strings because it is both computed
-     * very fast and distributes very well.
-     *
-     * The originator may be Dan Bernstein but the code in Berkeley DB
-     * cites Chris Torek as the source. The best citation I have found
-     * is "Chris Torek, Hash function for text in C, Usenet message
-     * <27038@mimsy.umd.edu> in comp.lang.c , October, 1990." in Rich
-     * Salz's USENIX 1992 paper about INN which can be found at
-     * <http://citeseer.nj.nec.com/salz92internetnews.html>.
-     *
-     * The magic of number 33, i.e. why it works better than many other
-     * constants, prime or not, has never been adequately explained by
-     * anyone. So I try an explanation: if one experimentally tests all
-     * multipliers between 1 and 256 (as I did while writing a low-level
-     * data structure library some time ago) one detects that even
-     * numbers are not useable at all. The remaining 128 odd numbers
-     * (except for the number 1) work more or less all equally well.
-     * They all distribute in an acceptable way and this way fill a hash
-     * table with an average percent of approx. 86%.
-     *
-     * If one compares the chi^2 values of the variants (see
-     * Bob Jenkins ``Hashing Frequently Asked Questions'' at
-     * http://burtleburtle.net/bob/hash/hashfaq.html for a description
-     * of chi^2), the number 33 not even has the best value. But the
-     * number 33 and a few other equally good numbers like 17, 31, 63,
-     * 127 and 129 have nevertheless a great advantage to the remaining
-     * numbers in the large set of possible multipliers: their multiply
-     * operation can be replaced by a faster operation based on just one
-     * shift plus either a single addition or subtraction operation. And
-     * because a hash function has to both distribute good _and_ has to
-     * be very fast to compute, those few numbers should be preferred.
-     *
-     *                        -- Ralf S. Engelschall <rse@engelschall.com>
-     */
-    hash = 0;
-
-    if(klen == HSH_KEY_STRING)
-    {
-        for(p = key; *p; p++)
-            hash = hash * 33 + *p;
-
-        klen = p - (const unsigned char *)key;
-    }
-    else
-    {
-        for(p = key, i = klen; i; i--, p++)
-            hash = hash * 33 + *p;
-    }
-
-    /* scan linked list */
-    for(hep = &ht->array[hash & ht->max], he = *hep;
-            he; hep = &he->next, he = *hep)
-    {
-     if(he->hash == hash &&
-        he->klen == klen &&
-        memcmp(KEY_DATA(he), key, klen) == 0)
-         break;
-    }
-
-    if(he || !val)
-        return hep;
-
-    /* add a new entry for non-NULL val */
-    he = int_malloc(sizeof(*he));
-
-    if(he)
-    {
-        /* Key points to external data */
-        he->key = key;
-        he->klen = klen;
-
-        he->next = NULL;
-        he->hash = hash;
-        he->val    = val;
-
-        *hep = he;
-        ht->count++;
-    }
-
-    return hep;
-}
+       hash_entry_t** hep;
+       hash_entry_t* he;
+       unsigned int hash;
+
+       /* Perform the hashing */
+       hash = ht->hash_func (key);
+
+       /* scan linked list */
+       for (hep = &ht->array[hash & ht->max], he = *hep;
+            he; hep = &he->next, he = *hep) {
+               if(he->hash == hash && ht->equal_func (he->key, key))
+                       break;
+       }
 
-void* hsh_get(hsh_t* ht, const void *key, size_t klen)
-{
-        hsh_entry_t** he = find_entry(ht, key, klen, NULL);
+       if(he || !val)
+               return hep;
+
+       /* add a new entry for non-NULL val */
+       he = int_malloc (sizeof (*he));
+
+       if(he) {
+               he->key = (void*)key;
+               he->next = NULL;
+               he->hash = hash;
+               he->val = val;
 
-        if(he && *he)
-            return (void*)((*he)->val);
-        else
-            return NULL;
+               *hep = he;
+               ht->count++;
+       }
+
+       return hep;
 }
 
-int hsh_set(hsh_t* ht, const void* key, size_t klen, void* val)
+void*
+hash_get (hash_t* ht, const void *key)
 {
-    hsh_entry_t** hep = find_entry(ht, key, klen, val);
-
-    if(hep && *hep)
-    {
-        /* replace entry */
-        (*hep)->val = val;
+       hash_entry_t** he = find_entry (ht, key, NULL);
+       if (he && *he)
+               return (void*)((*he)->val);
+       else
+               return NULL;
+}
 
-        /* check that the collision rate isn't too high */
-        if(ht->count > ht->max)
-        {
-            if(!expand_array(ht))
-                return 0;
-        }
+int
+hash_set (hash_t* ht, void* key, void* val)
+{
+       hash_entry_t** hep = find_entry (ht, key, val);
+       if(hep && *hep) {
+               /* replace entry */
+               (*hep)->val = val;
+
+               /* check that the collision rate isn't too high */
+               if (ht->count > ht->max) {
+                       if (!expand_array (ht))
+                               return 0;
+               }
 
-        return 1;
-    }
+               return 1;
+       }
 
-    return 0;
+       return 0;
 }
 
-void* hsh_rem(hsh_t* ht, const void* key, size_t klen)
+int
+hash_remove (hash_t* ht, const void* key)
 {
-    hsh_entry_t** hep = find_entry(ht, key, klen, NULL);
-    void* val = NULL;
-
-    if(hep && *hep)
-    {
-        hsh_entry_t* old = *hep;
-        *hep = (*hep)->next;
-        --ht->count;
-        val = (void*)old->val;
-        free(old);
-    }
-
-    return val;
+       hash_entry_t** hep = find_entry (ht, key, NULL);
+
+       if (hep && *hep) {
+               hash_entry_t* old = *hep;
+               *hep = (*hep)->next;
+               --ht->count;
+               if (ht->key_destroy_func)
+                       ht->key_destroy_func (old->key);
+               if (ht->value_destroy_func)
+                       ht->value_destroy_func (old->val);
+               free (old);
+               return 1;
+       }
+
+       return 0;
 }
 
-void hsh_clear(hsh_t* ht)
+void
+hash_clear (hash_t* ht)
 {
-       hsh_entry_t *he, *next;
+       hash_entry_t *he, *next;
        int i;
 
        /* Free all entries in the array */
@@ -384,17 +327,112 @@ void hsh_clear(hsh_t* ht)
                he = ht->array[i];
                while (he) {
                        next = he->next;
+                       if (ht->key_destroy_func)
+                               ht->key_destroy_func (he->key);
+                       if (ht->value_destroy_func)
+                               ht->value_destroy_func (he->val);
                        free (he);
                        he = next;
                }
        }
 
-       memset (ht->array, 0, ht->max * sizeof (hsh_entry_t*));
+       memset (ht->array, 0, ht->max * sizeof (hash_entry_t*));
        ht->count = 0;
 }
 
-unsigned int hsh_count(hsh_t* ht)
+unsigned int
+hash_count (hash_t* ht)
+{
+       return ht->count;
+}
+
+unsigned int
+hash_string_hash (const void *string)
+{
+       unsigned int hash;
+       const unsigned char *p;
+
+       assert (string);
+
+       /*
+        * This is the popular `times 33' hash algorithm which is used by
+        * perl and also appears in Berkeley DB. This is one of the best
+        * known hash functions for strings because it is both computed
+        * very fast and distributes very well.
+        *
+        * The originator may be Dan Bernstein but the code in Berkeley DB
+        * cites Chris Torek as the source. The best citation I have found
+        * is "Chris Torek, Hash function for text in C, Usenet message
+        * <27038@mimsy.umd.edu> in comp.lang.c , October, 1990." in Rich
+        * Salz's USENIX 1992 paper about INN which can be found at
+        * <http://citeseer.nj.nec.com/salz92internetnews.html>.
+        *
+        * The magic of number 33, i.e. why it works better than many other
+        * constants, prime or not, has never been adequately explained by
+        * anyone. So I try an explanation: if one experimentally tests all
+        * multipliers between 1 and 256 (as I did while writing a low-level
+        * data structure library some time ago) one detects that even
+        * numbers are not useable at all. The remaining 128 odd numbers
+        * (except for the number 1) work more or less all equally well.
+        * They all distribute in an acceptable way and this way fill a hash
+        * table with an average percent of approx. 86%.
+        *
+        * If one compares the chi^2 values of the variants (see
+        * Bob Jenkins ``Hashing Frequently Asked Questions'' at
+        * http://burtleburtle.net/bob/hash/hashfaq.html for a description
+        * of chi^2), the number 33 not even has the best value. But the
+        * number 33 and a few other equally good numbers like 17, 31, 63,
+        * 127 and 129 have nevertheless a great advantage to the remaining
+        * numbers in the large set of possible multipliers: their multiply
+        * operation can be replaced by a faster operation based on just one
+        * shift plus either a single addition or subtraction operation. And
+        * because a hash function has to both distribute good _and_ has to
+        * be very fast to compute, those few numbers should be preferred.
+        *
+        *                        -- Ralf S. Engelschall <rse@engelschall.com>
+        */
+
+       hash = 0;
+
+       for(p = string; *p; p++)
+               hash = hash * 33 + *p;
+
+       return hash;
+}
+
+int
+hash_string_equal (const void *string_one, const void *string_two)
+{
+       assert (string_one);
+       assert (string_two);
+
+       return strcmp (string_one, string_two) == 0;
+}
+
+unsigned int
+hash_ulongptr_hash (const void *to_ulong)
+{
+       assert (to_ulong);
+       return (unsigned int)*((unsigned long*)to_ulong);
+}
+
+int
+hash_ulongptr_equal (const void *ulong_one, const void *ulong_two)
+{
+       assert (ulong_one);
+       assert (ulong_two);
+       return *((unsigned long*)ulong_one) == *((unsigned long*)ulong_two);
+}
+
+unsigned int
+hash_direct_hash (const void *ptr)
+{
+       return (unsigned int)ptr;
+}
+
+int
+hash_direct_equal (const void *ptr_one, const void *ptr_two)
 {
-    return ht->count;
+       return ptr_one == ptr_two;
 }
 
index a02b8e359708cb13c4b541d2c49bc33dee466321..8649ed5235ee57c473fc6d9360ae1259c8515113 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2004, Stefan Walter
- * All rights reserved.
+ * Copyright (c) 2011, Collabora Ltd.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,6 +29,8 @@
  * 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 Waler <stefw@collabora.co.uk>
  */
 
 /*
 
 #include <sys/types.h>
 
-/*
- * OPTIONAL FEATURES
- *
- * Features to define. You need to build both this file and
- * the corresponding hash.c file with whatever options you set here.
- * These affect the method signatures, so see the sections below
- * for the actual options
- */
-
 /*
  * ARGUMENT DOCUMENTATION
  *
  */
 
 /* Abstract type for hash tables. */
-typedef struct hsh_t hsh_t;
+typedef struct hash hash_t;
 
-/* Abstract type for scanning hash tables.  */
-typedef struct hsh_index_t hsh_index_t;
+/* Type for scanning hash tables.  */
+typedef struct hash_iter
+{
+       hash_t* ht;
+       struct hash_entry* ths;
+       struct hash_entry* next;
+       unsigned int index;
+} hash_iter_t;
+
+typedef unsigned int (*hash_hash_func)            (const void *data);
+
+typedef int          (*hash_equal_func)           (const void *one,
+                                                   const void *two);
+
+typedef void         (*hash_destroy_func)         (void *data);
 
 /* -----------------------------------------------------------------------------
  * MAIN
  */
 
 /*
- * hsh_create : Create a hash table
+ * hash_create : Create a hash table
  * - returns an allocated hashtable
  */
-hsh_t* hsh_create(void);
+hash_t*            hash_create                 (hash_hash_func hash_func,
+                                                hash_equal_func equal_func,
+                                                hash_destroy_func key_destroy_func,
+                                                hash_destroy_func value_destroy_func);
 
 /*
- * hsh_free : Free a hash table
+ * hash_free : Free a hash table
  */
-void hsh_free(hsh_t* ht);
+void               hash_free                   (hash_t* ht);
 
 /*
- * hsh_count: Number of values in hash table
+ * hash_count: Number of values in hash table
  * - returns the number of entries in hash table
  */
-unsigned int hsh_count(hsh_t* ht);
+unsigned int       hash_count                  (hash_t* ht);
 
 /*
- * hsh_get: Retrieves a value from the hash table
+ * hash_get: Retrieves a value from the hash table
  * - returns the value of the entry
  */
-void* hsh_get(hsh_t* ht, const void* key, size_t klen);
+void*              hash_get                    (hash_t* ht,
+                                                const void *key);
 
 /*
- * hsh_set: Set a value in the hash table
+ * hash_set: Set a value in the hash table
  * - returns 1 if the entry was added properly
  */
-int hsh_set(hsh_t* ht, const void* key, size_t klen, void* val);
+int                hash_set                    (hash_t* ht,
+                                                void *key,
+                                                void *value);
 
 /*
- * hsh_rem: Remove a value from the hash table
- * - returns the value of the removed entry
+ * hash_remove: Remove a value from the hash table
+ * - returns 1 if the entry was found
  */
-void* hsh_rem(hsh_t* ht, const void* key, size_t klen);
+int                hash_remove                 (hash_t* ht,
+                                                const void* key);
 
 /*
- * hsh_first: Start enumerating through the hash table
+ * hash_first: Start enumerating through the hash table
  * - returns a hash iterator
  */
-hsh_index_t* hsh_first(hsh_t* ht);
+void               hash_iterate                (hash_t* ht,
+                                                hash_iter_t *hi);
 
 /*
- * hsh_next: Enumerate through hash table
- * - returns the hash iterator or null when no more entries
+ * hash_next: Enumerate through hash table
+ * - sets key and value to key and/or value
+ * - returns whether there was another entry
  */
-hsh_index_t* hsh_next(hsh_index_t* hi);
+int                hash_next                   (hash_iter_t* hi,
+                                                void **key,
+                                                void **value);
 
 /*
- * hsh_this: While enumerating get current value
- * - returns the value that the iterator currently points to
+ * hash_clear: Clear all values from has htable.
  */
-void* hsh_this(hsh_index_t* hi, const void** key, size_t* klen);
+void               hash_clear                  (hash_t* ht);
 
-/*
- * hsh_clear: Clear all values from has htable.
+/* -----------------------------------------------------------------------------
+ * HASH FUNCTIONS
  */
-void hsh_clear(hsh_t* ht);
 
-/*
- * This can be passed as 'klen' in any of the above functions to indicate
- * a string-valued key, and have hash compute the length automatically.
- */
-#define HSH_KEY_STRING     (-1)
+unsigned int       hash_string_hash            (const void *string);
+
+int                hash_string_equal           (const void *string_one,
+                                                const void *string_two);
+
+unsigned int       hash_ulongptr_hash          (const void *to_ulong);
+
+int                hash_ulongptr_equal         (const void *ulong_one,
+                                                const void *ulong_two);
+
+unsigned int       hash_direct_hash            (const void *ptr);
+
+int                hash_direct_equal           (const void *ptr_one,
+                                                const void *ptr_two);
 
-#endif  /* __HSH_H__ */
+#endif  /* __HASH_H__ */
diff --git a/module/p11-kit-lib.c b/module/p11-kit-lib.c
new file mode 100644 (file)
index 0000000..60662d1
--- /dev/null
@@ -0,0 +1,810 @@
+/*
+ * Copyright (C) 2011 Collabora Ltd.
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * 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@collabora.co.uk>
+ */
+
+#include "config.h"
+
+#include "conf.h"
+#include "hash.h"
+#include "pkcs11.h"
+#include "p11-kit.h"
+#include "p11-kit-private.h"
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+typedef struct _Module {
+       char *name;
+       hash_t *config;
+       void *dl_module;
+       CK_FUNCTION_LIST_PTR funcs;
+       int ref_count;
+       int initialize_count;
+} Module;
+
+/*
+ * This is the mutex that protects the global data of this library
+ * and the pkcs11 proxy module. Note that we *never* call into our
+ * underlying pkcs11 modules while holding this mutex. Therefore it
+ * doesn't have to be recursive and we can keep things simple.
+ */
+pthread_mutex_t _p11_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * Shared data between threads, protected by the mutex, a structure so
+ * we can audit thread safety easier.
+ */
+static struct _Shared {
+       hash_t *modules;
+       hash_t *config;
+} gl = { NULL, NULL };
+
+/* -----------------------------------------------------------------------------
+ * UTILITIES
+ */
+
+static void
+warning (const char* msg, ...)
+{
+       char buffer[512];
+       va_list va;
+
+       va_start (va, msg);
+
+       vsnprintf(buffer, sizeof (buffer) - 1, msg, va);
+       buffer[sizeof (buffer) - 1] = 0;
+       fprintf (stderr, "p11-kit: %s\n", buffer);
+
+       va_end (va);
+}
+
+void
+conf_error (const char *filename, const char *buffer)
+{
+       /* called from conf.c */
+       fprintf (stderr, "p11-kit: %s\n", buffer);
+}
+
+static char*
+strconcat (const char *first, ...)
+{
+       size_t length = 0;
+       const char *arg;
+       char *result, *at;
+       va_list va;
+
+       va_start (va, first);
+
+       for (arg = first; arg; arg = va_arg (va, const char*))
+               length += strlen (arg);
+
+       va_end (va);
+
+       at = result = malloc (length);
+       if (!result)
+               return NULL;
+
+       va_start (va, first);
+
+       for (arg = first; arg; arg = va_arg (va, const char*)) {
+               length = strlen (arg);
+               memcpy (at, arg, length);
+               at += length;
+       }
+
+       va_end (va);
+
+       *at = 0;
+       return result;
+}
+
+static int
+strequal (const char *one, const char *two)
+{
+       return strcmp (one, two) == 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * P11-KIT FUNCTIONALITY
+ */
+
+static void
+free_module_unlocked (void *data)
+{
+       Module *module = data;
+
+       assert (module);
+
+       /* Module must be finalized */
+       assert (module->initialize_count == 0);
+
+       /* Module must have no outstanding references */
+       assert (module->ref_count == 0);
+
+       dlclose (module->dl_module);
+       hash_free (module->config);
+       free (module->name);
+       free (module);
+}
+
+static CK_RV
+load_module_from_config_unlocked (const char *configfile, const char *name)
+{
+       Module *module, *prev;
+       const char *path;
+       CK_C_GetFunctionList gfl;
+       CK_RV rv;
+
+       assert (configfile);
+
+       module = calloc (sizeof (Module), 1);
+       if (!module)
+               return CKR_HOST_MEMORY;
+
+       module->config = conf_parse_file (configfile, 0);
+       if (!module->config) {
+               free_module_unlocked (module);
+               if (errno == ENOMEM)
+                       return CKR_HOST_MEMORY;
+               return CKR_GENERAL_ERROR;
+       }
+
+       module->name = strdup (name);
+       if (!module->name) {
+               free_module_unlocked (module);
+               return CKR_HOST_MEMORY;
+       }
+
+       path = hash_get (module->config, "module");
+       if (path == NULL) {
+               free_module_unlocked (module);
+               warning ("no module path specified in config: %s", configfile);
+               return CKR_GENERAL_ERROR;
+       }
+
+       module->dl_module = dlopen (path, RTLD_LOCAL | RTLD_NOW);
+       if (module->dl_module == NULL) {
+               warning ("couldn't load module: %s: %s", path, dlerror ());
+               free_module_unlocked (module);
+               return CKR_GENERAL_ERROR;
+       }
+
+       gfl = dlsym (module->dl_module, "C_GetFunctionList");
+       if (!gfl) {
+               warning ("couldn't find C_GetFunctionList entry point in module: %s: %s",
+                        path, dlerror ());
+               free_module_unlocked (module);
+               return CKR_GENERAL_ERROR;
+       }
+
+       rv = gfl (&module->funcs);
+       if (rv != CKR_OK) {
+               warning ("call to C_GetFunctiontList failed in module: %s: %lu",
+                        path, (unsigned long)rv);
+               free_module_unlocked (module);
+               return rv;
+       }
+
+       prev = hash_get (gl.modules, module->funcs);
+
+       /* Replace previous module that was loaded explicitly? */
+       if (prev && !prev->name) {
+               module->ref_count = prev->ref_count;
+               module->initialize_count = prev->initialize_count;
+               prev->ref_count = 0;
+               prev->initialize_count = 0;
+               hash_set (gl.modules, module->funcs, module);
+               prev = NULL; /* freed by hash above */
+       }
+
+       /* Refuse to load duplicate module */
+       if (prev) {
+               warning ("duplicate configured module: %s: %s",
+                        module->name, path);
+               free_module_unlocked (module);
+               return CKR_GENERAL_ERROR;
+       }
+
+       return CKR_OK;
+}
+
+static CK_RV
+load_modules_from_config_unlocked (const char *directory)
+{
+       struct dirent *dp;
+       CK_RV rv = CKR_OK;
+       DIR *dir;
+       char *path;
+
+       /* First we load all the modules */
+       dir = opendir (directory);
+       if (!dir) {
+               if (errno == ENOENT || errno == ENOTDIR)
+                       warning ("couldn't list directory: %s", directory);
+               return CKR_GENERAL_ERROR;
+       }
+
+       /* We're within a global mutex, so readdir is safe */
+       while ((dp = readdir(dir)) != NULL) {
+               path = strconcat (directory, "/", dp->d_name);
+               if (!path) {
+                       rv = CKR_HOST_MEMORY;
+                       break;
+               }
+
+               rv = load_module_from_config_unlocked (path, dp->d_name);
+               free (path);
+
+               if (rv != CKR_OK)
+                       break;
+       }
+
+       closedir (dir);
+
+       return rv;
+}
+
+static CK_RV
+load_config_modules_unlocked (hash_t *config)
+{
+       const char *user_config;
+       struct passwd *pwd;
+       char *path;
+       CK_RV rv;
+
+       /* Whether we should use or override from user directory */
+       user_config = hash_get (config, "user-config");
+       if (user_config == NULL)
+               user_config = "none";
+
+       /* Load each module from the main list */
+       if (strequal (user_config, "none") || strequal (user_config, "merge")) {
+               rv = load_modules_from_config_unlocked (PKCS11_CONFIG_LIBS);
+               if (rv != CKR_OK);
+                       return rv;
+       }
+       if (strequal (user_config, "override") || strequal (user_config, "merge")) {
+               pwd = getpwuid (getuid ());
+               if (!pwd)
+                       rv = CKR_GENERAL_ERROR;
+               else {
+                       path = strconcat (pwd->pw_dir, "/.pkcs11/libs");
+                       if (path == NULL)
+                               rv = CKR_HOST_MEMORY;
+                       else
+                               rv = load_modules_from_config_unlocked (path);
+                       free (path);
+               }
+               if (rv != CKR_OK);
+                       return rv;
+       }
+
+       return CKR_OK;
+}
+
+static CK_RV
+load_registered_modules_unlocked (void)
+{
+       hash_t *config;
+       CK_RV rv;
+
+       /* Should only be called after everything has been unloaded */
+       assert (!gl.config);
+
+       /* Load the main configuration */
+       config = conf_parse_file (PKCS11_CONFIG_FILE, CONF_IGNORE_MISSING);
+       if (!config) {
+               if (errno == ENOMEM)
+                       return CKR_HOST_MEMORY;
+               return CKR_GENERAL_ERROR;
+       }
+
+       rv = load_config_modules_unlocked (config);
+       if (rv != CKR_OK) {
+               hash_free (config);
+               return rv;
+       }
+
+       gl.config = config;
+       return CKR_OK;
+}
+
+static CK_RV
+create_mutex (CK_VOID_PTR_PTR mut)
+{
+       pthread_mutex_t *pmutex;
+       int err;
+
+       pmutex = malloc (sizeof (pthread_mutex_t));
+       if (!pmutex)
+               return CKR_HOST_MEMORY;
+       err = pthread_mutex_init (pmutex, NULL);
+       if (err == ENOMEM)
+               return CKR_HOST_MEMORY;
+       else if (err != 0)
+               return CKR_GENERAL_ERROR;
+       *mut = pmutex;
+       return CKR_OK;
+}
+
+static CK_RV
+destroy_mutex (CK_VOID_PTR mut)
+{
+       pthread_mutex_t *pmutex = mut;
+       int err;
+
+       err = pthread_mutex_destroy (pmutex);
+       if (err == EINVAL)
+               return CKR_MUTEX_BAD;
+       else if (err != 0)
+               return CKR_GENERAL_ERROR;
+       free (pmutex);
+       return CKR_OK;
+}
+
+static CK_RV
+lock_mutex (CK_VOID_PTR mut)
+{
+       pthread_mutex_t *pmutex = mut;
+       int err;
+
+       err = pthread_mutex_lock (pmutex);
+       if (err == EINVAL)
+               return CKR_MUTEX_BAD;
+       else if (err != 0)
+               return CKR_GENERAL_ERROR;
+       return CKR_OK;
+}
+
+static CK_RV
+unlock_mutex (CK_VOID_PTR mut)
+{
+       pthread_mutex_t *pmutex = mut;
+       int err;
+
+       err = pthread_mutex_unlock (pmutex);
+       if (err == EINVAL)
+               return CKR_MUTEX_BAD;
+       else if (err == EPERM)
+               return CKR_MUTEX_NOT_LOCKED;
+       else if (err != 0)
+               return CKR_GENERAL_ERROR;
+       return CKR_OK;
+}
+
+static CK_RV
+initialize_module_unlocked_reentrant (Module *module, CK_C_INITIALIZE_ARGS_PTR args)
+{
+       CK_RV rv = CKR_OK;
+
+       assert (module);
+
+       /*
+        * Initialize first, so module doesn't get freed out from
+        * underneath us when the mutex is unlocked below.
+        */
+       ++module->ref_count;
+
+       if (!module->initialize_count) {
+
+               _p11_unlock ();
+
+                       assert (module->funcs);
+                       rv = module->funcs->C_Initialize (args);
+
+               _p11_lock ();
+
+               /*
+                * Because we have the mutex unlocked above, two initializes could
+                * race. Therefore we need to take CKR_CRYPTOKI_ALREADY_INITIALIZED
+                * into account.
+                *
+                * We also need to take into account where in a race both calls return
+                * CKR_OK (which is not according to the spec but may happen, I mean we
+                * do it in this module, so it's not unimaginable).
+                */
+
+               if (rv == CKR_OK)
+                       ++module->initialize_count;
+               else if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED)
+                       rv = CKR_OK;
+               else
+                       --module->ref_count;
+       }
+
+       return rv;
+}
+
+static CK_RV
+init_modules_unlocked (void)
+{
+       if (!gl.modules)
+               gl.modules = hash_create (hash_direct_hash, hash_direct_equal,
+                                         NULL, free_module_unlocked);
+       if (!gl.modules)
+               return CKR_HOST_MEMORY;
+       return CKR_OK;
+}
+
+static void
+free_modules_when_no_refs_unlocked (void)
+{
+       Module *module;
+       hash_iter_t it;
+
+       /* Check if any modules have a ref count */
+       hash_iterate (gl.modules, &it);
+       while (hash_next (&it, NULL, (void**)&module)) {
+               if (module->ref_count)
+                       return;
+       }
+
+       hash_free (gl.modules);
+       gl.modules = NULL;
+       hash_free (gl.config);
+       gl.config = NULL;
+}
+
+static CK_RV
+finalize_module_unlocked_reentrant (Module *module, CK_VOID_PTR args)
+{
+       assert (module);
+
+       /*
+        * We leave module info around until all are finalized
+        * so we can encounter these zombie Module structures.
+        */
+       if (module->ref_count == 0)
+               return CKR_ARGUMENTS_BAD;
+
+       if (--module->ref_count > 0)
+               return CKR_OK;
+
+       /*
+        * Becuase of the mutex unlock below, we temporarily increase
+        * the ref count. This prevents module from being freed out
+        * from ounder us.
+        */
+       ++module->ref_count;
+
+       while (module->initialize_count > 0) {
+
+               _p11_unlock ();
+
+                       assert (module->funcs);
+                       module->funcs->C_Finalize (args);
+
+               _p11_lock ();
+
+               if (module->initialize_count > 0)
+                       --module->initialize_count;
+       }
+
+       /* Match the increment above */
+       --module->ref_count;
+
+       free_modules_when_no_refs_unlocked ();
+       return CKR_OK;
+}
+
+static Module*
+find_module_for_name_unlocked (const char *name)
+{
+       Module *module;
+       hash_iter_t it;
+
+       assert (name);
+
+       hash_iterate (gl.modules, &it);
+       while (hash_next (&it, NULL, (void**)&module))
+               if (module->ref_count && module->name && strcmp (name, module->name))
+                       return module;
+       return NULL;
+}
+
+CK_RV
+_p11_kit_initialize_registered_unlocked_reentrant (CK_C_INITIALIZE_ARGS_PTR args)
+{
+       Module *module;
+       hash_iter_t it;
+       CK_RV rv;
+
+       rv = load_registered_modules_unlocked ();
+       if (rv == CKR_OK) {
+               hash_iterate (gl.modules, &it);
+               while (hash_next (&it, NULL, (void**)&module)) {
+
+                       /* Skip all modules that aren't registered */
+                       if (!module->name)
+                               continue;
+
+                       rv = initialize_module_unlocked_reentrant (module, args);
+
+                       if (rv != CKR_OK)
+                               break;
+               }
+       }
+
+       return rv;
+}
+
+CK_RV
+p11_kit_initialize_registered (void)
+{
+       CK_C_INITIALIZE_ARGS args;
+       CK_RV rv;
+
+       /* WARNING: This function must be reentrant */
+
+       memset (&args, 0, sizeof (args));
+       args.CreateMutex = create_mutex;
+       args.DestroyMutex = destroy_mutex;
+       args.LockMutex = lock_mutex;
+       args.UnlockMutex = unlock_mutex;
+       args.flags = CKF_OS_LOCKING_OK;
+
+       _p11_lock ();
+
+               /* WARNING: Reentrancy can occur here */
+               rv = _p11_kit_initialize_registered_unlocked_reentrant (&args);
+
+       _p11_unlock ();
+
+       /* Cleanup any partial initialization */
+       if (rv != CKR_OK)
+               p11_kit_finalize_registered ();
+
+       return rv;
+}
+
+CK_RV
+_p11_kit_finalize_registered_unlocked_reentrant (CK_VOID_PTR args)
+{
+       Module *module;
+       hash_iter_t it;
+       Module **to_finalize;
+       int i, count;
+
+       if (!gl.modules)
+               return CKR_CRYPTOKI_NOT_INITIALIZED;
+
+       /* WARNING: This function must be reentrant */
+
+       to_finalize = calloc (hash_count (gl.modules), sizeof (Module*));
+       if (!to_finalize)
+               return CKR_HOST_MEMORY;
+
+       count = 0;
+       hash_iterate (gl.modules, &it);
+       while (hash_next (&it, NULL, (void**)&module)) {
+
+               /* Skip all modules that aren't registered */
+               if (module->name)
+                       to_finalize[count++] = module;
+       }
+
+       for (i = 0; i < count; ++i) {
+
+               /* WARNING: Reentrant calls can occur here */
+               finalize_module_unlocked_reentrant (to_finalize[i], args);
+       }
+
+       free (to_finalize);
+       return CKR_OK;
+}
+
+CK_RV
+p11_kit_finalize_registered (void)
+{
+       CK_RV rv;
+
+       /* WARNING: This function must be reentrant */
+
+       _p11_lock ();
+
+               /* WARNING: Reentrant calls can occur here */
+               rv = _p11_kit_finalize_registered_unlocked_reentrant (NULL);
+
+       _p11_unlock ();
+
+       return rv;
+}
+
+CK_FUNCTION_LIST_PTR_PTR
+_p11_kit_registered_modules_unlocked (void)
+{
+       CK_FUNCTION_LIST_PTR_PTR result;
+       Module *module;
+       hash_iter_t it;
+       int i = 0;
+
+       result = calloc (hash_count (gl.modules) + 1, sizeof (CK_FUNCTION_LIST_PTR));
+       if (result) {
+               hash_iterate (gl.modules, &it);
+               while (hash_next (&it, NULL, (void**)&module)) {
+                       if (module->ref_count && module->name)
+                               result[i++] = module->funcs;
+               }
+       }
+
+       return result;
+}
+
+CK_FUNCTION_LIST_PTR_PTR
+p11_kit_registered_modules (void)
+{
+       CK_FUNCTION_LIST_PTR_PTR result;
+
+       _p11_lock ();
+
+               result = _p11_kit_registered_modules_unlocked ();
+
+       _p11_unlock ();
+
+       return result;
+}
+
+char*
+p11_kit_registered_module_to_name (CK_FUNCTION_LIST_PTR funcs)
+{
+       Module *module;
+       char *name = NULL;
+
+       if (!funcs)
+               return NULL;
+
+       _p11_lock ();
+
+               module = gl.modules ? hash_get (gl.modules, funcs) : NULL;
+               if (module && module->name)
+                       name = strdup (module->name);
+
+       _p11_unlock ();
+
+       return name;
+}
+
+CK_FUNCTION_LIST_PTR
+p11_kit_registered_name_to_module (const char *name)
+{
+       CK_FUNCTION_LIST_PTR funcs = NULL;
+       Module *module;
+
+       _p11_lock ();
+
+               if (gl.modules) {
+                       module = find_module_for_name_unlocked (name);
+                       if (module)
+                               funcs = module->funcs;
+               }
+
+       _p11_unlock ();
+
+       return funcs;
+}
+
+char*
+p11_kit_registered_option (CK_FUNCTION_LIST_PTR funcs, const char *field)
+{
+       Module *module;
+       char *option = NULL;
+
+       if (!funcs || !field)
+               return NULL;
+
+       _p11_lock ();
+
+               module = gl.modules ? hash_get (gl.modules, funcs) : NULL;
+               if (module && module->config) {
+                       option = hash_get (module->config, field);
+                       if (option)
+                               option = strdup (option);
+               }
+
+       _p11_unlock ();
+
+       return option;
+}
+
+CK_RV
+p11_kit_initialize_module (CK_FUNCTION_LIST_PTR funcs, CK_C_INITIALIZE_ARGS_PTR init_args)
+{
+       Module *module;
+       Module *allocated = NULL;
+       CK_RV rv = CKR_OK;
+
+       /* WARNING: This function must be reentrant for the same arguments */
+
+       _p11_lock ();
+
+               rv = init_modules_unlocked ();
+               if (rv == CKR_OK) {
+
+                       module = hash_get (gl.modules, funcs);
+                       if (module == NULL) {
+                               allocated = module = calloc (1, sizeof (Module));
+                               module->funcs = funcs;
+                       }
+
+                       /* WARNING: Reentrancy can occur here */
+                       rv = initialize_module_unlocked_reentrant (module, init_args);
+
+                       /* If this was newly allocated, add it to the list */
+                       if (rv == CKR_OK && allocated) {
+                               hash_set (gl.modules, allocated->funcs, allocated);
+                               allocated = NULL;
+                       }
+
+                       free (allocated);
+               }
+
+       _p11_unlock ();
+
+       return rv;
+}
+
+CK_RV
+p11_kit_finalize_module (CK_FUNCTION_LIST_PTR funcs, CK_VOID_PTR reserved)
+{
+       Module *module;
+       CK_RV rv = CKR_OK;
+
+       /* WARNING: This function must be reentrant for the same arguments */
+
+       _p11_lock ();
+
+               module = gl.modules ? hash_get (gl.modules, funcs) : NULL;
+               if (module == NULL) {
+                       rv = CKR_ARGUMENTS_BAD;
+               } else {
+                       /* WARNING: Rentrancy can occur here */
+                       rv = finalize_module_unlocked_reentrant (module, reserved);
+               }
+
+       _p11_unlock ();
+
+       return rv;
+}
diff --git a/module/p11-kit-private.h b/module/p11-kit-private.h
new file mode 100644 (file)
index 0000000..d5498f8
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2011, Collabora Ltd.
+ *
+ * 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@collabora.co.uk>
+ */
+
+#ifndef __P11_KIT_PRIVATE_H__
+#define __P11_KIT_PRIVATE_H__
+
+extern pthread_mutex_t _p11_mutex;
+
+#define     _p11_lock()    pthread_mutex_lock (&_p11_mutex);
+
+#define     _p11_unlock()  pthread_mutex_unlock (&_p11_mutex);
+
+CK_FUNCTION_LIST_PTR_PTR   _p11_kit_registered_modules_unlocked (void);
+
+CK_RV       _p11_kit_initialize_registered_unlocked_reentrant   (CK_C_INITIALIZE_ARGS_PTR args);
+
+CK_RV       _p11_kit_finalize_registered_unlocked_reentrant     (CK_VOID_PTR args);
+
+
+#endif /* __P11_KIT_PRIVATE_H__ */
similarity index 69%
rename from module/p11-kit.c
rename to module/p11-kit-proxy.c
index ddce20973aaee2af626171d9331501e60a60eb07..b02722b5d45964955f4ec890e626548df130cb98 100644 (file)
 #include "hash.h"
 #include "pkcs11.h"
 #include "p11-kit.h"
+#include "p11-kit-private.h"
 
 #include <sys/types.h>
 #include <assert.h>
-#include <dirent.h>
-#include <dlfcn.h>
 #include <errno.h>
 #include <pthread.h>
 #include <stdarg.h>
@@ -67,27 +66,9 @@ typedef struct _Session {
        CK_SLOT_ID wrap_slot;
 } Session;
 
-typedef struct _Module {
-       char *name;
-       char *path;
-       void *dl_module;
-       CK_FUNCTION_LIST_PTR funcs;
-       int ref_count;
-       int initialize_count;
-       struct _Module *next;
-} Module;
-
 /* Forward declaration */
 static CK_FUNCTION_LIST proxy_function_list;
 
-/*
- * This is the mutex that protects the global data of this library
- * and the pkcs11 proxy module. Note that we *never* call into our
- * underlying pkcs11 modules while holding this mutex. Therefore it
- * doesn't have to be recursive and we can keep things simple.
- */
-static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-
 /*
  * Shared data between threads, protected by the mutex, a structure so
  * we can audit thread safety easier.
@@ -95,11 +76,10 @@ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 static struct _Shared {
        Mapping *mappings;
        unsigned int n_mappings;
-       hsh_t *sessions;
-       Module *modules;
+       int mappings_refs;
+       hash_t *sessions;
        CK_ULONG last_handle;
-       int registered_loaded;
-} gl = { NULL, 0, NULL, NULL, FIRST_HANDLE, 0 };
+} gl = { NULL, 0, 0, NULL, FIRST_HANDLE };
 
 #define MANUFACTURER_ID         "PKCS#11 Kit                     "
 #define LIBRARY_DESCRIPTION     "PKCS#11 Kit Proxy Module        "
@@ -110,71 +90,6 @@ static struct _Shared {
  * UTILITIES
  */
 
-static void
-warning (const char* msg, ...)
-{
-       char buffer[512];
-       va_list va;
-
-       va_start (va, msg);
-
-       vsnprintf(buffer, sizeof (buffer) - 1, msg, va);
-       buffer[sizeof (buffer) - 1] = 0;
-       fprintf (stderr, "p11-kit: %s\n", buffer);
-
-       va_end (va);
-}
-
-static char*
-strconcat (const char *first, ...)
-{
-       size_t length = 0;
-       const char *arg;
-       char *result, *at;
-       va_list va;
-
-       va_start (va, first);
-
-       for (arg = first; arg; arg = va_arg (va, const char*))
-               length += strlen (arg);
-
-       va_end (va);
-
-       at = result = malloc (length);
-       if (!result)
-               return NULL;
-
-       va_start (va, first);
-
-       for (arg = first; arg; arg = va_arg (va, const char*)) {
-               length = strlen (arg);
-               memcpy (at, arg, length);
-               at += length;
-       }
-
-       va_end (va);
-
-       *at = 0;
-       return result;
-}
-
-static int
-ends_with (const char *haystack, const char *needle)
-{
-       size_t haystack_len, needle_len;
-
-       assert (haystack);
-       assert (needle);
-
-       haystack_len = strlen (haystack);
-       needle_len = strlen (needle);
-
-       if (needle_len > haystack_len)
-               return 0;
-       return memcmp (haystack + (haystack_len - needle_len),
-                      needle, needle_len) == 0;
-}
-
 static void*
 xrealloc (void * memory, size_t length)
 {
@@ -184,516 +99,6 @@ xrealloc (void * memory, size_t length)
        return allocated;
 }
 
-/* -----------------------------------------------------------------------------
- * P11-KIT FUNCTIONALITY
- */
-
-static CK_RV
-load_module_unlocked (const char *name, Module *module)
-{
-       CK_C_GetFunctionList gfl;
-       CK_RV rv;
-
-       /*
-        * TODO: This function will change significantly once we're loading
-        * from a config, see below.
-        */
-       assert (name);
-       assert (module);
-
-       module->name = strdup (name);
-       if (!module->name)
-               return CKR_HOST_MEMORY;
-
-       module->path = strconcat (PKCS11_MODULE_PATH, "/", name, NULL);
-       if (!module->path)
-               return CKR_HOST_MEMORY;
-
-       module->dl_module = dlopen (module->path, RTLD_LOCAL | RTLD_NOW);
-       if (module->dl_module == NULL) {
-               warning ("couldn't load module: %s: %s",
-                        module->path, dlerror ());
-               return CKR_GENERAL_ERROR;
-       }
-
-       gfl = dlsym (module->dl_module, "C_GetFunctionList");
-       if (!gfl) {
-               warning ("couldn't find C_GetFunctionList entry point in module: %s: %s",
-                        module->path, dlerror ());
-               return CKR_GENERAL_ERROR;
-       }
-
-       rv = gfl (&module->funcs);
-       if (rv != CKR_OK) {
-               warning ("call to C_GetFunctiontList failed in module: %s: %lu",
-                        module->path, (unsigned long)rv);
-               return rv;
-       }
-
-       return CKR_OK;
-}
-
-static void
-unload_module_unlocked (Module *module)
-{
-       assert (module);
-
-       /* Should have been finalized before this */
-       assert (!module->initialize_count);
-
-       if (module->dl_module) {
-               dlclose (module->dl_module);
-               module->dl_module = NULL;
-       }
-
-       free (module->path);
-       module->path = NULL;
-
-       free (module->name);
-       module->name = NULL;
-
-       module->funcs = NULL;
-}
-
-static CK_RV
-load_registered_modules_unlocked (void)
-{
-       struct dirent *dp;
-       Module *module;
-       DIR *dir;
-       CK_RV rv;
-
-       /* First we load all the modules */
-       dir = opendir (PKCS11_MODULE_PATH);
-
-       /* We're within a global mutex, so readdir is safe */
-       while ((dp = readdir(dir)) != NULL) {
-               if ((dp->d_type == DT_LNK || dp->d_type == DT_REG) &&
-                   !ends_with (dp->d_name, ".la")) {
-
-                       module = calloc (sizeof (Module), 1);
-                       if (!module)
-                               rv = CKR_HOST_MEMORY;
-                       else
-                               rv = load_module_unlocked (dp->d_name, module);
-
-                       /* Cleanup for failures happens at caller */
-                       module->next = gl.modules;
-                       gl.modules = module;
-
-                       if (rv != CKR_OK)
-                               break;
-               }
-       }
-
-       closedir (dir);
-
-       return rv;
-}
-
-static CK_RV
-create_mutex (CK_VOID_PTR_PTR mut)
-{
-       pthread_mutex_t *pmutex;
-       int err;
-
-       pmutex = malloc (sizeof (pthread_mutex_t));
-       if (!pmutex)
-               return CKR_HOST_MEMORY;
-       err = pthread_mutex_init (pmutex, NULL);
-       if (err == ENOMEM)
-               return CKR_HOST_MEMORY;
-       else if (err != 0)
-               return CKR_GENERAL_ERROR;
-       *mut = pmutex;
-       return CKR_OK;
-}
-
-static CK_RV
-destroy_mutex (CK_VOID_PTR mut)
-{
-       pthread_mutex_t *pmutex = mut;
-       int err;
-
-       err = pthread_mutex_destroy (pmutex);
-       if (err == EINVAL)
-               return CKR_MUTEX_BAD;
-       else if (err != 0)
-               return CKR_GENERAL_ERROR;
-       free (pmutex);
-       return CKR_OK;
-}
-
-static CK_RV
-lock_mutex (CK_VOID_PTR mut)
-{
-       pthread_mutex_t *pmutex = mut;
-       int err;
-
-       err = pthread_mutex_lock (pmutex);
-       if (err == EINVAL)
-               return CKR_MUTEX_BAD;
-       else if (err != 0)
-               return CKR_GENERAL_ERROR;
-       return CKR_OK;
-}
-
-static CK_RV
-unlock_mutex (CK_VOID_PTR mut)
-{
-       pthread_mutex_t *pmutex = mut;
-       int err;
-
-       err = pthread_mutex_unlock (pmutex);
-       if (err == EINVAL)
-               return CKR_MUTEX_BAD;
-       else if (err == EPERM)
-               return CKR_MUTEX_NOT_LOCKED;
-       else if (err != 0)
-               return CKR_GENERAL_ERROR;
-       return CKR_OK;
-}
-
-static CK_RV
-initialize_module_unlocked_reentrant (Module *module, CK_C_INITIALIZE_ARGS_PTR args)
-{
-       CK_RV rv = CKR_OK;
-
-       assert (module);
-
-       /*
-        * Initialize first, so module doesn't get freed out from
-        * underneath us when the mutex is unlocked below.
-        */
-       ++module->ref_count;
-
-       if (!module->initialize_count) {
-
-               pthread_mutex_unlock (&mutex);
-
-                       assert (module->funcs);
-                       rv = module->funcs->C_Initialize (args);
-
-               pthread_mutex_lock (&mutex);
-
-               /*
-                * Because we have the mutex unlocked above, two initializes could
-                * race. Therefore we need to take CKR_CRYPTOKI_ALREADY_INITIALIZED
-                * into account.
-                *
-                * We also need to take into account where in a race both calls return
-                * CKR_OK (which is not according to the spec but may happen, I mean we
-                * do it in this module, so it's not unimaginable).
-                */
-
-               if (rv == CKR_OK)
-                       ++module->initialize_count;
-               else if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED)
-                       rv = CKR_OK;
-               else
-                       --module->ref_count;
-       }
-
-       return rv;
-}
-
-static CK_RV
-finalize_module_unlocked_reentrant (Module *module, CK_VOID_PTR args)
-{
-       Module *mod, *next;
-
-       assert (module);
-
-       /*
-        * We leave module info around until all are finalized
-        * so we can encounter these zombie Module structures.
-        */
-       if (module->ref_count == 0)
-               return CKR_ARGUMENTS_BAD;
-
-       if (--module->ref_count > 0)
-               return CKR_OK;
-
-       /*
-        * Becuase of the mutex unlock below, we temporarily increase
-        * the ref count. This prevents module from being freed out
-        * from ounder us.
-        */
-       ++module->ref_count;
-
-       while (module->initialize_count > 0) {
-
-               pthread_mutex_unlock (&mutex);
-
-                       assert (module->funcs);
-                       module->funcs->C_Finalize (args);
-
-               pthread_mutex_lock (&mutex);
-
-               if (module->initialize_count > 0)
-                       --module->initialize_count;
-       }
-
-       /* Match the increment above */
-       --module->ref_count;
-
-       /* Check if any modules have a ref count */
-       for (mod = gl.modules; mod; mod = mod->next) {
-               if (mod->ref_count)
-                       break;
-       }
-
-       /* No modules had a refcount? unload and free all info */
-       if (mod == NULL) {
-               for (mod = gl.modules; mod; mod = next) {
-                       next = mod->next;
-                       unload_module_unlocked (mod);
-                       free (mod);
-               }
-               gl.modules = NULL;
-               gl.registered_loaded = 0;
-       }
-
-       return CKR_OK;
-}
-
-static Module*
-find_module_for_funcs_unlocked (CK_FUNCTION_LIST_PTR funcs)
-{
-       Module *module;
-
-       assert (funcs);
-
-       for (module = gl.modules; module; module = module->next)
-               if (module->ref_count && module->funcs == funcs)
-                       return module;
-       return NULL;
-}
-
-static Module*
-find_module_for_name_unlocked (const char *name)
-{
-       Module *module;
-
-       assert (name);
-
-       for (module = gl.modules; module; module = module->next)
-               if (module->ref_count && module->name && strcmp (name, module->name))
-                       return module;
-       return NULL;
-}
-
-static CK_RV
-initialize_registered_unlocked_reentrant (CK_C_INITIALIZE_ARGS_PTR args)
-{
-       Module *module;
-       CK_RV rv;
-
-       rv = load_registered_modules_unlocked ();
-       if (rv == CKR_OK) {
-               for (module = gl.modules; module; module = module->next) {
-
-                       /* Skip all modules that aren't registered */
-                       if (!module->name)
-                               continue;
-
-                       rv = initialize_module_unlocked_reentrant (module, args);
-
-                       if (rv != CKR_OK)
-                               break;
-               }
-       }
-
-       return rv;
-}
-
-CK_RV
-p11_kit_initialize_registered (void)
-{
-       CK_C_INITIALIZE_ARGS args;
-       CK_RV rv;
-
-       /* WARNING: This function must be reentrant */
-
-       memset (&args, 0, sizeof (args));
-       args.CreateMutex = create_mutex;
-       args.DestroyMutex = destroy_mutex;
-       args.LockMutex = lock_mutex;
-       args.UnlockMutex = unlock_mutex;
-       args.flags = CKF_OS_LOCKING_OK;
-
-       pthread_mutex_lock (&mutex);
-
-               /* WARNING: Reentrancy can occur here */
-               rv = initialize_registered_unlocked_reentrant (&args);
-
-       pthread_mutex_unlock (&mutex);
-
-       /* Cleanup any partial initialization */
-       if (rv != CKR_OK)
-               p11_kit_finalize_registered ();
-
-       return rv;
-}
-
-static CK_RV
-finalize_registered_unlocked_reentrant (CK_VOID_PTR args)
-{
-       Module *module;
-
-       /* WARNING: This function must be reentrant */
-
-       for (module = gl.modules; module; module = module->next) {
-
-               /* Skip all modules that aren't registered */
-               if (!module->name)
-                       continue;
-
-               /* WARNING: Reentrant calls can occur here */
-               finalize_module_unlocked_reentrant (module, args);
-       }
-
-       return CKR_OK;
-}
-CK_RV
-p11_kit_finalize_registered (void)
-{
-       CK_RV rv;
-
-       /* WARNING: This function must be reentrant */
-
-       pthread_mutex_lock (&mutex);
-
-               /* WARNING: Reentrant calls can occur here */
-               rv = finalize_registered_unlocked_reentrant (NULL);
-
-       pthread_mutex_unlock (&mutex);
-
-       return rv;
-}
-
-char**
-p11_kit_registered_names (void)
-{
-       Module *module;
-       char **result;
-       int count, i;
-
-       pthread_mutex_lock (&mutex);
-
-               for (module = gl.modules, count = 0;
-                    module; module = module->next)
-                       ++count;
-               result = calloc (count + 1, sizeof (char*));
-               if (result) {
-                       for (module = gl.modules, i = 0;
-                            module; module = module->next, ++i)
-                               result[i] = strdup (module->name);
-               }
-
-       pthread_mutex_unlock (&mutex);
-
-       return result;
-}
-
-CK_FUNCTION_LIST_PTR
-p11_kit_registered_module (const char *module_name)
-{
-       CK_FUNCTION_LIST_PTR result;
-       Module *module;
-
-       if (!module_name)
-               return NULL;
-
-       pthread_mutex_lock (&mutex);
-
-               module = find_module_for_name_unlocked (module_name);
-               if (module) {
-                       assert (module);
-                       result = module->funcs;
-               }
-
-       pthread_mutex_unlock (&mutex);
-
-       return result;
-}
-
-void
-p11_kit_free_names (char **module_names)
-{
-       char **name;
-       for (name = module_names; *name; ++name)
-               free (name);
-}
-
-char*
-p11_kit_registered_option (const char *module_name, const char *field)
-{
-       /* TODO: Need to implement */
-       assert (0);
-       return NULL;
-}
-
-CK_RV
-p11_kit_initialize_module (CK_FUNCTION_LIST_PTR funcs, CK_C_INITIALIZE_ARGS_PTR init_args)
-{
-       Module *module;
-       Module *allocated = NULL;
-       CK_RV rv = CKR_OK;
-
-       /* WARNING: This function must be reentrant for the same arguments */
-
-       pthread_mutex_lock (&mutex);
-
-               module = find_module_for_funcs_unlocked (funcs);
-               if (module == NULL) {
-                       allocated = module = calloc (1, sizeof (Module));
-                       module->name = NULL;
-                       module->dl_module = NULL;
-                       module->path = NULL;
-                       module->funcs = funcs;
-               }
-
-               /* WARNING: Reentrancy can occur here */
-               rv = initialize_module_unlocked_reentrant (module, init_args);
-
-               /* If this was newly allocated, add it to the list */
-               if (rv == CKR_OK && allocated) {
-                       allocated->next = gl.modules;
-                       gl.modules = allocated;
-                       allocated = NULL;
-               }
-
-               free (allocated);
-
-       pthread_mutex_unlock (&mutex);
-
-       return rv;
-}
-
-CK_RV
-p11_kit_finalize_module (CK_FUNCTION_LIST_PTR funcs, CK_VOID_PTR reserved)
-{
-       Module *module;
-       CK_RV rv = CKR_OK;
-
-       /* WARNING: This function must be reentrant for the same arguments */
-
-       pthread_mutex_lock (&mutex);
-
-               module = find_module_for_funcs_unlocked (funcs);
-               if (module == NULL) {
-                       rv = CKR_ARGUMENTS_BAD;
-               } else {
-                       /* WARNING: Rentrancy can occur here */
-                       rv = finalize_module_unlocked_reentrant (module, reserved);
-               }
-
-       pthread_mutex_unlock (&mutex);
-
-       return rv;
-}
-
 /* -----------------------------------------------------------------------------
  * PKCS#11 PROXY MODULE
  */
@@ -723,7 +128,7 @@ map_slot_to_real (CK_SLOT_ID_PTR slot, Mapping *mapping)
 
        assert (mapping);
 
-       pthread_mutex_lock (&mutex);
+       _p11_lock ();
 
                if (!gl.mappings)
                        rv = CKR_CRYPTOKI_NOT_INITIALIZED;
@@ -732,7 +137,7 @@ map_slot_to_real (CK_SLOT_ID_PTR slot, Mapping *mapping)
                if (rv == CKR_OK)
                        *slot = mapping->real_slot;
 
-       pthread_mutex_unlock (&mutex);
+       _p11_unlock ();
 
        return rv;
 }
@@ -746,13 +151,13 @@ map_session_to_real (CK_SESSION_HANDLE_PTR handle, Mapping *mapping, Session *se
        assert (handle);
        assert (mapping);
 
-       pthread_mutex_lock (&mutex);
+       _p11_lock ();
 
                if (!gl.sessions) {
                        rv = CKR_CRYPTOKI_NOT_INITIALIZED;
                } else {
                        assert (gl.sessions);
-                       sess = hsh_get (gl.sessions, handle, sizeof (handle));
+                       sess = hash_get (gl.sessions, &handle);
                        if (sess != NULL) {
                                *handle = sess->real_session;
                                rv = map_slot_unlocked (sess->wrap_slot, mapping);
@@ -763,7 +168,7 @@ map_session_to_real (CK_SESSION_HANDLE_PTR handle, Mapping *mapping, Session *se
                        }
                }
 
-       pthread_mutex_unlock (&mutex);
+       _p11_unlock ();
 
        return rv;
 }
@@ -771,7 +176,10 @@ map_session_to_real (CK_SESSION_HANDLE_PTR handle, Mapping *mapping, Session *se
 static void
 finalize_mappings_unlocked (void)
 {
-       hsh_index_t *iter;
+       assert (gl.mappings_refs);
+
+       if (--gl.mappings_refs)
+               return;
 
        /* No more mappings */
        free (gl.mappings);
@@ -779,12 +187,8 @@ finalize_mappings_unlocked (void)
        gl.n_mappings = 0;
 
        /* no more sessions */
-       if (gl.sessions) {
-               for (iter = hsh_first (gl.sessions); iter; iter = hsh_next (iter))
-                       free (hsh_this (iter, NULL, NULL));
-               hsh_free (gl.sessions);
-               gl.sessions = NULL;
-       }
+       hash_free (gl.sessions);
+       gl.sessions = NULL;
 }
 
 static CK_RV
@@ -797,19 +201,19 @@ proxy_C_Finalize (CK_VOID_PTR reserved)
        if (reserved)
                return CKR_ARGUMENTS_BAD;
 
-       pthread_mutex_lock (&mutex);
+       _p11_lock ();
 
                /* WARNING: Reentrancy can occur here */
-               rv = finalize_registered_unlocked_reentrant (reserved);
+               rv = _p11_kit_finalize_registered_unlocked_reentrant (reserved);
 
                /*
                 * If modules are all gone, then this was the last
                 * finalize, so cleanup our mappings
                 */
-               if (gl.modules == NULL)
+               if (gl.mappings_refs)
                        finalize_mappings_unlocked ();
 
-       pthread_mutex_unlock (&mutex);
+       _p11_unlock ();
 
        return rv;
 }
@@ -817,27 +221,24 @@ proxy_C_Finalize (CK_VOID_PTR reserved)
 static CK_RV
 initialize_mappings_unlocked_reentrant (void)
 {
+       CK_FUNCTION_LIST_PTR *funcss, *f;
        CK_FUNCTION_LIST_PTR funcs;
        Mapping *mappings = NULL;
        int n_mappings = 0;
        CK_SLOT_ID_PTR slots;
        CK_ULONG i, count;
-       Module *module;
        CK_RV rv;
 
        assert (!gl.mappings);
 
-       for (module = gl.modules; module; module = module->next) {
+       funcss = _p11_kit_registered_modules_unlocked ();
+       for (f = funcss; *f; ++f) {
+               funcs = *f;
 
-               /* Only do registered modules */
-               if (module->ref_count && !module->name)
-                       continue;
-
-               funcs = module->funcs;
                assert (funcs);
                slots = NULL;
 
-               pthread_mutex_unlock (&mutex);
+               _p11_unlock ();
 
                        /* Ask module for its slots */
                        rv = (funcs->C_GetSlotList) (FALSE, NULL, &count);
@@ -849,7 +250,7 @@ initialize_mappings_unlocked_reentrant (void)
                                        rv = (funcs->C_GetSlotList) (FALSE, slots, &count);
                        }
 
-               pthread_mutex_lock (&mutex);
+               _p11_lock ();
 
                if (rv != CKR_OK) {
                        free (slots);
@@ -881,7 +282,8 @@ initialize_mappings_unlocked_reentrant (void)
        }
 
        assert (!gl.sessions);
-       gl.sessions = hsh_create ();
+       gl.sessions = hash_create (hash_ulongptr_hash, hash_ulongptr_equal, NULL, free);
+       ++gl.mappings_refs;
 
        /* Any cleanup necessary for failure will happen at caller */
        return rv;
@@ -894,16 +296,16 @@ proxy_C_Initialize (CK_VOID_PTR init_args)
 
        /* WARNING: This function must be reentrant */
 
-       pthread_mutex_lock (&mutex);
+       _p11_lock ();
 
                /* WARNING: Reentrancy can occur here */
-               rv = initialize_registered_unlocked_reentrant (init_args);
+               rv = _p11_kit_initialize_registered_unlocked_reentrant (init_args);
 
                /* WARNING: Reentrancy can occur here */
-               if (rv == CKR_OK && !gl.mappings)
+               if (rv == CKR_OK && !gl.mappings_refs == 0)
                        rv = initialize_mappings_unlocked_reentrant ();
 
-       pthread_mutex_unlock (&mutex);
+       _p11_unlock ();
 
        if (rv != CKR_OK)
                proxy_C_Finalize (NULL);
@@ -919,12 +321,12 @@ proxy_C_GetInfo (CK_INFO_PTR info)
        if (info == NULL)
                return CKR_ARGUMENTS_BAD;
 
-       pthread_mutex_lock (&mutex);
+       _p11_lock ();
 
                if (!gl.mappings)
                        rv = CKR_CRYPTOKI_NOT_INITIALIZED;
 
-       pthread_mutex_unlock (&mutex);
+       _p11_unlock ();
 
        if (rv != CKR_OK)
                return rv;
@@ -963,7 +365,7 @@ proxy_C_GetSlotList (CK_BBOOL token_present, CK_SLOT_ID_PTR slot_list,
        if (!count)
                return CKR_ARGUMENTS_BAD;
 
-       pthread_mutex_lock (&mutex);
+       _p11_lock ();
 
                if (!gl.mappings) {
                        rv = CKR_CRYPTOKI_NOT_INITIALIZED;
@@ -996,7 +398,7 @@ proxy_C_GetSlotList (CK_BBOOL token_present, CK_SLOT_ID_PTR slot_list,
                        *count = index;
                }
 
-       pthread_mutex_unlock (&mutex);
+       _p11_unlock ();
 
        return rv;
 }
@@ -1087,7 +489,7 @@ proxy_C_OpenSession (CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR user_data,
        rv = (map.funcs->C_OpenSession) (id, flags, user_data, callback, handle);
 
        if (rv == CKR_OK) {
-               pthread_mutex_lock (&mutex);
+               _p11_lock ();
 
                        if (!gl.sessions) {
                                /*
@@ -1103,11 +505,11 @@ proxy_C_OpenSession (CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR user_data,
                                sess->wrap_slot = map.wrap_slot;
                                sess->real_session = *handle;
                                sess->wrap_session = ++gl.last_handle; /* TODO: Handle wrapping, and then collisions */
-                               hsh_set (gl.sessions, &sess->wrap_session, sizeof (sess->wrap_session), sess);
+                               hash_set (gl.sessions, &sess->wrap_session, sess);
                                *handle = sess->wrap_session;
                        }
 
-               pthread_mutex_unlock (&mutex);
+               _p11_unlock ();
        }
 
        return rv;
@@ -1127,12 +529,12 @@ proxy_C_CloseSession (CK_SESSION_HANDLE handle)
        rv = (map.funcs->C_CloseSession) (handle);
 
        if (rv == CKR_OK) {
-               pthread_mutex_lock (&mutex);
+               _p11_lock ();
 
                        if (gl.sessions)
-                               hsh_rem (gl.sessions, &key, sizeof (key));
+                               hash_remove (gl.sessions, &key);
 
-               pthread_mutex_unlock (&mutex);
+               _p11_unlock ();
        }
 
        return rv;
@@ -1144,28 +546,28 @@ proxy_C_CloseAllSessions (CK_SLOT_ID id)
        CK_SESSION_HANDLE_PTR to_close;
        CK_RV rv = CKR_OK;
        Session *sess;
-       CK_ULONG i, count;
-       hsh_index_t *iter;
+       CK_ULONG i, count = 0;
+       hash_iter_t iter;
 
-       pthread_mutex_lock (&mutex);
+       _p11_lock ();
 
                if (!gl.sessions) {
                        rv = CKR_CRYPTOKI_NOT_INITIALIZED;
                } else {
-                       to_close = calloc (sizeof (CK_SESSION_HANDLE), hsh_count (gl.sessions));
+                       to_close = calloc (sizeof (CK_SESSION_HANDLE), hash_count (gl.sessions));
                        if (!to_close) {
                                rv = CKR_HOST_MEMORY;
                        } else {
-                               for (iter = hsh_first (gl.sessions), count = 0;
-                                    iter; iter = hsh_next (iter)) {
-                                       sess = hsh_this (iter, NULL, NULL);
+                               hash_iterate (gl.sessions, &iter);
+                               count = 0;
+                               while (hash_next (&iter, NULL, (void**)&sess)) {
                                        if (sess->wrap_slot == id && to_close)
                                                to_close[count++] = sess->wrap_session;
                                }
                        }
                }
 
-       pthread_mutex_unlock (&mutex);
+       _p11_unlock ();
 
        if (rv != CKR_OK)
                return rv;
index 88b0b8a6cf862b76e5e94d5d1972ba2e1e356094..919d6b86e975e3931646f5b4fbffabf137a4cb8e 100644 (file)
@@ -39,19 +39,19 @@ CK_RV                    p11_kit_initialize_registered     (void);
 
 CK_RV                    p11_kit_finalize_registered       (void);
 
-char**                   p11_kit_registered_names          (void);
+CK_FUNCTION_LIST_PTR*    p11_kit_registered_modules        (void);
 
-CK_FUNCTION_LIST_PTR     p11_kit_registered_module         (const char *module_name);
+char*                    p11_kit_registered_module_to_name (CK_FUNCTION_LIST_PTR funcs);
 
-void                     p11_kit_free_names                (char **module_names);
+CK_FUNCTION_LIST_PTR     p11_kit_registered_name_to_module (const char *name);
 
-char*                    p11_kit_registered_option         (const char *module_name,
+char*                    p11_kit_registered_option         (CK_FUNCTION_LIST_PTR funcs,
                                                             const char *field);
 
-CK_RV                    p11_kit_initialize_module         (CK_FUNCTION_LIST_PTR module,
+CK_RV                    p11_kit_initialize_module         (CK_FUNCTION_LIST_PTR funcs,
                                                             CK_C_INITIALIZE_ARGS_PTR init_args);
 
-CK_RV                    p11_kit_finalize_module           (CK_FUNCTION_LIST_PTR module,
+CK_RV                    p11_kit_finalize_module           (CK_FUNCTION_LIST_PTR funcs,
                                                             CK_VOID_PTR reserved);
 
 #endif /* __P11_KIT_H__ */