]> granicus.if.org Git - p11-kit/commitdiff
trust: Implement reloading of token data
authorStef Walter <stef@thewalter.net>
Fri, 28 Jun 2013 11:27:42 +0000 (13:27 +0200)
committerStef Walter <stef@thewalter.net>
Wed, 3 Jul 2013 09:46:27 +0000 (11:46 +0200)
 * Reload token data whenever a new session is opened.
 * Only reload files/directories that have changed.
 * Move duplicate anchor/blacklist detection logic into
   the extract code. This is in line with the approach
   being discussed on the mailing lists and spec document.
 * New internal attribute CKA_X_ORIGIN set on all objects
   so we can track where an object came from, and replace
   it when reloaded.

In general this is a prerequisite for modification of objects
reload before modify is necessary to prevent multiple callers
clobbering each other's changes.

14 files changed:
trust/builder.c
trust/extract-info.c
trust/index.c
trust/index.h
trust/module.c
trust/parser.c
trust/parser.h
trust/tests/test-extract.c
trust/tests/test-parser.c
trust/tests/test-token.c
trust/tests/test-trust.c
trust/tests/test-trust.h
trust/token.c
trust/token.h

index bfbc42d5b80613e72122c6c8159e4f041e8d0a26..f325be621557121c2058aa4af9d5018f756b6834 100644 (file)
@@ -322,7 +322,8 @@ type_der_cert (p11_builder *builder,
        { CKA_MODIFIABLE, CREATE | WANT, type_bool }, \
        { CKA_PRIVATE, CREATE, type_bool }, \
        { CKA_LABEL, CREATE | MODIFY | WANT, type_utf8 }, \
-       { CKA_X_GENERATED, CREATE }
+       { CKA_X_GENERATED, CREATE }, \
+       { CKA_X_ORIGIN, NONE } \
 
 static CK_ATTRIBUTE *
 common_populate (p11_builder *builder,
index a645d310121b54e89237c8bfea00b1fe3eac8fef..ec25bc16d53fef636c4b2e1334c8011e124a8b79 100644 (file)
@@ -143,46 +143,66 @@ extract_purposes (p11_extract_info *ex)
 }
 
 static bool
-should_collapse_certificate (p11_extract_info *ex,
-                             CK_ATTRIBUTE *value)
+check_blacklisted (P11KitIter *iter,
+                   CK_ATTRIBUTE *cert)
 {
-       CK_ATTRIBUTE *attrs;
+       CK_OBJECT_HANDLE dummy;
+       CK_FUNCTION_LIST *module;
+       CK_SESSION_HANDLE session;
+       CK_BBOOL distrusted = CK_TRUE;
+       CK_ULONG have;
+       CK_RV rv;
 
-       if (!(ex->flags & P11_EXTRACT_COLLAPSE))
-               return false;
+       CK_ATTRIBUTE match[] = {
+               { CKA_VALUE, cert->pValue, cert->ulValueLen },
+               { CKA_X_DISTRUSTED, &distrusted, sizeof (distrusted) },
+       };
+
+       module = p11_kit_iter_get_module (iter);
+       session = p11_kit_iter_get_session (iter);
 
-       if (!ex->already_seen) {
-               ex->already_seen = p11_dict_new (p11_attr_hash, p11_attr_equal,
-                                                NULL, p11_attrs_free);
-               return_val_if_fail (ex->already_seen != NULL, true);
+       rv = (module->C_FindObjectsInit) (session, match, 2);
+       if (rv == CKR_OK) {
+               rv = (module->C_FindObjects) (session, &dummy, 1, &have);
+               (module->C_FindObjectsFinal) (session);
        }
 
-       if (p11_dict_get (ex->already_seen, value))
+       if (rv != CKR_OK) {
+               p11_message ("couldn't check if certificate is on blacklist");
                return true;
+       }
 
-       attrs = p11_attrs_build (NULL, value, NULL);
-       return_val_if_fail (attrs != NULL, true);
-
-       if (!p11_dict_set (ex->already_seen, attrs, attrs))
-               return_val_if_reached (true);
-
-       return false;
+       if (have == 0) {
+               p11_debug ("anchor is not on blacklist");
+               return false;
+       } else {
+               p11_debug ("anchor is on blacklist");
+               return true;
+       }
 }
 
 static bool
-check_trust_flags_match (p11_extract_info *ex)
+check_trust_flags (P11KitIter *iter,
+                   p11_extract_info *ex,
+                   CK_ATTRIBUTE *cert)
 {
-       CK_BBOOL boolv;
+       CK_BBOOL trusted;
+       CK_BBOOL distrusted;
        int flags = 0;
 
        /* If no extract trust flags, then just continue */
        if (!(ex->flags & (P11_EXTRACT_ANCHORS | P11_EXTRACT_BLACKLIST)))
                return true;
 
-       if (p11_attrs_find_bool (ex->attrs, CKA_TRUSTED, &boolv) && boolv)
+       if (p11_attrs_find_bool (ex->attrs, CKA_TRUSTED, &trusted) &&
+           trusted && !check_blacklisted (iter, cert)) {
                flags |= P11_EXTRACT_ANCHORS;
-       if (p11_attrs_find_bool (ex->attrs, CKA_X_DISTRUSTED, &boolv) && boolv)
+       }
+
+       if (p11_attrs_find_bool (ex->attrs, CKA_X_DISTRUSTED, &distrusted) &&
+           distrusted) {
                flags |= P11_EXTRACT_BLACKLIST;
+       }
 
        /* Any of the flags can match */
        if (flags & ex->flags)
@@ -218,20 +238,28 @@ extract_certificate (P11KitIter *iter,
         * If collapsing and have already seen this certificate, and shouldn't
         * process it even again during this extract procedure.
         */
-       if (should_collapse_certificate (ex, attr)) {
-               p11_debug ("skipping certificate that has already been seen");
-               return false;
+       if (ex->flags & P11_EXTRACT_COLLAPSE) {
+               if (!ex->already_seen) {
+                       ex->already_seen = p11_dict_new (p11_attr_hash, p11_attr_equal,
+                                                        p11_attrs_free, NULL);
+                       return_val_if_fail (ex->already_seen != NULL, true);
+               }
+
+               if (p11_dict_get (ex->already_seen, attr))
+                       return false;
        }
 
-       /*
-        * We do these checks after collapsing, so that blacklisted certificates
-        * mask out anchors even if we're not exporting blacklisted stuff.
-        */
-       if (!check_trust_flags_match (ex)) {
+       if (!check_trust_flags (iter, ex, attr)) {
                p11_debug ("skipping certificate that doesn't match trust flags");
                return false;
        }
 
+       if (ex->already_seen) {
+               if (!p11_dict_set (ex->already_seen,
+                                  p11_attrs_build (NULL, attr, NULL), "x"))
+                       return_val_if_reached (true);
+       }
+
        ex->cert_der = attr->pValue;
        ex->cert_len = attr->ulValueLen;
        ex->cert_asn = p11_asn1_decode (ex->asn1_defs, "PKIX1.Certificate",
index c8632ccfdd890d8df9eb39671f8db94c6b5d59a4..4de65c94012dd4e457286341d0c02f9cf1689954 100644 (file)
@@ -154,6 +154,7 @@ is_indexable (p11_index *index,
        case CKA_VALUE:
        case CKA_OBJECT_ID:
        case CKA_ID:
+       case CKA_X_ORIGIN:
                return true;
        }
 
@@ -566,13 +567,18 @@ p11_index_replace_all (p11_index *index,
        handles = p11_index_find_all (index, match, -1);
 
        rv = index_replacev (index, handles, key,
-                            (CK_ATTRIBUTE **)replace->elem,
-                            replace->num);
+                            replace ? (CK_ATTRIBUTE **)replace->elem : NULL,
+                            replace ? replace->num : 0);
 
-       for (i = 0; i < replace->num; i++) {
-               if (!replace->elem[i]) {
-                       p11_array_remove (replace, i);
-                       i--;
+       if (rv == CKR_OK) {
+               if (replace)
+                       p11_array_clear (replace);
+       } else {
+               for (i = 0; replace && i < replace->num; i++) {
+                       if (!replace->elem[i]) {
+                               p11_array_remove (replace, i);
+                               i--;
+                       }
                }
        }
 
index a22117819808e2e9fce0639945378275d93d5da7..2f44d0c532b3b2e0ec352e59f8b23cbe0333d0f8 100644 (file)
@@ -38,6 +38,7 @@
 #include "array.h"
 #include "compat.h"
 #include "pkcs11.h"
+#include "pkcs11x.h"
 
 /*
  * A boolean value which denotes whether we auto generated
  */
 #define CKA_X_GENERATED (CKA_X_VENDOR + 8000)
 
+/*
+ * A string pointing to the filename from which this was loaded.
+ */
+#define CKA_X_ORIGIN    (CKA_X_VENDOR + 8001)
+
 typedef struct _p11_index p11_index;
 
 typedef CK_RV   (* p11_index_build_cb)   (void *data,
index 5f8692b21ce3f31af98397212601ed9ab3273386..22e288c2ca69917ae0811399e421541891e8291b 100644 (file)
@@ -1110,8 +1110,11 @@ sys_C_SetAttributeValue (CK_SESSION_HANDLE handle,
 
                        if (rv == CKR_OK)
                                rv = check_index_writable (session, index);
-                       if (rv == CKR_OK)
+                       if (rv == CKR_OK) {
+                               if (index == p11_token_index (session->token))
+                                       p11_token_reload (session->token, attrs);
                                rv = p11_index_set (index, object, template, count);
+                       }
                }
 
        p11_unlock ();
index 21b693b82fef78d2c95eccbcca5ee44e9175d35b..c5cbe15736516385e53e9dc6b81f0060998b6a2d 100644 (file)
 #include <unistd.h>
 
 struct _p11_parser {
-       p11_index *index;
        p11_asn1_cache *asn1_cache;
        p11_dict *asn1_defs;
        p11_persist *persist;
        char *basename;
+       p11_array *parsed;
        int flags;
 };
 
@@ -131,114 +131,20 @@ populate_trust (p11_parser *parser,
        return p11_attrs_build (attrs, &trusted, &distrust, NULL);
 }
 
-static bool
-lookup_cert_duplicate (p11_index *index,
-                       CK_ATTRIBUTE *attrs,
-                       CK_OBJECT_HANDLE *handle,
-                       CK_ATTRIBUTE **dupl)
-{
-       CK_OBJECT_CLASS klass = CKO_CERTIFICATE;
-       CK_ATTRIBUTE *value;
-
-       CK_ATTRIBUTE match[] = {
-               { CKA_VALUE, },
-               { CKA_CLASS, &klass, sizeof (klass) },
-               { CKA_INVALID },
-       };
-
-       /*
-        * TODO: This will need to be adapted when we support reload on
-        * the fly, but for now since we only load once, we can assume
-        * that any certs already present in the index are duplicates.
-        */
-
-       value = p11_attrs_find_valid (attrs, CKA_VALUE);
-       if (value != NULL) {
-               memcpy (match, value, sizeof (CK_ATTRIBUTE));
-               *handle = p11_index_find (index, match, -1);
-               if (*handle != 0) {
-                       *dupl = p11_index_lookup (index, *handle);
-                       return true;
-               }
-       }
-
-       return false;
-}
-
-static char *
-pull_cert_label (CK_ATTRIBUTE *attrs)
-{
-       char *label;
-       size_t len;
-
-       label = p11_attrs_find_value (attrs, CKA_LABEL, &len);
-       if (label)
-               label = strndup (label, len);
-
-       return label;
-}
-
-static int
-calc_cert_priority (CK_ATTRIBUTE *attrs)
-{
-       CK_BBOOL boolv;
-
-       enum {
-               PRI_UNKNOWN,
-               PRI_TRUSTED,
-               PRI_DISTRUST
-       };
-
-       if (p11_attrs_find_bool (attrs, CKA_X_DISTRUSTED, &boolv) && boolv)
-               return PRI_DISTRUST;
-       else if (p11_attrs_find_bool (attrs, CKA_TRUSTED, &boolv) && boolv)
-               return PRI_TRUSTED;
-
-       return PRI_UNKNOWN;
-}
-
 static void
 sink_object (p11_parser *parser,
              CK_ATTRIBUTE *attrs)
 {
-       CK_OBJECT_HANDLE handle;
        CK_OBJECT_CLASS klass;
-       CK_ATTRIBUTE *dupl;
-       char *label;
-       CK_RV rv;
-
-       /* By default not replacing anything */
-       handle = 0;
 
        if (p11_attrs_find_ulong (attrs, CKA_CLASS, &klass) &&
            klass == CKO_CERTIFICATE) {
                attrs = populate_trust (parser, attrs);
                return_if_fail (attrs != NULL);
-
-               if (lookup_cert_duplicate (parser->index, attrs, &handle, &dupl)) {
-
-                       /* This is not a good place to be for a well configured system */
-                       label = pull_cert_label (dupl);
-                       p11_message ("duplicate '%s' certificate found in: %s",
-                                    label ? label : "?", parser->basename);
-                       free (label);
-
-                       /*
-                        * Nevertheless we provide predictable behavior about what
-                        * overrides what. If we have a lower or equal priority
-                        * to what's there, then just go away, otherwise replace.
-                        */
-                       if (calc_cert_priority (attrs) <= calc_cert_priority (dupl)) {
-                               p11_attrs_free (attrs);
-                               return;
-                       }
-               }
        }
 
-       /* If handle is zero, this just adds */
-       rv = p11_index_replace (parser->index, handle, attrs);
-       if (rv != CKR_OK)
-               p11_message ("couldn't load file into objects: %s", parser->basename);
+       if (!p11_array_push (parser->parsed, attrs))
+               return_if_reached ();
 }
 
 static CK_ATTRIBUTE *
@@ -636,8 +542,6 @@ on_pem_block (const char *type,
        p11_parser *parser = user_data;
        int ret;
 
-       p11_index_batch (parser->index);
-
        if (strcmp (type, "CERTIFICATE") == 0) {
                ret = parse_der_x509_certificate (parser, contents, length);
 
@@ -649,8 +553,6 @@ on_pem_block (const char *type,
                ret = P11_PARSE_SUCCESS;
        }
 
-       p11_index_finish (parser->index);
-
        if (ret != P11_PARSE_SUCCESS)
                p11_message ("Couldn't parse PEM block of type %s", type);
 }
@@ -714,18 +616,18 @@ static parser_func all_parsers[] = {
 };
 
 p11_parser *
-p11_parser_new (p11_index *index,
-                p11_asn1_cache *asn1_cache)
+p11_parser_new (p11_asn1_cache *asn1_cache)
 {
        p11_parser parser = { 0, };
 
-       return_val_if_fail (index != NULL, NULL);
        return_val_if_fail (asn1_cache != NULL, NULL);
 
-       parser.index = index;
        parser.asn1_defs = p11_asn1_cache_defs (asn1_cache);
        parser.asn1_cache = asn1_cache;
 
+       parser.parsed = p11_array_new (p11_attrs_free);
+       return_val_if_fail (parser.parsed != NULL, NULL);
+
        return memdup (&parser, sizeof (parser));
 }
 
@@ -734,9 +636,17 @@ p11_parser_free (p11_parser *parser)
 {
        return_if_fail (parser != NULL);
        p11_persist_free (parser->persist);
+       p11_array_free (parser->parsed);
        free (parser);
 }
 
+p11_array *
+p11_parser_parsed (p11_parser *parser)
+{
+       return_val_if_fail (parser != NULL, NULL);
+       return parser->parsed;
+}
+
 int
 p11_parse_memory (p11_parser *parser,
                   const char *filename,
@@ -749,15 +659,15 @@ p11_parse_memory (p11_parser *parser,
        int i;
 
        return_val_if_fail (parser != NULL, P11_PARSE_FAILURE);
+       return_val_if_fail (filename != NULL, P11_PARSE_FAILURE);
 
+       p11_array_clear (parser->parsed);
        base = p11_path_base (filename);
        parser->basename = base;
        parser->flags = flags;
 
        for (i = 0; all_parsers[i] != NULL; i++) {
-               p11_index_batch (parser->index);
                ret = (all_parsers[i]) (parser, data, length);
-               p11_index_finish (parser->index);
 
                if (ret != P11_PARSE_UNRECOGNIZED)
                        break;
index ca41d26449589967631260d7aa354e3d779a318d..f956fb9e27f33bf0fa5ac2bd5d8ede82e7bd72e4 100644 (file)
@@ -55,8 +55,7 @@ enum {
 
 typedef struct _p11_parser p11_parser;
 
-p11_parser *  p11_parser_new       (p11_index *index,
-                                    p11_asn1_cache *asn1_cache);
+p11_parser *  p11_parser_new       (p11_asn1_cache *asn1_cache);
 
 void          p11_parser_free      (p11_parser *parser);
 
@@ -70,4 +69,6 @@ int           p11_parse_file       (p11_parser *parser,
                                     const char *filename,
                                     int flags);
 
-#endif
+p11_array *   p11_parser_parsed    (p11_parser *parser);
+
+#endif /* P11_PARSER_H_ */
index b121b214ffb672d2af7e7659b4d445c2827a9fd2..ddb4a4920a99b711282f34c13c14f63842a2565a 100644 (file)
@@ -380,13 +380,18 @@ test_duplicate_extract (void)
 }
 
 static void
-test_duplicate_collapse (void)
+test_duplicate_distrusted (void)
 {
        CK_ATTRIBUTE certificate = { CKA_CLASS, &certificate_class, sizeof (certificate_class) };
+       CK_ATTRIBUTE attrs[] = {
+               { CKA_X_DISTRUSTED, NULL, 0 },
+       };
+
+       CK_BBOOL val;
        CK_RV rv;
 
-       mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted);
        mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_distrusted);
+       mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted);
 
        test.ex.flags = P11_EXTRACT_COLLAPSE;
        p11_kit_iter_add_callback (test.iter, p11_extract_info_load_filter, &test.ex, NULL);
@@ -396,6 +401,12 @@ test_duplicate_collapse (void)
        rv = p11_kit_iter_next (test.iter);
        assert_num_eq (CKR_OK, rv);
 
+       rv = p11_kit_iter_load_attributes (test.iter, attrs, 1);
+       assert_num_eq (CKR_OK, rv);
+       assert (p11_attrs_findn_bool (attrs, 1, CKA_X_DISTRUSTED, &val));
+       assert_num_eq (val, CK_TRUE);
+       free (attrs[0].pValue);
+
        rv = p11_kit_iter_next (test.iter);
        assert_num_eq (CKR_CANCEL, rv);
 }
@@ -404,7 +415,6 @@ static void
 test_trusted_match (void)
 {
        CK_ATTRIBUTE certificate = { CKA_CLASS, &certificate_class, sizeof (certificate_class) };
-       CK_BBOOL boolv;
        CK_RV rv;
 
        mock_module_add_object (MOCK_SLOT_ONE_ID, cacert3_trusted);
@@ -415,13 +425,6 @@ test_trusted_match (void)
        p11_kit_iter_add_filter (test.iter, &certificate, 1);
        p11_kit_iter_begin_with (test.iter, &test.module, 0, 0);
 
-       rv = p11_kit_iter_next (test.iter);
-       assert_num_eq (CKR_OK, rv);
-
-       if (!p11_attrs_find_bool (test.ex.attrs, CKA_TRUSTED, &boolv))
-               boolv = CK_FALSE;
-       assert_num_eq (CK_TRUE, boolv);
-
        rv = p11_kit_iter_next (test.iter);
        assert_num_eq (CKR_CANCEL, rv);
 }
@@ -469,9 +472,6 @@ test_anytrust_match (void)
        rv = p11_kit_iter_next (test.iter);
        assert_num_eq (CKR_OK, rv);
 
-       rv = p11_kit_iter_next (test.iter);
-       assert_num_eq (CKR_OK, rv);
-
        rv = p11_kit_iter_next (test.iter);
        assert_num_eq (CKR_CANCEL, rv);
 }
@@ -495,7 +495,7 @@ main (int argc,
        p11_test (test_limit_to_purpose_match, "/extract/test_limit_to_purpose_match");
        p11_test (test_limit_to_purpose_no_match, "/extract/test_limit_to_purpose_no_match");
        p11_test (test_duplicate_extract, "/extract/test_duplicate_extract");
-       p11_test (test_duplicate_collapse, "/extract/test_duplicate_collapse");
+       p11_test (test_duplicate_distrusted, "/extract/test-duplicate-distrusted");
        p11_test (test_trusted_match, "/extract/test_trusted_match");
        p11_test (test_distrust_match, "/extract/test_distrust_match");
        p11_test (test_anytrust_match, "/extract/test_anytrust_match");
index 2b602541cec13e3a6a1c1886593aee98660e3b76..3eee984d235799267a868bdb2ab0d316d19f0253 100644 (file)
 
 struct {
        p11_parser *parser;
+       p11_array *parsed;
        p11_asn1_cache *cache;
-       p11_index *index;
 } test;
 
 static void
 setup (void *unused)
 {
-       test.index = p11_index_new (NULL, NULL, NULL);
        test.cache = p11_asn1_cache_new ();
-       test.parser = p11_parser_new (test.index, test.cache);
+       test.parser = p11_parser_new (test.cache);
        assert_ptr_not_null (test.parser);
+
+       test.parsed = p11_parser_parsed (test.parser);
+       assert_ptr_not_null (test.parsed);
 }
 
 static void
 teardown (void *unused)
 {
        p11_parser_free (test.parser);
-       p11_index_free (test.index);
        p11_asn1_cache_free (test.cache);
        memset (&test, 0, sizeof (test));
 }
@@ -85,12 +86,19 @@ static CK_ATTRIBUTE certificate_match[] = {
 };
 
 static CK_ATTRIBUTE *
-parsed_attrs (CK_ATTRIBUTE *match)
+parsed_attrs (CK_ATTRIBUTE *match,
+              int length)
 {
-       CK_OBJECT_HANDLE handle;
-       handle = p11_index_find (test.index, certificate_match, -1);
-       return p11_index_lookup (test.index, handle);
+       int i;
+
+       if (length < 0)
+               length = p11_attrs_count (match);
+       for (i = 0; i < test.parsed->num; i++) {
+               if (p11_attrs_matchn (test.parsed->elem[i], match, length))
+                       return test.parsed->elem[i];
+       }
 
+       return NULL;
 }
 
 static void
@@ -114,9 +122,9 @@ test_parse_der_certificate (void)
        assert_num_eq (P11_PARSE_SUCCESS, ret);
 
        /* Should have gotten certificate */
-       assert_num_eq (1, p11_index_size (test.index));
+       assert_num_eq (1, test.parsed->num);
 
-       cert = parsed_attrs (certificate_match);
+       cert = parsed_attrs (certificate_match, -1);
        test_check_attrs (expected, cert);
 }
 
@@ -141,9 +149,9 @@ test_parse_pem_certificate (void)
        assert_num_eq (P11_PARSE_SUCCESS, ret);
 
        /* Should have gotten certificate  */
-       assert_num_eq (1, p11_index_size (test.index));
+       assert_num_eq (1, test.parsed->num);
 
-       cert = parsed_attrs (certificate_match);
+       cert = parsed_attrs (certificate_match, -1);
        test_check_attrs (expected, cert);
 }
 
@@ -168,9 +176,9 @@ test_parse_p11_kit_persist (void)
        assert_num_eq (P11_PARSE_SUCCESS, ret);
 
        /* Should have gotten certificate  */
-       assert_num_eq (1, p11_index_size (test.index));
+       assert_num_eq (1, test.parsed->num);
 
-       cert = parsed_attrs (certificate_match);
+       cert = parsed_attrs (certificate_match, -1);
        test_check_attrs (expected, cert);
 }
 
@@ -212,7 +220,6 @@ test_parse_openssl_trusted (void)
 
        CK_ATTRIBUTE *cert;
        CK_ATTRIBUTE *object;
-       CK_OBJECT_HANDLE handle;
        int ret;
        int i;
 
@@ -225,18 +232,15 @@ test_parse_openssl_trusted (void)
         * - 1 certificate
         * - 2 stapled extensions
         */
-       assert_num_eq (3, p11_index_size (test.index));
+       assert_num_eq (3, test.parsed->num);
 
        /* The certificate */
-       cert = parsed_attrs (certificate_match);
+       cert = parsed_attrs (certificate_match, -1);
        test_check_attrs (expected[0], cert);
 
        /* The other objects */
        for (i = 1; expected[i]; i++) {
-               handle = p11_index_find (test.index, expected[i], 2);
-               assert (handle != 0);
-
-               object = p11_index_lookup (test.index, handle);
+               object = parsed_attrs (expected[i], 2);
                assert_ptr_not_null (object);
 
                test_check_attrs (expected[i], object);
@@ -281,7 +285,6 @@ test_parse_openssl_distrusted (void)
 
        CK_ATTRIBUTE *cert;
        CK_ATTRIBUTE *object;
-       CK_OBJECT_HANDLE handle;
        int ret;
        int i;
 
@@ -298,16 +301,13 @@ test_parse_openssl_distrusted (void)
         * - 1 certificate
         * - 2 stapled extensions
         */
-       assert_num_eq (3, p11_index_size (test.index));
-       cert = parsed_attrs (certificate_match);
+       assert_num_eq (3, test.parsed->num);
+       cert = parsed_attrs (certificate_match, -1);
        test_check_attrs (expected[0], cert);
 
        /* The other objects */
        for (i = 1; expected[i]; i++) {
-               handle = p11_index_find (test.index, expected[i], 2);
-               assert (handle != 0);
-
-               object = p11_index_lookup (test.index, handle);
+               object = parsed_attrs (expected[i], 2);
                assert_ptr_not_null (object);
 
                test_check_attrs (expected[i], object);
@@ -339,9 +339,9 @@ test_parse_anchor (void)
         * Should have gotten:
         * - 1 certificate
         */
-       assert_num_eq (1, p11_index_size (test.index));
+       assert_num_eq (1, test.parsed->num);
 
-       cert = parsed_attrs (certificate_match);
+       cert = parsed_attrs (certificate_match, -1);
        test_check_attrs (cacert3, cert);
 }
 
@@ -365,9 +365,9 @@ test_parse_thawte (void)
        assert_num_eq (P11_PARSE_SUCCESS, ret);
 
        /* Should have gotten certificate  */
-       assert_num_eq (1, p11_index_size (test.index));
+       assert_num_eq (1, test.parsed->num);
 
-       cert = parsed_attrs (certificate_match);
+       cert = parsed_attrs (certificate_match, -1);
        test_check_attrs (expected, cert);
 }
 
@@ -401,124 +401,6 @@ test_parse_unrecognized (void)
        p11_message_loud ();
 }
 
-static void
-test_duplicate (void)
-{
-       CK_ATTRIBUTE cacert3[] = {
-               { CKA_CLASS, &certificate, sizeof (certificate) },
-               { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) },
-               { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
-               { CKA_MODIFIABLE, &falsev, sizeof (falsev) },
-               { CKA_TRUSTED, &falsev, sizeof (falsev) },
-               { CKA_X_DISTRUSTED, &falsev, sizeof (falsev) },
-               { CKA_INVALID },
-       };
-
-       CK_OBJECT_HANDLE *handles;
-       CK_ATTRIBUTE *cert;
-       int ret;
-
-       ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der", 0);
-       assert_num_eq (P11_PARSE_SUCCESS, ret);
-
-       p11_message_quiet ();
-
-       /* This shouldn't be added, should print a message */
-       ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der", 0);
-       assert_num_eq (P11_PARSE_SUCCESS, ret);
-
-       assert (strstr (p11_message_last (), "duplicate") != NULL);
-
-       p11_message_loud ();
-
-       /* Should only be one certificate since the above two are identical */
-       handles = p11_index_find_all (test.index, cacert3, 2);
-       assert_ptr_not_null (handles);
-       assert (handles[0] != 0);
-       assert (handles[1] == 0);
-
-       cert = p11_index_lookup (test.index, handles[0]);
-       test_check_attrs (cacert3, cert);
-
-       free (handles);
-}
-
-static void
-test_duplicate_priority (void)
-{
-       CK_ATTRIBUTE cacert3[] = {
-               { CKA_CLASS, &certificate, sizeof (certificate) },
-               { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
-               { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) },
-               { CKA_MODIFIABLE, &falsev, sizeof (falsev) },
-               { CKA_INVALID },
-       };
-
-       CK_ATTRIBUTE trusted[] = {
-               { CKA_CLASS, &certificate, sizeof (certificate) },
-               { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
-               { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) },
-               { CKA_TRUSTED, &truev, sizeof (truev) },
-               { CKA_X_DISTRUSTED, &falsev, sizeof (falsev) },
-               { CKA_INVALID },
-       };
-
-       CK_ATTRIBUTE distrust[] = {
-               { CKA_CLASS, &certificate, sizeof (certificate) },
-               { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
-               { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) },
-               { CKA_TRUSTED, &falsev, sizeof (falsev) },
-               { CKA_X_DISTRUSTED, &truev, sizeof (truev) },
-               { CKA_INVALID },
-       };
-
-       CK_OBJECT_HANDLE *handles;
-       CK_ATTRIBUTE *cert;
-       int ret;
-
-       ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der", 0);
-       assert_num_eq (P11_PARSE_SUCCESS, ret);
-
-       p11_message_quiet ();
-
-       /* This shouldn't be added, should print a message */
-       ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der",
-                             P11_PARSE_FLAG_ANCHOR);
-       assert_num_eq (P11_PARSE_SUCCESS, ret);
-
-       assert (strstr (p11_message_last (), "duplicate") != NULL);
-
-       p11_message_loud ();
-
-       /* We should now find the trusted certificate */
-       handles = p11_index_find_all (test.index, cacert3, 2);
-       assert_ptr_not_null (handles);
-       assert (handles[0] != 0);
-       assert (handles[1] == 0);
-       cert = p11_index_lookup (test.index, handles[0]);
-       test_check_attrs (trusted, cert);
-       free (handles);
-
-       /* Now add a distrutsed one, this should override the trusted */
-
-       p11_message_quiet ();
-
-       ret = p11_parse_file (test.parser, SRCDIR "/files/cacert3.der",
-                             P11_PARSE_FLAG_BLACKLIST);
-       assert_num_eq (P11_PARSE_SUCCESS, ret);
-
-       p11_message_loud ();
-
-       /* We should now find the distrusted certificate */
-       handles = p11_index_find_all (test.index, cacert3, 2);
-       assert_ptr_not_null (handles);
-       assert (handles[0] != 0);
-       assert (handles[1] == 0);
-       cert = p11_index_lookup (test.index, handles[0]);
-       test_check_attrs (distrust, cert);
-       free (handles);
-}
-
 int
 main (int argc,
       char *argv[])
@@ -533,7 +415,5 @@ main (int argc,
        p11_test (test_parse_thawte, "/parser/parse_thawte");
        p11_test (test_parse_invalid_file, "/parser/parse_invalid_file");
        p11_test (test_parse_unrecognized, "/parser/parse_unrecognized");
-       p11_test (test_duplicate, "/parser/duplicate");
-       p11_test (test_duplicate_priority, "/parser/duplicate_priority");
        return p11_test_run (argc, argv);
 }
index d3728147f3142eb192e57bcf0cd9172fae7aa467..a518c9e31c43f7f5663a10103a85fc1d8c4e2685 100644 (file)
 #include "message.h"
 #include "token.h"
 
+static CK_OBJECT_CLASS certificate = CKO_CERTIFICATE;
+static CK_BBOOL falsev = CK_FALSE;
+static CK_BBOOL truev = CK_TRUE;
+
 struct {
        p11_token *token;
+       p11_index *index;
+       char *directory;
 } test;
 
 static void
@@ -56,6 +62,19 @@ setup (void *path)
 {
        test.token = p11_token_new (333, path, "Label");
        assert_ptr_not_null (test.token);
+
+       test.index = p11_token_index (test.token);
+       assert_ptr_not_null (test.token);
+}
+
+static void
+setup_temp (void *unused)
+{
+       test.directory = p11_path_expand ("$TEMP/test-module.XXXXXX");
+       if (!mkdtemp (test.directory))
+               assert_not_reached ();
+
+       setup (test.directory);
 }
 
 static void
@@ -65,6 +84,14 @@ teardown (void *path)
        memset (&test, 0, sizeof (test));
 }
 
+static void
+teardown_temp (void *unused)
+{
+       test_delete_directory (test.directory);
+       free (test.directory);
+       teardown (test.directory);
+}
+
 static void
 test_token_load (void *path)
 {
@@ -72,9 +99,9 @@ test_token_load (void *path)
        int count;
 
        count = p11_token_load (test.token);
-       assert_num_eq (7, count);
+       assert_num_eq (6, count);
 
-       /* A certificate and trust object for each parsed object + builtin */
+       /* A certificate and trust object for each parsed object */
        index = p11_token_index (test.token);
        assert (((count - 1) * 2) + 1 <= p11_index_size (index));
 }
@@ -82,10 +109,6 @@ test_token_load (void *path)
 static void
 test_token_flags (void *path)
 {
-       CK_OBJECT_CLASS certificate = CKO_CERTIFICATE;
-       CK_BBOOL falsev = CK_FALSE;
-       CK_BBOOL truev = CK_TRUE;
-
        /*
         * blacklist comes from the input/distrust.pem file. It is not in the blacklist
         * directory, but is an OpenSSL trusted certificate file, and is marked
@@ -228,24 +251,8 @@ test_not_writable (void)
 static void
 test_writable_exists (void)
 {
-       char *directory;
-       p11_token *token;
-
-       directory = p11_path_expand ("$TEMP/test-module.XXXXXX");
-       if (!mkdtemp (directory))
-               assert_not_reached ();
-
-       token = p11_token_new (333, directory, "Label");
-
        /* A writable directory since we created it */
-       assert (p11_token_is_writable (token));
-
-       p11_token_free (token);
-
-       if (rmdir (directory) < 0)
-               assert_not_reached ();
-
-       free (directory);
+       assert (p11_token_is_writable (test.token));
 }
 
 static void
@@ -276,6 +283,196 @@ test_writable_no_exist (void)
        free (directory);
 }
 
+static void
+test_load_already (void)
+{
+       CK_ATTRIBUTE cert[] = {
+               { CKA_CLASS, &certificate, sizeof (certificate) },
+               { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) },
+               { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
+               { CKA_INVALID },
+       };
+
+       CK_OBJECT_HANDLE handle;
+       int ret;
+
+       test_write_file (test.directory, "test.cer", test_cacert3_ca_der,
+                        sizeof (test_cacert3_ca_der));
+
+       ret = p11_token_load (test.token);
+       assert_num_eq (ret, 1);
+       handle = p11_index_find (test.index, cert, -1);
+       assert (handle != 0);
+
+       ret = p11_token_load (test.token);
+       assert_num_eq (ret, 0);
+       assert_num_eq (p11_index_find (test.index, cert, -1), handle);
+}
+
+static void
+test_load_unreadable (void)
+{
+       CK_ATTRIBUTE cert[] = {
+               { CKA_CLASS, &certificate, sizeof (certificate) },
+               { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) },
+               { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
+               { CKA_INVALID },
+       };
+
+       int ret;
+
+       test_write_file (test.directory, "test.cer", test_cacert3_ca_der,
+                        sizeof (test_cacert3_ca_der));
+
+       ret = p11_token_load (test.token);
+       assert_num_eq (ret, 1);
+       assert (p11_index_find (test.index, cert, -1) != 0);
+
+       test_write_file (test.directory, "test.cer", "", 0);
+
+       ret = p11_token_load (test.token);
+       assert_num_eq (ret, 0);
+       assert (p11_index_find (test.index, cert, -1) == 0);
+}
+
+static void
+test_load_gone (void)
+{
+       CK_ATTRIBUTE cert[] = {
+               { CKA_CLASS, &certificate, sizeof (certificate) },
+               { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) },
+               { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
+               { CKA_INVALID },
+       };
+
+       int ret;
+
+       test_write_file (test.directory, "test.cer", test_cacert3_ca_der,
+                        sizeof (test_cacert3_ca_der));
+
+       ret = p11_token_load (test.token);
+       assert_num_eq (ret, 1);
+       assert (p11_index_find (test.index, cert, -1) != 0);
+
+       test_delete_file (test.directory, "test.cer");
+
+       ret = p11_token_load (test.token);
+       assert_num_eq (ret, 0);
+       assert (p11_index_find (test.index, cert, -1) == 0);
+}
+
+static void
+test_load_found (void)
+{
+       CK_ATTRIBUTE cert[] = {
+               { CKA_CLASS, &certificate, sizeof (certificate) },
+               { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) },
+               { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
+               { CKA_INVALID },
+       };
+
+       int ret;
+
+       ret = p11_token_load (test.token);
+       assert_num_eq (ret, 0);
+       assert (p11_index_find (test.index, cert, -1) == 0);
+
+       test_write_file (test.directory, "test.cer", test_cacert3_ca_der,
+                        sizeof (test_cacert3_ca_der));
+
+       ret = p11_token_load (test.token);
+       assert_num_eq (ret, 1);
+       assert (p11_index_find (test.index, cert, -1) != 0);
+}
+
+static void
+test_reload_changed (void)
+{
+       CK_ATTRIBUTE cacert3[] = {
+               { CKA_CLASS, &certificate, sizeof (certificate) },
+               { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) },
+               { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
+               { CKA_INVALID },
+       };
+
+       CK_ATTRIBUTE verisign[] = {
+               { CKA_CLASS, &certificate, sizeof (certificate) },
+               { CKA_VALUE, (void *)verisign_v1_ca, sizeof (verisign_v1_ca) },
+               { CKA_INVALID },
+       };
+
+       CK_ATTRIBUTE *attrs;
+       CK_OBJECT_HANDLE handle;
+       int ret;
+
+       /* Just one file */
+       test_write_file (test.directory, "test.cer", test_cacert3_ca_der,
+                        sizeof (test_cacert3_ca_der));
+
+       ret = p11_token_load (test.token);
+       assert_num_eq (ret, 1);
+       handle = p11_index_find (test.index, cacert3, -1);
+       assert (handle != 0);
+
+       /* Replace the file with verisign */
+       test_write_file (test.directory, "test.cer", verisign_v1_ca,
+                        sizeof (verisign_v1_ca));
+
+       /* Add another file with cacert3, but not reloaded */
+       test_write_file (test.directory, "another.cer", test_cacert3_ca_der,
+                        sizeof (test_cacert3_ca_der));
+
+       attrs = p11_index_lookup (test.index, handle);
+       assert_ptr_not_null (attrs);
+       p11_token_reload (test.token, attrs);
+
+       assert (p11_index_find (test.index, cacert3, -1) == 0);
+       assert (p11_index_find (test.index, verisign, -1) != 0);
+}
+
+static void
+test_reload_gone (void)
+{
+       CK_ATTRIBUTE cacert3[] = {
+               { CKA_CLASS, &certificate, sizeof (certificate) },
+               { CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) },
+               { CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
+               { CKA_INVALID },
+       };
+
+       CK_ATTRIBUTE verisign[] = {
+               { CKA_CLASS, &certificate, sizeof (certificate) },
+               { CKA_VALUE, (void *)verisign_v1_ca, sizeof (verisign_v1_ca) },
+               { CKA_INVALID },
+       };
+
+       CK_ATTRIBUTE *attrs;
+       CK_OBJECT_HANDLE handle;
+       int ret;
+
+       /* Just one file */
+       test_write_file (test.directory, "cacert3.cer", test_cacert3_ca_der,
+                        sizeof (test_cacert3_ca_der));
+       test_write_file (test.directory, "verisign.cer", verisign_v1_ca,
+                        sizeof (verisign_v1_ca));
+
+       ret = p11_token_load (test.token);
+       assert_num_eq (ret, 2);
+       handle = p11_index_find (test.index, cacert3, -1);
+       assert (handle != 0);
+       assert (p11_index_find (test.index, verisign, -1) != 0);
+
+       test_delete_file (test.directory, "cacert3.cer");
+       test_delete_file (test.directory, "verisign.cer");
+
+       attrs = p11_index_lookup (test.index, handle);
+       assert_ptr_not_null (attrs);
+       p11_token_reload (test.token, attrs);
+
+       assert (p11_index_find (test.index, cacert3, -1) == 0);
+       assert (p11_index_find (test.index, verisign, -1) != 0);
+}
+
 int
 main (int argc,
       char *argv[])
@@ -283,16 +480,22 @@ main (int argc,
        p11_fixture (setup, teardown);
        p11_testx (test_token_load, SRCDIR "/input", "/token/load");
        p11_testx (test_token_flags, SRCDIR "/input", "/token/flags");
-
-       p11_fixture (setup, teardown);
        p11_testx (test_token_path, "/wheee", "/token/path");
        p11_testx (test_token_label, "/wheee", "/token/label");
        p11_testx (test_token_slot, "/unneeded", "/token/slot");
 
        p11_fixture (NULL, NULL);
        p11_test (test_not_writable, "/token/not-writable");
-       p11_test (test_writable_exists, "/token/writable-exists");
        p11_test (test_writable_no_exist, "/token/writable-no-exist");
 
+       p11_fixture (setup_temp, teardown_temp);
+       p11_test (test_writable_exists, "/token/writable-exists");
+       p11_test (test_load_found, "/token/load-found");
+       p11_test (test_load_already, "/token/load-already");
+       p11_test (test_load_unreadable, "/token/load-unreadable");
+       p11_test (test_load_gone, "/token/load-gone");
+       p11_test (test_reload_changed, "/token/reload-changed");
+       p11_test (test_reload_gone, "/token/reload-gone");
+
        return p11_test_run (argc, argv);
 }
index 33ba19eaf0233080828695ab25e0f94bbc2cfff0..fceaea766f887a4348a1713f11858290fff88d7f 100644 (file)
@@ -324,3 +324,78 @@ test_check_directory_msg (const char *file,
 
        p11_dict_free (files);
 }
+
+void
+test_write_file_msg (const char *file,
+                     int line,
+                     const char *function,
+                     const char *directory,
+                     const char *name,
+                     const void *contents,
+                     size_t length)
+{
+       char *path;
+       FILE *f;
+
+       if (asprintf (&path, "%s/%s", directory, name) < 0)
+               assert_not_reached ();
+
+       f = fopen (path, "wb");
+       if (f == NULL) {
+               p11_test_fail (file, line, function, "Couldn't open file for writing: %s: %s",
+                              path, strerror (errno));
+       }
+
+       if (fwrite (contents, 1, length, f) != length ||
+           fclose (f) != 0) {
+               p11_test_fail (file, line, function, "Couldn't write file: %s: %s",
+                              path, strerror (errno));
+       }
+
+       free (path);
+}
+
+void
+test_delete_file_msg (const char *file,
+                      int line,
+                      const char *function,
+                      const char *directory,
+                      const char *name)
+{
+       char *path;
+
+       if (asprintf (&path, "%s/%s", directory, name) < 0)
+               assert_not_reached ();
+
+       if (unlink (path) < 0)
+               p11_test_fail (file, line, function, "Couldn't delete file: %s", path);
+
+       free (path);
+}
+
+void
+test_delete_directory_msg (const char *file,
+                           int line,
+                           const char *function,
+                           const char *directory)
+{
+       struct dirent *dp;
+       DIR *dir;
+
+       dir = opendir (directory);
+       if (dir == NULL)
+               p11_test_fail (file ,line, function, "Couldn't open directory: %s", directory);
+
+       while ((dp = readdir (dir)) != NULL) {
+               if (strcmp (dp->d_name, ".") == 0 ||
+                   strcmp (dp->d_name, "..") == 0)
+                       continue;
+
+               test_delete_file_msg (file, line, function, directory, dp->d_name);
+       }
+
+       closedir (dir);
+
+       if (rmdir (directory) < 0)
+               p11_test_fail (file, line, function, "Couldn't remove directory: %s", directory);
+}
index 18ca13c1544d4db2ca10850b477f7688158eeed1..4d2c5bf9805322e2661c60f2eff3baa7660bf563 100644 (file)
@@ -344,4 +344,32 @@ void       test_check_directory_msg     (const char *file,
        (test_check_directory_msg (__FILE__, __LINE__, __FUNCTION__, directory, \
                                   test_check_directory_files files))
 
+#define test_write_file(directory, name, data, length) \
+       (test_write_file_msg (__FILE__, __LINE__, __FUNCTION__, directory, name, data, length))
+
+void      test_write_file_msg           (const char *file,
+                                         int line,
+                                         const char *function,
+                                         const char *directory,
+                                         const char *name,
+                                         const void *contents,
+                                         size_t length);
+
+#define test_delete_file(directory, name) \
+       (test_delete_file_msg (__FILE__, __LINE__, __FUNCTION__, directory, name))
+
+void      test_delete_file_msg          (const char *file,
+                                         int line,
+                                         const char *function,
+                                         const char *directory,
+                                         const char *name);
+
+#define test_delete_directory(directory) \
+       (test_delete_directory_msg (__FILE__, __LINE__, __FUNCTION__, directory))
+
+void      test_delete_directory_msg     (const char *file,
+                                         int line,
+                                         const char *function,
+                                         const char *directory);
+
 #endif /* TEST_DATA_H_ */
index c5991dff00a2b92f175c597351e78bd801723953..ec34f6cb0a2d5d1acb63b214b00c559ba2829c40 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 Red Hat Inc.
+ * Copyright (C) 2012-2013 Red Hat Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include <string.h>
 
 struct _p11_token {
-       p11_parser *parser;
-       p11_index *index;
-       p11_builder *builder;
-       char *path;
-       char *label;
-       CK_SLOT_ID slot;
-       int loaded;
+       p11_parser *parser;       /* Parser we use to load files */
+       p11_index *index;         /* Index we load objects into */
+       p11_builder *builder;     /* Expands objects and applies policy */
+       p11_dict *loaded;         /* stat structs for loaded files, track reloads */
+
+       char *path;               /* Main path to load from */
+       char *anchors;            /* Path to load anchors from */
+       char *blacklist;          /* Path to load blacklist from */
+       char *label;              /* The token label */
+       CK_SLOT_ID slot;          /* The slot id */
 
        bool checked_writable;
        bool is_writable;
 };
 
+static bool
+loader_is_necessary (p11_token *token,
+                     const char *filename,
+                     struct stat *sb)
+{
+       struct stat *last;
+
+       last = p11_dict_get (token->loaded, filename);
+
+       /* Never seen this before, load it */
+       if (last == NULL)
+               return true;
+
+       /*
+        * If any of these are different assume that the file
+        * needs to be reloaded
+        */
+       return (sb->st_mode != last->st_mode ||
+               sb->st_mtime != last->st_mtime ||
+               sb->st_size != last->st_size);
+}
+
+static void
+loader_was_loaded (p11_token *token,
+                   const char *filename,
+                   struct stat *sb)
+{
+       char *key;
+
+       key = strdup (filename);
+       return_if_fail (key != NULL);
+
+       sb = memdup (sb, sizeof (struct stat));
+       return_if_fail (sb != NULL);
+
+       /* Track the info about this file, so we don't reload unnecessarily */
+       if (!p11_dict_set (token->loaded, key, sb))
+               return_if_reached ();
+}
+
+static void
+loader_not_loaded (p11_token *token,
+                   const char *filename)
+{
+       /* No longer track info about this file */
+       p11_dict_remove (token->loaded, filename);
+}
+
+static void
+loader_gone_file (p11_token *token,
+                  const char *filename)
+{
+       CK_ATTRIBUTE origin[] = {
+               { CKA_X_ORIGIN, (void *)filename, strlen (filename) },
+               { CKA_INVALID },
+       };
+
+       CK_RV rv;
+
+       /* Remove everything at this origin */
+       rv = p11_index_replace_all (token->index, origin, CKA_INVALID, NULL);
+       return_if_fail (rv == CKR_OK);
+
+       /* No longer track info about this file */
+       loader_not_loaded (token, filename);
+}
+
 static int
 loader_load_file (p11_token *token,
                   const char *filename,
-                  struct stat *sb,
-                  int flags)
+                  struct stat *sb)
 {
+       CK_ATTRIBUTE origin[] = {
+               { CKA_X_ORIGIN, (void *)filename, strlen (filename) },
+               { CKA_INVALID },
+       };
+
+       CK_BBOOL modifiablev;
+
+       CK_ATTRIBUTE modifiable = {
+               CKA_MODIFIABLE,
+               &modifiablev,
+               sizeof (modifiablev)
+       };
+
+       p11_array *parsed;
+       CK_RV rv;
+       int flags;
        int ret;
+       int i;
+
+       /* Check if this file is already loaded */
+       if (!loader_is_necessary (token, filename, sb))
+               return 0;
+
+       flags = P11_PARSE_FLAG_NONE;
+
+       /* If it's in the anchors subdirectory, treat as an anchor */
+       if (p11_path_prefix (filename, token->anchors))
+               flags = P11_PARSE_FLAG_ANCHOR;
+
+       /* If it's in the blacklist subdirectory, treat as a blacklist */
+       else if (p11_path_prefix (filename, token->blacklist))
+               flags = P11_PARSE_FLAG_BLACKLIST;
+
+       /* If the token is just one path, then assume they are anchors */
+       else if (strcmp (filename, token->path) == 0 && !S_ISDIR (sb->st_mode))
+               flags = P11_PARSE_FLAG_ANCHOR;
 
        ret = p11_parse_file (token->parser, filename, flags);
 
        switch (ret) {
        case P11_PARSE_SUCCESS:
                p11_debug ("loaded: %s", filename);
-               return 1;
+               break;
        case P11_PARSE_UNRECOGNIZED:
                p11_debug ("skipped: %s", filename);
+               loader_gone_file (token, filename);
                return 0;
        default:
                p11_debug ("failed to parse: %s", filename);
+               loader_gone_file (token, filename);
                return 0;
        }
+
+       /* TODO: We should check if in the right format */
+       modifiablev = CK_FALSE;
+
+       /* Update each parsed object with the origin */
+       parsed = p11_parser_parsed (token->parser);
+       for (i = 0; i < parsed->num; i++) {
+               parsed->elem[i] = p11_attrs_build (parsed->elem[i], origin, &modifiable, NULL);
+               return_val_if_fail (parsed->elem[i] != NULL, 0);
+       }
+
+       p11_index_batch (token->index);
+
+       /* Now place all of these in the index */
+       rv = p11_index_replace_all (token->index, origin, CKA_CLASS, parsed);
+
+       p11_index_finish (token->index);
+
+       if (rv != CKR_OK) {
+               p11_message ("couldn't load file into objects: %s", filename);
+               return 0;
+       }
+
+       loader_was_loaded (token, filename, sb);
+       return 1;
+}
+
+static int
+loader_load_if_file (p11_token *token,
+                     const char *path)
+{
+       struct stat sb;
+
+       if (stat (path, &sb) < 0) {
+               if (errno == ENOENT) {
+                       p11_message ("couldn't stat path: %s: %s",
+                                    path, strerror (errno));
+               }
+
+       } else if (!S_ISDIR (sb.st_mode)) {
+               return loader_load_file (token, path, &sb);
+       }
+
+       /* Perhaps the file became unloadable, so track properly */
+       loader_gone_file (token, path);
+       return 0;
 }
 
 static int
 loader_load_directory (p11_token *token,
                        const char *directory,
-                       int flags)
+                       p11_dict *present)
 {
+       p11_dictiter iter;
        struct dirent *dp;
-       struct stat sb;
        char *path;
        int total = 0;
        int ret;
@@ -110,6 +262,7 @@ loader_load_directory (p11_token *token,
        if (!dir) {
                p11_message ("couldn't list directory: %s: %s",
                             directory, strerror (errno));
+               loader_not_loaded (token, directory);
                return 0;
        }
 
@@ -118,81 +271,81 @@ loader_load_directory (p11_token *token,
                path = p11_path_build (directory, dp->d_name, NULL);
                return_val_if_fail (path != NULL, -1);
 
-               if (stat (path, &sb) < 0) {
-                       p11_message ("couldn't stat path: %s", path);
+               ret = loader_load_if_file (token, path);
+               return_val_if_fail (ret >=0, -1);
+               total += ret;
 
-               } else if (!S_ISDIR (sb.st_mode)) {
-                       ret = loader_load_file (token, path, &sb, flags);
-                       return_val_if_fail (ret >= 0, ret);
-                       total += ret;
-               }
+               /* Make note that this file was seen */
+               p11_dict_remove (present, path);
 
                free (path);
        }
 
        closedir (dir);
-       return total;
-}
 
-static int
-loader_load_subdirectory (p11_token *token,
-                          const char *directory,
-                          const char *subdir,
-                          int flags)
-{
-       struct stat sb;
-       char *path;
-       int ret = 0;
+       /* All other files that were present, not here now */
+       p11_dict_iterate (present, &iter);
+       while (p11_dict_next (&iter, (void **)&path, NULL))
+               loader_gone_file (token, path);
 
-       if (asprintf (&path, "%s/%s", directory, subdir) < 0)
-               return_val_if_reached (-1);
-
-       if (stat (path, &sb) >= 0 && S_ISDIR (sb.st_mode))
-               ret = loader_load_directory (token, path, flags);
-
-       free (path);
-       return ret;
+       return total;
 }
 
 static int
 loader_load_path (p11_token *token,
                   const char *path)
 {
+       p11_dictiter iter;
+       p11_dict *present;
+       char *filename;
        struct stat sb;
        int total;
        int ret;
 
        if (stat (path, &sb) < 0) {
-               if (errno == ENOENT) {
-                       p11_message ("trust certificate path does not exist: %s",
-                                    path);
-               } else {
+               if (errno != ENOENT) {
                        p11_message ("cannot access trust certificate path: %s: %s",
                                     path, strerror (errno));
                }
-
+               loader_gone_file (token, path);
                return 0;
        }
 
        if (S_ISDIR (sb.st_mode)) {
-               total = 0;
 
-               ret = loader_load_subdirectory (token, path, "anchors", P11_PARSE_FLAG_ANCHOR);
-               return_val_if_fail (ret >= 0, ret);
-               total += ret;
+               /* All the files we know about at this path */
+               present = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, NULL, NULL);
+               p11_dict_iterate (token->loaded, &iter);
+               while (p11_dict_next (&iter, (void **)&filename, NULL)) {
+                       if (p11_path_prefix (filename, path)) {
+                               if (!p11_dict_set (present, filename, filename))
+                                       return_val_if_reached (-1);
+                       }
+               }
 
-               ret = loader_load_subdirectory (token, path, "blacklist", P11_PARSE_FLAG_BLACKLIST);
-               return_val_if_fail (ret >= 0, ret);
-               total += ret;
+               /* If the directory has changed, reload it */
+               if (loader_is_necessary (token, path, &sb)) {
+                       ret = loader_load_directory (token, path, present);
 
-               ret = loader_load_directory (token, path, P11_PARSE_FLAG_NONE);
-               return_val_if_fail (ret >= 0, ret);
-               total += ret;
+               /* Directory didn't change, but maybe files changed? */
+               } else {
+                       total = 0;
+                       p11_dict_iterate (present, &iter);
+                       while (p11_dict_next (&iter, (void **)&filename, NULL)) {
+                               ret = loader_load_if_file (token, filename);
+                               return_val_if_fail (ret >= 0, ret);
+                               total += ret;
+                       }
+               }
+
+               p11_dict_free (present);
+               loader_was_loaded (token, path, &sb);
 
-               return total;
        } else {
-               return loader_load_file (token, path, &sb, P11_PARSE_FLAG_ANCHOR);
+               ret = loader_load_file (token, path, &sb);
        }
+
+       return ret;
 }
 
 static int
@@ -223,19 +376,49 @@ load_builtin_objects (p11_token *token)
 int
 p11_token_load (p11_token *token)
 {
-       int builtins;
-       int count;
+       int total = 0;
+       int ret;
 
-       if (token->loaded)
-               return 0;
-       token->loaded = 1;
+       ret = loader_load_path (token, token->path);
+       return_val_if_fail (ret >= 0, -1);
+       total += ret;
+
+       ret = loader_load_path (token, token->anchors);
+       return_val_if_fail (ret >= 0, -1);
+       total += ret;
+
+       ret = loader_load_path (token, token->blacklist);
+       return_val_if_fail (ret >= 0, -1);
+       total += ret;
+
+       return total;
+}
 
-       builtins = load_builtin_objects (token);
+void
+p11_token_reload (p11_token *token,
+                  CK_ATTRIBUTE *attrs)
+{
+       CK_ATTRIBUTE *attr;
+       struct stat sb;
+       char *origin;
 
-       count = loader_load_path (token, token->path);
-       return_val_if_fail (count >= 0, count);
+       attr = p11_attrs_find (attrs, CKA_X_ORIGIN);
+       if (attr == NULL)
+               return;
 
-       return count + builtins;
+       origin = strndup (attr->pValue, attr->ulValueLen);
+       return_if_fail (origin != NULL);
+
+       if (stat (origin, &sb) < 0) {
+               if (errno == ENOENT) {
+                       loader_gone_file (token, origin);
+               } else {
+                       p11_message ("cannot access trust file: %s: %s",
+                                    origin, strerror (errno));
+               }
+       } else {
+               loader_load_file (token, origin, &sb);
+       }
 }
 
 void
@@ -247,7 +430,10 @@ p11_token_free (p11_token *token)
        p11_index_free (token->index);
        p11_parser_free (token->parser);
        p11_builder_free (token->builder);
+       p11_dict_free (token->loaded);
        free (token->path);
+       free (token->anchors);
+       free (token->blacklist);
        free (token->label);
        free (token);
 }
@@ -273,18 +459,27 @@ p11_token_new (CK_SLOT_ID slot,
                                      token->builder);
        return_val_if_fail (token->index != NULL, NULL);
 
-       token->parser = p11_parser_new (token->index,
-                                       p11_builder_get_cache (token->builder));
+       token->parser = p11_parser_new (p11_builder_get_cache (token->builder));
        return_val_if_fail (token->parser != NULL, NULL);
 
+       token->loaded = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, free, free);
+       return_val_if_fail (token->loaded != NULL, NULL);
+
        token->path = strdup (path);
        return_val_if_fail (token->path != NULL, NULL);
 
+       token->anchors = p11_path_build (token->path, "anchors", NULL);
+       return_val_if_fail (token->anchors != NULL, NULL);
+
+       token->blacklist = p11_path_build (token->path, "blacklist", NULL);
+       return_val_if_fail (token->blacklist != NULL, NULL);
+
        token->label = strdup (label);
        return_val_if_fail (token->label != NULL, NULL);
 
        token->slot = slot;
-       token->loaded = 0;
+
+       load_builtin_objects (token);
 
        p11_debug ("token: %s: %s", token->label, token->path);
        return token;
index 49140bb3ef6f6675c898cedb7ab1ca0c166fdd4c..6d50c6c4c72206cd90d673ec9681f3b07a86969e 100644 (file)
@@ -49,6 +49,9 @@ void            p11_token_free        (p11_token *token);
 
 int             p11_token_load        (p11_token *token);
 
+void            p11_token_reload      (p11_token *token,
+                                       CK_ATTRIBUTE *attrs);
+
 p11_index *     p11_token_index       (p11_token *token);
 
 const char *    p11_token_get_path    (p11_token *token);