From dee46ac0c6287fbd57ec9b57ddeade27933fea05 Mon Sep 17 00:00:00 2001
From: Stef Walter <stef@thewalter.net>
Date: Wed, 28 Aug 2013 10:46:13 +0200
Subject: [PATCH] trust: Add support for removing trust token objects

---
 trust/tests/test-token.c | 99 ++++++++++++++++++++++++++++++++++++++++
 trust/token.c            | 87 ++++++++++++++++++++++++++++++++++-
 2 files changed, 185 insertions(+), 1 deletion(-)

diff --git a/trust/tests/test-token.c b/trust/tests/test-token.c
index 855b56b..965de76 100644
--- a/trust/tests/test-token.c
+++ b/trust/tests/test-token.c
@@ -658,6 +658,103 @@ test_modify_multiple (void)
 	test_check_attrs (third, parsed->elem[2]);
 }
 
+static void
+test_remove_one (void)
+{
+	const char *test_data =
+		"[p11-kit-object-v1]\n"
+		"class: data\n"
+		"label: \"first\"\n"
+		"value: \"1\"\n"
+		"\n";
+
+	CK_ATTRIBUTE match = { CKA_LABEL, "first", 5 };
+
+	CK_OBJECT_HANDLE handle;
+	CK_RV rv;
+
+	test_write_file (test.directory, "Test.p11-kit", test_data, strlen (test_data));
+	test_check_directory (test.directory, ("Test.p11-kit", NULL));
+
+	/* Reload now that we have this new file */
+	p11_token_load (test.token);
+
+	handle = p11_index_find (test.index, &match, 1);
+	assert_num_cmp (handle, !=, 0);
+
+	rv = p11_index_remove (test.index, handle);
+	assert_num_eq (rv, CKR_OK);
+
+	/* No other files in the test directory, all files gone */
+	test_check_directory (test.directory, (NULL, NULL));
+}
+
+static void
+test_remove_multiple (void)
+{
+	const char *test_data =
+		"[p11-kit-object-v1]\n"
+		"class: data\n"
+		"label: \"first\"\n"
+		"value: \"1\"\n"
+		"\n"
+		"[p11-kit-object-v1]\n"
+		"class: data\n"
+		"label: \"second\"\n"
+		"value: \"2\"\n"
+		"\n"
+		"[p11-kit-object-v1]\n"
+		"class: data\n"
+		"label: \"third\"\n"
+		"value: \"3\"\n";
+
+	CK_ATTRIBUTE first[] = {
+		{ CKA_CLASS, &data, sizeof (data) },
+		{ CKA_LABEL, "first", 5 },
+		{ CKA_VALUE, "1", 1 },
+		{ CKA_INVALID },
+	};
+
+	CK_ATTRIBUTE third[] = {
+		{ CKA_CLASS, &data, sizeof (data) },
+		{ CKA_LABEL, "third", 5 },
+		{ CKA_VALUE, "3", 1 },
+		{ CKA_INVALID },
+	};
+
+	CK_ATTRIBUTE match = { CKA_LABEL, "second", 6 };
+
+	CK_OBJECT_HANDLE handle;
+	p11_array *parsed;
+	char *path;
+	int ret;
+	CK_RV rv;
+
+	test_write_file (test.directory, "Test.p11-kit", test_data, strlen (test_data));
+
+	/* Reload now that we have this new file */
+	p11_token_load (test.token);
+
+	handle = p11_index_find (test.index, &match, 1);
+	assert_num_cmp (handle, !=, 0);
+
+	rv = p11_index_remove (test.index, handle);
+	assert_num_eq (rv, CKR_OK);
+
+	/* Now read in the file and make sure it has all the objects */
+	path = p11_path_build (test.directory, "Test.p11-kit", NULL);
+	ret = p11_parse_file (test.parser, path, NULL, 0);
+	assert_num_eq (ret, P11_PARSE_SUCCESS);
+	free (path);
+
+	parsed = p11_parser_parsed (test.parser);
+	assert_num_eq (parsed->num, 2);
+
+	/* The modified one will be first */
+	test_check_attrs (first, parsed->elem[0]);
+	test_check_attrs (third, parsed->elem[1]);
+}
+
 int
 main (int argc,
       char *argv[])
@@ -685,6 +782,8 @@ main (int argc,
 	p11_test (test_write_new, "/token/write-new");
 	p11_test (test_write_no_label, "/token/write-no-label");
 	p11_test (test_modify_multiple, "/token/modify-multiple");
+	p11_test (test_remove_one, "/token/remove-one");
+	p11_test (test_remove_multiple, "/token/remove-multiple");
 
 	return p11_test_run (argc, argv);
 }
diff --git a/trust/token.c b/trust/token.c
index eeebb82..15ca018 100644
--- a/trust/token.c
+++ b/trust/token.c
@@ -479,6 +479,25 @@ check_token_directory (p11_token *token)
 	return token->checked_path;
 }
 
+static bool
+writer_remove_origin (p11_token *token,
+                         CK_ATTRIBUTE *origin)
+{
+	bool ret = true;
+	char *path;
+
+	path = strndup (origin->pValue, origin->ulValueLen);
+	return_val_if_fail (path != NULL, false);
+
+	if (unlink (path) < 0) {
+		p11_message_err (errno, "couldn't remove file: %s", path);
+		ret = false;
+	}
+
+	free (path);
+	return ret;
+}
+
 static p11_save_file *
 writer_overwrite_origin (p11_token *token,
                          CK_ATTRIBUTE *origin)
@@ -701,6 +720,72 @@ on_index_store (void *data,
 	return rv;
 }
 
+static CK_RV
+on_index_remove (void *data,
+                 p11_index *index,
+                 CK_ATTRIBUTE *attrs)
+{
+	p11_token *token = data;
+	CK_OBJECT_HANDLE *other;
+	p11_persist *persist;
+	p11_buffer buffer;
+	CK_ATTRIBUTE *origin;
+	CK_ATTRIBUTE *object;
+	p11_save_file *file;
+	CK_RV rv = CKR_OK;
+	int i;
+
+	/* Signifies that data is being loaded, don't write out */
+	if (p11_index_loading (index))
+		return CKR_OK;
+
+	if (!check_token_directory (token))
+		return CKR_FUNCTION_FAILED;
+
+	/* We should have a file name */
+	origin = p11_attrs_find (attrs, CKA_X_ORIGIN);
+	return_val_if_fail (origin != NULL, CKR_GENERAL_ERROR);
+
+	/* If there are other objects in this file, then rewrite it */
+	other = p11_index_find_all (index, origin, 1);
+	if (other && other[0]) {
+		file = writer_overwrite_origin (token, origin);
+		if (file == NULL) {
+			free (other);
+			return CKR_GENERAL_ERROR;
+		}
+
+		persist = p11_persist_new ();
+		p11_buffer_init (&buffer, 1024);
+
+		rv = writer_put_header (file);
+		for (i = 0; rv == CKR_OK && other && other[i] != 0; i++) {
+			object = p11_index_lookup (index, other[i]);
+			if (object != NULL)
+				rv = writer_put_object (file, persist, &buffer, object);
+		}
+
+		if (rv == CKR_OK) {
+			if (!p11_save_finish_file (file, NULL, true))
+				rv = CKR_FUNCTION_FAILED;
+		} else {
+			p11_save_finish_file (file, NULL, false);
+		}
+
+		p11_persist_free (persist);
+		p11_buffer_uninit (&buffer);
+
+	/* Otherwise just remove the file */
+	} else {
+		if (!writer_remove_origin (token, origin))
+			rv = CKR_FUNCTION_FAILED;
+	}
+
+	free (other);
+
+	return rv;
+}
+
 static void
 on_index_notify (void *data,
                  p11_index *index,
@@ -746,7 +831,7 @@ p11_token_new (CK_SLOT_ID slot,
 
 	token->index = p11_index_new (on_index_build,
 	                              on_index_store,
-	                              NULL,
+	                              on_index_remove,
 	                              on_index_notify,
 	                              token);
 	return_val_if_fail (token->index != NULL, NULL);
-- 
2.40.0