1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3    Copyright (C) 2009 Stefan Walter
4 
5    The Gnome Keyring Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9 
10    The Gnome Keyring Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14 
15    You should have received a copy of the GNU Library General Public
16    License along with the Gnome Library; see the file COPYING.LIB.  If not,
17    <http://www.gnu.org/licenses/>.
18 
19    Author: Stef Walter <stef@memberwebs.com>
20 */
21 
22 #include "config.h"
23 
24 #include "mock-secret-module.h"
25 
26 #include "secret-store/gkm-secret-collection.h"
27 #include "secret-store/gkm-secret-fields.h"
28 #include "secret-store/gkm-secret-item.h"
29 #include "secret-store/gkm-secret-search.h"
30 
31 #include "gkm/gkm-session.h"
32 #include "gkm/gkm-transaction.h"
33 #include "gkm/gkm-test.h"
34 
35 #include "pkcs11/pkcs11i.h"
36 
37 #include <glib.h>
38 
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42 
43 typedef struct {
44 	GkmModule *module;
45 	GkmSession *session;
46 	GkmFactory *factory;
47 	GkmSecretCollection *collection;
48 	GkmSecretItem *item;
49 } Test;
50 
51 static void
setup(Test * test,gconstpointer unused)52 setup (Test *test, gconstpointer unused)
53 {
54 	GHashTable *fields;
55 
56 	test->module = test_secret_module_initialize_and_enter ();
57 	test->session = test_secret_module_open_session (TRUE);
58 	test->factory = GKM_FACTORY_SECRET_SEARCH;
59 	g_assert (test->factory);
60 
61 	test->collection = g_object_new (GKM_TYPE_SECRET_COLLECTION,
62 	                           "module", test->module,
63 	                           "manager", gkm_session_get_manager (test->session),
64 	                           "identifier", "test-collection",
65 	                           NULL);
66 
67 	/* Create an test->item */
68 	test->item = gkm_secret_collection_new_item (test->collection, "test-item");
69 	fields = gkm_secret_fields_new ();
70 	gkm_secret_fields_add (fields, "name1", "value1");
71 	gkm_secret_fields_add (fields, "name2", "value2");
72 	gkm_secret_item_set_fields (test->item, fields);
73 	g_hash_table_unref (fields);
74 
75 	gkm_object_expose (GKM_OBJECT (test->collection), TRUE);
76 }
77 
78 static void
teardown(Test * test,gconstpointer unused)79 teardown (Test *test, gconstpointer unused)
80 {
81 	g_object_unref (test->collection);
82 	test_secret_module_leave_and_finalize ();
83 }
84 
85 static void
test_incomplete(Test * test,gconstpointer unused)86 test_incomplete (Test *test, gconstpointer unused)
87 {
88 	CK_ATTRIBUTE attrs[1];
89 	GkmObject *object = NULL;
90 	GkmTransaction *transaction = gkm_transaction_new ();
91 
92 	object = gkm_session_create_object_for_factory (test->session, test->factory, transaction, attrs, 0);
93 	g_assert (gkm_transaction_complete_and_unref (transaction) == CKR_TEMPLATE_INCOMPLETE);
94 	g_assert (object == NULL);
95 }
96 
97 static void
test_bad_fields(Test * test,gconstpointer unused)98 test_bad_fields (Test *test, gconstpointer unused)
99 {
100 	CK_ATTRIBUTE attrs[] = {
101 	        { CKA_G_FIELDS, "bad-value", 9 },
102 	};
103 
104 	GkmObject *object = NULL;
105 	GkmTransaction *transaction = gkm_transaction_new ();
106 
107 	object = gkm_session_create_object_for_factory (test->session, test->factory, transaction, attrs, 1);
108 	g_assert (gkm_transaction_complete_and_unref (transaction) == CKR_ATTRIBUTE_VALUE_INVALID);
109 	g_assert (object == NULL);
110 }
111 
112 static void
test_new(Test * test,gconstpointer unused)113 test_new (Test *test, gconstpointer unused)
114 {
115 	CK_ATTRIBUTE attrs[] = {
116 	        { CKA_G_FIELDS, "test\0value\0two\0value2", 22 },
117 	};
118 
119 	const gchar *identifier;
120 	GkmObject *object = NULL;
121 	GHashTable *fields;
122 	gpointer vdata;
123 	gulong vulong;
124 	gboolean vbool;
125 	gsize vsize;
126 
127 	object = gkm_session_create_object_for_factory (test->session, test->factory, NULL, attrs, 1);
128 	g_assert (object != NULL);
129 	g_assert (GKM_IS_SECRET_SEARCH (object));
130 
131 	if (!gkm_object_get_attribute_ulong (object, test->session, CKA_CLASS, &vulong))
132 		g_assert_not_reached ();
133 	g_assert (vulong == CKO_G_SEARCH);
134 
135 	if (!gkm_object_get_attribute_boolean (object, test->session, CKA_MODIFIABLE, &vbool))
136 		g_assert_not_reached ();
137 	g_assert (vbool == CK_TRUE);
138 
139 	vdata = gkm_object_get_attribute_data (object, test->session, CKA_G_FIELDS, &vsize);
140 	g_assert (vdata);
141 	g_assert (vsize == attrs[0].ulValueLen);
142 	g_free (vdata);
143 
144 	vdata = gkm_object_get_attribute_data (object, test->session, CKA_G_COLLECTION, &vsize);
145 	g_assert (vdata);
146 	g_assert (vsize == 0);
147 	g_free (vdata);
148 
149 	/* No objects matched */
150 	vdata = gkm_object_get_attribute_data (object, test->session, CKA_G_MATCHED, &vsize);
151 	g_assert (vdata);
152 	g_assert (vsize == 0);
153 	g_free (vdata);
154 
155 	/* Get the fields object and check */
156 	fields = gkm_secret_search_get_fields (GKM_SECRET_SEARCH (object));
157 	g_assert (fields);
158 	g_assert_cmpstr (gkm_secret_fields_get (fields, "test"), ==, "value");
159 
160 	/* No test->collection */
161 	identifier = gkm_secret_search_get_collection_id (GKM_SECRET_SEARCH (object));
162 	g_assert (identifier == NULL);
163 
164 	g_object_unref (object);
165 }
166 
167 static void
test_and_match(Test * test,gconstpointer unused)168 test_and_match (Test *test, gconstpointer unused)
169 {
170 	CK_ATTRIBUTE attrs[] = {
171 	        { CKA_G_FIELDS, "name1\0value1\0name2\0value2", 26 },
172 	};
173 
174 	GkmObject *object = NULL;
175 	gpointer vdata;
176 	gsize vsize;
177 
178 	object = gkm_session_create_object_for_factory (test->session, test->factory, NULL, attrs, 1);
179 	g_assert (object != NULL);
180 	g_assert (GKM_IS_SECRET_SEARCH (object));
181 
182 	/* One object matched */
183 	vdata = gkm_object_get_attribute_data (object, test->session, CKA_G_MATCHED, &vsize);
184 	g_assert (vdata);
185 	g_assert (vsize == sizeof (CK_OBJECT_HANDLE));
186 	g_assert (*((CK_OBJECT_HANDLE_PTR)vdata) == gkm_object_get_handle (GKM_OBJECT (test->item)));
187 	g_free (vdata);
188 
189 	g_object_unref (object);
190 }
191 
192 static void
test_and_change_to_match(Test * test,gconstpointer unused)193 test_and_change_to_match (Test *test, gconstpointer unused)
194 {
195 	CK_ATTRIBUTE attrs[] = {
196 	        { CKA_G_FIELDS, "name1\0value1", 13 },
197 	};
198 
199 	GkmObject *object = NULL;
200 	GHashTable *fields;
201 	gpointer vdata;
202 	gsize vsize;
203 
204 	/* Make it not match */
205 	fields = gkm_secret_fields_new ();
206 	gkm_secret_item_set_fields (test->item, fields);
207 	g_hash_table_unref (fields);
208 
209 	object = gkm_session_create_object_for_factory (test->session, test->factory, NULL, attrs, 1);
210 	g_assert (object != NULL);
211 	g_assert (GKM_IS_SECRET_SEARCH (object));
212 
213 	/* Nothing matched */
214 	vdata = gkm_object_get_attribute_data (object, test->session, CKA_G_MATCHED, &vsize);
215 	g_assert (vsize == 0);
216 	g_free (vdata);
217 
218 	/* Make it match */
219 	fields = gkm_secret_fields_new ();
220 	gkm_secret_fields_add (fields, "name1", "value1");
221 	gkm_secret_fields_add (fields, "name2", "value2");
222 	gkm_secret_item_set_fields (test->item, fields);
223 	g_hash_table_unref (fields);
224 
225 	/* One object matched */
226 	vdata = gkm_object_get_attribute_data (object, test->session, CKA_G_MATCHED, &vsize);
227 	g_assert (vdata);
228 	g_assert (vsize == sizeof (CK_OBJECT_HANDLE));
229 	g_assert (*((CK_OBJECT_HANDLE_PTR)vdata) == gkm_object_get_handle (GKM_OBJECT (test->item)));
230 	g_free (vdata);
231 
232 	g_object_unref (object);
233 }
234 
235 static void
test_and_change_to_not_match(Test * test,gconstpointer unused)236 test_and_change_to_not_match (Test *test, gconstpointer unused)
237 {
238 	CK_ATTRIBUTE attrs[] = {
239 	        { CKA_G_FIELDS, "name1\0value1", 13 },
240 	};
241 
242 	GkmObject *object = NULL;
243 	GHashTable *fields;
244 	gpointer vdata;
245 	gsize vsize;
246 
247 	object = gkm_session_create_object_for_factory (test->session, test->factory, NULL, attrs, 1);
248 	g_assert (object != NULL);
249 	g_assert (GKM_IS_SECRET_SEARCH (object));
250 
251 	/* One object matched */
252 	vdata = gkm_object_get_attribute_data (object, test->session, CKA_G_MATCHED, &vsize);
253 	g_assert (vdata);
254 	g_assert (vsize == sizeof (CK_OBJECT_HANDLE));
255 	g_assert (*((CK_OBJECT_HANDLE_PTR)vdata) == gkm_object_get_handle (GKM_OBJECT (test->item)));
256 	g_free (vdata);
257 
258 	/* Make it not match */
259 	fields = gkm_secret_fields_new ();
260 	gkm_secret_item_set_fields (test->item, fields);
261 	g_hash_table_unref (fields);
262 
263 	/* Nothing matched */
264 	vdata = gkm_object_get_attribute_data (object, test->session, CKA_G_MATCHED, &vsize);
265 	g_assert (vsize == 0);
266 	g_free (vdata);
267 
268 	g_object_unref (object);
269 }
270 
271 static void
test_for_bad_collection(Test * test,gconstpointer unused)272 test_for_bad_collection (Test *test, gconstpointer unused)
273 {
274 	CK_ATTRIBUTE attrs[] = {
275 	        { CKA_G_FIELDS, "name1\0value1", 13 },
276 	        { CKA_G_COLLECTION, "bad-test->collection", 14 },
277 	};
278 
279 	GkmObject *object = NULL;
280 	GkmTransaction *transaction = gkm_transaction_new ();
281 
282 	object = gkm_session_create_object_for_factory (test->session, test->factory, transaction, attrs, 2);
283 	g_assert (gkm_transaction_complete_and_unref (transaction) == CKR_OK);
284 
285 	g_object_unref (object);
286 }
287 
288 static void
test_for_collection(Test * test,gconstpointer unused)289 test_for_collection (Test *test, gconstpointer unused)
290 {
291 	CK_ATTRIBUTE attrs[] = {
292 	        { CKA_G_FIELDS, "name1\0value1", 13 },
293 	        { CKA_G_COLLECTION, "test-collection", 15 },
294 	};
295 
296 	GkmObject *object = NULL;
297 	gpointer vdata;
298 	gsize vsize;
299 
300 	object = gkm_session_create_object_for_factory (test->session, test->factory, NULL, attrs, 2);
301 	g_assert (object != NULL);
302 	g_assert (GKM_IS_SECRET_SEARCH (object));
303 
304 	/* Should have the test->collection set properly */
305 	vdata = gkm_object_get_attribute_data (object, test->session, CKA_G_COLLECTION , &vsize);
306 	g_assert (vdata);
307 	g_assert (vsize == 15);
308 	g_assert (memcmp (vdata, "test-collection", 15) == 0);
309 	g_free (vdata);
310 
311 	/* One object matched */
312 	vdata = gkm_object_get_attribute_data (object, test->session, CKA_G_MATCHED, &vsize);
313 	g_assert (vdata);
314 	g_assert (vsize == sizeof (CK_OBJECT_HANDLE));
315 	g_assert (*((CK_OBJECT_HANDLE_PTR)vdata) == gkm_object_get_handle (GKM_OBJECT (test->item)));
316 	g_free (vdata);
317 
318 	g_object_unref (object);
319 }
320 
321 static void
test_for_collection_no_match(Test * test,gconstpointer unused)322 test_for_collection_no_match (Test *test, gconstpointer unused)
323 {
324 	CK_ATTRIBUTE attrs[] = {
325 	        { CKA_G_FIELDS, "test\0value", 11 },
326 	        { CKA_G_COLLECTION, "test-collection", 15 },
327 	};
328 
329 	GkmObject *object = NULL;
330 	GkmSecretCollection *ocoll;
331 	GkmSecretItem *oitem;
332 	GHashTable *fields;
333 	gpointer vdata;
334 	gsize vsize;
335 
336 	ocoll = g_object_new (GKM_TYPE_SECRET_COLLECTION,
337 	                      "module", test->module,
338 	                      "manager", gkm_session_get_manager (test->session),
339 	                      "identifier", "other-collection",
340 	                      NULL);
341 	oitem = gkm_secret_collection_new_item (ocoll, "other-item");
342 	gkm_object_expose (GKM_OBJECT (ocoll), TRUE);
343 
344 	/* Make it match, but remember, wrong collection*/
345 	fields = gkm_secret_fields_new ();
346 	gkm_secret_fields_add (fields, "test", "value");
347 	gkm_secret_item_set_fields (oitem, fields);
348 	g_hash_table_unref (fields);
349 
350 	object = gkm_session_create_object_for_factory (test->session, test->factory, NULL, attrs, 2);
351 	g_assert (object != NULL);
352 	g_assert (GKM_IS_SECRET_SEARCH (object));
353 
354 	/* No objects matched */
355 	vdata = gkm_object_get_attribute_data (object, test->session, CKA_G_MATCHED, &vsize);
356 	g_assert (vsize == 0);
357 	g_free (vdata);
358 
359 	g_object_unref (object);
360 	g_object_unref (ocoll);
361 }
362 
363 static void
test_order(Test * test,gconstpointer unused)364 test_order (Test *test,
365             gconstpointer unused)
366 {
367 	CK_ATTRIBUTE attrs[] = {
368 	        { CKA_G_FIELDS, "test\0value", 11 },
369 	        { CKA_G_COLLECTION, "other-collection", 16 },
370 	};
371 
372 	GkmObject *object = NULL;
373 	GkmSecretCollection *collection;
374 	GkmSecretItem *item;
375 	GHashTable *fields;
376 	gulong *matched;
377 	gsize vsize;
378 	gchar *identifier;
379 	glong modified;
380 	glong last;
381 	gint i;
382 	CK_RV rv;
383 
384 	collection = g_object_new (GKM_TYPE_SECRET_COLLECTION,
385 	                           "module", test->module,
386 	                           "manager", gkm_session_get_manager (test->session),
387 	                           "identifier", "other-collection",
388 	                           NULL);
389 
390 	gkm_object_expose (GKM_OBJECT (collection), TRUE);
391 
392 	/* Add a bunch of items */
393 	for (i = 0; i < 2000; i++) {
394 		identifier = g_strdup_printf ("item-%d", i);
395 		item = gkm_secret_collection_new_item (collection, identifier);
396 		g_free (identifier);
397 
398 		/* Make it match, but remember, wrong collection*/
399 		fields = gkm_secret_fields_new ();
400 		gkm_secret_fields_add (fields, "test", "value");
401 		gkm_secret_item_set_fields (item, fields);
402 		g_hash_table_unref (fields);
403 
404 		gkm_secret_object_set_modified (GKM_SECRET_OBJECT (item),
405 		                                (glong)g_random_int ());
406 		gkm_object_expose (GKM_OBJECT (item), TRUE);
407 	}
408 
409 	object = gkm_session_create_object_for_factory (test->session, test->factory, NULL, attrs, 2);
410 	g_assert (object != NULL);
411 	g_assert (GKM_IS_SECRET_SEARCH (object));
412 
413 	/* No objects matched */
414 	matched = gkm_object_get_attribute_data (object, test->session, CKA_G_MATCHED, &vsize);
415 	g_assert (matched != NULL);
416 	gkm_assert_cmpulong (vsize, ==, sizeof (gulong) * 2000);
417 
418 	last = G_MAXLONG;
419 	for (i = 0; i < vsize / sizeof (gulong); i++) {
420 		rv = gkm_session_lookup_readable_object (test->session, matched[i], (GkmObject **)&item);
421 		gkm_assert_cmprv (rv, ==, CKR_OK);
422 
423 		modified = gkm_secret_object_get_modified (GKM_SECRET_OBJECT (item));
424 		g_assert (last > modified);
425 		last = modified;
426 	}
427 
428 	g_free (matched);
429 
430 	g_object_unref (object);
431 	g_object_unref (collection);
432 }
433 
434 int
main(int argc,char ** argv)435 main (int argc, char **argv)
436 {
437 #if !GLIB_CHECK_VERSION(2,35,0)
438 	g_type_init ();
439 #endif
440 	g_test_init (&argc, &argv, NULL);
441 
442 	g_test_add ("/secret-store/search/new", Test, NULL, setup, test_new, teardown);
443 	g_test_add ("/secret-store/search/incomplete", Test, NULL, setup, test_incomplete, teardown);
444 	g_test_add ("/secret-store/search/bad_fields", Test, NULL, setup, test_bad_fields, teardown);
445 	g_test_add ("/secret-store/search/and_match", Test, NULL, setup, test_and_match, teardown);
446 	g_test_add ("/secret-store/search/and_change_to_match", Test, NULL, setup, test_and_change_to_match, teardown);
447 	g_test_add ("/secret-store/search/and_change_to_not_match", Test, NULL, setup, test_and_change_to_not_match, teardown);
448 	g_test_add ("/secret-store/search/for_bad_collection", Test, NULL, setup, test_for_bad_collection, teardown);
449 	g_test_add ("/secret-store/search/for_collection", Test, NULL, setup, test_for_collection, teardown);
450 	g_test_add ("/secret-store/search/for_collection_no_match", Test, NULL, setup, test_for_collection_no_match, teardown);
451 	g_test_add ("/secret-store/search/order", Test, NULL, setup, test_order, teardown);
452 
453 	return g_test_run ();
454 }
455