]> granicus.if.org Git - p11-kit/commitdiff
Implement support for registering and calling pinfile callbacks
authorStef Walter <stefw@collabora.co.uk>
Mon, 20 Jun 2011 19:17:03 +0000 (21:17 +0200)
committerStef Walter <stefw@collabora.co.uk>
Wed, 6 Jul 2011 10:49:26 +0000 (12:49 +0200)
 * These are callbacks that hanlde the pinfile part of a PKCS#11 URI.
 * One library can register a callback that another can then call
   in a thread-safe and simple fashion.

.gitignore
p11-kit/Makefile.am
p11-kit/pin.c [new file with mode: 0644]
p11-kit/pin.h [new file with mode: 0644]
p11-kit/ptr-array.c [new file with mode: 0644]
p11-kit/ptr-array.h [new file with mode: 0644]
tests/Makefile.am
tests/pin-test.c [new file with mode: 0644]
tests/ptr-array-test.c [new file with mode: 0644]

index a844dce640031d55ec26c6ba0fea7933fd0ab089..c5a95f59ad7b222bc45051d9ff57d02abad083b2 100644 (file)
@@ -67,6 +67,8 @@ temp.txt
 /tests/coverage
 /tests/coverage.info
 /tests/hash-test
+/tests/pin-test
+/tests/ptr-array-test
 /tests/conf-test
 /tests/uri-test
 
index 9afc6b6ca2fbc6102bcb281a9edcc53f81fb339a..9366a05f7a9eb473262eedc4d4890a0e31fd97b4 100644 (file)
@@ -7,6 +7,7 @@ incdir = $(includedir)/p11-kit-1/p11-kit
 
 inc_HEADERS = \
        p11-kit.h \
+       pin.h \
        uri.h \
        pkcs11.h
 
@@ -16,8 +17,10 @@ MODULE_SRCS = \
        debug.c debug.h \
        hash.c hash.h \
        modules.c \
+       pin.c \
        proxy.c \
        private.h \
+       ptr-array.c ptr-array.h \
        messages.c \
        uri.c \
        $(inc_HEADERS)
diff --git a/p11-kit/pin.c b/p11-kit/pin.c
new file mode 100644 (file)
index 0000000..328785f
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * 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>
+ */
+
+#include "config.h"
+
+#define DEBUG_FLAG DEBUG_PIN
+#include "debug.h"
+#include "hash.h"
+#include "pkcs11.h"
+#include "p11-kit.h"
+#include "pin.h"
+#include "private.h"
+#include "ptr-array.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * SECTION:p11-pin
+ * @title: PIN Callbacks
+ * @short_description: PIN Callbacks
+ *
+ * Applications can register a callback which will be called to provide a password
+ * associated with a given pin file.
+ * PKCS\#11 URIs can be used in configuration files or applications to represent
+ * PKCS\#11 modules, tokens or objects. An example of a URI might be:
+ *
+ * <code><literallayout>
+ *      pkcs11:token=The\%20Software\%20PKCS\#11\%20softtoken;
+ *          manufacturer=Snake\%20Oil,\%20Inc.;serial=;object=my-certificate;
+ *          model=1.0;objecttype=cert;id=\%69\%95\%3e\%5c\%f4\%bd\%ec\%91
+ * </literallayout></code>
+ *
+ * You can use p11_kit_uri_parse() to parse such a URI, and p11_kit_uri_format()
+ * to build one. URIs are represented by the #P11KitUri structure. You can match
+ * a parsed URI against PKCS\#11 tokens with p11_kit_uri_match_token_info()
+ * or attributes with p11_kit_uri_match_attributes().
+ *
+ * Since URIs can represent different sorts of things, when parsing or formatting
+ * a URI a 'context' can be used to indicate which sort of URI is expected.
+ *
+ * URIs have an <code>unrecognized</code> flag. This flag is set during parsing
+ * if any parts of the URI are not recognized. This may be because the part is
+ * from a newer version of the PKCS\#11 spec or because that part was not valid
+ * inside of the desired context used when parsing.
+ */
+
+/**
+ * P11KitUri:
+ *
+ * A structure representing a PKCS\#11 URI. There are no public fields
+ * visible in this structure. Use the various accessor functions.
+ */
+
+/**
+ * P11KitUriType:
+ * @P11_KIT_URI_FOR_OBJECT: The URI represents one or more objects
+ * @P11_KIT_URI_FOR_TOKEN: The URI represents one or more tokens
+ * @P11_KIT_URI_FOR_MODULE: The URI represents one or more modules
+ * @P11_KIT_URI_FOR_MODULE_WITH_VERSION: The URI represents a module with
+ *     a specific version.
+ * @P11_KIT_URI_FOR_OBJECT_ON_TOKEN: The URI represents one or more objects
+ *     that are present on a specific token.
+ * @P11_KIT_URI_FOR_OBJECT_ON_TOKEN_AND_MODULE: The URI represents one or more
+ *     objects that are present on a specific token, being used with a certain
+ *     module.
+ * @P11_KIT_URI_FOR_ANY: The URI can represent anything
+ *
+ * A PKCS\#11 URI can represent different kinds of things. This flag is used by
+ * p11_kit_uri_parse() to denote in what context the URI will be used.
+ *
+ * The various types can be combined.
+ */
+
+/**
+ * P11KitUriResult:
+ * @P11_KIT_URI_OK: Success
+ * @P11_KIT_URI_NO_MEMORY: Memory allocation failed
+ * @P11_KIT_URI_BAD_SCHEME: The URI had a bad scheme
+ * @P11_KIT_URI_BAD_ENCODING: The URI had a bad encoding
+ * @P11_KIT_URI_BAD_SYNTAX: The URI had a bad syntax
+ * @P11_KIT_URI_BAD_VERSION: The URI contained a bad version number
+ * @P11_KIT_URI_NOT_FOUND: A requested part of the URI was not found
+ *
+ * Error codes returned by various functions. The functions each clearly state
+ * which error codes they are capable of returning.
+ */
+
+/**
+ * P11_KIT_URI_SCHEME:
+ *
+ * String of URI scheme for PKCS\#11 URIs.
+ */
+
+/**
+ * P11_KIT_URI_SCHEME_LEN:
+ *
+ * Length of %P11_KIT_URI_SCHEME.
+ */
+
+typedef struct _PinfileCallback {
+       /* Only used/modified within the lock */
+       int refs;
+
+       /* Readonly after construct */
+       p11_kit_pin_callback func;
+       void *user_data;
+       p11_kit_pin_callback_destroy destroy;
+} PinfileCallback;
+
+/*
+ * Shared data between threads, protected by the mutex, a structure so
+ * we can audit thread safety easier.
+ */
+static struct _Shared {
+       hash_t *pinfiles;
+} gl = { NULL };
+
+static void*
+ref_pinfile_callback (void *pointer)
+{
+       PinfileCallback *cb = pointer;
+       cb->refs++;
+       return pointer;
+}
+
+static void
+unref_pinfile_callback (void *pointer)
+{
+       PinfileCallback *cb = pointer;
+       assert (cb->refs >= 1);
+
+       cb->refs--;
+       if (cb->refs == 0) {
+               if (cb->destroy)
+                       (cb->destroy) (cb->user_data);
+               free (cb);
+       }
+}
+
+int
+p11_kit_pin_register_callback (const char *pinfile, p11_kit_pin_callback callback,
+                               void *callback_data, p11_kit_pin_callback_destroy callback_destroy)
+{
+       PinfileCallback *cb;
+       ptr_array_t *callbacks;
+       char *name;
+       int ret;
+
+       cb = calloc (1, sizeof (PinfileCallback));
+       if (cb == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       name = strdup (pinfile);
+       if (name == NULL) {
+               free (cb);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       cb->refs = 1;
+       cb->func = callback;
+       cb->user_data = callback_data;
+       cb->destroy = callback_destroy;
+
+       _p11_lock ();
+
+               if (gl.pinfiles == NULL) {
+                       gl.pinfiles = hash_create (hash_string_hash, hash_string_equal,
+                                                  free, (hash_destroy_func)ptr_array_free);
+                       if (gl.pinfiles == NULL) {
+                               errno = ENOMEM;
+                               ret = -1;
+                       }
+               }
+
+               if (gl.pinfiles != NULL)
+                       callbacks = hash_get (gl.pinfiles, pinfile);
+
+               if (callbacks == NULL) {
+                       callbacks = ptr_array_create (unref_pinfile_callback);
+                       if (callbacks == NULL) {
+                               errno = ENOMEM;
+                               ret = -1;
+                       } else if (!hash_set (gl.pinfiles, name, callbacks)) {
+                               ptr_array_free (callbacks);
+                               callbacks = NULL;
+                               errno = ENOMEM;
+                               ret = -1;
+                       } else {
+                               /* Note that we've consumed the name */
+                               name = NULL;
+                       }
+               }
+
+               if (callbacks != NULL) {
+                       if (ptr_array_add (callbacks, cb) < 0) {
+                               errno = ENOMEM;
+                               ret = -1;
+                       } else {
+                               /* Note that we've consumed the callback */
+                               cb = NULL;
+                       }
+               }
+
+       _p11_unlock ();
+
+       /* Unless consumed above */
+       free (name);
+       if (cb != NULL)
+               unref_pinfile_callback (cb);
+
+       return ret;
+}
+
+void
+p11_kit_pin_unregister_callback (const char *pinfile, p11_kit_pin_callback callback,
+                                 void *callback_data)
+{
+       PinfileCallback *cb;
+       ptr_array_t *callbacks;
+       unsigned int i;
+
+       _p11_lock ();
+
+               if (gl.pinfiles) {
+                       callbacks = hash_get (gl.pinfiles, pinfile);
+                       if (callbacks) {
+                               for (i = 0; i < ptr_array_count (callbacks); i++) {
+                                       cb = ptr_array_at (callbacks, i);
+                                       if (cb->func == callback && cb->user_data == callback_data) {
+                                               ptr_array_remove (callbacks, i);
+                                               break;
+                                       }
+                               }
+
+                               if (ptr_array_count (callbacks) == 0)
+                                       hash_remove (gl.pinfiles, pinfile);
+                       }
+
+                       /* When there are no more pinfiles, get rid of the hash table */
+                       if (hash_count (gl.pinfiles) == 0) {
+                               hash_free (gl.pinfiles);
+                               gl.pinfiles = NULL;
+                       }
+               }
+
+       _p11_unlock ();
+}
+
+int
+p11_kit_pin_read_pinfile (const char *pinfile, P11KitUri *pin_uri,
+                          const char *pin_description, P11KitPinFlags flags,
+                          char *pin, size_t pin_max)
+{
+       PinfileCallback **snapshot = NULL;
+       unsigned int snapshot_count = 0;
+       ptr_array_t *callbacks;
+       unsigned int i;
+       int ret;
+
+       _p11_lock ();
+
+               /* Find and ref the pinfile data */
+               if (gl.pinfiles) {
+                       callbacks = hash_get (gl.pinfiles, pinfile);
+
+                       /* If we didn't find any snapshots try the global ones */
+                       if (callbacks == NULL)
+                               callbacks = hash_get (gl.pinfiles, P11_KIT_PIN_FALLBACK);
+
+                       if (callbacks != NULL) {
+                               snapshot = (PinfileCallback**)ptr_array_snapshot (callbacks);
+                               snapshot_count = ptr_array_count (callbacks);
+                               for (i = 0; i < snapshot_count; i++)
+                                       ref_pinfile_callback (snapshot[i]);
+                       }
+               }
+
+       _p11_unlock ();
+
+       if (snapshot == NULL)
+               return 0;
+
+       for (i = 0; i < snapshot_count; i++) {
+               ret = (snapshot[i]->func) (pinfile, pin_uri, pin_description, flags,
+                                          snapshot[i]->user_data, pin, pin_max);
+       }
+
+       _p11_lock ();
+               for (i = 0; i < snapshot_count; i++)
+                       unref_pinfile_callback (snapshot[i]);
+               free (snapshot);
+       _p11_unlock ();
+
+       return ret;
+}
diff --git a/p11-kit/pin.h b/p11-kit/pin.h
new file mode 100644 (file)
index 0000000..780e72d
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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_PIN_H
+#define P11_KIT_PIN_H
+
+#include <p11-kit/uri.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+       P11_KIT_PIN_FLAGS_USER_LOGIN = 1,
+       P11_KIT_PIN_FLAGS_SO_LOGIN = 2,
+       P11_KIT_PIN_FLAGS_CONTEXT_LOGIN = 4,
+       P11_KIT_PIN_FLAGS_RETRY = 10,
+       P11_KIT_PIN_FLAGS_MANY_TRIES = 20,
+       P11_KIT_PIN_FLAGS_FINAL_TRY = 40
+} P11KitPinFlags;
+
+#define P11_KIT_PIN_FALLBACK ""
+
+typedef int         (*p11_kit_pin_callback)                 (const char *pinfile,
+                                                             P11KitUri *pin_uri,
+                                                             const char *pin_description,
+                                                             P11KitPinFlags pin_flags,
+                                                             void *callback_data,
+                                                             char *pin,
+                                                             size_t pin_max);
+
+typedef void        (*p11_kit_pin_callback_destroy)         (void *callback_data);
+
+int                 p11_kit_pin_register_callback           (const char *pinfile,
+                                                             p11_kit_pin_callback callback,
+                                                             void *callback_data,
+                                                             p11_kit_pin_callback_destroy callback_destroy);
+
+void                p11_kit_pin_unregister_callback         (const char *pinfile,
+                                                             p11_kit_pin_callback callback,
+                                                             void *callback_data);
+
+int                 p11_kit_pin_read_pinfile                (const char *pinfile,
+                                                             P11KitUri *pin_uri,
+                                                             const char *pin_description,
+                                                             P11KitPinFlags pin_flags,
+                                                             char *pin,
+                                                             size_t pin_max);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* P11_KIT_URI_H */
diff --git a/p11-kit/ptr-array.c b/p11-kit/ptr-array.c
new file mode 100644 (file)
index 0000000..6a5ac4f
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+
+#include "ptr-array.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+struct ptr_array {
+       void **memory;
+       unsigned int length;
+       unsigned int allocated;
+       ptr_array_destroy_func destroy;
+};
+
+static int
+maybe_expand_array (ptr_array_t *array, unsigned int length)
+{
+       unsigned int new_allocated;
+       void **new_memory;
+
+       if (length <= array->allocated)
+               return 1;
+
+       new_allocated = array->allocated + 16;
+       if (new_allocated < length)
+               new_allocated = length;
+
+       new_memory = realloc (array->memory, new_allocated * sizeof (void*));
+       if (new_memory == NULL)
+               return 0;
+
+       array->memory = new_memory;
+       array->allocated = new_allocated;
+       return 1;
+}
+
+ptr_array_t*
+ptr_array_create (ptr_array_destroy_func destroy_func)
+{
+       ptr_array_t *array;
+
+       array = calloc (1, sizeof (ptr_array_t));
+       if (array == NULL)
+               return NULL;
+
+       if (!maybe_expand_array (array, 2)) {
+               ptr_array_free (array);
+               return NULL;
+       }
+
+       array->destroy = destroy_func;
+       return array;
+}
+
+void
+ptr_array_free (ptr_array_t *array)
+{
+       unsigned int i;
+
+       if (array == NULL)
+               return;
+
+       if (array->destroy) {
+               for (i = 0; i < array->length; i++)
+                       (array->destroy) (array->memory[i]);
+       }
+
+       free (array->memory);
+       free (array);
+}
+
+unsigned int
+ptr_array_count (ptr_array_t *array)
+{
+       return array->length;
+}
+
+int
+ptr_array_add (ptr_array_t *array, void *value)
+{
+       if (!maybe_expand_array (array, array->length + 1))
+               return 0;
+
+       array->memory[array->length] = value;
+       array->length++;
+       return 1;
+}
+
+void
+ptr_array_remove (ptr_array_t *array, unsigned int index)
+{
+       if (array->destroy)
+               (array->destroy) (array->memory[index]);
+       memmove (array->memory + index, array->memory + index + 1,
+                (array->length - (index + 1)) * sizeof (void*));
+       array->length--;
+}
+
+void*
+ptr_array_at (ptr_array_t *array, unsigned int index)
+{
+       return array->memory[index];
+}
+
+void**
+ptr_array_snapshot (ptr_array_t *array)
+{
+       void **snapshot;
+       size_t bytes;
+
+       bytes = array->length * sizeof (void*);
+       snapshot = malloc (bytes);
+       if (!snapshot)
+               return NULL;
+
+       memcpy (snapshot, array->memory, bytes);
+       return snapshot;
+}
diff --git a/p11-kit/ptr-array.h b/p11-kit/ptr-array.h
new file mode 100644 (file)
index 0000000..acd894d
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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 Waler <stefw@collabora.co.uk>
+ */
+
+#ifndef __PTR_ARRAY_H__
+#define __PTR_ARRAY_H__
+
+#include <sys/types.h>
+
+typedef struct ptr_array ptr_array_t;
+
+typedef void         (*ptr_array_destroy_func)         (void *data);
+
+ptr_array_t*         ptr_array_create                  (ptr_array_destroy_func destroy_func);
+
+void                 ptr_array_free                    (ptr_array_t *array);
+
+unsigned int         ptr_array_count                   (ptr_array_t *array);
+
+int                  ptr_array_add                     (ptr_array_t *array,
+                                                        void *value);
+
+void                 ptr_array_remove                  (ptr_array_t *array,
+                                                        unsigned int index);
+
+void*                ptr_array_at                      (ptr_array_t *array,
+                                                        unsigned int index);
+
+void**               ptr_array_snapshot                (ptr_array_t *array);
+
+#endif  /* __PTR_ARRAY_H__ */
index 6b988b8faf7fc440dcd74d42429d537b0a9432ee..cde804f6cc3e2f5548d96e315e95706532e686aa 100644 (file)
@@ -8,22 +8,32 @@ INCLUDES = \
 
 noinst_PROGRAMS = \
        hash-test \
+       ptr-array-test \
        conf-test \
-       uri-test
+       uri-test \
+       pin-test
 
 hash_test_LDADD = \
        $(top_builddir)/p11-kit/libp11-kit-testable.la
 
+ptr_array_test_LDADD = \
+       $(top_builddir)/p11-kit/libp11-kit-testable.la
+
 conf_test_LDADD = \
        $(top_builddir)/p11-kit/libp11-kit-testable.la
 
 uri_test_LDADD = \
        $(top_builddir)/p11-kit/libp11-kit-testable.la
 
+pin_test_LDADD = \
+       $(top_builddir)/p11-kit/libp11-kit-testable.la
+
 check-am:
        ./hash-test
+       ./ptr-array-test
        ./conf-test
        ./uri-test
+       ./pin-test
 
 EXTRA_DIST = \
        cutest \
diff --git a/tests/pin-test.c b/tests/pin-test.c
new file mode 100644 (file)
index 0000000..7f1bc08
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * 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>
+ */
+
+#include "config.h"
+#include "CuTest.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "p11-kit/pin.h"
+
+static int
+callback_one (const char *pinfile, P11KitUri *pin_uri, const char *pin_description,
+              P11KitPinFlags pin_flags, void *callback_data, char *pin,
+              size_t pin_max)
+{
+       int *data = callback_data;
+       assert (*data == 33);
+       strncpy (pin, "one", pin_max);
+       return 1;
+}
+
+static int
+callback_other (const char *pinfile, P11KitUri *pin_uri, const char *pin_description,
+                P11KitPinFlags pin_flags, void *callback_data, char *pin,
+                size_t pin_max)
+{
+       char *data = callback_data;
+       strncpy (pin, data, pin_max);
+       return 1;
+}
+
+static void
+destroy_data (void *callback_data)
+{
+       int *data = callback_data;
+       (*data)++;
+}
+
+static void
+test_pin_register_unregister (CuTest *tc)
+{
+       int data = 33;
+
+       p11_kit_pin_register_callback ("/the/pinfile", callback_one,
+                                      &data, destroy_data);
+
+       p11_kit_pin_unregister_callback ("/the/pinfile", callback_one,
+                                        &data);
+
+       CuAssertIntEquals (tc, 34, data);
+}
+
+static void
+test_pin_read (CuTest *tc)
+{
+       P11KitUri *uri;
+       char buffer[256];
+       int data = 33;
+       int ret;
+
+       p11_kit_pin_register_callback ("/the/pinfile", callback_one,
+                                      &data, destroy_data);
+
+       uri = p11_kit_uri_new ();
+       ret = p11_kit_pin_read_pinfile ("/the/pinfile", uri, "The token",
+                                       P11_KIT_PIN_FLAGS_USER_LOGIN,
+                                       buffer, sizeof (buffer));
+       p11_kit_uri_free (uri);
+
+       CuAssertIntEquals (tc, 1, ret);
+       CuAssertStrEquals (tc, "one", buffer);
+
+       p11_kit_pin_unregister_callback ("/the/pinfile", callback_one,
+                                        &data);
+}
+
+static void
+test_pin_read_no_match (CuTest *tc)
+{
+       P11KitUri *uri;
+       char buffer[256];
+       int ret;
+
+       uri = p11_kit_uri_new ();
+       ret = p11_kit_pin_read_pinfile ("/the/pinfile", uri, "The token",
+                                       P11_KIT_PIN_FLAGS_USER_LOGIN,
+                                       buffer, sizeof (buffer));
+       p11_kit_uri_free (uri);
+
+       CuAssertIntEquals (tc, 0, ret);
+}
+
+static void
+test_pin_register_duplicate (CuTest *tc)
+{
+       P11KitUri *uri;
+       char *value = "secret";
+       char buffer[256];
+       int data = 33;
+       int ret;
+
+       uri = p11_kit_uri_new ();
+
+       p11_kit_pin_register_callback ("/the/pinfile", callback_one,
+                                      &data, destroy_data);
+
+       p11_kit_pin_register_callback ("/the/pinfile", callback_other,
+                                      value, NULL);
+
+       ret = p11_kit_pin_read_pinfile ("/the/pinfile", uri, "The token",
+                                       P11_KIT_PIN_FLAGS_USER_LOGIN,
+                                       buffer, sizeof (buffer));
+
+       CuAssertIntEquals (tc, 1, ret);
+       CuAssertStrEquals (tc, "secret", buffer);
+
+       p11_kit_pin_unregister_callback ("/the/pinfile", callback_other,
+                                        value);
+
+       ret = p11_kit_pin_read_pinfile ("/the/pinfile", uri, "The token",
+                                       P11_KIT_PIN_FLAGS_USER_LOGIN,
+                                       buffer, sizeof (buffer));
+
+       CuAssertIntEquals (tc, 1, ret);
+       CuAssertStrEquals (tc, "one", buffer);
+
+       p11_kit_pin_unregister_callback ("/the/pinfile", callback_one,
+                                        &data);
+
+       ret = p11_kit_pin_read_pinfile ("/the/pinfile", uri, "The token",
+                                       P11_KIT_PIN_FLAGS_USER_LOGIN,
+                                       buffer, sizeof (buffer));
+
+       CuAssertIntEquals (tc, 0, ret);
+
+       p11_kit_uri_free (uri);
+}
+
+static void
+test_pin_register_fallback (CuTest *tc)
+{
+       char *value = "secret";
+       P11KitUri *uri;
+       char buffer[256];
+       int data = 33;
+       int ret;
+
+       uri = p11_kit_uri_new ();
+
+       p11_kit_pin_register_callback (P11_KIT_PIN_FALLBACK, callback_one,
+                                      &data, destroy_data);
+
+       ret = p11_kit_pin_read_pinfile ("/the/pinfile", uri, "The token",
+                                       P11_KIT_PIN_FLAGS_USER_LOGIN,
+                                       buffer, sizeof (buffer));
+
+       CuAssertIntEquals (tc, 1, ret);
+       CuAssertStrEquals (tc, "one", buffer);
+
+       p11_kit_pin_register_callback ("/the/pinfile", callback_other,
+                                      value, NULL);
+
+       ret = p11_kit_pin_read_pinfile ("/the/pinfile", uri, "The token",
+                                       P11_KIT_PIN_FLAGS_USER_LOGIN,
+                                       buffer, sizeof (buffer));
+
+       CuAssertIntEquals (tc, 1, ret);
+       CuAssertStrEquals (tc, "secret", buffer);
+
+       p11_kit_pin_unregister_callback ("/the/pinfile", callback_other,
+                                        value);
+
+       p11_kit_pin_unregister_callback (P11_KIT_PIN_FALLBACK, callback_one,
+                                        &data);
+
+       p11_kit_uri_free (uri);
+}
+
+int
+main (void)
+{
+       CuString *output = CuStringNew ();
+       CuSuite* suite = CuSuiteNew ();
+       int ret;
+
+       SUITE_ADD_TEST (suite, test_pin_register_unregister);
+       SUITE_ADD_TEST (suite, test_pin_read);
+       SUITE_ADD_TEST (suite, test_pin_read_no_match);
+       SUITE_ADD_TEST (suite, test_pin_register_duplicate);
+       SUITE_ADD_TEST (suite, test_pin_register_fallback);
+
+       CuSuiteRun (suite);
+       CuSuiteSummary (suite, output);
+       CuSuiteDetails (suite, output);
+       printf ("%s\n", output->buffer);
+       ret = suite->failCount;
+       CuSuiteDelete (suite);
+       CuStringDelete (output);
+
+       return ret;
+}
+
+#include "CuTest.c"
diff --git a/tests/ptr-array-test.c b/tests/ptr-array-test.c
new file mode 100644 (file)
index 0000000..ff9959d
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * 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>
+ */
+
+#include "config.h"
+#include "CuTest.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ptr-array.h"
+
+static void
+test_ptr_array_create (CuTest *tc)
+{
+       ptr_array_t *array;
+
+       array = ptr_array_create (NULL);
+       CuAssertPtrNotNull (tc, array);
+       ptr_array_free (array);
+}
+
+static void
+test_ptr_array_free_null (CuTest *tc)
+{
+       ptr_array_free (NULL);
+}
+
+static void
+destroy_value (void *data)
+{
+       int *value = data;
+       *value = 2;
+}
+
+static void
+test_ptr_array_free_destroys (CuTest *tc)
+{
+       ptr_array_t *array;
+       int value = 0;
+
+       array = ptr_array_create (destroy_value);
+       CuAssertPtrNotNull (tc, array);
+       if (!ptr_array_add (array, &value))
+               CuFail (tc, "should not be reached");
+       ptr_array_free (array);
+
+       CuAssertIntEquals (tc, 2, value);
+}
+
+#if 0
+static void
+test_hash_iterate (CuTest *tc)
+{
+       hash_t *ht;
+       hash_iter_t hi;
+       int key = 1;
+       int value = 2;
+       void *pkey;
+       void *pvalue;
+       int ret;
+
+       ht = hash_create (hash_direct_hash, hash_direct_equal, NULL, NULL);
+       CuAssertPtrNotNull (tc, ht);
+       if (!hash_set (ht, &key, &value))
+               CuFail (tc, "should not be reached");
+
+       hash_iterate (ht, &hi);
+
+       ret = hash_next (&hi, &pkey, &pvalue);
+       CuAssertIntEquals (tc, 1, ret);
+       CuAssertPtrEquals (tc, pkey, &key);
+       CuAssertPtrEquals (tc, pvalue, &value);
+
+       ret = hash_next (&hi, &pkey, &pvalue);
+       CuAssertIntEquals (tc, 0, ret);
+
+       hash_free (ht);
+}
+
+#endif
+
+static void
+test_ptr_array_add (CuTest *tc)
+{
+       char *value = "VALUE";
+       char *check;
+       ptr_array_t *array;
+
+       array = ptr_array_create (NULL);
+       if (!ptr_array_add (array, value))
+               CuFail (tc, "should not be reached");
+
+       CuAssertIntEquals (tc, 1, ptr_array_count (array));
+
+       check = ptr_array_at (array, 0);
+       CuAssertPtrEquals (tc, check, value);
+
+       ptr_array_free (array);
+}
+
+static void
+test_ptr_array_add_remove (CuTest *tc)
+{
+       char *value = "VALUE";
+       char *check;
+       ptr_array_t *array;
+
+       array = ptr_array_create (NULL);
+       if (!ptr_array_add (array, value))
+               CuFail (tc, "should not be reached");
+
+       CuAssertIntEquals (tc, 1, ptr_array_count (array));
+
+       check = ptr_array_at (array, 0);
+       CuAssertPtrEquals (tc, check, value);
+
+       ptr_array_remove (array, 0);
+
+       CuAssertIntEquals (tc, 0, ptr_array_count (array));
+
+       ptr_array_free (array);
+}
+
+static void
+test_ptr_array_remove_destroys (CuTest *tc)
+{
+       ptr_array_t *array;
+       int value = 0;
+
+       array = ptr_array_create (destroy_value);
+       if (!ptr_array_add (array, &value))
+               CuFail (tc, "should not be reached");
+
+       ptr_array_remove (array, 0);
+
+       CuAssertIntEquals (tc, 2, value);
+
+       /* should not be destroyed again */
+       value = 0;
+
+       ptr_array_free (array);
+
+       CuAssertIntEquals (tc, 0, value);
+}
+
+static void
+test_ptr_array_remove_and_count (CuTest *tc)
+{
+       ptr_array_t *array;
+       int *value;
+       int i;
+
+       array = ptr_array_create (free);
+
+       CuAssertIntEquals (tc, 0, ptr_array_count (array));
+
+       for (i = 0; i < 20000; ++i) {
+               value = malloc (sizeof (int));
+               *value = i;
+               if (!ptr_array_add (array, value))
+                       CuFail (tc, "should not be reached");
+               CuAssertIntEquals (tc, i + 1, ptr_array_count (array));
+       }
+
+       for (i = 10; i < 20000; ++i) {
+               ptr_array_remove (array, 10);
+               CuAssertIntEquals (tc, 20010 - (i + 1), ptr_array_count (array));
+       }
+
+       CuAssertIntEquals (tc, 10, ptr_array_count (array));
+
+       ptr_array_free (array);
+}
+
+static void
+test_ptr_array_snapshot (CuTest *tc)
+{
+       ptr_array_t *array;
+       void **snapshot;
+
+       array = ptr_array_create (NULL);
+
+       ptr_array_add (array, "1");
+       ptr_array_add (array, "2");
+       ptr_array_add (array, "3");
+       ptr_array_add (array, "4");
+       CuAssertIntEquals (tc, 4, ptr_array_count (array));
+
+       snapshot = ptr_array_snapshot (array);
+
+       CuAssertStrEquals (tc, "1", snapshot[0]);
+       CuAssertStrEquals (tc, "2", snapshot[1]);
+       CuAssertStrEquals (tc, "3", snapshot[2]);
+       CuAssertStrEquals (tc, "4", snapshot[3]);
+
+       free (snapshot);
+       ptr_array_free (array);
+}
+
+int
+main (void)
+{
+       CuString *output = CuStringNew ();
+       CuSuite* suite = CuSuiteNew ();
+       int ret;
+
+       SUITE_ADD_TEST (suite, test_ptr_array_create);
+       SUITE_ADD_TEST (suite, test_ptr_array_add);
+       SUITE_ADD_TEST (suite, test_ptr_array_add_remove);
+       SUITE_ADD_TEST (suite, test_ptr_array_remove_destroys);
+       SUITE_ADD_TEST (suite, test_ptr_array_remove_and_count);
+       SUITE_ADD_TEST (suite, test_ptr_array_free_null);
+       SUITE_ADD_TEST (suite, test_ptr_array_free_destroys);
+       SUITE_ADD_TEST (suite, test_ptr_array_snapshot);
+
+       CuSuiteRun (suite);
+       CuSuiteSummary (suite, output);
+       CuSuiteDetails (suite, output);
+       printf ("%s\n", output->buffer);
+       ret = suite->failCount;
+       CuSuiteDelete (suite);
+       CuStringDelete (output);
+
+       return ret;
+}
+
+#include "CuTest.c"