1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* gck-enumerator.c - the GObject PKCS#11 wrapper library
3 
4    Copyright (C) 2010, Stefan Walter
5 
6    The Gnome Keyring Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10 
11    The Gnome Keyring Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15 
16    You should have received a copy of the GNU Library General Public
17    License along with the Gnome Library; see the file COPYING.LIB.  If not,
18    see <http://www.gnu.org/licenses/>.
19 
20    Author: Stef Walter <nielsen@memberwebs.com>
21 */
22 
23 #include "config.h"
24 
25 #include "gck.h"
26 #include "gck-private.h"
27 
28 #include <string.h>
29 
30 /**
31  * SECTION:gck-enumerator
32  * @title: GckEnumerator
33  * @short_description: Enumerates through PKCS\#11 objects.
34  *
35  * A GckEnumerator can be used to enumerate through PKCS\#11 objects. It will
36  * automatically create sessions as necessary.
37  *
38  * Use gck_modules_enumerate_objects() or gck_modules_enumerate_uri() to create
39  * an enumerator. To get the objects use gck_enumerator_next() or
40  * gck_enumerator_next_async() functions.
41  */
42 
43 enum {
44 	PROP_0,
45 	PROP_INTERACTION,
46 	PROP_OBJECT_TYPE,
47 	PROP_CHAINED
48 };
49 
50 /**
51  * GckEnumerator:
52  *
53  * An object that allows enumerating of objects across modules, tokens.
54  */
55 
56 typedef struct _GckEnumeratorResult {
57 	gulong handle;
58 	GckSession *session;
59 	GckAttributes *attrs;
60 } GckEnumeratorResult;
61 
62 typedef struct _GckEnumeratorState GckEnumeratorState;
63 
64 typedef gpointer (*GckEnumeratorFunc)     (GckEnumeratorState *args,
65                                            gboolean forward);
66 
67 struct _GckEnumeratorState {
68 	gpointer enumerator;
69 	GckEnumeratorState *chained;
70 
71 	/* For the current call */
72 	gint want_objects;
73 
74 	/* The state we're currently in */
75 	GckEnumeratorFunc handler;
76 
77 	/* Input to enumerator */
78 	GList *modules;
79 	GckUriData *match;
80 	GckSessionOptions session_options;
81 	GTlsInteraction *interaction;
82 
83 	/* The type of objects to create */
84 	GType object_type;
85 	gpointer object_class;
86 	const gulong *attr_types;
87 	gint attr_count;
88 
89 	/* state_slots */
90 	GList *slots;
91 
92 	/* state_slot */
93 	GckSlot *slot;
94 	GckTokenInfo *token_info;
95 	CK_FUNCTION_LIST_PTR funcs;
96 
97 	/* state_session */
98 	GckSession *session;
99 
100 	/* state_find */
101 	GQueue *found;
102 
103 	/* state_results */
104 	GQueue *results;
105 };
106 
107 struct _GckEnumeratorPrivate {
108 	GMutex *mutex;
109 	GckEnumeratorState *the_state;
110 	GTlsInteraction *interaction;
111 	GType object_type;
112 	GckObjectClass *object_class;
113 	gulong *attr_types;
114 	gint attr_count;
115 	GckEnumerator *chained;
116 };
117 
118 G_DEFINE_TYPE_WITH_PRIVATE (GckEnumerator, gck_enumerator, G_TYPE_OBJECT);
119 
120 static gpointer state_modules        (GckEnumeratorState *args,
121                                       gboolean forward);
122 
123 static gpointer state_slots          (GckEnumeratorState *args,
124                                       gboolean forward);
125 
126 static gpointer state_slot           (GckEnumeratorState *args,
127                                       gboolean forward);
128 
129 static gpointer state_session        (GckEnumeratorState *args,
130                                       gboolean forward);
131 
132 static gpointer state_find           (GckEnumeratorState *args,
133                                       gboolean forward);
134 
135 static gpointer state_results        (GckEnumeratorState *args,
136                                       gboolean forward);
137 
138 
139 static void
_gck_enumerator_result_free(gpointer data)140 _gck_enumerator_result_free (gpointer data)
141 {
142 	GckEnumeratorResult *result = data;
143 	g_object_unref (result->session);
144 	if (result->attrs)
145 		gck_attributes_unref (result->attrs);
146 	g_slice_free (GckEnumeratorResult, result);
147 }
148 
149 static gpointer
rewind_state(GckEnumeratorState * args,GckEnumeratorFunc handler)150 rewind_state (GckEnumeratorState *args, GckEnumeratorFunc handler)
151 {
152 	g_assert (args);
153 	g_assert (handler);
154 	g_assert (args->handler);
155 
156 	while (handler != args->handler) {
157 		args->handler = (args->handler) (args, FALSE);
158 		g_assert (args->handler);
159 	}
160 
161 	return handler;
162 }
163 
164 static void
cleanup_state(GckEnumeratorState * args)165 cleanup_state (GckEnumeratorState *args)
166 {
167 	g_assert (args);
168 
169 	/* Have each state cleanup */
170 	rewind_state (args, state_modules);
171 
172 	/* state_slots */
173 	g_assert (!args->slots);
174 
175 	/* state_slot */
176 	g_assert (!args->slot);
177 	g_assert (!args->token_info);
178 	g_assert (!args->funcs);
179 
180 	/* state_session */
181 	g_assert (!args->session);
182 
183 	/* state_find */
184 	if (args->found) {
185 		g_queue_foreach (args->found, (GFunc) _gck_enumerator_result_free, NULL);
186 		g_queue_free (args->found);
187 		args->found = NULL;
188 	}
189 
190 	/* state_results */
191 	if (args->results) {
192 		g_queue_foreach (args->results, (GFunc) _gck_enumerator_result_free, NULL);
193 		g_queue_free (args->results);
194 		args->results = NULL;
195 	}
196 
197 	gck_list_unref_free (args->modules);
198 	args->modules = NULL;
199 
200 	g_clear_object (&args->interaction);
201 
202 	if (args->object_class)
203 		g_type_class_unref (args->object_class);
204 	args->object_class = NULL;
205 	args->object_type = 0;
206 
207 	if (args->match) {
208 		gck_uri_data_free (args->match);
209 		args->match = NULL;
210 	}
211 }
212 
213 static gpointer
state_modules(GckEnumeratorState * args,gboolean forward)214 state_modules (GckEnumeratorState *args, gboolean forward)
215 {
216 	GckModule *module;
217 
218 	g_assert (args->slots == NULL);
219 
220 	if (forward) {
221 
222 		/* There are no more modules? */
223 		if (!args->modules) {
224 			g_debug ("no more modules, stopping enumerator");
225 			return NULL;
226 		}
227 
228 		/* Pop off the current module */
229 		module = args->modules->data;
230 		g_assert (GCK_IS_MODULE (module));
231 		args->modules = g_list_delete_link (args->modules, args->modules);
232 
233 		args->slots = gck_module_get_slots (module, TRUE);
234 
235 		GckModuleInfo *info = gck_module_get_info (module);
236 		g_debug ("enumerating into module: %s", info->library_description);
237 		gck_module_info_free (info);
238 
239 		g_object_unref (module);
240 		return state_slots;
241 	}
242 
243 	/* Should never be asked to go backward from start state */
244 	g_assert_not_reached ();
245 }
246 
247 static gpointer
state_slots(GckEnumeratorState * args,gboolean forward)248 state_slots (GckEnumeratorState *args, gboolean forward)
249 {
250 	GckSlot *slot;
251 	GckModule *module;
252 	GckTokenInfo *token_info;
253 	gboolean matched;
254 
255 	g_assert (args->slot == NULL);
256 
257 	/* slots to slot state */
258 	if (forward) {
259 
260 		/* If there are no more slots go back to start state */
261 		if (!args->slots) {
262 			g_debug ("no more slots, want next module");
263 			return rewind_state (args, state_modules);
264 		}
265 
266 		/* Pop the next slot off the stack */
267 		slot = args->slots->data;
268 		args->slots = g_list_delete_link (args->slots, args->slots);
269 
270 		token_info = gck_slot_get_token_info (slot);
271 		if (!token_info) {
272 			g_message ("couldn't get token info for slot while enumerating");
273 			g_object_unref (slot);
274 
275 			/* Skip over this slot to the next slot */
276 			return state_slots;
277 		}
278 
279 		/* Do we have unrecognized matches? */
280 		if (args->match->any_unrecognized) {
281 			g_debug ("token uri had unrecognized, not matching any tokens");
282 			matched = FALSE;
283 
284 		/* Are we trying to match the slot? */
285 		} else if (args->match->token_info) {
286 			/* No match? Go to next slot */
287 			matched = _gck_token_info_match (args->match->token_info, token_info);
288 
289 			g_debug ("%s token: %s", matched ? "matched" : "did not match",
290 			         token_info->label);
291 
292 		} else {
293 			g_debug ("matching all tokens: %s", token_info->label);
294 			matched = TRUE;
295 		}
296 
297 		if (!matched) {
298 			g_object_unref (slot);
299 			gck_token_info_free (token_info);
300 			return state_slots;
301 		}
302 
303 		module = gck_slot_get_module (slot);
304 		args->funcs = gck_module_get_functions (module);
305 		g_assert (args->funcs);
306 		g_object_unref (module);
307 
308 		/* We have a slot */
309 		args->slot = slot;
310 		args->token_info = token_info;
311 		return state_slot;
312 
313 	/* slots state to modules state */
314 	} else {
315 
316 		gck_list_unref_free (args->slots);
317 		args->slots = NULL;
318 		return state_modules;
319 	}
320 }
321 
322 static gpointer
state_slot(GckEnumeratorState * args,gboolean forward)323 state_slot (GckEnumeratorState *args, gboolean forward)
324 {
325 	CK_SESSION_HANDLE session;
326 	CK_FLAGS flags;
327 	CK_RV rv;
328 
329 	g_assert (args->slot);
330 	g_assert (args->funcs);
331 	g_assert (args->session == NULL);
332 
333 	/* slot to session state */
334 	if (forward) {
335 		flags = CKF_SERIAL_SESSION;
336 		if ((args->session_options & GCK_SESSION_READ_WRITE) == GCK_SESSION_READ_WRITE)
337 			flags |= CKF_RW_SESSION;
338 
339 		rv = (args->funcs->C_OpenSession) (gck_slot_get_handle (args->slot),
340 		                                   flags, NULL, NULL, &session);
341 
342 		if (rv != CKR_OK) {
343 			g_message ("couldn't open session on module while enumerating objects: %s",
344 			           gck_message_from_rv (rv));
345 			return rewind_state (args, state_slots);
346 		}
347 
348 		g_debug ("opened %s session", flags & CKF_RW_SESSION ? "read-write" : "read-only");
349 		args->session = gck_session_from_handle (args->slot, session, args->session_options);
350 		return state_session;
351 
352 	/* slot to slots state */
353 	} else {
354 		g_object_unref (args->slot);
355 		args->slot = NULL;
356 		args->funcs = NULL;
357 
358 		gck_token_info_free (args->token_info);
359 		args->token_info = NULL;
360 
361 		return state_slots;
362 	}
363 }
364 
365 static gpointer
state_session(GckEnumeratorState * args,gboolean forward)366 state_session (GckEnumeratorState *args, gboolean forward)
367 {
368 	GTlsInteraction *interaction;
369 	CK_RV rv;
370 
371 	g_assert (args->funcs);
372 	g_assert (args->session);
373 	g_assert (args->token_info);
374 
375 	/* session to authenticated state */
376 	if (forward) {
377 
378 		/* Don't want to authenticate? */
379 		if ((args->session_options & GCK_SESSION_LOGIN_USER) == 0) {
380 			g_debug ("no authentication necessary, skipping");
381 			return state_find;
382 		}
383 
384 		/* Compatibility, hook into GckModule signals if no interaction set */
385 		if (args->interaction)
386 			interaction = g_object_ref (args->interaction);
387 		else
388 			interaction = _gck_interaction_new (args->slot);
389 
390 		rv = _gck_session_authenticate_token (args->funcs,
391 		                                      gck_session_get_handle (args->session),
392 		                                      args->slot, interaction, NULL);
393 
394 		g_object_unref (interaction);
395 
396 		if (rv != CKR_OK)
397 			g_message ("couldn't authenticate when enumerating: %s", gck_message_from_rv (rv));
398 
399 		/* We try to proceed anyway with the enumeration */
400 		return state_find;
401 
402 	/* Session to slot state */
403 	} else {
404 		g_object_unref (args->session);
405 		args->session = NULL;
406 		return state_slot;
407 	}
408 }
409 
410 static gpointer
state_find(GckEnumeratorState * args,gboolean forward)411 state_find (GckEnumeratorState *args,
412             gboolean forward)
413 {
414 	CK_OBJECT_HANDLE objects[128];
415 	CK_SESSION_HANDLE session;
416 	CK_ATTRIBUTE_PTR attrs;
417 	CK_ULONG n_attrs, i,count;
418 	GckEnumeratorResult *result;
419 	CK_RV rv;
420 
421 	/* Just go back, no logout */
422 	if (!forward)
423 		return state_session;
424 
425 	/* This is where we do the actual searching */
426 
427 	g_assert (args->session != NULL);
428 	g_assert (args->want_objects > 0);
429 	g_assert (args->funcs != NULL);
430 
431 	if (!args->found)
432 		args->found = g_queue_new ();
433 
434 	if (args->match->attributes) {
435 		attrs = _gck_attributes_commit_out (args->match->attributes, &n_attrs);
436 		gchar *string = gck_attributes_to_string (args->match->attributes);
437 		g_debug ("finding objects matching: %s", string);
438 		g_free (string);
439 	} else {
440 		attrs = NULL;
441 		n_attrs = 0;
442 		g_debug ("finding all objects");
443 	}
444 
445 	session = gck_session_get_handle (args->session);
446 	g_return_val_if_fail (session, NULL);
447 
448 	/* Get all the objects */
449 	rv = (args->funcs->C_FindObjectsInit) (session, attrs, n_attrs);
450 
451 	if (rv == CKR_OK) {
452 		for(;;) {
453 			rv = (args->funcs->C_FindObjects) (session, objects, G_N_ELEMENTS (objects), &count);
454 			if (rv != CKR_OK || count == 0)
455 				break;
456 
457 			g_debug ("matched %lu objects", count);
458 
459 			for (i = 0; i < count; i++) {
460 				result = g_slice_new0 (GckEnumeratorResult);
461 				result->handle = objects[i];
462 				result->session = g_object_ref (args->session);
463 				g_queue_push_tail (args->found, result);
464 			}
465 		}
466 
467 		(args->funcs->C_FindObjectsFinal) (session);
468 	}
469 
470 	g_debug ("finding objects completed with: %s", _gck_stringize_rv (rv));
471 	return state_results;
472 }
473 
474 static gpointer
state_results(GckEnumeratorState * args,gboolean forward)475 state_results (GckEnumeratorState *args,
476                gboolean forward)
477 {
478 	GckEnumeratorResult *result;
479 	GckBuilder builder;
480 	GckAttributes *attrs;
481 	CK_ATTRIBUTE_PTR template;
482 	CK_ULONG n_template;
483 	CK_SESSION_HANDLE session;
484 	gint count;
485 	CK_RV rv;
486 	gint i;
487 
488 	g_assert (args->funcs != NULL);
489 	g_assert (args->object_class != NULL);
490 	g_assert (args->found != NULL);
491 
492 	/* No cleanup, just unwind */
493 	if (!forward)
494 		return state_find;
495 
496 	if (!args->results)
497 		args->results = g_queue_new ();
498 
499 	session = gck_session_get_handle (args->session);
500 	g_return_val_if_fail (session, NULL);
501 
502 	/* Get the attributes for want_objects */
503 	for (count = 0; count < args->want_objects; count++) {
504 		result = g_queue_pop_head (args->found);
505 		if (result == NULL) {
506 			g_debug ("wanted %d objects, have %d, looking for more",
507 			         args->want_objects, g_queue_get_length (args->results));
508 			return rewind_state (args, state_slots);
509 		}
510 
511 		/* If no request for attributes, just go forward */
512 		if (args->attr_count == 0) {
513 			g_queue_push_tail (args->results, result);
514 			continue;
515 		}
516 
517 		gck_builder_init (&builder);
518 
519 		for (i = 0; i < args->attr_count; ++i)
520 			gck_builder_add_empty (&builder, args->attr_types[i]);
521 
522 		/* Ask for attribute sizes */
523 		template = _gck_builder_prepare_in (&builder, &n_template);
524 
525 		rv = (args->funcs->C_GetAttributeValue) (session, result->handle, template, n_template);
526 		if (GCK_IS_GET_ATTRIBUTE_RV_OK (rv)) {
527 
528 			/* Allocate memory for each value */
529 			template = _gck_builder_commit_in (&builder, &n_template);
530 
531 			/* Now get the actual values */
532 			rv = (args->funcs->C_GetAttributeValue) (session, result->handle, template, n_template);
533 		}
534 
535 		attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
536 
537 		if (GCK_IS_GET_ATTRIBUTE_RV_OK (rv)) {
538 			gchar *string = gck_attributes_to_string (attrs);
539 			g_debug ("retrieved attributes for object %lu: %s",
540 			         result->handle, string);
541 			g_free (string);
542 			result->attrs = attrs;
543 			g_queue_push_tail (args->results, result);
544 
545 		} else {
546 			g_message ("couldn't retrieve attributes when enumerating: %s",
547 			           gck_message_from_rv (rv));
548 			gck_attributes_unref (attrs);
549 			_gck_enumerator_result_free (result);
550 		}
551 	}
552 
553 	g_debug ("wanted %d objects, returned %d objects",
554 	         args->want_objects, g_queue_get_length (args->results));
555 
556 	/* We got all the results we wanted */
557 	return NULL;
558 }
559 
560 static void
gck_enumerator_init(GckEnumerator * self)561 gck_enumerator_init (GckEnumerator *self)
562 {
563 	self->pv = gck_enumerator_get_instance_private (self);
564 	self->pv->mutex = g_new0 (GMutex, 1);
565 	g_mutex_init (self->pv->mutex);
566 	self->pv->the_state = g_new0 (GckEnumeratorState, 1);
567 	self->pv->object_type = GCK_TYPE_OBJECT;
568 	self->pv->object_class = g_type_class_ref (self->pv->object_type);
569 	g_assert (self->pv->object_class);
570 }
571 
572 static void
gck_enumerator_get_property(GObject * obj,guint prop_id,GValue * value,GParamSpec * pspec)573 gck_enumerator_get_property (GObject *obj,
574                              guint prop_id,
575                              GValue *value,
576                              GParamSpec *pspec)
577 {
578 	GckEnumerator *self = GCK_ENUMERATOR (obj);
579 
580 	switch (prop_id) {
581 	case PROP_INTERACTION:
582 		g_value_take_object (value, gck_enumerator_get_interaction (self));
583 		break;
584 	case PROP_OBJECT_TYPE:
585 		g_value_set_gtype (value, gck_enumerator_get_object_type (self));
586 		break;
587 	case PROP_CHAINED:
588 		g_value_set_object (value, gck_enumerator_get_chained (self));
589 		break;
590 	default:
591 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
592 		break;
593 	}
594 }
595 
596 static void
gck_enumerator_set_property(GObject * obj,guint prop_id,const GValue * value,GParamSpec * pspec)597 gck_enumerator_set_property (GObject *obj,
598                              guint prop_id,
599                              const GValue *value,
600                              GParamSpec *pspec)
601 {
602 	GckEnumerator *self = GCK_ENUMERATOR (obj);
603 
604 	switch (prop_id) {
605 	case PROP_INTERACTION:
606 		gck_enumerator_set_interaction (self, g_value_get_object (value));
607 		break;
608 	case PROP_OBJECT_TYPE:
609 		gck_enumerator_set_object_type (self, g_value_get_gtype (value));
610 		break;
611 	case PROP_CHAINED:
612 		gck_enumerator_set_chained (self, g_value_get_object (value));
613 		break;
614 	default:
615 		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
616 		break;
617 	}
618 }
619 
620 static void
gck_enumerator_dispose(GObject * obj)621 gck_enumerator_dispose (GObject *obj)
622 {
623 	GckEnumerator *self = GCK_ENUMERATOR (obj);
624 
625 	gck_enumerator_set_interaction (self, NULL);
626 	gck_enumerator_set_chained (self, NULL);
627 
628 	G_OBJECT_CLASS (gck_enumerator_parent_class)->dispose (obj);
629 }
630 
631 static void
gck_enumerator_finalize(GObject * obj)632 gck_enumerator_finalize (GObject *obj)
633 {
634 	GckEnumerator *self = GCK_ENUMERATOR (obj);
635 
636 	g_assert (self->pv->interaction == NULL);
637 
638 	g_assert (self->pv->the_state != NULL);
639 	cleanup_state (self->pv->the_state);
640 	g_free (self->pv->the_state);
641 
642 	g_mutex_clear (self->pv->mutex);
643 	g_free (self->pv->mutex);
644 	g_type_class_unref (self->pv->object_class);
645 	g_free (self->pv->attr_types);
646 
647 	G_OBJECT_CLASS (gck_enumerator_parent_class)->finalize (obj);
648 }
649 
650 static void
gck_enumerator_class_init(GckEnumeratorClass * klass)651 gck_enumerator_class_init (GckEnumeratorClass *klass)
652 {
653 	GObjectClass *gobject_class = (GObjectClass*)klass;
654 
655 	gobject_class->get_property = gck_enumerator_get_property;
656 	gobject_class->set_property = gck_enumerator_set_property;
657 	gobject_class->dispose = gck_enumerator_dispose;
658 	gobject_class->finalize = gck_enumerator_finalize;
659 
660 	/**
661 	 * GckEnumerator:interaction:
662 	 *
663 	 * Interaction object used to ask the user for pins when opening
664 	 * sessions. Used if the session_options of the enumerator have
665 	 * %GCK_SESSION_LOGIN_USER
666 	 */
667 	g_object_class_install_property (gobject_class, PROP_INTERACTION,
668 		g_param_spec_object ("interaction", "Interaction", "Interaction asking for pins",
669 		                     G_TYPE_TLS_INTERACTION,
670 		                     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
671 
672 	/**
673 	 * GckEnumerator:object-type: (skip)
674 	 *
675 	 * The type of objects that are created by the enumerator. Must be
676 	 * GckObject or derived from it.
677 	 */
678 	g_object_class_install_property (gobject_class, PROP_OBJECT_TYPE,
679 		g_param_spec_gtype ("object-type", "Object Type", "Type of objects created",
680 		                    GCK_TYPE_OBJECT,
681 		                    G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
682 
683 	/**
684 	 * GckEnumerator:chained:
685 	 *
686 	 * Chained enumerator, which will be enumerated when this enumerator
687 	 * has enumerated all its objects.
688 	 */
689 	g_object_class_install_property (gobject_class, PROP_CHAINED,
690 		g_param_spec_object ("chained", "Chained", "Chained enumerator",
691 		                     GCK_TYPE_ENUMERATOR,
692 		                     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
693 }
694 
695 static void
created_enumerator(GckUriData * uri_data,const gchar * type)696 created_enumerator (GckUriData *uri_data,
697                     const gchar *type)
698 {
699 	gchar *attrs, *uri;
700 	attrs = uri_data->attributes ? gck_attributes_to_string (uri_data->attributes) : NULL;
701 	uri = uri_data ? gck_uri_build (uri_data, GCK_URI_FOR_TOKEN | GCK_URI_FOR_MODULE) : NULL;
702 	g_debug ("for = %s, tokens = %s, objects = %s", type, uri, attrs);
703 	g_free (attrs);
704 	g_free (uri);
705 }
706 
707 GckEnumerator *
_gck_enumerator_new_for_modules(GList * modules,GckSessionOptions session_options,GckUriData * uri_data)708 _gck_enumerator_new_for_modules (GList *modules,
709                                  GckSessionOptions session_options,
710                                  GckUriData *uri_data)
711 {
712 	GckEnumerator *self;
713 	GckEnumeratorState *state;
714 
715 	self = g_object_new (GCK_TYPE_ENUMERATOR, NULL);
716 	state = self->pv->the_state;
717 
718 	state->session_options = session_options;
719 
720 	state->modules = gck_list_ref_copy (modules);
721 	state->slots = NULL;
722 	state->handler = state_modules;
723 	state->match = uri_data;
724 
725 	created_enumerator (uri_data, "modules");
726 	return self;
727 }
728 
729 GckEnumerator *
_gck_enumerator_new_for_slots(GList * slots,GckSessionOptions session_options,GckUriData * uri_data)730 _gck_enumerator_new_for_slots (GList *slots,
731                                GckSessionOptions session_options,
732                                GckUriData *uri_data)
733 {
734 	GckEnumerator *self;
735 	GckEnumeratorState *state;
736 
737 	self = g_object_new (GCK_TYPE_ENUMERATOR, NULL);
738 	state = self->pv->the_state;
739 
740 	state->session_options = session_options;
741 
742 	state->slots = gck_list_ref_copy (slots);
743 	state->modules = NULL;
744 	state->handler = state_slots;
745 	state->match = uri_data;
746 
747 	created_enumerator (uri_data, "slots");
748 	return self;
749 }
750 
751 GckEnumerator *
_gck_enumerator_new_for_session(GckSession * session,GckUriData * uri_data)752 _gck_enumerator_new_for_session (GckSession *session,
753                                  GckUriData *uri_data)
754 {
755 	GckEnumerator *self;
756 	GckEnumeratorState *state;
757 	GckModule *module;
758 
759 	self = g_object_new (GCK_TYPE_ENUMERATOR, NULL);
760 	state = self->pv->the_state;
761 
762 	state->session = g_object_ref (session);
763 	state->modules = NULL;
764 	state->slots = NULL;
765 	state->handler = state_session;
766 	state->match = uri_data;
767 
768 	state->slot = gck_session_get_slot (session);
769 	state->token_info = gck_slot_get_token_info (state->slot);
770 
771 	module = gck_session_get_module (session);
772 	state->funcs = gck_module_get_functions (module);
773 	g_object_unref (module);
774 
775 	created_enumerator (uri_data, "session");
776 	return self;
777 }
778 
779 typedef struct _EnumerateNext {
780 	GckArguments base;
781 	GckEnumeratorState *state;
782 	gint want_objects;
783 } EnumerateNext;
784 
785 static CK_RV
perform_enumerate_next(EnumerateNext * args)786 perform_enumerate_next (EnumerateNext *args)
787 {
788 	GckEnumeratorFunc handler;
789 	GckEnumeratorState *state;
790 	gint count = 0;
791 
792 	g_assert (args->state);
793 
794 	for (state = args->state; state != NULL; state = state->chained) {
795 		g_assert (state->handler);
796 		state->want_objects = args->want_objects - count;
797 		for (;;) {
798 			handler = (state->handler) (state, TRUE);
799 			if (!handler)
800 				break;
801 			state->handler = handler;
802 		}
803 
804 		count += state->results ? g_queue_get_length (state->results) : 0;
805 		if (count >= args->want_objects)
806 			break;
807 	}
808 
809 	/* TODO: In some modes, errors */
810 	return CKR_OK;
811 }
812 
813 static void
free_enumerate_next(EnumerateNext * args)814 free_enumerate_next (EnumerateNext *args)
815 {
816 	/* Should have been assigned back to enumerator */
817 	g_assert (!args->state);
818 
819 	g_free (args);
820 }
821 
822 /**
823  * gck_enumerator_get_object_type:
824  * @self: an enumerator
825  *
826  * Get the type of objects created by this enumerator. The type will always
827  * either be #GckObject or derived from it.
828  *
829  * Returns: the type of objects created
830  */
831 GType
gck_enumerator_get_object_type(GckEnumerator * self)832 gck_enumerator_get_object_type (GckEnumerator *self)
833 {
834 	GType result;
835 
836 	g_return_val_if_fail (GCK_IS_ENUMERATOR (self), 0);
837 
838 	g_mutex_lock (self->pv->mutex);
839 
840 		result = self->pv->object_type;
841 
842 	g_mutex_unlock (self->pv->mutex);
843 
844 	return result;
845 }
846 
847 /**
848  * gck_enumerator_set_object_type: (skip)
849  * @self: an enumerator
850  * @object_type: the type of objects to create
851  *
852  * Set the type of objects to be created by this enumerator. The type must
853  * always be either #GckObject or derived from it.
854  *
855  * If the #GckObjectCache interface is implemented on the derived class
856  * and the default_types class field is set, then the enumerator will retrieve
857  * attributes for each object.
858  */
859 void
gck_enumerator_set_object_type(GckEnumerator * self,GType object_type)860 gck_enumerator_set_object_type (GckEnumerator *self,
861                                 GType object_type)
862 {
863 	gck_enumerator_set_object_type_full (self, object_type, NULL, 0);
864 }
865 
866 /**
867  * gck_enumerator_set_object_type_full: (rename-to gck_enumerator_set_object_type)
868  * @self: an enumerator
869  * @object_type: the type of objects to create
870  * @attr_types: (array length=attr_count): types of attributes to retrieve for objects
871  * @attr_count: the number of attributes to retrieve
872  *
873  * Set the type of objects to be created by this enumerator. The type must
874  * always be either #GckObject or derived from it.
875  *
876  * If @attr_types and @attr_count are non-NULL and non-zero respectively,
877  * then the #GckObjectCache interface is expected to be implemented on the
878  * derived class, then the enumerator will retrieve attributes for each object.
879  */
880 void
gck_enumerator_set_object_type_full(GckEnumerator * self,GType object_type,const gulong * attr_types,gint attr_count)881 gck_enumerator_set_object_type_full (GckEnumerator *self,
882                                      GType object_type,
883                                      const gulong *attr_types,
884                                      gint attr_count)
885 {
886 	gpointer klass;
887 
888 	g_return_if_fail (GCK_IS_ENUMERATOR (self));
889 
890 	if (!g_type_is_a (object_type, GCK_TYPE_OBJECT)) {
891 		g_warning ("the object_type '%s' is not a derived type of GckObject",
892 		           g_type_name (object_type));
893 		return;
894 	}
895 
896 	klass = g_type_class_ref (object_type);
897 
898 	g_mutex_lock (self->pv->mutex);
899 
900 		if (self->pv->object_type)
901 			g_type_class_unref (self->pv->object_class);
902 		self->pv->object_type = object_type;
903 		self->pv->object_class = klass;
904 
905 		g_free (self->pv->attr_types);
906 		self->pv->attr_types = NULL;
907 		self->pv->attr_count = 0;
908 
909 		if (attr_types) {
910 			self->pv->attr_types = g_memdup (attr_types, sizeof (gulong) * attr_count);
911 			self->pv->attr_count = attr_count;
912 		}
913 
914 	g_mutex_unlock (self->pv->mutex);
915 }
916 
917 /**
918  * gck_enumerator_get_chained:
919  * @self: the enumerator
920  *
921  * Get the enumerator that will be run after all objects from this one
922  * are seen.
923  *
924  * Returns: (transfer full) (nullable): the chained enumerator or %NULL
925  */
926 GckEnumerator *
gck_enumerator_get_chained(GckEnumerator * self)927 gck_enumerator_get_chained (GckEnumerator *self)
928 {
929 	GckEnumerator *chained = NULL;
930 
931 	g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL);
932 
933 	g_mutex_lock (self->pv->mutex);
934 
935 		if (self->pv->chained)
936 			chained = g_object_ref (self->pv->chained);
937 
938 	g_mutex_unlock (self->pv->mutex);
939 
940 	return chained;
941 }
942 
943 /**
944  * gck_enumerator_set_chained:
945  * @self: the enumerator
946  * @chained: (nullable): the chained enumerator or %NULL
947  *
948  * Set a chained enumerator that will be run after all objects from this one
949  * are seen.
950  */
951 void
gck_enumerator_set_chained(GckEnumerator * self,GckEnumerator * chained)952 gck_enumerator_set_chained (GckEnumerator *self,
953                             GckEnumerator *chained)
954 {
955 	GckEnumerator *old_chained = NULL;
956 
957 	g_return_if_fail (GCK_IS_ENUMERATOR (self));
958 	g_return_if_fail (chained == NULL || GCK_IS_ENUMERATOR (chained));
959 
960 	g_mutex_lock (self->pv->mutex);
961 
962 		old_chained = self->pv->chained;
963 		if (chained)
964 			g_object_ref (chained);
965 		self->pv->chained = chained;
966 
967 	g_mutex_unlock (self->pv->mutex);
968 
969 	if (old_chained)
970 		g_object_unref (old_chained);
971 
972 	g_object_notify (G_OBJECT (self), "chained");
973 }
974 
975 /**
976  * gck_enumerator_get_interaction:
977  * @self: the enumerator
978  *
979  * Get the interaction used when a pin is needed
980  *
981  * Returns: (transfer full) (nullable): the interaction or %NULL
982  */
983 GTlsInteraction *
gck_enumerator_get_interaction(GckEnumerator * self)984 gck_enumerator_get_interaction (GckEnumerator *self)
985 {
986 	GTlsInteraction *result = NULL;
987 
988 	g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL);
989 
990 	g_mutex_lock (self->pv->mutex);
991 
992 		if (self->pv->interaction)
993 			result = g_object_ref (self->pv->interaction);
994 
995 	g_mutex_unlock (self->pv->mutex);
996 
997 	return result;
998 }
999 
1000 /**
1001  * gck_enumerator_set_interaction:
1002  * @self: the enumerator
1003  * @interaction: (nullable): the interaction or %NULL
1004  *
1005  * Set the interaction used when a pin is needed
1006  */
1007 void
gck_enumerator_set_interaction(GckEnumerator * self,GTlsInteraction * interaction)1008 gck_enumerator_set_interaction (GckEnumerator *self,
1009                                 GTlsInteraction *interaction)
1010 {
1011 	GTlsInteraction *previous = NULL;
1012 
1013 	g_return_if_fail (GCK_IS_ENUMERATOR (self));
1014 	g_return_if_fail (interaction == NULL || G_IS_TLS_INTERACTION (interaction));
1015 
1016 	g_mutex_lock (self->pv->mutex);
1017 
1018 		if (interaction != self->pv->interaction) {
1019 			previous = self->pv->interaction;
1020 			self->pv->interaction = interaction;
1021 			if (interaction)
1022 				g_object_ref (interaction);
1023 		}
1024 
1025 	g_mutex_unlock (self->pv->mutex);
1026 
1027 	g_clear_object (&previous);
1028 	g_object_notify (G_OBJECT (self), "interaction");
1029 }
1030 
1031 static GckEnumeratorState *
check_out_enumerator_state(GckEnumerator * self)1032 check_out_enumerator_state (GckEnumerator *self)
1033 {
1034 	GckEnumeratorState *state = NULL;
1035 	GTlsInteraction *old_interaction = NULL;
1036 	gpointer old_object_class = NULL;
1037 	GckEnumeratorState *chained_state = NULL;
1038 	GckObjectCacheIface *object_iface;
1039 	GckEnumerator *chained;
1040 
1041 	chained = gck_enumerator_get_chained (self);
1042 	if (chained) {
1043 		chained_state = check_out_enumerator_state (chained);
1044 		g_object_unref (chained);
1045 	}
1046 
1047 	g_mutex_lock (self->pv->mutex);
1048 
1049 		if (self->pv->the_state) {
1050 			state = self->pv->the_state;
1051 			self->pv->the_state = NULL;
1052 
1053 			state->enumerator = g_object_ref (self);
1054 			g_assert (state->chained == NULL);
1055 			state->chained = chained_state;
1056 
1057 			old_interaction = state->interaction;
1058 			if (self->pv->interaction)
1059 				state->interaction = g_object_ref (self->pv->interaction);
1060 			else
1061 				state->interaction = NULL;
1062 
1063 			old_object_class = state->object_class;
1064 
1065 			/* Must already be holding a reference, state also holds a ref */
1066 			state->object_type = self->pv->object_type;
1067 			state->object_class = g_type_class_peek (state->object_type);
1068 			g_assert (state->object_class == self->pv->object_class);
1069 
1070 			object_iface = g_type_interface_peek (state->object_class,
1071 			                                      GCK_TYPE_OBJECT_CACHE);
1072 
1073 			if (self->pv->attr_types) {
1074 				state->attr_types = self->pv->attr_types;
1075 				state->attr_count = self->pv->attr_count;
1076 			} else if (object_iface && object_iface->default_types) {
1077 				state->attr_types = object_iface->default_types;
1078 				state->attr_count = object_iface->n_default_types;
1079 			}
1080 
1081 			g_type_class_ref (state->object_type);
1082 		}
1083 
1084 	g_mutex_unlock (self->pv->mutex);
1085 
1086 	if (state == NULL)
1087 		g_warning ("this enumerator is already running a next operation");
1088 
1089 	/* Free these outside the lock */
1090 	if (old_interaction)
1091 		g_object_unref (old_interaction);
1092 	if (old_object_class)
1093 		g_type_class_unref (old_object_class);
1094 
1095 	return state;
1096 }
1097 
1098 static void
check_in_enumerator_state(GckEnumeratorState * state)1099 check_in_enumerator_state (GckEnumeratorState *state)
1100 {
1101 	GckEnumeratorState *chained = NULL;
1102 	GckEnumerator *self;
1103 
1104 	g_assert (GCK_IS_ENUMERATOR (state->enumerator));
1105 	self = state->enumerator;
1106 
1107 	g_mutex_lock (self->pv->mutex);
1108 
1109 		state->enumerator = NULL;
1110 		g_assert (self->pv->the_state == NULL);
1111 		self->pv->the_state = state;
1112 		chained = state->chained;
1113 		state->chained = NULL;
1114 
1115 	g_mutex_unlock (self->pv->mutex);
1116 
1117 	/* matches ref in check_in */
1118 	g_object_unref (self);
1119 
1120 	if (chained)
1121 		check_in_enumerator_state (chained);
1122 }
1123 
1124 static GckObject *
extract_result(GckEnumeratorState * state)1125 extract_result (GckEnumeratorState *state)
1126 {
1127 	GckEnumeratorResult *result = NULL;
1128 	GckModule *module;
1129 	GckObject *object;
1130 
1131 	g_assert (state != NULL);
1132 
1133 	if (state->results != NULL)
1134 		result = g_queue_pop_head (state->results);
1135 	if (result == NULL) {
1136 		if (state->chained)
1137 			return extract_result (state->chained);
1138 		return NULL;
1139 	}
1140 
1141 	module = gck_session_get_module (result->session);
1142 	object = g_object_new (state->object_type,
1143 	                       "module", module,
1144 	                       "handle", result->handle,
1145 	                       "session", result->session,
1146 	                       result->attrs ? "attributes" : NULL, result->attrs,
1147 	                       NULL);
1148 	g_object_unref (module);
1149 
1150 	_gck_enumerator_result_free (result);
1151 	return object;
1152 }
1153 
1154 static GList *
extract_results(GckEnumeratorState * state,gint * want_objects)1155 extract_results (GckEnumeratorState *state,
1156                  gint *want_objects)
1157 {
1158 	GList *objects = NULL;
1159 	GckObject *object;
1160 	gint i;
1161 
1162 	g_assert (state != NULL);
1163 	g_assert (want_objects != NULL);
1164 
1165 	for (i = 0; i < *want_objects; i++) {
1166 		object = extract_result (state);
1167 		if (object == NULL)
1168 			break;
1169 		objects = g_list_prepend (objects, object);
1170 	}
1171 
1172 	*want_objects -= i;
1173 	return g_list_reverse (objects);
1174 }
1175 
1176 /**
1177  * gck_enumerator_next:
1178  * @self: The enumerator
1179  * @cancellable: A #GCancellable or %NULL
1180  * @error: A location to store an error on failure
1181  *
1182  * Get the next object in the enumerator, or %NULL if there are no more objects.
1183  *
1184  * %NULL is also returned if the function fails. Use the @error to determine
1185  * whether a failure occurred or not.
1186  *
1187  * Returns: (transfer full) (nullable): The next object, which must be released
1188  * using g_object_unref, or %NULL.
1189  */
1190 GckObject *
gck_enumerator_next(GckEnumerator * self,GCancellable * cancellable,GError ** error)1191 gck_enumerator_next (GckEnumerator *self,
1192                      GCancellable *cancellable,
1193                      GError **error)
1194 {
1195 	EnumerateNext args = { GCK_ARGUMENTS_INIT, NULL, 0, };
1196 	GckObject *result = NULL;
1197 
1198 	g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL);
1199 	g_return_val_if_fail (!error || !*error, NULL);
1200 
1201 	args.state = check_out_enumerator_state (self);
1202 	g_return_val_if_fail (args.state != NULL, NULL);
1203 
1204 	/* A result from a previous run? */
1205 	result = extract_result (args.state);
1206 	if (result == NULL) {
1207 		args.want_objects = 1;
1208 
1209 		/* Run the operation and steal away the results */
1210 		if (_gck_call_sync (NULL, perform_enumerate_next, NULL, &args, cancellable, error))
1211 			result = extract_result (args.state);
1212 
1213 		args.want_objects = 0;
1214 	}
1215 
1216 	/* Put the state back */
1217 	check_in_enumerator_state (args.state);
1218 
1219 	return result;
1220 }
1221 
1222 /**
1223  * gck_enumerator_next_n:
1224  * @self: An enumerator
1225  * @max_objects: The maximum amount of objects to enumerate
1226  * @cancellable: A #GCancellable or %NULL
1227  * @error: A location to store an error on failure
1228  *
1229  * Get the next set of objects from the enumerator. The maximum number of
1230  * objects can be specified with @max_objects. If -1 is specified, then all
1231  * the remaining objects will be returned.
1232  *
1233  * %NULL is also returned if the function fails. Use the @error to determine
1234  * whether a failure occurred or not.
1235  *
1236  * Returns: (transfer full) (element-type Gck.Object): A list of objects, which
1237  * should be freed using gck_list_unref_free().
1238  */
1239 GList *
gck_enumerator_next_n(GckEnumerator * self,gint max_objects,GCancellable * cancellable,GError ** error)1240 gck_enumerator_next_n (GckEnumerator *self,
1241                        gint max_objects,
1242                        GCancellable *cancellable,
1243                        GError **error)
1244 {
1245 	EnumerateNext args = { GCK_ARGUMENTS_INIT, NULL, 0, };
1246 	GList *results = NULL;
1247 	gint want_objects;
1248 
1249 	g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL);
1250 	g_return_val_if_fail (max_objects == -1 || max_objects > 0, NULL);
1251 	g_return_val_if_fail (!error || !*error, NULL);
1252 
1253 	/* Remove the state and own it ourselves */
1254 	args.state = check_out_enumerator_state (self);
1255 	g_return_val_if_fail (args.state != NULL, NULL);
1256 
1257 	want_objects = max_objects <= 0 ? G_MAXINT : max_objects;
1258 
1259 	/* A result from a previous run? */
1260 	results = extract_results (args.state, &want_objects);
1261 	if (want_objects > 0) {
1262 		args.want_objects = want_objects;
1263 
1264 		/* Run the operation and steal away the results */
1265 		if (_gck_call_sync (NULL, perform_enumerate_next, NULL, &args, cancellable, error))
1266 			results = g_list_concat (results, extract_results (args.state, &want_objects));
1267 
1268 		args.want_objects = 0;
1269 	}
1270 
1271 	/* Put the state back */
1272 	check_in_enumerator_state (args.state);
1273 
1274 	if (results)
1275 		g_clear_error (error);
1276 
1277 	return results;
1278 }
1279 
1280 /**
1281  * gck_enumerator_next_async:
1282  * @self: An enumerator
1283  * @max_objects: The maximum number of objects to get
1284  * @cancellable: A #GCancellable or %NULL
1285  * @callback: Called when the result is ready
1286  * @user_data: Data to pass to the callback
1287  *
1288  * Get the next set of objects from the enumerator. This operation completes
1289  * asynchronously.The maximum number of objects can be specified with
1290  * @max_objects. If -1 is specified, then all the remaining objects will be
1291  * enumerated.
1292  */
1293 void
gck_enumerator_next_async(GckEnumerator * self,gint max_objects,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1294 gck_enumerator_next_async (GckEnumerator *self, gint max_objects, GCancellable *cancellable,
1295                            GAsyncReadyCallback callback, gpointer user_data)
1296 {
1297 	GckEnumeratorState *state;
1298 	EnumerateNext *args;
1299 	GckCall *call;
1300 
1301 	g_return_if_fail (GCK_IS_ENUMERATOR (self));
1302 	g_return_if_fail (max_objects == -1 || max_objects > 0);
1303 
1304 	g_object_ref (self);
1305 
1306 	/* Remove the state and own it ourselves */
1307 	state = check_out_enumerator_state (self);
1308 	g_return_if_fail (state != NULL);
1309 
1310 	call = _gck_call_async_prep (NULL, perform_enumerate_next, NULL,
1311 	                             sizeof (*args), free_enumerate_next);
1312 	args = _gck_call_get_arguments (call);
1313 	args->want_objects = max_objects <= 0 ? G_MAXINT : max_objects;
1314 
1315 	args->state = state;
1316 	_gck_call_async_ready_go (call, self, cancellable, callback, user_data);
1317 	g_object_unref (self);
1318 }
1319 
1320 /**
1321  * gck_enumerator_next_finish:
1322  * @self: An enumerator
1323  * @result: The result passed to the callback
1324  * @error: A location to raise an error on failure.
1325  *
1326  * Complete an operation to enumerate next objects.
1327  *
1328  * %NULL is also returned if the function fails. Use the @error to determine
1329  * whether a failure occurred or not.
1330  *
1331  * Returns: (element-type Gck.Object) (transfer full): The list of objects, which
1332  * should be freed with gck_list_unref_free()
1333  */
1334 GList*
gck_enumerator_next_finish(GckEnumerator * self,GAsyncResult * result,GError ** error)1335 gck_enumerator_next_finish (GckEnumerator *self, GAsyncResult *result, GError **error)
1336 {
1337 	EnumerateNext *args;
1338 	GckEnumeratorState *state;
1339 	GList *results = NULL;
1340 	gint want_objects;
1341 
1342 	g_object_ref (self);
1343 
1344 	args = _gck_call_async_result_arguments (result, EnumerateNext);
1345 	state = args->state;
1346 	args->state = NULL;
1347 	want_objects = args->want_objects;
1348 	args->want_objects = 0;
1349 
1350 	if (_gck_call_basic_finish (result, error))
1351 		results = extract_results (state, &want_objects);
1352 
1353 	/* Put the state back */
1354 	check_in_enumerator_state (state);
1355 
1356 	g_object_unref (self);
1357 
1358 	return results;
1359 }
1360