Coverage Report

Created: 2023-06-07 06:14

/src/p11-kit/p11-kit/iter.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2013,2016 Red Hat Inc.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 *
8
 *     * Redistributions of source code must retain the above
9
 *       copyright notice, this list of conditions and the
10
 *       following disclaimer.
11
 *     * Redistributions in binary form must reproduce the
12
 *       above copyright notice, this list of conditions and
13
 *       the following disclaimer in the documentation and/or
14
 *       other materials provided with the distribution.
15
 *     * The names of contributors to this software may not be
16
 *       used to endorse or promote products derived from this
17
 *       software without specific prior written permission.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
29
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30
 * DAMAGE.
31
 *
32
 * Author: Stef Walter <stefw@redhat.com>
33
 */
34
35
#include "config.h"
36
37
#include "array.h"
38
#include "attrs.h"
39
#include "debug.h"
40
#include "iter.h"
41
#include "pin.h"
42
#include "private.h"
43
44
#include <assert.h>
45
#include <stdlib.h>
46
#include <string.h>
47
48
typedef struct _Callback {
49
  p11_kit_iter_callback func;
50
  void *callback_data;
51
  p11_kit_destroyer destroyer;
52
  struct _Callback *next;
53
} Callback;
54
55
/**
56
 * P11KitIter:
57
 *
58
 * Used to iterate over PKCS\#11 objects, tokens, slots, and modules.
59
 */
60
struct p11_kit_iter {
61
62
  /* Iterator matching data */
63
  CK_INFO match_module;
64
  CK_SLOT_INFO match_slot;
65
  CK_TOKEN_INFO match_token;
66
  CK_ATTRIBUTE *match_attrs;
67
  CK_SLOT_ID match_slot_id;
68
  Callback *callbacks;
69
70
  /* The input modules */
71
  p11_array *modules;
72
73
  /* The results of C_GetSlotList */
74
  CK_SLOT_ID *slots;
75
  CK_ULONG num_slots;
76
  CK_ULONG saw_slots;
77
78
  /* The results of C_FindObjects */
79
  CK_OBJECT_HANDLE *objects;
80
  CK_ULONG max_objects;
81
  CK_ULONG num_objects;
82
  CK_ULONG saw_objects;
83
84
  /* The current iteration */
85
  P11KitIterKind kind;
86
  CK_FUNCTION_LIST_PTR module;
87
  CK_SLOT_ID slot;
88
  CK_SESSION_HANDLE session;
89
  CK_OBJECT_HANDLE object;
90
  CK_SLOT_INFO slot_info;
91
  CK_TOKEN_INFO token_info;
92
  int move_next_session_state;
93
  int iter_next_state;
94
95
  /* And various flags */
96
  unsigned int searching : 1;
97
  unsigned int searched : 1;
98
  unsigned int iterating : 1;
99
  unsigned int match_nothing : 1;
100
  unsigned int keep_session : 1;
101
  unsigned int preload_results : 1;
102
  unsigned int want_writable : 1;
103
  unsigned int with_modules : 1;
104
  unsigned int with_slots : 1;
105
  unsigned int with_tokens : 1;
106
  unsigned int with_objects : 1;
107
};
108
109
/**
110
 * P11KitIterKind:
111
 * @P11_KIT_ITER_KIND_MODULE: The iterator is pointing to a module.
112
 * @P11_KIT_ITER_KIND_SLOT: The iterator is pointing to a slot.
113
 * @P11_KIT_ITER_KIND_TOKEN: The iterator is pointing to a token.
114
 * @P11_KIT_ITER_KIND_OBJECT: The iterator is pointing to an object.
115
 * @P11_KIT_ITER_KIND_UNKNOWN: The iterator doesn't point to anything.
116
 *
117
 * The kind of the current match.
118
 */
119
120
/**
121
 * P11KitIterBehavior:
122
 * @P11_KIT_ITER_BUSY_SESSIONS: Allow the iterator's sessions to be
123
 *   in a busy state when the iterator returns an object.
124
 * @P11_KIT_ITER_WANT_WRITABLE: Try to open read-write sessions when
125
 *   iterating over objects.
126
 * @P11_KIT_ITER_WITH_MODULES: Stop at each module while iterating.
127
 * @P11_KIT_ITER_WITH_SLOTS: Stop at each slot while iterating.
128
 * @P11_KIT_ITER_WITH_TOKENS: Stop at each token while iterating.
129
 * @P11_KIT_ITER_WITHOUT_OBJECTS: Ignore objects while iterating.
130
 *
131
 * Various flags controlling the behavior of the iterator.
132
 */
133
134
/**
135
 * p11_kit_iter_new:
136
 * @uri: (allow-none): a PKCS\#11 URI to filter on, or %NULL
137
 * @behavior: various behavior flags for iterator
138
 *
139
 * Create a new PKCS\#11 iterator for iterating over objects. Only
140
 * objects that match the @uri will be returned by the iterator.
141
 * Relevant information in @uri is copied, and you need not keep
142
 * @uri around.
143
 *
144
 * If no @uri is specified then the iterator will iterate over all
145
 * objects, unless otherwise filtered.
146
 *
147
 * Returns: (transfer full): a new iterator, which should be freed
148
 *          with p11_kit_iter_free()
149
 */
150
P11KitIter *
151
p11_kit_iter_new (P11KitUri *uri,
152
                  P11KitIterBehavior behavior)
153
0
{
154
0
  P11KitIter *iter;
155
156
0
  iter = calloc (1, sizeof (P11KitIter));
157
0
  return_val_if_fail (iter != NULL, NULL);
158
159
0
  iter->modules = p11_array_new (NULL);
160
0
  if (iter->modules == NULL) {
161
0
    p11_kit_iter_free (iter);
162
0
    return_val_if_reached (NULL);
163
0
  }
164
165
0
  iter->want_writable = !!(behavior & P11_KIT_ITER_WANT_WRITABLE);
166
0
  iter->preload_results = !(behavior & P11_KIT_ITER_BUSY_SESSIONS);
167
0
  iter->with_modules = !!(behavior & P11_KIT_ITER_WITH_MODULES);
168
0
  iter->with_slots = !!(behavior & P11_KIT_ITER_WITH_SLOTS);
169
0
  iter->with_tokens = !!(behavior & P11_KIT_ITER_WITH_TOKENS);
170
0
  iter->with_objects = !(behavior & P11_KIT_ITER_WITHOUT_OBJECTS);
171
172
0
  p11_kit_iter_set_uri (iter, uri);
173
0
  return iter;
174
0
}
175
176
/**
177
 * p11_kit_iter_set_uri:
178
 * @iter: the iterator
179
 * @uri: (allow-none): a PKCS\#11 URI to filter on, or %NULL
180
 *
181
 * Set the PKCS\#11 uri for iterator. Only
182
 * objects that match the @uri will be returned by the iterator.
183
 * Relevant information in @uri is copied, and you need not keep
184
 * @uri around.
185
 *
186
 * If no @uri is specified then the iterator will iterate over all
187
 * objects, unless otherwise filtered.
188
 *
189
 * This function should be called at most once, and should be
190
 * called before iterating begins.
191
 *
192
 */
193
void
194
p11_kit_iter_set_uri (P11KitIter *iter,
195
                      P11KitUri *uri)
196
0
{
197
0
  CK_ATTRIBUTE *attrs;
198
0
  CK_TOKEN_INFO *tinfo;
199
0
  CK_SLOT_INFO *sinfo;
200
0
  CK_INFO *minfo;
201
0
  CK_ULONG count;
202
203
0
  return_if_fail (iter != NULL);
204
205
0
  if (uri != NULL) {
206
207
0
    if (p11_kit_uri_any_unrecognized (uri)) {
208
0
      iter->match_nothing = 1;
209
210
0
    } else {
211
0
      attrs = p11_kit_uri_get_attributes (uri, &count);
212
0
      iter->match_attrs = p11_attrs_buildn (NULL, attrs, count);
213
214
0
      iter->match_slot_id = p11_kit_uri_get_slot_id (uri);
215
216
0
      minfo = p11_kit_uri_get_module_info (uri);
217
0
      if (minfo != NULL)
218
0
        memcpy (&iter->match_module, minfo, sizeof (CK_INFO));
219
220
0
      sinfo = p11_kit_uri_get_slot_info (uri);
221
0
      if (sinfo != NULL)
222
0
        memcpy (&iter->match_slot, sinfo, sizeof (CK_SLOT_INFO));
223
224
0
      tinfo = p11_kit_uri_get_token_info (uri);
225
0
      if (tinfo != NULL)
226
0
        memcpy (&iter->match_token, tinfo, sizeof (CK_TOKEN_INFO));
227
0
    }
228
0
  } else {
229
    /* Match any module version number and slot ID */
230
0
    memset (&iter->match_module, 0, sizeof (iter->match_module));
231
0
    iter->match_module.libraryVersion.major = (CK_BYTE)-1;
232
0
    iter->match_module.libraryVersion.minor = (CK_BYTE)-1;
233
0
    iter->match_slot_id = (CK_SLOT_ID)-1;
234
0
  }
235
0
}
236
237
/**
238
 * p11_kit_destroyer:
239
 * @data: data to destroy
240
 *
241
 * A callback called to free a resource.
242
 */
243
244
/**
245
 * p11_kit_iter_callback:
246
 * @iter: the iterator
247
 * @matches: (out): whether to match the current object
248
 * @data: callback data
249
 *
250
 * A callback setup with p11_kit_iter_add_callback(). This callback is
251
 * called for each object iterated.
252
 *
253
 * If the callback sets @matches to CK_FALSE, then this object is
254
 * skipped and not matched by p11_kit_iter_next(). If you return
255
 * anything but CKR_OK, then the iteration is stopped, and
256
 * p11_kit_iter_next() returns the result code.
257
 *
258
 * Returns: CKR_OK to continue iterating, CKR_CANCEL to stop, or
259
 *          anything else to fail
260
 */
261
262
/**
263
 * p11_kit_iter_add_callback:
264
 * @iter: the iterator
265
 * @callback: a function to call for each iteration
266
 * @callback_data: (allow-none): data to pass to the function
267
 * @callback_destroy: (allow-none): used to cleanup the data
268
 *
269
 * Adds a callback to the iterator which will be called each time
270
 * that an object is iterated.
271
 *
272
 * These callbacks can also perform filtering. If any callback
273
 * indicates through it's <literal>matches</literal> argument that
274
 * the object should not match, then that object will not be iterated
275
 * as far as p11_kit_iter_next() is concerned.
276
 *
277
 * The callbacks will be called with the <literal>matches</literal>
278
 * set to <literal>CK_TRUE</literal> and it's up to filters to change
279
 * it to <literal>CK_FALSE</literal> when necessary.
280
 */
281
void
282
p11_kit_iter_add_callback (P11KitIter *iter,
283
                           p11_kit_iter_callback callback,
284
                           void *callback_data,
285
                           p11_kit_destroyer callback_destroy)
286
0
{
287
0
  Callback *cb;
288
289
0
  return_if_fail (iter != NULL);
290
0
  return_if_fail (callback != NULL);
291
292
0
  cb = calloc (1, sizeof (Callback));
293
0
  return_if_fail (cb != NULL);
294
295
0
  cb->func = callback;
296
0
  cb->destroyer = callback_destroy;
297
0
  cb->callback_data = callback_data;
298
0
  cb->next = iter->callbacks;
299
0
  iter->callbacks = cb;
300
0
}
301
302
/**
303
 * p11_kit_iter_add_filter:
304
 * @iter: the iterator
305
 * @matching: (array length=count): the attributes that the objects should match
306
 * @count: the number of attributes
307
 *
308
 * Add a filter to limit the objects that the iterator iterates over.
309
 *
310
 * Only objects matching the passed in attributes will be iterated.
311
 * This function can be called multiple times.
312
 *
313
 * The @matching attributes are copied.
314
 */
315
void
316
p11_kit_iter_add_filter (P11KitIter *iter,
317
                         CK_ATTRIBUTE *matching,
318
                         CK_ULONG count)
319
0
{
320
0
  return_if_fail (iter != NULL);
321
0
  return_if_fail (!iter->iterating);
322
323
0
  iter->match_attrs = p11_attrs_buildn (iter->match_attrs, matching, count);
324
0
  return_if_fail (iter->match_attrs != NULL);
325
0
}
326
327
static void
328
finish_object (P11KitIter *iter)
329
0
{
330
0
  iter->object = 0;
331
0
}
332
333
static void
334
finish_slot (P11KitIter *iter)
335
0
{
336
0
  if (iter->session && !iter->keep_session) {
337
0
    assert (iter->module != NULL);
338
0
    (iter->module->C_CloseSession) (iter->session);
339
0
  }
340
341
0
  iter->keep_session = 0;
342
0
  iter->session = 0;
343
0
  iter->searched = 0;
344
0
  iter->searching = 0;
345
0
  iter->slot = 0;
346
0
}
347
348
static void
349
finish_module (P11KitIter *iter)
350
0
{
351
0
  iter->num_slots = 0;
352
0
  iter->saw_slots = 0;
353
0
  iter->module = NULL;
354
0
}
355
356
static CK_RV
357
finish_iterating (P11KitIter *iter,
358
                  CK_RV rv)
359
0
{
360
0
  finish_object (iter);
361
0
  finish_slot (iter);
362
0
  finish_module (iter);
363
0
  p11_array_clear (iter->modules);
364
365
0
  iter->iterating = 0;
366
0
  iter->move_next_session_state = 0;
367
0
  iter->iter_next_state = 0;
368
0
  iter->kind = P11_KIT_ITER_KIND_UNKNOWN;
369
0
  return rv;
370
0
}
371
372
/**
373
 * p11_kit_iter_begin:
374
 * @iter: the iterator
375
 * @modules: (array zero-terminated=1): null-terminated list of
376
 *           modules to iterate over
377
 *
378
 * Begin iterating PKCS\#11 objects in the given @modules.
379
 *
380
 * The @modules arguments should be a null-terminated list of
381
 * pointers to the modules' PKCS\#11 function pointers.
382
 *
383
 * For each module, all initialized slots will be iterated over,
384
 * having sessions opened for each of them in turn, and searched
385
 * for objects matching the search criteria.
386
 */
387
void
388
p11_kit_iter_begin (P11KitIter *iter,
389
                    CK_FUNCTION_LIST_PTR *modules)
390
0
{
391
0
  int i;
392
393
0
  return_if_fail (modules != NULL);
394
395
0
  finish_iterating (iter, CKR_OK);
396
397
  /* Use this module */
398
0
  for (i = 0; modules[i] != NULL; i++) {
399
0
    if (!p11_array_push (iter->modules, modules[i]))
400
0
      return_if_reached ();
401
0
  }
402
403
0
  iter->iterating = 1;
404
0
  iter->searched = 1;
405
0
}
406
407
/**
408
 * p11_kit_iter_begin_with:
409
 * @iter: the iterator
410
 * @module: the module to iterate over
411
 * @slot: (allow-none): the slot to iterate objects in, or zero
412
 * @session: (allow-none): the session to search for objects on, or zero
413
 *
414
 * Begin iterating PKCS\#11 objects in the given @module.
415
 *
416
 * If @slot is non-zero then the iteration will be limited to that
417
 * slot.
418
 *
419
 * If @session is non-zero then the iteration will be limited to
420
 * objects visible through that session, which implies that they
421
 * are also limited to the slot which the session was opened for.
422
 */
423
void
424
p11_kit_iter_begin_with (P11KitIter *iter,
425
                         CK_FUNCTION_LIST_PTR module,
426
                         CK_SLOT_ID slot,
427
                         CK_SESSION_HANDLE session)
428
0
{
429
0
  CK_SESSION_INFO info;
430
0
  CK_RV rv;
431
432
0
  finish_iterating (iter, CKR_OK);
433
434
0
  return_if_fail (module != NULL);
435
436
0
  if (session != 0) {
437
    /*
438
     * A currently active session. Initialize as if we're ready
439
     * to search using this session.
440
     */
441
442
    /* If we have a session, but no slot, then look it up */
443
0
    if (slot == 0) {
444
0
      assert (module != NULL);
445
0
      rv = (module->C_GetSessionInfo) (session, &info);
446
0
      if (rv == CKR_OK)
447
0
        slot = info.slotID;
448
0
    }
449
450
    /* So initialize as if we're ready to search */
451
0
    iter->session = session;
452
0
    iter->slot = slot;
453
0
    iter->module = module;
454
0
    iter->keep_session = 1;
455
456
0
  } else if (slot != 0) {
457
0
    CK_SLOT_ID *slots;
458
459
    /*
460
     * Limit to this slot. Initialize as if we're ready to use the
461
     * slot from the slots list.
462
     */
463
464
0
    iter->module = module;
465
0
    slots = realloc (iter->slots, sizeof (CK_SLOT_ID));
466
0
    return_if_fail (slots != NULL);
467
0
    iter->slots = slots;
468
0
    iter->slots[0] = slot;
469
0
    iter->num_slots = 1;
470
0
    iter->searched = 1;
471
472
0
  } else {
473
474
    /*
475
     * Limit to this module. Initialize as if we're ready to use
476
     * the module from the modules array.
477
     */
478
479
0
    assert (module != NULL);
480
0
    p11_array_push (iter->modules, module);
481
0
    iter->session = 0;
482
0
    iter->slot = 0;
483
0
    iter->searched = 1;
484
0
  }
485
486
0
  iter->iterating = 1;
487
0
}
488
489
static CK_RV
490
call_all_filters (P11KitIter *iter,
491
                  CK_BBOOL *matches)
492
0
{
493
0
  Callback *cb;
494
0
  CK_RV rv;
495
496
0
  *matches = CK_TRUE;
497
498
0
  for (cb = iter->callbacks; cb != NULL; cb = cb->next) {
499
0
    rv = (cb->func) (iter, matches, cb->callback_data);
500
0
    if (rv != CKR_OK || !*matches)
501
0
      return rv;
502
0
  }
503
504
0
  return CKR_OK;
505
0
}
506
507
0
#define COROUTINE_BEGIN(name) switch (iter->name ## _state) { case 0:
508
0
#define COROUTINE_RETURN(name,i,x) do { iter->name ## _state = i; return x; case i:; } while (0)
509
0
#define COROUTINE_END(name) }
510
511
static CK_RV
512
move_next_session (P11KitIter *iter)
513
0
{
514
0
  CK_ULONG session_flags;
515
0
  CK_ULONG num_slots;
516
0
  CK_INFO minfo;
517
0
  CK_RV rv;
518
519
0
  COROUTINE_BEGIN (move_next_session);
520
521
0
  finish_slot (iter);
522
523
  /* If we have no more slots, then move to next module */
524
0
  while (iter->saw_slots >= iter->num_slots) {
525
0
    finish_module (iter);
526
527
    /* Iter is finished */
528
0
    if (iter->modules->num == 0)
529
0
      return finish_iterating (iter, CKR_CANCEL);
530
531
0
    iter->module = iter->modules->elem[0];
532
0
    p11_array_remove (iter->modules, 0);
533
534
    /* Skip module if it doesn't match uri */
535
0
    assert (iter->module != NULL);
536
0
    rv = (iter->module->C_GetInfo) (&minfo);
537
0
    if (rv != CKR_OK || !p11_match_uri_module_info (&iter->match_module, &minfo))
538
0
      continue;
539
540
0
    if (iter->with_modules) {
541
0
      iter->kind = P11_KIT_ITER_KIND_MODULE;
542
0
      COROUTINE_RETURN (move_next_session, 1, CKR_OK);
543
0
    }
544
545
0
    if (iter->with_slots || iter->with_tokens || iter->with_objects) {
546
0
      CK_SLOT_ID *slots;
547
548
0
      rv = (iter->module->C_GetSlotList) (CK_TRUE, NULL, &num_slots);
549
0
      if (rv != CKR_OK)
550
0
        return finish_iterating (iter, rv);
551
552
0
      slots = reallocarray (iter->slots, num_slots + 1, sizeof (CK_SLOT_ID));
553
0
      return_val_if_fail (slots != NULL, CKR_HOST_MEMORY);
554
0
      iter->slots = slots;
555
556
0
      rv = (iter->module->C_GetSlotList) (CK_TRUE, iter->slots, &num_slots);
557
0
      if (rv != CKR_OK)
558
0
        return finish_iterating (iter, rv);
559
560
0
      iter->num_slots = num_slots;
561
0
      assert (iter->saw_slots == 0);
562
0
    }
563
0
  }
564
565
  /* Move to the next slot, and open a session on it */
566
0
  while ((iter->with_slots || iter->with_tokens || iter->with_objects) &&
567
0
         iter->saw_slots < iter->num_slots) {
568
0
    iter->slot = iter->slots[iter->saw_slots++];
569
570
0
    assert (iter->module != NULL);
571
0
    if (iter->match_slot_id != (CK_SLOT_ID)-1 && iter->slot != iter->match_slot_id)
572
0
      continue;
573
0
    rv = (iter->module->C_GetSlotInfo) (iter->slot, &iter->slot_info);
574
0
    if (rv != CKR_OK || !p11_match_uri_slot_info (&iter->match_slot, &iter->slot_info))
575
0
      continue;
576
0
    if (iter->with_slots) {
577
0
      iter->kind = P11_KIT_ITER_KIND_SLOT;
578
0
      COROUTINE_RETURN (move_next_session, 2, CKR_OK);
579
0
    }
580
0
    rv = (iter->module->C_GetTokenInfo) (iter->slot, &iter->token_info);
581
0
    if (rv != CKR_OK || !p11_match_uri_token_info (&iter->match_token, &iter->token_info))
582
0
      continue;
583
0
    if (iter->with_tokens) {
584
0
      iter->kind = P11_KIT_ITER_KIND_TOKEN;
585
0
      COROUTINE_RETURN (move_next_session, 3, CKR_OK);
586
0
    }
587
588
0
    session_flags = CKF_SERIAL_SESSION;
589
590
    /* Skip if the read/write on a read-only token */
591
0
    if (iter->want_writable && (iter->token_info.flags & CKF_WRITE_PROTECTED) == 0)
592
0
      session_flags |= CKF_RW_SESSION;
593
594
0
    rv = (iter->module->C_OpenSession) (iter->slot, session_flags,
595
0
                                        NULL, NULL, &iter->session);
596
0
    if (rv != CKR_OK)
597
0
      return finish_iterating (iter, rv);
598
599
0
    if (iter->session != 0) {
600
0
      iter->move_next_session_state = 0;
601
0
      iter->kind = P11_KIT_ITER_KIND_UNKNOWN;
602
0
      return CKR_OK;
603
0
    }
604
0
  }
605
606
0
  COROUTINE_END (move_next_session);
607
608
  /* Otherwise try again */
609
0
  iter->move_next_session_state = 0;
610
0
  return move_next_session (iter);
611
0
}
612
613
/**
614
 * p11_kit_iter_next:
615
 * @iter: the iterator
616
 *
617
 * Iterate to the next matching object.
618
 *
619
 * To access the object, session and so on, use the p11_kit_iter_get_object(),
620
 * p11_kit_iter_get_session(), and p11_kit_iter_get_module() functions.
621
 *
622
 * This call must only be called after either p11_kit_iter_begin()
623
 * or p11_kit_iter_begin_with() have been called.
624
 *
625
 * Objects which are skipped by callbacks will not be returned here
626
 * as matching objects.
627
 *
628
 * Returns: CKR_OK if an object matched, CKR_CANCEL if no more objects, or another error
629
 */
630
CK_RV
631
p11_kit_iter_next (P11KitIter *iter)
632
0
{
633
0
  CK_ULONG batch;
634
0
  CK_ULONG count;
635
0
  CK_BBOOL matches;
636
0
  CK_RV rv;
637
638
0
  return_val_if_fail (iter->iterating, CKR_OPERATION_NOT_INITIALIZED);
639
640
0
  COROUTINE_BEGIN (iter_next);
641
642
0
  iter->object = 0;
643
644
0
  if (iter->match_nothing)
645
0
    return finish_iterating (iter, CKR_CANCEL);
646
647
0
  if (!(iter->with_modules || iter->with_slots || iter->with_tokens || iter->with_objects))
648
0
    return finish_iterating (iter, CKR_CANCEL);
649
650
  /*
651
   * If we have outstanding objects, then iterate one through those
652
   * Note that we pass each object through the filters, and only
653
   * assume it's iterated if it matches
654
   */
655
0
  while (iter->with_objects && iter->saw_objects < iter->num_objects) {
656
0
    iter->object = iter->objects[iter->saw_objects++];
657
658
0
    rv = call_all_filters (iter, &matches);
659
0
    if (rv != CKR_OK)
660
0
      return finish_iterating (iter, rv);
661
662
0
    if (matches && iter->with_objects) {
663
0
      iter->kind = P11_KIT_ITER_KIND_OBJECT;
664
0
      COROUTINE_RETURN (iter_next, 1, CKR_OK);
665
0
    }
666
0
  }
667
668
  /* Move to next session, if we have finished searching
669
   * objects, or we are looking for modules/slots/tokens */
670
0
  if ((iter->with_objects && iter->searched) ||
671
0
      (!iter->with_objects &&
672
0
       (iter->with_modules || iter->with_slots || iter->with_tokens))) {
673
    /* Use iter->kind as the sentinel to detect the case where
674
     * any match (except object) is successful in
675
     * move_next_session() */
676
0
    do {
677
0
      iter->kind = P11_KIT_ITER_KIND_UNKNOWN;
678
0
      rv = move_next_session (iter);
679
0
      if (rv != CKR_OK)
680
0
        return finish_iterating (iter, rv);
681
0
      if (iter->kind != P11_KIT_ITER_KIND_UNKNOWN)
682
0
        COROUTINE_RETURN (iter_next, 2, CKR_OK);
683
0
    } while (iter->move_next_session_state > 0);
684
0
  }
685
686
  /* Ready to start searching */
687
0
  if (iter->with_objects && !iter->searching && !iter->searched) {
688
0
    count = p11_attrs_count (iter->match_attrs);
689
0
    rv = (iter->module->C_FindObjectsInit) (iter->session, iter->match_attrs, count);
690
0
    if (rv != CKR_OK)
691
0
      return finish_iterating (iter, rv);
692
0
    iter->searching = 1;
693
0
    iter->searched = 0;
694
0
  }
695
696
  /* If we have searched on this session then try to continue */
697
0
  if (iter->with_objects && iter->searching) {
698
0
    assert (iter->module != NULL);
699
0
    assert (iter->session != 0);
700
0
    iter->num_objects = 0;
701
0
    iter->saw_objects = 0;
702
703
0
    for (;;) {
704
0
      if (iter->max_objects - iter->num_objects == 0) {
705
0
        CK_OBJECT_HANDLE *objects;
706
707
0
        iter->max_objects = iter->max_objects ? iter->max_objects * 2 : 64;
708
0
        objects = reallocarray (iter->objects, iter->max_objects, sizeof (CK_ULONG));
709
0
        return_val_if_fail (objects != NULL, CKR_HOST_MEMORY);
710
0
        iter->objects = objects;
711
0
      }
712
713
0
      batch = iter->max_objects - iter->num_objects;
714
0
      rv = (iter->module->C_FindObjects) (iter->session,
715
0
                                          iter->objects + iter->num_objects,
716
0
                                          batch, &count);
717
0
      if (rv != CKR_OK)
718
0
        return finish_iterating (iter, rv);
719
720
0
      iter->num_objects += count;
721
722
      /*
723
       * Done searching on this session, although there are still
724
       * objects outstanding, which will be returned on next
725
       * iterations.
726
       */
727
0
      if (batch != count) {
728
0
        iter->searching = 0;
729
0
        iter->searched = 1;
730
0
        (iter->module->C_FindObjectsFinal) (iter->session);
731
0
        break;
732
0
      }
733
734
0
      if (!iter->preload_results)
735
0
        break;
736
0
    }
737
0
  }
738
739
0
  COROUTINE_END (iter_next);
740
741
  /* Try again */
742
0
  iter->iter_next_state = 0;
743
0
  iter->move_next_session_state = 0;
744
0
  iter->kind = P11_KIT_ITER_KIND_UNKNOWN;
745
0
  return p11_kit_iter_next (iter);
746
0
}
747
748
/**
749
 * p11_kit_iter_get_kind:
750
 * @iter: the iterator
751
 *
752
 * Get the kind of the current match (a module, slot, token, or an
753
 * object).
754
 *
755
 * This can only be called after p11_kit_iter_next() succeeds.
756
 *
757
 * Returns: a #P11KitIterKind value
758
 */
759
P11KitIterKind
760
p11_kit_iter_get_kind (P11KitIter *iter)
761
0
{
762
0
  return_val_if_fail (iter != NULL, P11_KIT_ITER_KIND_UNKNOWN);
763
0
  return_val_if_fail (iter->iterating, P11_KIT_ITER_KIND_UNKNOWN);
764
0
  return iter->kind;
765
0
}
766
767
/**
768
 * p11_kit_iter_get_module:
769
 * @iter: the iterator
770
 *
771
 * Get the module function pointers for the current matching object.
772
 *
773
 * This can only be called after p11_kit_iter_next() succeeds.
774
 *
775
 * Returns: the module which the current matching object is in
776
 */
777
CK_FUNCTION_LIST_PTR
778
p11_kit_iter_get_module (P11KitIter *iter)
779
0
{
780
0
  return_val_if_fail (iter != NULL, NULL);
781
0
  return_val_if_fail (iter->iterating, 0);
782
0
  return iter->module;
783
0
}
784
785
/**
786
 * p11_kit_iter_get_slot:
787
 * @iter: the iterator
788
 *
789
 * Get the slot which the current matching object is on.
790
 *
791
 * This can only be called after p11_kit_iter_next() succeeds.
792
 *
793
 * Returns: the slot of the current matching object
794
 */
795
CK_SLOT_ID
796
p11_kit_iter_get_slot (P11KitIter *iter)
797
0
{
798
0
  return_val_if_fail (iter != NULL, 0);
799
0
  return_val_if_fail (iter->iterating, 0);
800
0
  return iter->slot;
801
0
}
802
803
/**
804
 * p11_kit_iter_get_slot_info:
805
 * @iter: the iterator
806
 *
807
 * Get the slot info for the slot which the current matching object is on.
808
 *
809
 * This can only be called after p11_kit_iter_next() succeeds.
810
 *
811
 * Returns: the slot of the current matching object.
812
 */
813
CK_SLOT_INFO *
814
p11_kit_iter_get_slot_info (P11KitIter *iter)
815
0
{
816
0
  return_val_if_fail (iter != NULL, NULL);
817
0
  return &iter->slot_info;
818
0
}
819
820
/**
821
 * p11_kit_iter_get_token:
822
 * @iter: the iterator
823
 *
824
 * Get the token info for the token which the current matching object is on.
825
 *
826
 * This can only be called after p11_kit_iter_next() succeeds.
827
 *
828
 * Returns: the slot of the current matching object.
829
 */
830
CK_TOKEN_INFO *
831
p11_kit_iter_get_token (P11KitIter *iter)
832
0
{
833
0
  return_val_if_fail (iter != NULL, NULL);
834
0
  return &iter->token_info;
835
0
}
836
837
/**
838
 * p11_kit_iter_get_session:
839
 * @iter: the iterator
840
 *
841
 * Get the session which the current matching object is accessible
842
 * through.
843
 *
844
 * This can only be called after p11_kit_iter_next() succeeds.
845
 *
846
 * The session may be closed after the next p11_kit_iter_next() call
847
 * unless p11_kit_iter_keep_session() is called.
848
 *
849
 * Returns: the session used to find the current matching object
850
 */
851
CK_SESSION_HANDLE
852
p11_kit_iter_get_session (P11KitIter *iter)
853
0
{
854
0
  return_val_if_fail (iter != NULL, 0);
855
0
  return_val_if_fail (iter->iterating, 0);
856
0
  return iter->session;
857
0
}
858
859
/**
860
 * p11_kit_iter_get_object:
861
 * @iter: the iterator
862
 *
863
 * Get the current matching object.
864
 *
865
 * This can only be called after p11_kit_iter_next() succeeds.
866
 *
867
 * Returns: the current matching object
868
 */
869
CK_OBJECT_HANDLE
870
p11_kit_iter_get_object (P11KitIter *iter)
871
0
{
872
0
  return_val_if_fail (iter != NULL, 0);
873
0
  return iter->object;
874
0
}
875
876
/**
877
 * p11_kit_iter_destroy_object:
878
 * @iter: the iterator
879
 *
880
 * Destroy the current matching object.
881
 *
882
 * This can only be called after p11_kit_iter_next() succeeds.
883
 *
884
 * Returns: CKR_OK or a failure code
885
 */
886
CK_RV
887
p11_kit_iter_destroy_object (P11KitIter *iter)
888
0
{
889
0
  return_val_if_fail (iter != NULL, CKR_GENERAL_ERROR);
890
0
  return_val_if_fail (iter->iterating, CKR_GENERAL_ERROR);
891
0
  return (iter->module->C_DestroyObject) (iter->session, iter->object);
892
0
}
893
894
/**
895
 * p11_kit_iter_get_attributes:
896
 * @iter: the iterator
897
 * @template: (array length=count) (inout): the attributes to get
898
 * @count: the number of attributes
899
 *
900
 * Get attributes for the current matching object.
901
 *
902
 * This calls <literal>C_GetAttributeValue</literal> for the object
903
 * currently iterated to. Return value and attribute memory behavior
904
 * is identical to the PKCS\#11 <literal>C_GetAttributeValue</literal>
905
 * function.
906
 *
907
 * You might choose to use p11_kit_iter_load_attributes() for a more
908
 * helpful variant.
909
 *
910
 * This can only be called after p11_kit_iter_next() succeeds.
911
 *
912
 * Returns: The result from <literal>C_GetAttributeValue</literal>.
913
 */
914
CK_RV
915
p11_kit_iter_get_attributes (P11KitIter *iter,
916
                             CK_ATTRIBUTE *template,
917
                             CK_ULONG count)
918
0
{
919
0
  return_val_if_fail (iter != NULL, CKR_GENERAL_ERROR);
920
0
  return_val_if_fail (iter->iterating, CKR_GENERAL_ERROR);
921
0
  return_val_if_fail (iter->module != NULL, CKR_GENERAL_ERROR);
922
0
  return_val_if_fail (iter->session != 0, CKR_GENERAL_ERROR);
923
0
  return_val_if_fail (iter->object != 0, CKR_GENERAL_ERROR);
924
925
0
  return (iter->module->C_GetAttributeValue) (iter->session, iter->object,
926
0
                                              template, count);
927
0
}
928
929
/**
930
 * p11_kit_iter_load_attributes:
931
 * @iter: the iterator
932
 * @template: (array length=count) (inout): the attributes to load
933
 * @count: the number of attributes
934
 *
935
 * Retrieve attributes for the current matching object.
936
 *
937
 * Each attribute in the array will be filled in with the value
938
 * of that attribute retrieved from the object. After use the
939
 * attribute value memory pointed to by the <literal>pValue</literal>
940
 * of each attribute should be freed with the <literal>free<!-- -->()</literal>
941
 * function.
942
 *
943
 * If the <literal>pValue</literal> of an attribute is not %NULL passed
944
 * to this function, then it will be passed to
945
 * <literal>realloc<!-- -->()</literal> to allocate the correct amount
946
 * of space for the attribute value.
947
 *
948
 * If any attribute is not present on the object, or is sensitive and
949
 * cannot be retrieved, then the <literal>pValue</literal> will be NULL.
950
 * If <literal>pValue</literal> was not %NULL when passed to this function
951
 * then it will be freed with <literal>free<!-- -->()</literal>. In these
952
 * cases <literal>CKR_OK</literal> is returned.
953
 *
954
 * This can only be called after p11_kit_iter_next() succeeds.
955
 *
956
 * Returns: CKR_OK or a failure code
957
 */
958
CK_RV
959
p11_kit_iter_load_attributes (P11KitIter *iter,
960
                              CK_ATTRIBUTE *template,
961
                              CK_ULONG count)
962
0
{
963
0
  CK_ATTRIBUTE *original = NULL;
964
0
  CK_ULONG i;
965
0
  CK_RV rv;
966
967
0
  return_val_if_fail (iter != NULL, CKR_GENERAL_ERROR);
968
0
  return_val_if_fail (iter->iterating, CKR_GENERAL_ERROR);
969
0
  return_val_if_fail (iter->module != NULL, CKR_GENERAL_ERROR);
970
0
  return_val_if_fail (iter->session != 0, CKR_GENERAL_ERROR);
971
0
  return_val_if_fail (iter->object != 0, CKR_GENERAL_ERROR);
972
973
0
  if (count == 0)
974
0
    return CKR_OK;
975
976
0
  original = memdup (template, count * sizeof (CK_ATTRIBUTE));
977
0
  return_val_if_fail (original != NULL, CKR_HOST_MEMORY);
978
979
0
  for (i = 0; i < count; i++)
980
0
    template[i].pValue = NULL;
981
982
0
  rv = (iter->module->C_GetAttributeValue) (iter->session, iter->object, template, count);
983
984
0
  switch (rv) {
985
0
  case CKR_OK:
986
0
  case CKR_ATTRIBUTE_TYPE_INVALID:
987
0
  case CKR_ATTRIBUTE_SENSITIVE:
988
0
  case CKR_BUFFER_TOO_SMALL:
989
0
    break;
990
0
  default:
991
0
    free (original);
992
0
    return rv;
993
0
  }
994
995
0
  for (i = 0; i < count; i++) {
996
0
    if (template[i].ulValueLen == (CK_ULONG)-1 ||
997
0
        template[i].ulValueLen == 0) {
998
0
      free (original[i].pValue);
999
1000
0
    } else if (original[i].pValue != NULL &&
1001
0
               template[i].ulValueLen == original[i].ulValueLen) {
1002
0
      template[i].pValue = original[i].pValue;
1003
1004
0
    } else {
1005
0
      template[i].pValue = realloc (original[i].pValue, template[i].ulValueLen);
1006
0
      return_val_if_fail (template[i].pValue != NULL, CKR_HOST_MEMORY);
1007
0
    }
1008
0
  }
1009
1010
0
  free (original);
1011
1012
0
  rv = (iter->module->C_GetAttributeValue) (iter->session, iter->object, template, count);
1013
1014
0
  switch (rv) {
1015
0
  case CKR_OK:
1016
0
  case CKR_ATTRIBUTE_TYPE_INVALID:
1017
0
  case CKR_ATTRIBUTE_SENSITIVE:
1018
0
    rv = CKR_OK;
1019
0
    break;
1020
0
  default:
1021
0
    return_val_if_fail (rv != CKR_BUFFER_TOO_SMALL, rv);
1022
0
    return rv;
1023
0
  }
1024
1025
0
  for (i = 0; i < count; i++) {
1026
0
    if (template[i].ulValueLen == (CK_ULONG)-1 ||
1027
0
        template[i].ulValueLen == 0) {
1028
0
      free (template[i].pValue);
1029
0
      template[i].pValue = NULL;
1030
0
    }
1031
0
  }
1032
1033
0
  return rv;
1034
0
}
1035
1036
/**
1037
 * p11_kit_iter_keep_session:
1038
 * @iter: the iterator
1039
 *
1040
 * After calling this function the session open for iterating
1041
 * the current object will not be automatically closed by
1042
 * the iterator after later calls to p11_kit_iter_next() or
1043
 * p11_kit_iter_free().
1044
 *
1045
 * It is the callers responsibility to close this session,
1046
 * after the iterator has been freed. The session may still be
1047
 * used by the iterator if further iterations are performed.
1048
 *
1049
 * This can only be called after p11_kit_iter_next() succeeds.
1050
 *
1051
 * Returns: the current session
1052
 */
1053
CK_SESSION_HANDLE
1054
p11_kit_iter_keep_session (P11KitIter *iter)
1055
0
{
1056
0
  return_val_if_fail (iter != NULL, 0);
1057
0
  return_val_if_fail (iter->iterating, 0);
1058
0
  return_val_if_fail (iter->session != 0, 0);
1059
1060
0
  iter->keep_session = 1;
1061
0
  return iter->session;
1062
0
}
1063
1064
/**
1065
 * p11_kit_iter_free:
1066
 * @iter: the iterator
1067
 *
1068
 * Frees the iterator and all resources, such as sessions
1069
 * or callbacks held by the iterator.
1070
 */
1071
void
1072
p11_kit_iter_free (P11KitIter *iter)
1073
0
{
1074
0
  Callback *cb, *next;
1075
1076
0
  if (iter == NULL)
1077
0
    return;
1078
1079
0
  finish_iterating (iter, CKR_OK);
1080
0
  p11_array_free (iter->modules);
1081
0
  p11_attrs_free (iter->match_attrs);
1082
0
  free (iter->objects);
1083
0
  free (iter->slots);
1084
1085
0
  for (cb = iter->callbacks; cb != NULL; cb = next) {
1086
0
    next = cb->next;
1087
0
    if (cb->destroyer)
1088
0
      (cb->destroyer) (cb->callback_data);
1089
0
    free (cb);
1090
0
  }
1091
1092
0
  free (iter);
1093
0
}