Coverage Report

Created: 2026-01-16 06:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/p11-kit/p11-kit/proxy.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2008 Stefan Walter
3
 * Copyright (C) 2011 Collabora Ltd.
4
 * Copyright (C) 2021-2023 Red Hat Inc.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 *
10
 *     * Redistributions of source code must retain the above
11
 *       copyright notice, this list of conditions and the
12
 *       following disclaimer.
13
 *     * Redistributions in binary form must reproduce the
14
 *       above copyright notice, this list of conditions and
15
 *       the following disclaimer in the documentation and/or
16
 *       other materials provided with the distribution.
17
 *     * The names of contributors to this software may not be
18
 *       used to endorse or promote products derived from this
19
 *       software without specific prior written permission.
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
31
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
32
 * DAMAGE.
33
 *
34
 * Author: Stef Walter <stefw@collabora.co.uk>
35
 */
36
37
#include "config.h"
38
39
#include "compat.h"
40
0
#define P11_DEBUG_FLAG P11_DEBUG_PROXY
41
#define CRYPTOKI_EXPORTS
42
43
#include "debug.h"
44
#include "dict.h"
45
#include "library.h"
46
#include "message.h"
47
#include "modules.h"
48
#include "pkcs11.h"
49
#include "pkcs11x.h"
50
#include "p11-kit.h"
51
#include "private.h"
52
#include "proxy.h"
53
#include "virtual.h"
54
55
#include <sys/types.h>
56
#include <assert.h>
57
#include <errno.h>
58
#include <stdarg.h>
59
#include <stddef.h>
60
#include <stdlib.h>
61
#include <stdio.h>
62
#include <string.h>
63
64
/* Start wrap slots slightly higher for testing */
65
0
#define MAPPING_OFFSET 0x10
66
0
#define FIRST_HANDLE   0x10
67
68
typedef struct _Mapping {
69
  CK_SLOT_ID wrap_slot;
70
  CK_SLOT_ID real_slot;
71
  CK_FUNCTION_LIST_PTR funcs;
72
} Mapping;
73
74
typedef struct _Session {
75
  CK_SESSION_HANDLE wrap_session;
76
  CK_SESSION_HANDLE real_session;
77
  CK_SLOT_ID wrap_slot;
78
} Session;
79
80
typedef struct {
81
  int refs;
82
  Mapping *mappings;
83
  unsigned int n_mappings;
84
  p11_dict *sessions;
85
  CK_FUNCTION_LIST **inited;
86
  unsigned int forkid;
87
  CK_SLOT_ID last_id;
88
} Proxy;
89
90
typedef struct _State {
91
  p11_virtual virt;
92
  struct _State *next;
93
  CK_FUNCTION_LIST **loaded;
94
  CK_INTERFACE wrapped;
95
  CK_ULONG last_handle;
96
  Proxy *px;
97
} State;
98
99
static State *all_instances = NULL;
100
101
0
#define PROXY_VALID(px) ((px) && (px)->forkid == p11_forkid)
102
0
#define PROXY_FORKED(px) ((px) && (px)->forkid != p11_forkid)
103
104
0
#define MANUFACTURER_ID         "PKCS#11 Kit                     "
105
0
#define LIBRARY_DESCRIPTION     "PKCS#11 Kit Proxy Module        "
106
0
#define LIBRARY_VERSION_MAJOR   1
107
0
#define LIBRARY_VERSION_MINOR   1
108
109
/* -----------------------------------------------------------------------------
110
 * PKCS#11 PROXY MODULE
111
 */
112
113
static CK_RV
114
map_slot_unlocked (Proxy *px,
115
                   CK_SLOT_ID slot,
116
                   Mapping *mapping)
117
0
{
118
0
  unsigned int i;
119
120
0
  assert (px != NULL);
121
0
  assert (mapping != NULL);
122
123
0
  for (i = 0; i < px->n_mappings; i++) {
124
0
    assert (px->mappings != NULL);
125
0
    if (px->mappings[i].wrap_slot == slot) {
126
0
      memcpy (mapping, &px->mappings[i], sizeof(Mapping));
127
0
      return CKR_OK;
128
0
    }
129
0
  }
130
131
0
  return CKR_SLOT_ID_INVALID;
132
0
}
133
134
static CK_RV
135
map_slot_to_real (Proxy *px,
136
                  CK_SLOT_ID_PTR slot,
137
                  Mapping *mapping)
138
0
{
139
0
  CK_RV rv;
140
141
0
  assert (mapping != NULL);
142
143
0
  p11_lock ();
144
145
0
    if (!PROXY_VALID (px))
146
0
      rv = CKR_CRYPTOKI_NOT_INITIALIZED;
147
0
    else
148
0
      rv = map_slot_unlocked (px, *slot, mapping);
149
0
    if (rv == CKR_OK)
150
0
      *slot = mapping->real_slot;
151
152
0
  p11_unlock ();
153
154
0
  return rv;
155
0
}
156
157
static CK_RV
158
map_session_to_real (Proxy *px,
159
                     CK_SESSION_HANDLE_PTR handle,
160
                     Mapping *mapping,
161
                     Session *session)
162
0
{
163
0
  CK_RV rv = CKR_OK;
164
0
  Session *sess;
165
166
0
  assert (handle != NULL);
167
0
  assert (mapping != NULL);
168
169
0
  p11_lock ();
170
171
0
    if (!PROXY_VALID (px)) {
172
0
      rv = CKR_CRYPTOKI_NOT_INITIALIZED;
173
0
    } else {
174
0
      assert (px->sessions);
175
0
      sess = p11_dict_get (px->sessions, handle);
176
0
      if (sess != NULL) {
177
0
        *handle = sess->real_session;
178
0
        rv = map_slot_unlocked (px, sess->wrap_slot, mapping);
179
0
        if (session != NULL)
180
0
          memcpy (session, sess, sizeof (Session));
181
0
      } else {
182
0
        rv = CKR_SESSION_HANDLE_INVALID;
183
0
      }
184
0
    }
185
186
0
  p11_unlock ();
187
188
0
  return rv;
189
0
}
190
191
static void
192
proxy_free (Proxy *py, unsigned finalize)
193
0
{
194
0
  if (py) {
195
0
    if (finalize)
196
0
      p11_kit_modules_finalize ((CK_FUNCTION_LIST **)py->inited);
197
0
    free (py->inited);
198
0
    p11_dict_free (py->sessions);
199
0
    free (py->mappings);
200
0
    free (py);
201
0
  }
202
0
}
203
204
static CK_RV
205
proxy_C_Finalize (CK_X_FUNCTION_LIST *self,
206
                  CK_VOID_PTR reserved)
207
0
{
208
0
  Proxy *py = NULL;
209
0
  State *state = (State *)self;
210
0
  CK_RV rv = CKR_OK;
211
212
0
  p11_debug ("in");
213
214
  /* WARNING: This function must be reentrant */
215
216
0
  if (reserved) {
217
0
    rv = CKR_ARGUMENTS_BAD;
218
219
0
  } else {
220
0
    p11_lock ();
221
222
0
      if (!PROXY_VALID (state->px)) {
223
0
        rv = CKR_CRYPTOKI_NOT_INITIALIZED;
224
0
        py = state->px;
225
0
        state->px = NULL;
226
0
      } else if (state->px->refs-- == 1) {
227
0
        py = state->px;
228
0
        state->px = NULL;
229
0
      }
230
231
0
    p11_unlock ();
232
233
0
    proxy_free (py, 1);
234
0
  }
235
236
0
  p11_debug ("out: %lu", rv);
237
0
  return rv;
238
0
}
239
240
static CK_FUNCTION_LIST **
241
modules_dup (CK_FUNCTION_LIST **modules)
242
0
{
243
0
  int count = 0;
244
245
0
  while (modules[count] != NULL)
246
0
    count++;
247
248
0
  return memdup (modules, sizeof (CK_FUNCTION_LIST *) * (count + 1));
249
0
}
250
251
static CK_RV
252
proxy_list_slots (Proxy *py, Mapping *mappings, unsigned int n_mappings)
253
0
{
254
0
  CK_FUNCTION_LIST_PTR *f;
255
0
  CK_FUNCTION_LIST_PTR funcs;
256
0
  CK_SLOT_ID_PTR slots;
257
0
  CK_ULONG i, count;
258
0
  unsigned int j;
259
0
  CK_RV rv = CKR_OK;
260
261
0
  for (f = py->inited; *f; ++f) {
262
0
    funcs = *f;
263
0
    assert (funcs != NULL);
264
0
    slots = NULL;
265
266
    /* Ask module for its slots */
267
0
    rv = (funcs->C_GetSlotList) (FALSE, NULL, &count);
268
0
    if (rv == CKR_OK && count) {
269
0
      slots = calloc (count, sizeof (CK_SLOT_ID));
270
0
      rv = (funcs->C_GetSlotList) (FALSE, slots, &count);
271
0
    }
272
273
0
    if (rv != CKR_OK) {
274
0
      free (slots);
275
0
      break;
276
0
    }
277
278
0
    return_val_if_fail (count == 0 || slots != NULL, CKR_GENERAL_ERROR);
279
280
0
    if (count > 0) {
281
0
      Mapping *new_mappings;
282
0
      CK_SLOT_ID_PTR new_slots;
283
0
      int new_slots_count = 0;
284
285
0
      new_slots = calloc (count, sizeof(CK_SLOT_ID));
286
0
      return_val_if_fail (new_slots != NULL, CKR_HOST_MEMORY);
287
0
      new_mappings = reallocarray (py->mappings, (py->n_mappings + count), sizeof (Mapping));
288
0
      return_val_if_fail (new_mappings != NULL, CKR_HOST_MEMORY);
289
0
      py->mappings = new_mappings;
290
291
      /* Reuse the existing mapping if any */
292
0
      for (i = 0; i < count; ++i) {
293
0
        for (j = 0; j < n_mappings; ++j) {
294
          /* cppcheck-suppress nullPointer symbolName=mappings */
295
          /* false-positive: https://trac.cppcheck.net/ticket/9573 */
296
0
          if (mappings[j].funcs == funcs &&
297
0
              mappings[j].real_slot == slots[i]) {
298
0
            py->mappings[py->n_mappings].funcs = funcs;
299
0
            py->mappings[py->n_mappings].real_slot = slots[i];
300
0
            py->mappings[py->n_mappings].wrap_slot =
301
0
              mappings[j].wrap_slot;
302
0
            ++py->n_mappings;
303
0
            break;
304
0
          }
305
0
        }
306
0
        if (n_mappings == 0 || j == n_mappings) {
307
0
          new_slots[new_slots_count] = slots[i];
308
0
          ++new_slots_count;
309
0
        }
310
0
      }
311
312
      /* And now add a mapping for each new slot */
313
0
      for (i = 0; i < new_slots_count; ++i) {
314
0
        ++py->last_id;
315
0
        py->mappings[py->n_mappings].funcs = funcs;
316
0
        py->mappings[py->n_mappings].wrap_slot =
317
0
          py->last_id + MAPPING_OFFSET;
318
0
        py->mappings[py->n_mappings].real_slot = new_slots[i];
319
0
        ++py->n_mappings;
320
0
      }
321
322
0
      free(new_slots);
323
0
    }
324
325
0
    free (slots);
326
0
  }
327
0
  return rv;
328
0
}
329
330
static CK_RV
331
proxy_create (Proxy **res, CK_FUNCTION_LIST **loaded,
332
        Mapping *mappings, unsigned int n_mappings)
333
0
{
334
0
  CK_RV rv = CKR_OK;
335
0
  Proxy *py;
336
337
0
  py = calloc (1, sizeof (Proxy));
338
0
  return_val_if_fail (py != NULL, CKR_HOST_MEMORY);
339
340
0
  py->forkid = p11_forkid;
341
0
  py->last_id = 0;
342
343
0
  py->inited = modules_dup (loaded);
344
0
  if (py->inited == NULL) {
345
0
    proxy_free (py, 0);
346
0
    return_val_if_reached (CKR_HOST_MEMORY);
347
0
  }
348
349
0
  rv = p11_kit_modules_initialize (py->inited, NULL);
350
351
0
  if (rv == CKR_OK) {
352
0
    rv = proxy_list_slots (py, mappings, n_mappings);
353
0
  }
354
355
0
  if (rv != CKR_OK) {
356
0
    proxy_free (py, 1);
357
0
    return rv;
358
0
  }
359
360
0
  py->sessions = p11_dict_new (p11_dict_ulongptr_hash, p11_dict_ulongptr_equal, NULL, free);
361
0
  if (py->sessions == NULL) {
362
0
    proxy_free (py, 1);
363
0
    return_val_if_reached (CKR_HOST_MEMORY);
364
0
  }
365
0
  py->refs = 1;
366
367
0
  *res = py;
368
0
  return CKR_OK;
369
0
}
370
371
static CK_RV
372
proxy_C_Initialize (CK_X_FUNCTION_LIST *self,
373
                    CK_VOID_PTR init_args)
374
0
{
375
0
  State *state = (State *)self;
376
0
  bool initialize = false;
377
0
  Mapping *mappings = NULL;
378
0
  unsigned int n_mappings = 0;
379
0
  Proxy *py;
380
0
  CK_RV rv;
381
382
0
  p11_library_init_once ();
383
384
  /* WARNING: This function must be reentrant */
385
386
0
  p11_debug ("in");
387
388
0
  p11_lock ();
389
390
0
    if (!PROXY_VALID (state->px)) {
391
0
      unsigned call_finalize = 1;
392
393
0
      initialize = true;
394
0
      if (PROXY_FORKED(state->px)) {
395
0
        call_finalize = 0;
396
0
        if (state->px->mappings) {
397
0
          mappings = state->px->mappings;
398
0
          n_mappings = state->px->n_mappings;
399
0
          state->px->mappings = NULL;
400
0
          state->px->n_mappings = 0;
401
0
        }
402
0
      }
403
0
      proxy_free (state->px, call_finalize);
404
405
0
      state->px = NULL;
406
0
    } else {
407
0
      state->px->refs++;
408
0
    }
409
410
0
  p11_unlock ();
411
412
0
  if (!initialize) {
413
0
    p11_debug ("out: already: %lu", CKR_OK);
414
0
    return CKR_OK;
415
0
  }
416
417
0
  rv = proxy_create (&py, state->loaded, mappings, n_mappings);
418
0
  free (mappings);
419
0
  if (rv != CKR_OK) {
420
0
    p11_debug ("out: %lu", rv);
421
0
    return rv;
422
0
  }
423
424
0
  p11_lock ();
425
426
0
    if (state->px == NULL) {
427
0
      state->px = py;
428
0
      py = NULL;
429
0
    }
430
431
0
  p11_unlock ();
432
433
0
  proxy_free (py, 1);
434
0
  p11_debug ("out: 0");
435
0
  return rv;
436
0
}
437
438
static CK_RV
439
proxy_C_GetInfo (CK_X_FUNCTION_LIST *self,
440
                 CK_INFO_PTR info)
441
0
{
442
0
  State *state = (State *)self;
443
0
  CK_RV rv = CKR_OK;
444
445
0
  p11_library_init_once ();
446
447
0
  return_val_if_fail (info != NULL, CKR_ARGUMENTS_BAD);
448
449
0
  p11_lock ();
450
451
0
    if (!PROXY_VALID (state->px))
452
0
      rv = CKR_CRYPTOKI_NOT_INITIALIZED;
453
454
0
  p11_unlock ();
455
456
0
  if (rv != CKR_OK)
457
0
    return rv;
458
459
0
  memset (info, 0, sizeof (CK_INFO));
460
0
  info->cryptokiVersion.major = self->version.major;
461
0
  info->cryptokiVersion.minor = self->version.minor;
462
0
  info->libraryVersion.major = LIBRARY_VERSION_MAJOR;
463
0
  info->libraryVersion.minor = LIBRARY_VERSION_MINOR;
464
0
  info->flags = 0;
465
0
  memcpy ((char*)info->manufacturerID, MANUFACTURER_ID, 32);
466
0
  memcpy ((char*)info->libraryDescription, LIBRARY_DESCRIPTION, 32);
467
0
  return CKR_OK;
468
0
}
469
470
static CK_RV
471
proxy_C_GetSlotList (CK_X_FUNCTION_LIST *self,
472
                     CK_BBOOL token_present,
473
                     CK_SLOT_ID_PTR slot_list,
474
                     CK_ULONG_PTR count)
475
0
{
476
0
  State *state = (State *)self;
477
0
  CK_SLOT_INFO info;
478
0
  Mapping *mapping;
479
0
  CK_ULONG index;
480
0
  CK_RV rv = CKR_OK;
481
0
  unsigned int i;
482
483
0
  return_val_if_fail (count != NULL, CKR_ARGUMENTS_BAD);
484
485
0
  p11_lock ();
486
487
0
    if (!PROXY_VALID (state->px)) {
488
0
      rv = CKR_CRYPTOKI_NOT_INITIALIZED;
489
0
    }
490
491
0
    if (rv == CKR_OK) {
492
0
      Mapping *mappings = NULL;
493
0
      unsigned int n_mappings = 0;
494
495
0
      if (state->px->n_mappings > 0) {
496
0
        mappings = state->px->mappings;
497
0
        n_mappings = state->px->n_mappings;
498
0
        state->px->mappings = NULL;
499
0
        state->px->n_mappings = 0;
500
0
      }
501
0
      rv = proxy_list_slots (state->px, mappings, n_mappings);
502
0
      if (rv == CKR_OK) {
503
0
        free (mappings);
504
0
      } else {
505
0
        p11_debug ("failed to list slots: %lu", rv);
506
0
        state->px->mappings = mappings;
507
0
        state->px->n_mappings = n_mappings;
508
0
      }
509
0
    }
510
511
0
    if (rv == CKR_OK) {
512
0
      index = 0;
513
514
      /* Go through and build up a map */
515
0
      for (i = 0; i < state->px->n_mappings; ++i) {
516
0
        mapping = &state->px->mappings[i];
517
518
        /* Skip ones without a token if requested */
519
0
        if (token_present) {
520
0
          rv = (mapping->funcs->C_GetSlotInfo) (mapping->real_slot, &info);
521
0
          if (rv != CKR_OK)
522
0
            break;
523
0
          if (!(info.flags & CKF_TOKEN_PRESENT))
524
0
            continue;
525
0
        }
526
527
        /* Fill in the slot if we can */
528
0
        if (slot_list && *count > index)
529
0
          slot_list[index] = mapping->wrap_slot;
530
531
0
        ++index;
532
0
      }
533
534
0
      if (slot_list && *count < index)
535
0
        rv = CKR_BUFFER_TOO_SMALL;
536
537
0
      *count = index;
538
0
    }
539
540
0
  p11_unlock ();
541
542
0
  return rv;
543
0
}
544
545
static CK_RV
546
proxy_C_WaitForSlotEvent (CK_X_FUNCTION_LIST *self,
547
                          CK_FLAGS flags,
548
                          CK_SLOT_ID_PTR slot,
549
                          CK_VOID_PTR reserved)
550
0
{
551
0
  State *state = (State *)self;
552
0
  Proxy *py = state->px;
553
0
  CK_FUNCTION_LIST_PTR *f;
554
0
  CK_FUNCTION_LIST_PTR funcs;
555
0
  CK_SLOT_ID real_slot;
556
0
  unsigned int i;
557
0
  CK_RV rv = CKR_NO_EVENT;
558
559
  /* Only the non-blocking case is supported. */
560
0
  if ((flags & CKF_DONT_BLOCK) == 0)
561
0
    return CKR_FUNCTION_NOT_SUPPORTED;
562
563
0
  p11_lock ();
564
565
0
  for (f = py->inited; *f; ++f) {
566
0
    funcs = *f;
567
0
    assert (funcs != NULL);
568
569
0
    rv = (funcs->C_WaitForSlotEvent) (flags, &real_slot, reserved);
570
0
    if (rv == CKR_NO_EVENT)
571
0
      continue;
572
0
    if (rv != CKR_OK)
573
0
      break;
574
0
    for (i = 0; i < py->n_mappings; i++)
575
0
      if (py->mappings[i].funcs == funcs &&
576
0
          py->mappings[i].real_slot == real_slot) {
577
0
        *slot = py->mappings[i].wrap_slot;
578
0
        break;
579
0
      }
580
0
  }
581
582
0
  p11_unlock ();
583
584
0
  return rv;
585
0
}
586
587
static CK_RV
588
proxy_C_OpenSession (CK_X_FUNCTION_LIST *self,
589
                     CK_SLOT_ID id,
590
                     CK_FLAGS flags,
591
                     CK_VOID_PTR user_data,
592
                     CK_NOTIFY callback,
593
                     CK_SESSION_HANDLE_PTR handle)
594
0
{
595
0
  State *state = (State *)self;
596
0
  Session *sess;
597
0
  Mapping map;
598
0
  CK_RV rv;
599
600
0
  return_val_if_fail (handle != NULL, CKR_ARGUMENTS_BAD);
601
602
0
  rv = map_slot_to_real (state->px, &id, &map);
603
0
  if (rv != CKR_OK)
604
0
    return rv;
605
606
0
  rv = (map.funcs->C_OpenSession) (id, flags, user_data, callback, handle);
607
608
0
  if (rv == CKR_OK) {
609
0
    p11_lock ();
610
611
0
      if (!PROXY_VALID (state->px)) {
612
        /*
613
         * The underlying module should have returned an error, so this
614
         * code should never be reached with properly behaving modules.
615
         * That's why we don't cleanup and close the newly opened session here
616
         * or anything like that.
617
         */
618
0
        rv = CKR_CRYPTOKI_NOT_INITIALIZED;
619
620
0
      } else {
621
0
        sess = calloc (1, sizeof (Session));
622
0
        return_val_if_fail (sess != NULL, CKR_HOST_MEMORY);
623
0
        sess->wrap_slot = map.wrap_slot;
624
0
        sess->real_session = *handle;
625
0
        sess->wrap_session = ++state->last_handle; /* TODO: Handle wrapping, and then collisions */
626
0
        if (!p11_dict_set (state->px->sessions, &sess->wrap_session, sess))
627
0
          warn_if_reached ();
628
0
        *handle = sess->wrap_session;
629
0
      }
630
631
0
    p11_unlock ();
632
0
  }
633
634
0
  return rv;
635
0
}
636
637
static CK_RV
638
proxy_C_CloseSession (CK_X_FUNCTION_LIST *self,
639
                      CK_SESSION_HANDLE handle)
640
0
{
641
0
  State *state = (State *)self;
642
0
  CK_SESSION_HANDLE key;
643
0
  Mapping map;
644
0
  CK_RV rv;
645
646
0
  key = handle;
647
0
  rv = map_session_to_real (state->px, &handle, &map, NULL);
648
0
  if (rv != CKR_OK)
649
0
    return rv;
650
0
  rv = (map.funcs->C_CloseSession) (handle);
651
652
0
  if (rv == CKR_OK) {
653
0
    p11_lock ();
654
655
0
      if (state->px)
656
0
        p11_dict_remove (state->px->sessions, &key);
657
658
0
    p11_unlock ();
659
0
  }
660
661
0
  return rv;
662
0
}
663
664
static CK_RV
665
proxy_C_CloseAllSessions (CK_X_FUNCTION_LIST *self,
666
                          CK_SLOT_ID id)
667
0
{
668
0
  State *state = (State *)self;
669
0
  CK_SESSION_HANDLE_PTR to_close = NULL;
670
0
  CK_RV rv = CKR_OK;
671
0
  Session *sess;
672
0
  CK_ULONG i, count = 0;
673
0
  p11_dictiter iter;
674
675
0
  p11_lock ();
676
677
0
    if (!PROXY_VALID (state->px)) {
678
0
      rv = CKR_CRYPTOKI_NOT_INITIALIZED;
679
0
    } else {
680
0
      assert (state->px->sessions != NULL);
681
0
      to_close = calloc (p11_dict_size (state->px->sessions) + 1, sizeof (CK_SESSION_HANDLE));
682
0
      if (!to_close) {
683
0
        rv = CKR_HOST_MEMORY;
684
0
      } else {
685
0
        p11_dict_iterate (state->px->sessions, &iter);
686
0
        count = 0;
687
0
        while (p11_dict_next (&iter, NULL, (void**)&sess)) {
688
0
          if (sess->wrap_slot == id)
689
0
            to_close[count++] = sess->wrap_session;
690
0
        }
691
0
      }
692
0
    }
693
694
0
  p11_unlock ();
695
696
0
  if (rv != CKR_OK)
697
0
    return rv;
698
699
0
  for (i = 0; i < count; ++i)
700
0
    proxy_C_CloseSession (self, to_close[i]);
701
702
0
  free (to_close);
703
0
  return CKR_OK;
704
0
}
705
706
static CK_RV
707
proxy_C_GetSessionInfo (CK_X_FUNCTION_LIST *self,
708
                        CK_SESSION_HANDLE handle,
709
                        CK_SESSION_INFO_PTR info)
710
0
{
711
0
  State *state = (State *)self;
712
0
  Mapping map;
713
0
  CK_RV rv;
714
715
0
  if (info == NULL)
716
0
    return CKR_ARGUMENTS_BAD;
717
718
0
  rv = map_session_to_real (state->px, &handle, &map, NULL);
719
0
  if (rv != CKR_OK)
720
0
    return rv;
721
722
0
  rv = (map.funcs->C_GetSessionInfo) (handle, info);
723
0
  if (rv == CKR_OK)
724
0
    info->slotID = map.wrap_slot;
725
726
0
  return rv;
727
0
}
728
729
#include "p11-kit/proxy-generated.h"
730
731
static const char p11_interface_name[] = "PKCS 11";
732
733
static const CK_VERSION version_two = {
734
  CRYPTOKI_LEGACY_VERSION_MAJOR,
735
  CRYPTOKI_LEGACY_VERSION_MINOR
736
};
737
738
static const CK_VERSION version_three = {
739
  CRYPTOKI_VERSION_MAJOR,
740
  CRYPTOKI_VERSION_MINOR
741
};
742
743
/* We are not going to support any special interfaces */
744
0
#define NUM_INTERFACES 2
745
746
static CK_RV
747
get_interface_inlock(CK_INTERFACE **interface, const CK_VERSION *version, CK_FLAGS flags)
748
0
{
749
0
  CK_FUNCTION_LIST_PTR module = NULL;
750
0
  CK_FUNCTION_LIST **loaded = NULL;
751
0
  State *state = NULL;
752
0
  CK_RV rv;
753
754
0
  return_val_if_fail (interface, CKR_ARGUMENTS_BAD);
755
0
  return_val_if_fail (version, CKR_ARGUMENTS_BAD);
756
757
0
  if (memcmp (version, &version_three, sizeof(*version)) != 0 &&
758
0
      memcmp (version, &version_two, sizeof(*version)) != 0)
759
0
    return CKR_ARGUMENTS_BAD;
760
761
  /* WARNING: Reentrancy can occur here */
762
0
  rv = p11_modules_load_inlock_reentrant (P11_KIT_MODULE_LOADED_FROM_PROXY, &loaded);
763
0
  if (rv != CKR_OK)
764
0
    goto cleanup;
765
766
0
  state = calloc (1, sizeof (State));
767
0
  if (!state) {
768
0
    rv = CKR_HOST_MEMORY;
769
0
    goto cleanup;
770
0
  }
771
772
0
  p11_virtual_init (&state->virt, &proxy_functions, state, NULL);
773
774
0
  state->last_handle = FIRST_HANDLE;
775
776
0
  state->loaded = loaded;
777
0
  loaded = NULL;
778
779
  /* Version must be set before calling p11_virtual_wrap, as it
780
   * is used to determine which functions are wrapped with
781
   * libffi closure.
782
   */
783
0
  state->virt.funcs.version = *version;
784
785
0
  module = p11_virtual_wrap (&state->virt, free);
786
0
  if (module == NULL) {
787
0
    rv = CKR_GENERAL_ERROR;
788
0
    goto cleanup;
789
0
  }
790
791
0
  module->version = *version;
792
793
0
  state->wrapped.pInterfaceName = (char *)p11_interface_name;
794
795
0
  state->wrapped.pFunctionList = module;
796
0
  module = NULL;
797
798
0
  state->wrapped.flags = flags;
799
800
0
  *interface = &state->wrapped;
801
802
0
  state->next = all_instances;
803
0
  all_instances = state;
804
0
  state = NULL;
805
806
0
 cleanup:
807
0
  if (module)
808
0
    p11_virtual_unwrap (module);
809
0
  if (loaded)
810
0
    p11_kit_modules_release (loaded);
811
0
  if (state) {
812
0
    p11_virtual_unwrap (state->wrapped.pFunctionList);
813
0
    p11_kit_modules_release (state->loaded);
814
0
    free (state);
815
0
  }
816
0
  return rv;
817
0
}
818
819
#ifdef OS_WIN32
820
__declspec(dllexport)
821
#endif
822
CK_RV
823
C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list)
824
0
{
825
0
  CK_RV rv = CKR_OK;
826
0
  CK_INTERFACE *res = NULL;
827
828
0
  p11_library_init_once ();
829
0
  p11_lock ();
830
831
0
  rv = get_interface_inlock (&res, &version_two, 0);
832
0
  if (rv == CKR_OK)
833
0
    *list = res->pFunctionList;
834
835
0
  p11_unlock ();
836
837
0
  return rv;
838
0
}
839
840
#ifdef OS_WIN32
841
__declspec(dllexport)
842
#endif
843
CK_RV
844
C_GetInterfaceList (CK_INTERFACE_PTR pInterfacesList, CK_ULONG_PTR pulCount)
845
0
{
846
0
  CK_RV rv = CKR_OK;
847
0
  CK_INTERFACE *interfaces[NUM_INTERFACES];
848
0
  CK_ULONG count = 0;
849
0
  CK_ULONG i;
850
851
0
  if (pulCount == NULL_PTR)
852
0
    return CKR_ARGUMENTS_BAD;
853
854
0
  if (pInterfacesList == NULL_PTR) {
855
0
    *pulCount = NUM_INTERFACES;
856
0
    return CKR_OK;
857
0
  }
858
859
0
  if (*pulCount < NUM_INTERFACES) {
860
0
    *pulCount = NUM_INTERFACES;
861
0
    return CKR_BUFFER_TOO_SMALL;
862
0
  }
863
864
0
  p11_library_init_once ();
865
0
  p11_lock ();
866
867
0
  rv = get_interface_inlock (&interfaces[count++], &version_three, 0);
868
0
  if (rv != CKR_OK)
869
0
    goto cleanup;
870
871
0
  rv = get_interface_inlock (&interfaces[count++], &version_two, 0);
872
0
  if (rv != CKR_OK)
873
0
    goto cleanup;
874
875
0
  for (i = 0; i < count; i++)
876
0
    pInterfacesList[i] = *interfaces[i];
877
0
  *pulCount = count;
878
879
0
 cleanup:
880
0
  p11_unlock ();
881
882
0
  return rv;
883
0
}
884
885
#ifdef OS_WIN32
886
__declspec(dllexport)
887
#endif
888
CK_RV
889
C_GetInterface (CK_UTF8CHAR_PTR pInterfaceName, CK_VERSION_PTR pVersion,
890
                CK_INTERFACE_PTR_PTR ppInterface, CK_FLAGS flags)
891
0
{
892
0
  int rv;
893
894
0
  if (ppInterface == NULL) {
895
0
    return CKR_ARGUMENTS_BAD;
896
0
  }
897
898
0
  if (pInterfaceName &&
899
0
      strcmp ((const char *)pInterfaceName, p11_interface_name) != 0) {
900
0
    return CKR_ARGUMENTS_BAD;
901
0
  }
902
903
0
  p11_library_init_once ();
904
0
  p11_lock ();
905
906
0
  rv = get_interface_inlock (ppInterface,
907
0
           pVersion ? pVersion : &version_three,
908
0
           flags);
909
910
0
  p11_unlock ();
911
912
0
  return rv;
913
0
}
914
915
void
916
p11_proxy_module_cleanup (void)
917
0
{
918
0
  State *state, *next;
919
920
0
  state = all_instances;
921
0
  all_instances = NULL;
922
923
0
  for (; state != NULL; state = next) {
924
0
    next = state->next;
925
0
    p11_kit_modules_release (state->loaded);
926
0
    p11_virtual_unwrap (state->wrapped.pFunctionList);
927
0
  }
928
0
}
929
930
bool
931
p11_proxy_module_check (CK_FUNCTION_LIST_PTR module)
932
{
933
  State *state;
934
  bool ret = false;
935
936
  if (!p11_virtual_is_wrapper (module))
937
    return false;
938
939
  p11_lock ();
940
  for (state = all_instances; state != NULL; state = state->next)
941
    if (state->wrapped.pFunctionList == module) {
942
      ret = true;
943
      break;
944
    }
945
  p11_unlock ();
946
947
  return ret;
948
}
949
950
CK_RV
951
p11_proxy_module_create (CK_FUNCTION_LIST_PTR *module,
952
       CK_FUNCTION_LIST_PTR *modules)
953
0
{
954
0
  State *state;
955
0
  CK_RV rv = CKR_OK;
956
957
0
  assert (module != NULL);
958
0
  assert (modules != NULL);
959
960
0
  state = calloc (1, sizeof (State));
961
0
  if (!state)
962
0
    return CKR_HOST_MEMORY;
963
964
0
  p11_virtual_init (&state->virt, &proxy_functions, state, NULL);
965
0
  state->last_handle = FIRST_HANDLE;
966
0
  state->loaded = modules_dup (modules);
967
0
  state->wrapped.pFunctionList = p11_virtual_wrap (&state->virt, (p11_destroyer)p11_virtual_uninit);
968
0
  if (state->wrapped.pFunctionList == NULL) {
969
0
    p11_kit_modules_release (state->loaded);
970
0
    free (state);
971
0
    return CKR_GENERAL_ERROR;
972
0
  }
973
974
0
  *module = state->wrapped.pFunctionList;
975
976
0
  return rv;
977
0
}