]> granicus.if.org Git - p11-kit/commitdiff
trust: Initial support for writing out token objects
authorStef Walter <stef@thewalter.net>
Wed, 3 Jul 2013 10:47:14 +0000 (12:47 +0200)
committerStef Walter <stef@thewalter.net>
Wed, 3 Jul 2013 11:14:48 +0000 (13:14 +0200)
 * The objects are written out in the p11-kit persist format
 * Parser marks files in p11-kit persist format as modifiable

trust/Makefile.am
trust/module.c
trust/parser.c
trust/tests/test-module.c
trust/tests/test-parser.c
trust/tests/test-token.c
trust/tests/test-trust.c
trust/token.c
trust/token.h

index 70a79463c35829a3c593d2f7dcc9ccd8d2176dde..13f65f01dc7c8d2e77d2137b5d01eca3294d0192 100644 (file)
@@ -35,6 +35,7 @@ MODULE_SRCS = \
        parser.c parser.h \
        persist.c persist.h \
        module.c module.h \
+       save.c save.h \
        session.c session.h \
        token.c token.h \
        types.h \
index 22e288c2ca69917ae0811399e421541891e8291b..d2fcba688bd13773286d11eff26b05f5fdf69d6c 100644 (file)
@@ -1102,7 +1102,6 @@ sys_C_SetAttributeValue (CK_SESSION_HANDLE handle,
                        attrs = lookup_object_inlock (session, object, &index);
                        if (attrs == NULL) {
                                rv = CKR_OBJECT_HANDLE_INVALID;
-
                        } else if (p11_attrs_find_bool (attrs, CKA_MODIFIABLE, &val) && !val) {
                                /* TODO: This should be replaced with CKR_ACTION_PROHIBITED */
                                rv = CKR_ATTRIBUTE_READ_ONLY;
@@ -1110,11 +1109,20 @@ sys_C_SetAttributeValue (CK_SESSION_HANDLE handle,
 
                        if (rv == CKR_OK)
                                rv = check_index_writable (session, index);
-                       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);
+
+                       /* Reload the item if applicable */
+                       if (rv == CKR_OK && index == p11_token_index (session->token)) {
+                               if (p11_token_reload (session->token, attrs)) {
+                                       attrs = p11_index_lookup (index, object);
+                                       if (p11_attrs_find_bool (attrs, CKA_MODIFIABLE, &val) && !val) {
+                                               /* TODO: This should be replaced with CKR_ACTION_PROHIBITED */
+                                               rv = CKR_ATTRIBUTE_READ_ONLY;
+                                       }
+                               }
                        }
+
+                       if (rv == CKR_OK)
+                               rv = p11_index_set (index, object, template, count);
                }
 
        p11_unlock ();
index c5cbe15736516385e53e9dc6b81f0060998b6a2d..1ae3dc1c34c49c277631bc45494d918b0b34ade8 100644 (file)
@@ -577,7 +577,7 @@ parse_p11_kit_persist (p11_parser *parser,
                        const unsigned char *data,
                        size_t length)
 {
-       CK_BBOOL modifiablev = CK_FALSE;
+       CK_BBOOL modifiablev = CK_TRUE;
        CK_ATTRIBUTE *attrs;
        p11_array *objects;
        bool ret;
index f5d882e6fd4abb80210e0e6af007fa83e9725594..f1813a3d2a5f6119731e612f03b1d83ad4aff3f2 100644 (file)
@@ -46,6 +46,7 @@
 #include "hash.h"
 #include "library.h"
 #include "path.h"
+#include "parser.h"
 #include "pkcs11x.h"
 #include "token.h"
 
@@ -67,6 +68,8 @@ struct {
        CK_FUNCTION_LIST *module;
        CK_SLOT_ID slots[NUM_SLOTS];
        char *directory;
+       p11_asn1_cache *cache;
+       p11_parser *parser;
 } test;
 
 static void
@@ -109,6 +112,10 @@ teardown (void *unused)
 {
        CK_RV rv;
 
+       if (test.parser)
+               p11_parser_free (test.parser);
+       p11_asn1_cache_free (test.cache);
+
        rv = test.module->C_Finalize (NULL);
        assert (rv == CKR_OK);
 
@@ -150,6 +157,9 @@ setup_writable (void *unused)
        rv = test.module->C_GetSlotList (CK_TRUE, test.slots, &count);
        assert_num_eq (rv, CKR_OK);
        assert_num_eq (count, 1);
+
+       test.cache = p11_asn1_cache_new ();
+       test.parser = p11_parser_new (test.cache);
 }
 
 static void
@@ -449,7 +459,6 @@ check_trust_object_equiv (CK_SESSION_HANDLE session,
        unsigned char subject[1024];
        unsigned char issuer[1024];
        unsigned char serial[128];
-       CK_BBOOL modifiable;
        CK_BBOOL private;
        CK_BBOOL token;
        CK_RV rv;
@@ -458,14 +467,13 @@ check_trust_object_equiv (CK_SESSION_HANDLE session,
        CK_ATTRIBUTE equiv[] = {
                { CKA_TOKEN, &token, sizeof (token) },
                { CKA_PRIVATE, &private, sizeof (private) },
-               { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) },
                { CKA_ISSUER, issuer, sizeof (issuer) },
                { CKA_SUBJECT, subject, sizeof (subject) },
                { CKA_SERIAL_NUMBER, serial, sizeof (serial) },
                { CKA_INVALID, },
        };
 
-       rv = test.module->C_GetAttributeValue (session, trust, equiv, 6);
+       rv = test.module->C_GetAttributeValue (session, trust, equiv, 5);
        assert_num_eq (CKR_OK, rv);
 
        test_check_attrs (equiv, cert);
@@ -541,7 +549,6 @@ check_certificate (CK_SESSION_HANDLE session,
        CK_DATE start;
        CK_DATE end;
        CK_ULONG category;
-       CK_BBOOL modifiable;
        CK_BBOOL private;
        CK_BBOOL token;
        CK_RV rv;
@@ -550,7 +557,6 @@ check_certificate (CK_SESSION_HANDLE session,
                { CKA_CLASS, &klass, sizeof (klass) },
                { CKA_TOKEN, &token, sizeof (token) },
                { CKA_PRIVATE, &private, sizeof (private) },
-               { CKA_MODIFIABLE, &modifiable, sizeof (modifiable) },
                { CKA_VALUE, value, sizeof (value) },
                { CKA_ISSUER, issuer, sizeof (issuer) },
                { CKA_SUBJECT, subject, sizeof (subject) },
@@ -566,8 +572,8 @@ check_certificate (CK_SESSION_HANDLE session,
        };
 
        /* Note that we don't pass the CKA_INVALID attribute in */
-       rv = test.module->C_GetAttributeValue (session, handle, attrs, 15);
-       assert (rv == CKR_OK);
+       rv = test.module->C_GetAttributeValue (session, handle, attrs, 14);
+       assert_num_eq (rv, CKR_OK);
 
        /* If this is the cacert3 certificate, check its values */
        if (memcmp (value, test_cacert3_ca_der, sizeof (test_cacert3_ca_der)) == 0) {
@@ -1064,6 +1070,110 @@ test_session_read_only_create (void)
        assert_num_eq (rv, CKR_SESSION_READ_ONLY);
 }
 
+static void
+test_create_and_write (void)
+{
+       CK_ATTRIBUTE original[] = {
+               { CKA_CLASS, &data, sizeof (data) },
+               { CKA_LABEL, "yay", 3 },
+               { CKA_VALUE, "eight", 5 },
+               { CKA_TOKEN, &vtrue, sizeof (vtrue) },
+               { CKA_INVALID }
+       };
+
+       CK_ATTRIBUTE expected[] = {
+               { CKA_CLASS, &data, sizeof (data) },
+               { CKA_LABEL, "yay", 3 },
+               { CKA_VALUE, "eight", 5 },
+               { CKA_APPLICATION, "", 0 },
+               { CKA_OBJECT_ID, "", 0 },
+               { CKA_INVALID }
+       };
+
+       CK_SESSION_HANDLE session;
+       CK_OBJECT_HANDLE handle;
+       p11_array *parsed;
+       char *path;
+       CK_RV rv;
+       int ret;
+
+       /* Read-only session */
+       rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION,
+                                        NULL, NULL, &session);
+       assert_num_eq (rv, CKR_OK);
+
+       /* Create a token object */
+       rv = test.module->C_CreateObject (session, original, 4, &handle);
+       assert_num_eq (rv, CKR_OK);
+
+       /* The expected file name */
+       path = p11_path_build (test.directory, "yay.p11-kit", NULL);
+       ret = p11_parse_file (test.parser, path, 0);
+       assert_num_eq (ret, P11_PARSE_SUCCESS);
+       free (path);
+
+       parsed = p11_parser_parsed (test.parser);
+       assert_num_eq (parsed->num, 1);
+
+       test_check_attrs (expected, parsed->elem[0]);
+}
+
+static void
+test_modify_and_write (void)
+{
+       CK_ATTRIBUTE original[] = {
+               { CKA_VALUE, "eight", 5 },
+               { CKA_CLASS, &data, sizeof (data) },
+               { CKA_LABEL, "yay", 3 },
+               { CKA_TOKEN, &vtrue, sizeof (vtrue) },
+               { CKA_MODIFIABLE, &vtrue, sizeof (vtrue) },
+               { CKA_INVALID }
+       };
+
+       CK_ATTRIBUTE expected[] = {
+               { CKA_CLASS, &data, sizeof (data) },
+               { CKA_LABEL, "yay", 3 },
+               { CKA_VALUE, "nine", 4 },
+               { CKA_APPLICATION, "", 0 },
+               { CKA_OBJECT_ID, "", 0 },
+               { CKA_INVALID }
+       };
+
+       CK_SESSION_HANDLE session;
+       CK_OBJECT_HANDLE handle;
+       p11_array *parsed;
+       char *path;
+       CK_RV rv;
+       int ret;
+
+       /* Read-only session */
+       rv = test.module->C_OpenSession (test.slots[0], CKF_SERIAL_SESSION | CKF_RW_SESSION,
+                                        NULL, NULL, &session);
+       assert_num_eq (rv, CKR_OK);
+
+       /* Create a token object */
+       rv = test.module->C_CreateObject (session, original, 5, &handle);
+       assert_num_eq (rv, CKR_OK);
+
+       /* Now modify the object */
+       original[0].pValue = "nine";
+       original[0].ulValueLen = 4;
+
+       rv = test.module->C_SetAttributeValue (session, handle, original, 5);
+       assert_num_eq (rv, CKR_OK);
+
+       /* The expected file name */
+       path = p11_path_build (test.directory, "yay.p11-kit", NULL);
+       ret = p11_parse_file (test.parser, path, 0);
+       assert_num_eq (ret, P11_PARSE_SUCCESS);
+       free (path);
+
+       parsed = p11_parser_parsed (test.parser);
+       assert_num_eq (parsed->num, 1);
+
+       test_check_attrs (expected, parsed->elem[0]);
+}
+
 int
 main (int argc,
       char *argv[])
@@ -1100,6 +1210,8 @@ main (int argc,
        p11_fixture (setup_writable, teardown);
        p11_test (test_token_writable, "/module/token-writable");
        p11_test (test_session_read_only_create, "/module/session-read-only-create");
+       p11_test (test_create_and_write, "/module/create-and-write");
+       p11_test (test_modify_and_write, "/module/modify-and-write");
 
        return p11_test_run (argc, argv);
 }
index 3eee984d235799267a868bdb2ab0d316d19f0253..b8d31df488392a6967690ab4a0a5284af8d72d37 100644 (file)
@@ -165,7 +165,6 @@ test_parse_p11_kit_persist (void)
                { CKA_CERTIFICATE_TYPE, &x509, sizeof (x509) },
                { CKA_CLASS, &certificate, sizeof (certificate) },
                { CKA_VALUE, (void *)verisign_v1_ca, sizeof (verisign_v1_ca) },
-               { CKA_MODIFIABLE, &falsev, sizeof (falsev) },
                { CKA_TRUSTED, &truev, sizeof (truev) },
                { CKA_X_DISTRUSTED, &falsev, sizeof (falsev) },
                { CKA_INVALID },
index a518c9e31c43f7f5663a10103a85fc1d8c4e2685..6b998ca25cdedb08851c1b21fbfd9f18e6c6e9af 100644 (file)
 
 #include "attrs.h"
 #include "debug.h"
+#include "parser.h"
 #include "path.h"
 #include "pkcs11x.h"
 #include "message.h"
 #include "token.h"
 
 static CK_OBJECT_CLASS certificate = CKO_CERTIFICATE;
+static CK_OBJECT_CLASS data = CKO_DATA;
 static CK_BBOOL falsev = CK_FALSE;
 static CK_BBOOL truev = CK_TRUE;
 
 struct {
        p11_token *token;
        p11_index *index;
+       p11_parser *parser;
        char *directory;
 } test;
 
@@ -65,6 +68,9 @@ setup (void *path)
 
        test.index = p11_token_index (test.token);
        assert_ptr_not_null (test.token);
+
+       test.parser = p11_token_parser (test.token);
+       assert_ptr_not_null (test.parser);
 }
 
 static void
@@ -424,7 +430,8 @@ test_reload_changed (void)
 
        attrs = p11_index_lookup (test.index, handle);
        assert_ptr_not_null (attrs);
-       p11_token_reload (test.token, attrs);
+       if (!p11_token_reload (test.token, attrs))
+               assert_not_reached ();
 
        assert (p11_index_find (test.index, cacert3, -1) == 0);
        assert (p11_index_find (test.index, verisign, -1) != 0);
@@ -467,12 +474,108 @@ test_reload_gone (void)
 
        attrs = p11_index_lookup (test.index, handle);
        assert_ptr_not_null (attrs);
-       p11_token_reload (test.token, attrs);
+       if (p11_token_reload (test.token, attrs))
+               assert_not_reached ();
 
        assert (p11_index_find (test.index, cacert3, -1) == 0);
        assert (p11_index_find (test.index, verisign, -1) != 0);
 }
 
+static void
+test_reload_no_origin (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 },
+       };
+
+       if (p11_token_reload (test.token, cacert3))
+               assert_not_reached ();
+}
+
+static void
+test_write_new (void)
+{
+       CK_ATTRIBUTE original[] = {
+               { CKA_CLASS, &data, sizeof (data) },
+               { CKA_LABEL, "Yay!", 4 },
+               { CKA_VALUE, "eight", 5 },
+               { CKA_TOKEN, &truev, sizeof (truev) },
+               { CKA_INVALID }
+       };
+
+       CK_ATTRIBUTE expected[] = {
+               { CKA_CLASS, &data, sizeof (data) },
+               { CKA_LABEL, "Yay!", 4 },
+               { CKA_VALUE, "eight", 5 },
+               { CKA_APPLICATION, "", 0 },
+               { CKA_OBJECT_ID, "", 0 },
+               { CKA_INVALID }
+       };
+
+       CK_OBJECT_HANDLE handle;
+       p11_array *parsed;
+       char *path;
+       CK_RV rv;
+       int ret;
+
+       rv = p11_index_add (test.index, original, 4, &handle);
+       assert_num_eq (rv, CKR_OK);
+
+       /* The expected file name */
+       path = p11_path_build (test.directory, "Yay_.p11-kit", NULL);
+       ret = p11_parse_file (test.parser, path, 0);
+       assert_num_eq (ret, P11_PARSE_SUCCESS);
+       free (path);
+
+       parsed = p11_parser_parsed (test.parser);
+       assert_num_eq (parsed->num, 1);
+
+       test_check_attrs (expected, parsed->elem[0]);
+}
+
+static void
+test_write_no_label (void)
+{
+       CK_ATTRIBUTE original[] = {
+               { CKA_CLASS, &data, sizeof (data) },
+               { CKA_VALUE, "eight", 5 },
+               { CKA_TOKEN, &truev, sizeof (truev) },
+               { CKA_INVALID }
+       };
+
+       CK_ATTRIBUTE expected[] = {
+               { CKA_CLASS, &data, sizeof (data) },
+               { CKA_LABEL, "", 0 },
+               { CKA_VALUE, "eight", 5 },
+               { CKA_APPLICATION, "", 0 },
+               { CKA_OBJECT_ID, "", 0 },
+               { CKA_INVALID }
+       };
+
+       CK_OBJECT_HANDLE handle;
+       p11_array *parsed;
+       char *path;
+       CK_RV rv;
+       int ret;
+
+       rv = p11_index_add (test.index, original, 4, &handle);
+       assert_num_eq (rv, CKR_OK);
+
+       /* The expected file name */
+       path = p11_path_build (test.directory, "data.p11-kit", NULL);
+       ret = p11_parse_file (test.parser, path, 0);
+       assert_num_eq (ret, P11_PARSE_SUCCESS);
+       free (path);
+
+       parsed = p11_parser_parsed (test.parser);
+       assert_num_eq (parsed->num, 1);
+
+       test_check_attrs (expected, parsed->elem[0]);
+}
+
 int
 main (int argc,
       char *argv[])
@@ -496,6 +599,9 @@ main (int argc,
        p11_test (test_load_gone, "/token/load-gone");
        p11_test (test_reload_changed, "/token/reload-changed");
        p11_test (test_reload_gone, "/token/reload-gone");
+       p11_test (test_reload_no_origin, "/token/reload-no-origin");
+       p11_test (test_write_new, "/token/write-new");
+       p11_test (test_write_no_label, "/token/write-no-label");
 
        return p11_test_run (argc, argv);
 }
index fceaea766f887a4348a1713f11858290fff88d7f..205a08a0f278164db74ee62ee66b88f28263d5ef 100644 (file)
@@ -64,7 +64,6 @@ test_check_object_msg (const char *file,
 
        CK_ATTRIBUTE expected[] = {
                { CKA_PRIVATE, &vfalse, sizeof (vfalse) },
-               { CKA_MODIFIABLE, &vfalse, sizeof (vfalse) },
                { CKA_CLASS, &klass, sizeof (klass) },
                { label ? CKA_LABEL : CKA_INVALID, (void *)label, label ? strlen (label) : 0 },
                { CKA_INVALID },
index 6b88fc604beb82c28ccc75220653b1c307e261f4..e9bcf44970494995eeb0102678f659a1f3afe913 100644 (file)
@@ -38,6 +38,7 @@
 #include "attrs.h"
 #include "builder.h"
 #include "compat.h"
+#include "constants.h"
 #define P11_DEBUG_FLAG P11_DEBUG_TRUST
 #include "debug.h"
 #include "errno.h"
 #include "module.h"
 #include "parser.h"
 #include "path.h"
+#include "persist.h"
 #include "pkcs11.h"
 #include "pkcs11x.h"
+#include "save.h"
 #include "token.h"
 
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <assert.h>
 #include <dirent.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -113,12 +117,12 @@ loader_was_loaded (p11_token *token,
                return_if_reached ();
 }
 
-static void
+static bool
 loader_not_loaded (p11_token *token,
                    const char *filename)
 {
        /* No longer track info about this file */
-       p11_dict_remove (token->loaded, filename);
+       return p11_dict_remove (token->loaded, filename);
 }
 
 static void
@@ -150,14 +154,6 @@ loader_load_file (p11_token *token,
                { CKA_INVALID },
        };
 
-       CK_BBOOL modifiablev;
-
-       CK_ATTRIBUTE modifiable = {
-               CKA_MODIFIABLE,
-               &modifiablev,
-               sizeof (modifiablev)
-       };
-
        p11_array *parsed;
        CK_RV rv;
        int flags;
@@ -198,13 +194,10 @@ loader_load_file (p11_token *token,
                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);
+               parsed->elem[i] = p11_attrs_build (parsed->elem[i], origin, NULL);
                return_val_if_fail (parsed->elem[i] != NULL, 0);
        }
 
@@ -401,7 +394,7 @@ p11_token_load (p11_token *token)
        return total;
 }
 
-void
+bool
 p11_token_reload (p11_token *token,
                   CK_ATTRIBUTE *attrs)
 {
@@ -411,10 +404,10 @@ p11_token_reload (p11_token *token,
 
        attr = p11_attrs_find (attrs, CKA_X_ORIGIN);
        if (attr == NULL)
-               return;
+               return false;
 
        origin = strndup (attr->pValue, attr->ulValueLen);
-       return_if_fail (origin != NULL);
+       return_val_if_fail (origin != NULL, false);
 
        if (stat (origin, &sb) < 0) {
                if (errno == ENOENT) {
@@ -423,9 +416,187 @@ p11_token_reload (p11_token *token,
                        p11_message ("cannot access trust file: %s: %s",
                                     origin, strerror (errno));
                }
+               return false;
+       }
+
+       return loader_load_file (token, origin, &sb) > 0;
+}
+
+static p11_save_file *
+writer_overwrite_origin (p11_token *token,
+                         CK_ATTRIBUTE *origin)
+{
+       p11_save_file *file;
+       char *path;
+
+       path = strndup (origin->pValue, origin->ulValueLen);
+       return_val_if_fail (path != NULL, NULL);
+
+       file = p11_save_open_file (path, NULL, P11_SAVE_OVERWRITE);
+       free (path);
+
+       return file;
+}
+
+static char *
+writer_suggest_name (CK_ATTRIBUTE *attrs)
+{
+       CK_ATTRIBUTE *label;
+       CK_OBJECT_CLASS klass;
+       const char *nick;
+
+       label = p11_attrs_find (attrs, CKA_LABEL);
+       if (label && label->ulValueLen)
+               return strndup (label->pValue, label->ulValueLen);
+
+       nick = NULL;
+       if (p11_attrs_find_ulong (attrs, CKA_CLASS, &klass))
+               nick = p11_constant_nick (p11_constant_classes, klass);
+       if (nick == NULL)
+               nick = "object";
+       return strdup (nick);
+}
+
+static p11_save_file *
+writer_create_origin (p11_token *token,
+                      CK_ATTRIBUTE *attrs)
+{
+       p11_save_file *file;
+       char *name;
+       char *path;
+
+       name = writer_suggest_name (attrs);
+       return_val_if_fail (name != NULL, NULL);
+
+       p11_path_canon (name);
+
+       path = p11_path_build (token->path, name, NULL);
+       free (name);
+
+       file = p11_save_open_file (path, ".p11-kit", P11_SAVE_UNIQUE);
+       free (path);
+
+       return file;
+}
+
+static CK_RV
+writer_put_header (p11_save_file *file)
+{
+       const char *header =
+               "# This file has been auto-generated and written by p11-kit. Changes will be\n"
+               "# unceremoniously overwritten.\n"
+               "#\n"
+               "# The format is designed to be somewhat human readable and debuggable, and a\n"
+               "# bit transparent but it is not encouraged to read/write this format from other\n"
+               "# applications or tools without first discussing this at the the mailing list:\n"
+               "#\n"
+               "#       p11-glue@lists.freedesktop.org\n"
+               "#\n";
+
+       if (!p11_save_write (file, header, -1))
+               return CKR_FUNCTION_FAILED;
+
+       return CKR_OK;
+}
+
+static CK_RV
+writer_put_object (p11_save_file *file,
+                   p11_persist *persist,
+                   p11_buffer *buffer,
+                   CK_ATTRIBUTE *attrs)
+{
+       if (!p11_buffer_reset (buffer, 0))
+               assert_not_reached ();
+       if (!p11_persist_write (persist, attrs, buffer))
+               return_val_if_reached (CKR_GENERAL_ERROR);
+       if (!p11_save_write (file, buffer->data, buffer->len))
+               return CKR_FUNCTION_FAILED;
+
+       return CKR_OK;
+}
+
+static CK_RV
+on_index_build (void *data,
+                p11_index *index,
+                CK_ATTRIBUTE **attrs,
+                CK_ATTRIBUTE *merge)
+{
+       p11_token *token = data;
+       CK_OBJECT_HANDLE *other;
+       p11_persist *persist;
+       p11_buffer buffer;
+       CK_ATTRIBUTE *origin;
+       CK_ATTRIBUTE *object;
+       p11_save_file *file;
+       bool creating = false;
+       char *path;
+       CK_RV rv;
+       int i;
+
+       rv = p11_builder_build (token->builder, index, attrs, merge);
+       if (rv != CKR_OK)
+               return rv;
+
+       /* Signifies that data is being loaded, don't write out */
+       if (p11_index_loading (index))
+               return CKR_OK;
+
+       /* Do we already have a filename? */
+       origin = p11_attrs_find (*attrs, CKA_X_ORIGIN);
+       if (origin == NULL) {
+               file = writer_create_origin (token, *attrs);
+               creating = true;
+               other = NULL;
+
+       } else {
+               other = p11_index_find_all (index, origin, 1);
+               file = writer_overwrite_origin (token, origin);
+               creating = false;
+       }
+
+       if (file == NULL) {
+               free (origin);
+               return CKR_GENERAL_ERROR;
+       }
+
+       persist = p11_persist_new ();
+       p11_buffer_init (&buffer, 1024);
+
+       rv = writer_put_header (file);
+       if (rv == CKR_OK)
+               rv = writer_put_object (file, persist, &buffer, *attrs);
+
+       for (i = 0; rv == CKR_OK && other && other[i] != 0; i++) {
+               object = p11_index_lookup (index, other[i]);
+               if (object != NULL && object != *attrs)
+                       rv = writer_put_object (file, persist, &buffer, object);
+       }
+
+       p11_buffer_uninit (&buffer);
+       p11_persist_free (persist);
+
+       if (rv == CKR_OK) {
+               if (!p11_save_finish_file (file, &path, true))
+                       rv = CKR_FUNCTION_FAILED;
+               else if (creating)
+                       *attrs = p11_attrs_take (*attrs, CKA_X_ORIGIN, path, strlen (path));
+               else
+                       free (path);
        } else {
-               loader_load_file (token, origin, &sb);
+               p11_save_finish_file (file, NULL, false);
        }
+
+       return rv;
+}
+
+static void
+on_index_notify (void *data,
+                 p11_index *index,
+                 CK_OBJECT_HANDLE handle,
+                 CK_ATTRIBUTE *attrs)
+{
+       p11_token *token = data;
+       p11_builder_changed (token->builder, index, handle, attrs);
 }
 
 void
@@ -461,9 +632,7 @@ p11_token_new (CK_SLOT_ID slot,
        token->builder = p11_builder_new (P11_BUILDER_FLAG_TOKEN);
        return_val_if_fail (token->builder != NULL, NULL);
 
-       token->index = p11_index_new (p11_builder_build,
-                                     p11_builder_changed,
-                                     token->builder);
+       token->index = p11_index_new (on_index_build, on_index_notify, token);
        return_val_if_fail (token->index != NULL, NULL);
 
        token->parser = p11_parser_new (p11_builder_get_cache (token->builder));
@@ -520,6 +689,13 @@ p11_token_index (p11_token *token)
        return token->index;
 }
 
+p11_parser *
+p11_token_parser (p11_token *token)
+{
+       return_val_if_fail (token != NULL, NULL);
+       return token->parser;
+}
+
 static bool
 check_writable_directory (const char *path)
 {
index 6d50c6c4c72206cd90d673ec9681f3b07a86969e..1180b27f7faaf59915f883f9dd8e17bbf19fc8d5 100644 (file)
@@ -37,6 +37,7 @@
 
 #include "dict.h"
 #include "index.h"
+#include "parser.h"
 #include "pkcs11.h"
 
 typedef struct _p11_token p11_token;
@@ -49,11 +50,13 @@ void            p11_token_free        (p11_token *token);
 
 int             p11_token_load        (p11_token *token);
 
-void            p11_token_reload      (p11_token *token,
+bool            p11_token_reload      (p11_token *token,
                                        CK_ATTRIBUTE *attrs);
 
 p11_index *     p11_token_index       (p11_token *token);
 
+p11_parser *    p11_token_parser      (p11_token *token);
+
 const char *    p11_token_get_path    (p11_token *token);
 
 const char *    p11_token_get_label   (p11_token *token);