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