Line data Source code
1 : /*
2 : * gnome-keyring
3 : *
4 : * Copyright (C) 2008 Stefan Walter
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this program; if not, see
18 : * <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "config.h"
22 :
23 : #include "pkcs11/pkcs11.h"
24 : #include "pkcs11/pkcs11i.h"
25 :
26 : #include "gkm-aes-key.h"
27 : #include "gkm-aes-mechanism.h"
28 : #include "gkm-attributes.h"
29 : #include "gkm-certificate.h"
30 : #include "gkm-credential.h"
31 : #include "gkm-factory.h"
32 : #include "gkm-generic-key.h"
33 : #include "gkm-manager.h"
34 : #include "gkm-memory-store.h"
35 : #include "gkm-module.h"
36 : #include "gkm-null-key.h"
37 : #include "gkm-null-mechanism.h"
38 : #include "gkm-dh-private-key.h"
39 : #include "gkm-private-xsa-key.h"
40 : #include "gkm-dh-public-key.h"
41 : #include "gkm-public-xsa-key.h"
42 : #include "gkm-session.h"
43 : #include "gkm-store.h"
44 : #include "gkm-timer.h"
45 : #include "gkm-transaction.h"
46 : #include "gkm-util.h"
47 :
48 : enum {
49 : PROP_0,
50 : PROP_MANAGER,
51 : PROP_WRITE_PROTECTED,
52 : PROP_INITIALIZE_ARGS,
53 : PROP_MUTEX
54 : };
55 :
56 : #define APARTMENT_APP(apt) \
57 : ((apt) & ~CK_GNOME_MAX_SLOT)
58 : #define APARTMENT_SLOT(apt) \
59 : ((apt) & CK_GNOME_MAX_SLOT)
60 : #define APARTMENT_ID(slot, app) \
61 : (((slot) & CK_GNOME_MAX_SLOT) | ((app) & ~CK_GNOME_MAX_SLOT))
62 :
63 : struct _GkmModulePrivate {
64 : GMutex *mutex; /* The mutex controlling entry to this module */
65 :
66 : GkmManager *token_manager;
67 : GHashTable *apartments_by_id; /* Apartment (slot + application) by their id */
68 : GHashTable *sessions_by_handle; /* Mapping of handle to all open sessions */
69 : gulong handle_counter; /* Constantly incrementing counter for handles and the like */
70 : GArray *factories; /* Various registered object factories */
71 : gboolean factories_sorted; /* Whether we need to sort the object factories */
72 :
73 : GHashTable *transient_objects; /* Token objects that are not stored permanently. */
74 : GkmStore *transient_store; /* Store for trantsient objects. */
75 : };
76 :
77 : typedef struct _Apartment {
78 : CK_ULONG apt_id;
79 : CK_SLOT_ID slot_id;
80 : CK_G_APPLICATION_ID app_id;
81 : CK_G_APPLICATION_PTR app_ptr;
82 : GkmManager *session_manager;
83 : GList *sessions;
84 : CK_USER_TYPE logged_in;
85 : } Apartment;
86 :
87 24688 : G_DEFINE_TYPE_WITH_PRIVATE (GkmModule, gkm_module, G_TYPE_OBJECT);
88 :
89 : /* These info blocks are used unless derived class overrides */
90 :
91 : static const CK_INFO default_module_info = {
92 : { CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR },
93 : "Gnome Keyring",
94 : CKF_G_APPLICATIONS,
95 : "Gnome Keyring Module",
96 : { 1, 1 },
97 : };
98 :
99 : static const CK_SLOT_INFO default_slot_info = {
100 : "Unnamed Slot",
101 : "Gnome Keyring",
102 : CKF_TOKEN_PRESENT,
103 : { 0, 0 },
104 : { 0, 0 }
105 : };
106 :
107 : static const CK_TOKEN_INFO default_token_info = {
108 : "Unnamed Token",
109 : "Gnome Keyring",
110 : "1.0",
111 : "1",
112 : CKF_TOKEN_INITIALIZED | CKF_WRITE_PROTECTED,
113 : CK_EFFECTIVELY_INFINITE,
114 : CK_EFFECTIVELY_INFINITE,
115 : CK_EFFECTIVELY_INFINITE,
116 : CK_EFFECTIVELY_INFINITE,
117 : 1024,
118 : 1,
119 : CK_UNAVAILABLE_INFORMATION,
120 : CK_UNAVAILABLE_INFORMATION,
121 : CK_UNAVAILABLE_INFORMATION,
122 : CK_UNAVAILABLE_INFORMATION,
123 : { 0, 0 },
124 : { 0, 0 },
125 : ""
126 : };
127 :
128 : typedef struct _MechanismAndInfo {
129 : CK_MECHANISM_TYPE mechanism;
130 : CK_MECHANISM_INFO info;
131 : } MechanismAndInfo;
132 :
133 : static const MechanismAndInfo mechanism_list[] = {
134 : /*
135 : * CKM_RSA_PKCS
136 : * For RSA, min and max are the minimum and maximum modulus in bits
137 : */
138 : { CKM_RSA_PKCS, { 256, 32768, CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY } },
139 :
140 : /*
141 : * CKM_RSA_X509
142 : * For RSA, min and max are the minimum and maximum modulus in bits
143 : */
144 : { CKM_RSA_X_509, { 256, 32768, CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY } },
145 :
146 : /*
147 : * CKM_DSA
148 : * For DSA, min and max are the minimum and maximum modulus in bits
149 : */
150 : { CKM_DSA, { 512, 1024, CKF_SIGN | CKF_VERIFY } },
151 :
152 : /*
153 : * CKM_DH_PKCS_KEY_PAIR_GEN
154 : * For DH derivation the min and max are sizes of prime in bits.
155 : */
156 : { CKM_DH_PKCS_KEY_PAIR_GEN, { 768, 8192, CKF_GENERATE_KEY_PAIR } },
157 :
158 : /*
159 : * CKM_DH_PKCS_DERIVE
160 : * For DH derivation the min and max are sizes of output key in bytes.
161 : */
162 : { CKM_DH_PKCS_DERIVE, { 1, 255, CKF_DERIVE } },
163 :
164 : /*
165 : * CKM_ECDSA
166 : * For ECDSA, min and max are the minimum and maximum modulus in bits
167 : */
168 : { CKM_ECDSA, { 256, 521, CKF_SIGN | CKF_VERIFY } },
169 :
170 : /*
171 : * CKM_G_HKDF_DERIVE
172 : * For HKDF derivation the min and max are sizes of prime in bits.
173 : */
174 : { CKM_G_HKDF_SHA256_DERIVE, { 768, 8192, CKF_DERIVE } },
175 :
176 : /*
177 : * CKM_AES_CBC_PAD
178 : * For AES the min and max are sizes of key in bytes.
179 : */
180 : { CKM_AES_CBC_PAD, { GKM_AES_MECHANISM_MIN_LENGTH, GKM_AES_MECHANISM_MAX_LENGTH, CKF_WRAP | CKF_UNWRAP } },
181 :
182 : /*
183 : * CKM_G_NULL
184 : * For NULL min and max are zero
185 : */
186 : { CKM_G_NULL, { GKM_NULL_MECHANISM_MIN_LENGTH, GKM_NULL_MECHANISM_MAX_LENGTH, CKF_WRAP | CKF_UNWRAP } },
187 : };
188 :
189 : /* Hidden function that you should not use */
190 : GMutex* _gkm_module_get_scary_mutex_that_you_should_not_touch (GkmModule *self);
191 :
192 : static void remove_transient_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object);
193 :
194 : static void add_transient_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object);
195 :
196 : /* -----------------------------------------------------------------------------
197 : * INTERNAL
198 : */
199 :
200 : static gint
201 1215 : sort_factory_by_n_attrs (gconstpointer a, gconstpointer b)
202 : {
203 1215 : const GkmFactory *fa = a;
204 1215 : const GkmFactory *fb = b;
205 :
206 1215 : g_assert (a);
207 1215 : g_assert (b);
208 :
209 : /* Note we're sorting in reverse order */
210 1215 : if (fa->n_attrs < fb->n_attrs)
211 403 : return 1;
212 812 : return (fa->n_attrs == fb->n_attrs) ? 0 : -1;
213 : }
214 :
215 : static void
216 966 : extend_space_string (CK_UTF8CHAR_PTR string, gsize length)
217 : {
218 : CK_UTF8CHAR_PTR at;
219 :
220 : /* Find a null pointer in the string */
221 966 : at = memchr (string, 0, length);
222 966 : g_assert (at != NULL && at < string + length);
223 25532 : for (; at < string + length; ++at)
224 24566 : *at = ' ';
225 966 : }
226 :
227 : static void
228 208 : apartment_free (gpointer data)
229 : {
230 : Apartment *apt;
231 : GList *l;
232 :
233 208 : g_assert (data != NULL);
234 208 : apt = (Apartment*)data;
235 :
236 208 : g_return_if_fail (GKM_IS_MANAGER (apt->session_manager));
237 :
238 : /* Unreference all the sessions */
239 362 : for (l = apt->sessions; l; l = g_list_next (l)) {
240 :
241 : /* Some sanity checks to make sure things have remained as expected */
242 154 : g_return_if_fail (GKM_IS_SESSION (l->data));
243 154 : g_return_if_fail (gkm_session_get_apartment (l->data) == apt->apt_id);
244 154 : g_return_if_fail (gkm_session_get_manager (l->data) == apt->session_manager);
245 154 : g_return_if_fail (gkm_session_get_logged_in (l->data) == apt->logged_in);
246 :
247 154 : g_object_unref (l->data);
248 : }
249 :
250 208 : g_list_free (apt->sessions);
251 208 : g_object_unref (apt->session_manager);
252 :
253 208 : g_slice_free (Apartment, apt);
254 : }
255 :
256 : static Apartment*
257 208 : apartment_new (GkmModuleClass *klass, CK_SLOT_ID slot_id, CK_G_APPLICATION_PTR app)
258 : {
259 : Apartment *apt;
260 :
261 208 : apt = g_slice_new0 (Apartment);
262 208 : apt->session_manager = g_object_new (GKM_TYPE_MANAGER, "for-token", FALSE, NULL);
263 208 : apt->logged_in = CKU_NONE;
264 208 : apt->sessions = NULL;
265 208 : apt->slot_id = slot_id;
266 :
267 208 : if (app) {
268 17 : if (!app->applicationId)
269 17 : app->applicationId = gkm_util_next_handle () << 8;
270 17 : apt->app_id = app->applicationId;
271 17 : apt->app_ptr = app;
272 : } else {
273 191 : apt->app_id = 0;
274 191 : apt->app_ptr = NULL;
275 : }
276 :
277 208 : apt->apt_id = APARTMENT_ID (apt->slot_id, apt->app_id);
278 :
279 208 : return apt;
280 : }
281 :
282 : static Apartment*
283 686 : lookup_apartment (GkmModule *self, CK_ULONG apartment)
284 : {
285 686 : g_assert (GKM_IS_MODULE (self));
286 686 : return g_hash_table_lookup (self->pv->apartments_by_id, &apartment);
287 : }
288 :
289 : static void
290 208 : register_apartment (GkmModule *self, Apartment *apt)
291 : {
292 208 : g_assert (apt);
293 208 : g_assert (GKM_IS_MODULE (self));
294 208 : g_assert (!g_hash_table_lookup (self->pv->apartments_by_id, &(apt->apt_id)));
295 :
296 208 : g_hash_table_insert (self->pv->apartments_by_id,
297 208 : gkm_util_ulong_alloc (apt->apt_id), apt);
298 208 : }
299 :
300 : static void
301 54 : unregister_apartment (GkmModule *self, Apartment *apt)
302 : {
303 54 : g_assert (apt);
304 54 : g_assert (GKM_IS_MODULE (self));
305 :
306 54 : switch (apt->logged_in) {
307 0 : case CKU_NONE:
308 0 : break;
309 50 : case CKU_USER:
310 50 : gkm_module_logout_user (self, apt->apt_id);
311 50 : break;
312 4 : case CKU_SO:
313 4 : gkm_module_logout_so (self, apt->apt_id);
314 4 : break;
315 0 : default:
316 0 : g_return_if_reached ();
317 : break;
318 : }
319 :
320 54 : if (!g_hash_table_remove (self->pv->apartments_by_id, &(apt->apt_id)))
321 0 : g_assert_not_reached ();
322 : }
323 :
324 : static void
325 237 : mark_login_apartment (GkmModule *self, Apartment *apt, CK_USER_TYPE user)
326 : {
327 : GList *l;
328 :
329 237 : g_assert (apt);
330 237 : g_assert (GKM_IS_MODULE (self));
331 :
332 : /* Mark all sessions in the partition as logged in */
333 420 : for (l = apt->sessions; l; l = g_list_next (l))
334 183 : gkm_session_set_logged_in (l->data, user);
335 237 : apt->logged_in = user;
336 237 : }
337 :
338 : static void
339 223 : parse_argument (GkmModule *self, char *arg)
340 : {
341 : gchar *value;
342 :
343 223 : g_assert (GKM_IS_MODULE (self));
344 :
345 223 : value = arg + strcspn (arg, ":=");
346 223 : if (!*value)
347 0 : value = NULL;
348 : else
349 223 : *(value++) = 0;
350 :
351 223 : g_strstrip (arg);
352 223 : if (value)
353 223 : g_strstrip (value);
354 :
355 223 : g_return_if_fail (GKM_MODULE_GET_CLASS (self)->parse_argument);
356 223 : GKM_MODULE_GET_CLASS (self)->parse_argument (self, arg, value);
357 : }
358 :
359 : static void
360 223 : parse_arguments (GkmModule *self, const gchar *string)
361 : {
362 223 : gchar quote = '\0';
363 : gchar *src, *dup, *at, *arg;
364 :
365 223 : g_assert (GKM_IS_MODULE (self));
366 :
367 223 : if (!string)
368 0 : return;
369 :
370 223 : src = dup = g_strdup (string);
371 :
372 223 : arg = at = src;
373 10963 : for (src = dup; *src; src++) {
374 :
375 : /* Matching quote */
376 10740 : if (quote == *src) {
377 223 : quote = '\0';
378 :
379 : /* Inside of quotes */
380 10517 : } else if (quote != '\0') {
381 8064 : if (*src == '\\') {
382 0 : *at++ = *src++;
383 0 : if (!*src) {
384 0 : g_warning ("couldn't parse module argument string");
385 0 : goto done;
386 : }
387 0 : if (*src != quote)
388 0 : *at++ = '\\';
389 : }
390 8064 : *at++ = *src;
391 :
392 : /* Space, not inside of quotes */
393 2453 : } else if (g_ascii_isspace(*src)) {
394 0 : *at = 0;
395 0 : parse_argument (self, arg);
396 0 : arg = at;
397 :
398 : /* Other character outside of quotes */
399 : } else {
400 2453 : switch (*src) {
401 223 : case '\'':
402 : case '"':
403 223 : quote = *src;
404 223 : break;
405 0 : case '\\':
406 0 : *at++ = *src++;
407 0 : if (!*src) {
408 0 : g_warning ("couldn't parse module argument string");
409 0 : goto done;
410 : }
411 : /* fall through */
412 : default:
413 2230 : *at++ = *src;
414 2230 : break;
415 : }
416 : }
417 : }
418 :
419 :
420 223 : if (at != arg) {
421 223 : *at = 0;
422 223 : parse_argument (self, arg);
423 : }
424 :
425 0 : done:
426 223 : g_free (dup);
427 : }
428 :
429 :
430 : static gboolean
431 22 : complete_transient_remove (GkmTransaction *transaction, GkmModule *self, GkmObject *object)
432 : {
433 22 : if (gkm_transaction_get_failed (transaction))
434 0 : add_transient_object (self, NULL, object);
435 22 : g_object_unref (object);
436 22 : return TRUE;
437 : }
438 :
439 : static void
440 23 : remove_transient_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
441 : {
442 23 : g_assert (GKM_IS_MODULE (self));
443 23 : g_assert (GKM_IS_OBJECT (object));
444 :
445 23 : g_object_ref (object);
446 :
447 23 : gkm_object_expose (object, FALSE);
448 23 : if (!g_hash_table_remove (self->pv->transient_objects, object))
449 0 : g_return_if_reached ();
450 23 : g_object_set (object, "store", NULL, NULL);
451 :
452 23 : if (transaction) {
453 22 : gkm_transaction_add (transaction, self,
454 : (GkmTransactionFunc)complete_transient_remove,
455 : g_object_ref (object));
456 : }
457 :
458 23 : g_object_unref (object);
459 : }
460 :
461 : static gboolean
462 23 : complete_transient_add (GkmTransaction *transaction, GkmModule *self, GkmObject *object)
463 : {
464 23 : if (gkm_transaction_get_failed (transaction))
465 1 : remove_transient_object (self, NULL, object);
466 23 : g_object_unref (object);
467 23 : return TRUE;
468 : }
469 :
470 : static void
471 132 : add_transient_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
472 : {
473 132 : g_assert (GKM_IS_MODULE (self));
474 132 : g_assert (GKM_IS_OBJECT (object));
475 :
476 : /* Must not already be associated with a session or manager */
477 132 : g_return_if_fail (gkm_object_get_manager (object) == self->pv->token_manager);
478 132 : g_return_if_fail (g_hash_table_lookup (self->pv->transient_objects, object) == NULL);
479 :
480 132 : g_hash_table_insert (self->pv->transient_objects, object, g_object_ref (object));
481 132 : g_object_set (object, "store", self->pv->transient_store, NULL);
482 132 : gkm_object_expose (object, TRUE);
483 :
484 132 : if (transaction) {
485 23 : gkm_transaction_add (transaction, self,
486 : (GkmTransactionFunc)complete_transient_add,
487 : g_object_ref (object));
488 : }
489 : }
490 :
491 : /* -----------------------------------------------------------------------------
492 : * OBJECT
493 : */
494 :
495 : static const CK_SLOT_INFO*
496 0 : gkm_module_real_get_slot_info (GkmModule *self)
497 : {
498 0 : return &default_slot_info;
499 : }
500 :
501 : static const CK_TOKEN_INFO*
502 0 : gkm_module_real_get_token_info (GkmModule *self)
503 : {
504 0 : return &default_token_info;
505 : }
506 :
507 : static void
508 0 : gkm_module_real_parse_argument (GkmModule *self, const gchar *name, const gchar *value)
509 : {
510 : /* Derived classes should do something interesting */
511 0 : }
512 :
513 : static CK_RV
514 2 : gkm_module_real_refresh_token (GkmModule *self)
515 : {
516 : /* Derived classes should do something interesting */
517 2 : return CKR_OK;
518 : }
519 :
520 : static void
521 0 : gkm_module_real_add_token_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
522 : {
523 : /* Derived class should override, default does nothing */
524 0 : }
525 :
526 : static void
527 0 : gkm_module_real_store_token_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
528 : {
529 : /* Derived classes should do something interesting */
530 0 : gkm_transaction_fail (transaction, CKR_FUNCTION_NOT_SUPPORTED);
531 0 : }
532 :
533 : static void
534 0 : gkm_module_real_remove_token_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
535 : {
536 : /* Derived classes should do something interesting */
537 0 : gkm_transaction_fail (transaction, CKR_FUNCTION_NOT_SUPPORTED);
538 0 : }
539 :
540 : static CK_RV
541 2 : gkm_module_real_login_change (GkmModule *self, CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR old_pin,
542 : CK_ULONG n_old_pin, CK_UTF8CHAR_PTR new_pin, CK_ULONG n_new_pin)
543 : {
544 2 : return CKR_FUNCTION_NOT_SUPPORTED;
545 : }
546 :
547 : static CK_RV
548 179 : gkm_module_real_login_user (GkmModule *self, CK_ULONG apartment, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
549 : {
550 : Apartment *apt;
551 :
552 179 : apt = lookup_apartment (self, apartment);
553 179 : g_return_val_if_fail (apt, CKR_GENERAL_ERROR);
554 :
555 179 : mark_login_apartment (self, apt, CKU_USER);
556 179 : return CKR_OK;
557 : }
558 :
559 : static CK_RV
560 4 : gkm_module_real_login_so (GkmModule *self, CK_ULONG apartment, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
561 : {
562 : Apartment *apt;
563 :
564 4 : apt = lookup_apartment (self, apartment);
565 4 : g_return_val_if_fail (apt, CKR_GENERAL_ERROR);
566 :
567 4 : mark_login_apartment (self, apt, CKU_SO);
568 4 : return CKR_OK;
569 : }
570 :
571 : static CK_RV
572 54 : gkm_module_real_logout_any (GkmModule *self, CK_ULONG apartment)
573 : {
574 : Apartment *apt;
575 :
576 : /* Calculate the partition identifier */
577 54 : apt = lookup_apartment (self, apartment);
578 54 : g_return_val_if_fail (apt, CKR_GENERAL_ERROR);
579 :
580 54 : mark_login_apartment (self, apt, CKU_NONE);
581 54 : return CKR_OK;
582 : }
583 :
584 : static GObject*
585 287 : gkm_module_constructor (GType type, guint n_props, GObjectConstructParam *props)
586 : {
587 287 : GkmModule *self = GKM_MODULE (G_OBJECT_CLASS (gkm_module_parent_class)->constructor(type, n_props, props));
588 : CK_ATTRIBUTE attr;
589 :
590 287 : g_return_val_if_fail (self, NULL);
591 :
592 : /* Register store attributes */
593 287 : attr.type = CKA_LABEL;
594 287 : attr.pValue = "";
595 287 : attr.ulValueLen = 0;
596 287 : gkm_store_register_schema (self->pv->transient_store, &attr, NULL, 0);
597 :
598 287 : return G_OBJECT (self);
599 : }
600 :
601 : static void
602 287 : gkm_module_init (GkmModule *self)
603 : {
604 287 : gkm_timer_initialize ();
605 :
606 287 : self->pv = gkm_module_get_instance_private (self);
607 287 : self->pv->token_manager = g_object_new (GKM_TYPE_MANAGER, "for-token", TRUE, NULL);
608 287 : self->pv->sessions_by_handle = g_hash_table_new_full (gkm_util_ulong_hash, gkm_util_ulong_equal,
609 : gkm_util_ulong_free, g_object_unref);
610 287 : self->pv->apartments_by_id = g_hash_table_new_full (gkm_util_ulong_hash, gkm_util_ulong_equal,
611 : gkm_util_ulong_free, apartment_free);
612 287 : self->pv->factories = g_array_new (FALSE, TRUE, sizeof (GkmFactory));
613 :
614 287 : self->pv->handle_counter = 1;
615 :
616 : /* Create the store for transient objects */
617 287 : self->pv->transient_store = GKM_STORE (gkm_memory_store_new ());
618 287 : self->pv->transient_objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, gkm_util_dispose_unref);
619 :
620 : /* Register session object factories */
621 287 : gkm_module_register_factory (self, GKM_FACTORY_AES_KEY);
622 287 : gkm_module_register_factory (self, GKM_FACTORY_CERTIFICATE);
623 287 : gkm_module_register_factory (self, GKM_FACTORY_CREDENTIAL);
624 287 : gkm_module_register_factory (self, GKM_FACTORY_GENERIC_KEY);
625 287 : gkm_module_register_factory (self, GKM_FACTORY_NULL_KEY);
626 287 : gkm_module_register_factory (self, GKM_FACTORY_DH_PRIVATE_KEY);
627 287 : gkm_module_register_factory (self, GKM_FACTORY_PRIVATE_XSA_KEY);
628 287 : gkm_module_register_factory (self, GKM_FACTORY_DH_PUBLIC_KEY);
629 287 : gkm_module_register_factory (self, GKM_FACTORY_PUBLIC_XSA_KEY);
630 287 : }
631 :
632 : static void
633 574 : gkm_module_dispose (GObject *obj)
634 : {
635 574 : GkmModule *self = GKM_MODULE (obj);
636 :
637 574 : g_hash_table_remove_all (self->pv->transient_objects);
638 574 : g_hash_table_remove_all (self->pv->sessions_by_handle);
639 574 : g_hash_table_remove_all (self->pv->apartments_by_id);
640 :
641 574 : if (self->pv->token_manager)
642 287 : g_object_unref (self->pv->token_manager);
643 574 : self->pv->token_manager = NULL;
644 :
645 574 : g_array_set_size (self->pv->factories, 0);
646 :
647 574 : G_OBJECT_CLASS (gkm_module_parent_class)->dispose (obj);
648 574 : }
649 :
650 : static void
651 287 : gkm_module_finalize (GObject *obj)
652 : {
653 287 : GkmModule *self = GKM_MODULE (obj);
654 :
655 287 : g_hash_table_destroy (self->pv->transient_objects);
656 287 : self->pv->transient_objects = NULL;
657 :
658 287 : g_object_unref (self->pv->transient_store);
659 287 : self->pv->transient_store = NULL;
660 :
661 287 : g_assert (self->pv->token_manager == NULL);
662 :
663 287 : g_assert (g_hash_table_size (self->pv->apartments_by_id) == 0);
664 287 : g_hash_table_destroy (self->pv->apartments_by_id);
665 287 : self->pv->apartments_by_id = NULL;
666 :
667 287 : g_assert (g_hash_table_size (self->pv->sessions_by_handle) == 0);
668 287 : g_hash_table_destroy (self->pv->sessions_by_handle);
669 287 : self->pv->sessions_by_handle = NULL;
670 :
671 287 : g_array_free (self->pv->factories, TRUE);
672 287 : self->pv->factories = NULL;
673 :
674 287 : gkm_timer_shutdown ();
675 :
676 287 : G_OBJECT_CLASS (gkm_module_parent_class)->finalize (obj);
677 287 : }
678 :
679 : static void
680 574 : gkm_module_set_property (GObject *obj, guint prop_id, const GValue *value,
681 : GParamSpec *pspec)
682 : {
683 574 : GkmModule *self = GKM_MODULE (obj);
684 : CK_C_INITIALIZE_ARGS_PTR args;
685 :
686 574 : switch (prop_id) {
687 287 : case PROP_INITIALIZE_ARGS:
688 287 : args = g_value_get_pointer (value);
689 287 : if (args != NULL && args->pReserved != NULL)
690 223 : parse_arguments (self, args->pReserved);
691 287 : break;
692 287 : case PROP_MUTEX:
693 287 : self->pv->mutex = g_value_get_pointer (value);
694 287 : g_return_if_fail (self->pv->mutex);
695 287 : break;
696 0 : default:
697 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
698 0 : break;
699 : }
700 : }
701 :
702 : static void
703 0 : gkm_module_get_property (GObject *obj, guint prop_id, GValue *value,
704 : GParamSpec *pspec)
705 : {
706 0 : GkmModule *self = GKM_MODULE (obj);
707 :
708 0 : switch (prop_id) {
709 0 : case PROP_MANAGER:
710 0 : g_value_set_object (value, gkm_module_get_manager (self));
711 0 : break;
712 0 : case PROP_WRITE_PROTECTED:
713 0 : g_value_set_boolean (value, gkm_module_get_write_protected (self));
714 0 : break;
715 0 : default:
716 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
717 0 : break;
718 : }
719 0 : }
720 :
721 : static void
722 47 : gkm_module_class_init (GkmModuleClass *klass)
723 : {
724 47 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
725 :
726 47 : gobject_class->constructor = gkm_module_constructor;
727 47 : gobject_class->dispose = gkm_module_dispose;
728 47 : gobject_class->finalize = gkm_module_finalize;
729 47 : gobject_class->set_property = gkm_module_set_property;
730 47 : gobject_class->get_property = gkm_module_get_property;
731 :
732 47 : klass->get_slot_info = gkm_module_real_get_slot_info;
733 47 : klass->get_token_info = gkm_module_real_get_token_info;
734 47 : klass->parse_argument = gkm_module_real_parse_argument;
735 47 : klass->refresh_token = gkm_module_real_refresh_token;
736 47 : klass->add_token_object = gkm_module_real_add_token_object;
737 47 : klass->store_token_object = gkm_module_real_store_token_object;
738 47 : klass->remove_token_object = gkm_module_real_remove_token_object;
739 47 : klass->login_change = gkm_module_real_login_change;
740 47 : klass->login_user = gkm_module_real_login_user;
741 47 : klass->logout_user = gkm_module_real_logout_any;
742 47 : klass->login_so = gkm_module_real_login_so;
743 47 : klass->logout_so = gkm_module_real_logout_any;
744 :
745 47 : g_object_class_install_property (gobject_class, PROP_MANAGER,
746 : g_param_spec_object ("manager", "Manager", "Token object manager",
747 : GKM_TYPE_MANAGER, G_PARAM_READABLE));
748 :
749 47 : g_object_class_install_property (gobject_class, PROP_WRITE_PROTECTED,
750 : g_param_spec_boolean ("write-protected", "Write Protected", "Token is write protected",
751 : TRUE, G_PARAM_READABLE));
752 :
753 47 : g_object_class_install_property (gobject_class, PROP_INITIALIZE_ARGS,
754 : g_param_spec_pointer ("initialize-args", "Initialize Args", "Arguments passed to C_Initialize",
755 : G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
756 :
757 47 : g_object_class_install_property (gobject_class, PROP_MUTEX,
758 : g_param_spec_pointer ("mutex", "Mutex", "Module mutex",
759 : G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
760 47 : }
761 :
762 : /* -----------------------------------------------------------------------------
763 : * PUBLIC
764 : */
765 :
766 : GkmManager*
767 3390 : gkm_module_get_manager (GkmModule *self)
768 : {
769 3390 : g_return_val_if_fail (GKM_IS_MODULE (self), NULL);
770 3390 : g_return_val_if_fail (GKM_IS_MANAGER (self->pv->token_manager), NULL);
771 3390 : return self->pv->token_manager;
772 : }
773 :
774 : gboolean
775 31 : gkm_module_get_write_protected (GkmModule *self)
776 : {
777 : const CK_TOKEN_INFO* info;
778 :
779 31 : g_return_val_if_fail (GKM_IS_MODULE (self), TRUE);
780 31 : g_return_val_if_fail (GKM_MODULE_GET_CLASS (self)->get_token_info, TRUE);
781 :
782 31 : info = (GKM_MODULE_GET_CLASS (self)->get_token_info) (self);
783 31 : g_return_val_if_fail (info, TRUE);
784 :
785 31 : return info->flags & CKF_WRITE_PROTECTED;
786 : }
787 :
788 : GkmSession*
789 1690 : gkm_module_lookup_session (GkmModule *self, CK_SESSION_HANDLE handle)
790 : {
791 : GkmSession *session;
792 :
793 1690 : g_return_val_if_fail (GKM_IS_MODULE (self), NULL);
794 :
795 1690 : session = g_hash_table_lookup (self->pv->sessions_by_handle, &handle);
796 1690 : if (!session)
797 0 : return NULL;
798 :
799 1690 : g_return_val_if_fail (GKM_IS_SESSION (session), NULL);
800 1690 : return session;
801 : }
802 :
803 : CK_RV
804 5 : gkm_module_login_change (GkmModule *self, CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR old_pin,
805 : CK_ULONG n_old_pin, CK_UTF8CHAR_PTR new_pin, CK_ULONG n_new_pin)
806 : {
807 5 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_GENERAL_ERROR);
808 5 : g_assert (GKM_MODULE_GET_CLASS (self)->login_change);
809 5 : return GKM_MODULE_GET_CLASS (self)->login_change (self, slot_id, old_pin, n_old_pin, new_pin, n_new_pin);
810 : }
811 :
812 : CK_RV
813 179 : gkm_module_login_user (GkmModule *self, CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
814 : {
815 179 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_GENERAL_ERROR);
816 179 : g_assert (GKM_MODULE_GET_CLASS (self)->login_user);
817 179 : return GKM_MODULE_GET_CLASS (self)->login_user (self, slot_id, pin, n_pin);
818 : }
819 :
820 : CK_RV
821 50 : gkm_module_logout_user (GkmModule *self, CK_SLOT_ID slot_id)
822 : {
823 50 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_GENERAL_ERROR);
824 50 : g_assert (GKM_MODULE_GET_CLASS (self)->logout_user);
825 50 : return GKM_MODULE_GET_CLASS (self)->logout_user (self, slot_id);
826 : }
827 :
828 : CK_RV
829 4 : gkm_module_login_so (GkmModule *self, CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
830 : {
831 4 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_GENERAL_ERROR);
832 4 : g_assert (GKM_MODULE_GET_CLASS (self)->login_so);
833 4 : return GKM_MODULE_GET_CLASS (self)->login_so (self, slot_id, pin, n_pin);
834 : }
835 :
836 : CK_RV
837 4 : gkm_module_logout_so (GkmModule *self, CK_SLOT_ID slot_id)
838 : {
839 4 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_GENERAL_ERROR);
840 4 : g_assert (GKM_MODULE_GET_CLASS (self)->logout_so);
841 4 : return GKM_MODULE_GET_CLASS (self)->logout_so (self, slot_id);
842 : }
843 :
844 : CK_ULONG
845 215 : gkm_module_next_handle (GkmModule *self)
846 : {
847 215 : g_return_val_if_fail (GKM_IS_MODULE (self), 0);
848 215 : if (self->pv->handle_counter == CK_GNOME_MAX_HANDLE) {
849 0 : g_warning ("handle counter wrapped");
850 0 : self->pv->handle_counter = 0;
851 : }
852 215 : return (self->pv->handle_counter)++;
853 : }
854 :
855 : CK_RV
856 244 : gkm_module_refresh_token (GkmModule *self)
857 : {
858 244 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_GENERAL_ERROR);
859 244 : g_assert (GKM_MODULE_GET_CLASS (self)->refresh_token);
860 244 : return GKM_MODULE_GET_CLASS (self)->refresh_token (self);
861 : }
862 :
863 : void
864 153 : gkm_module_add_token_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
865 : {
866 153 : g_return_if_fail (GKM_IS_MODULE (self));
867 153 : g_return_if_fail (GKM_IS_OBJECT (object));
868 153 : g_assert (GKM_MODULE_GET_CLASS (self)->add_token_object);
869 :
870 153 : if (gkm_object_is_transient (object)) {
871 132 : if (g_hash_table_lookup (self->pv->transient_objects, object) == NULL)
872 132 : add_transient_object (self, transaction, object);
873 : } else {
874 21 : GKM_MODULE_GET_CLASS (self)->add_token_object (self, transaction, object);
875 : }
876 : }
877 :
878 : void
879 58 : gkm_module_store_token_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
880 : {
881 58 : g_return_if_fail (GKM_IS_MODULE (self));
882 58 : g_return_if_fail (GKM_IS_OBJECT (object));
883 58 : g_assert (GKM_MODULE_GET_CLASS (self)->store_token_object);
884 :
885 58 : if (!gkm_object_is_transient (object))
886 36 : GKM_MODULE_GET_CLASS (self)->store_token_object (self, transaction, object);
887 : }
888 :
889 : void
890 28 : gkm_module_remove_token_object (GkmModule *self, GkmTransaction *transaction, GkmObject *object)
891 : {
892 28 : g_return_if_fail (GKM_IS_MODULE (self));
893 28 : g_return_if_fail (GKM_IS_OBJECT (object));
894 28 : g_assert (GKM_MODULE_GET_CLASS (self)->remove_token_object);
895 :
896 28 : if (gkm_object_is_transient (object))
897 22 : remove_transient_object (self, transaction, object);
898 : else
899 6 : GKM_MODULE_GET_CLASS (self)->remove_token_object (self, transaction, object);
900 : }
901 :
902 : void
903 3096 : gkm_module_register_factory (GkmModule *self, GkmFactory *factory)
904 : {
905 3096 : g_return_if_fail (GKM_IS_MODULE (self));
906 3096 : g_return_if_fail (factory);
907 3096 : g_return_if_fail (factory->attrs || !factory->n_attrs);
908 3096 : g_return_if_fail (factory->func);
909 :
910 3096 : g_array_append_val (self->pv->factories, *factory);
911 3096 : self->pv->factories_sorted = FALSE;
912 : }
913 :
914 : GkmFactory*
915 115 : gkm_module_find_factory (GkmModule *self, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
916 : {
917 : GkmFactory *factory;
918 : gboolean matched;
919 : gulong j;
920 : gsize i;
921 :
922 115 : g_return_val_if_fail (GKM_IS_MODULE (self), NULL);
923 115 : g_return_val_if_fail (attrs || !n_attrs, NULL);
924 :
925 115 : if (!self->pv->factories_sorted) {
926 53 : g_array_sort (self->pv->factories, sort_factory_by_n_attrs);
927 53 : self->pv->factories_sorted = TRUE;
928 : }
929 :
930 936 : for (i = 0; i < self->pv->factories->len; ++i) {
931 936 : factory = &(g_array_index (self->pv->factories, GkmFactory, i));
932 :
933 936 : matched = TRUE;
934 1138 : for (j = 0; j < factory->n_attrs; ++j) {
935 1023 : if (!gkm_attributes_contains (attrs, n_attrs, &factory->attrs[j])) {
936 821 : matched = FALSE;
937 821 : break;
938 : }
939 : }
940 :
941 936 : if (matched)
942 115 : return factory;
943 : }
944 :
945 0 : return NULL;
946 : }
947 :
948 : /*
949 : * Hidden method to get the mutex for a module. This is for timers to be
950 : * able to reenter the module. Don't use this method.
951 : */
952 :
953 : GMutex*
954 136 : _gkm_module_get_scary_mutex_that_you_should_not_touch (GkmModule *self)
955 : {
956 136 : g_return_val_if_fail (GKM_IS_MODULE (self), NULL);
957 136 : return self->pv->mutex;
958 : }
959 :
960 : /* -----------------------------------------------------------------------------
961 : * PKCS#11
962 : */
963 :
964 : CK_RV
965 2 : gkm_module_C_GetInfo (GkmModule *self, CK_INFO_PTR info)
966 : {
967 : GkmModuleClass *klass;
968 :
969 2 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
970 :
971 2 : if (!info)
972 0 : return CKR_ARGUMENTS_BAD;
973 :
974 2 : klass = GKM_MODULE_GET_CLASS (self);
975 2 : g_return_val_if_fail (klass, CKR_GENERAL_ERROR);
976 :
977 2 : memcpy (info, &default_module_info, sizeof (CK_INFO));
978 :
979 : /* Extend all the strings appropriately */
980 2 : extend_space_string (info->libraryDescription, sizeof (info->libraryDescription));
981 2 : extend_space_string (info->manufacturerID, sizeof (info->manufacturerID));
982 :
983 2 : return CKR_OK;
984 : }
985 :
986 : CK_RV
987 218 : gkm_module_C_GetSlotList (GkmModule *self, CK_BBOOL token_present, CK_SLOT_ID_PTR slot_list, CK_ULONG_PTR count)
988 : {
989 218 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
990 :
991 218 : if (!count)
992 0 : return CKR_ARGUMENTS_BAD;
993 :
994 : /* Just want to get the count */
995 218 : if (slot_list == NULL) {
996 109 : *count = 1;
997 109 : return CKR_OK;
998 : }
999 :
1000 : /* Buffer too small? */
1001 109 : if (*count == 0) {
1002 0 : *count = 1;
1003 0 : return CKR_BUFFER_TOO_SMALL;
1004 : }
1005 :
1006 109 : g_return_val_if_fail (slot_list, CKR_ARGUMENTS_BAD);
1007 :
1008 : /* Answer C_GetSlotList with 0 for app */
1009 109 : slot_list[0] = GKM_SLOT_ID;
1010 109 : *count = 1;
1011 109 : return CKR_OK;
1012 : }
1013 :
1014 : CK_RV
1015 265 : gkm_module_C_GetSlotInfo (GkmModule *self, CK_SLOT_ID id, CK_SLOT_INFO_PTR info)
1016 : {
1017 : const CK_SLOT_INFO *original;
1018 : GkmModuleClass *klass;
1019 :
1020 265 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
1021 :
1022 265 : if (id != GKM_SLOT_ID)
1023 0 : return CKR_SLOT_ID_INVALID;
1024 265 : if (info == NULL)
1025 0 : return CKR_ARGUMENTS_BAD;
1026 :
1027 : /* Any slot ID is valid for partitioned module */
1028 :
1029 265 : klass = GKM_MODULE_GET_CLASS (self);
1030 265 : g_return_val_if_fail (klass, CKR_GENERAL_ERROR);
1031 265 : g_return_val_if_fail (klass->get_slot_info, CKR_GENERAL_ERROR);
1032 :
1033 265 : original = (klass->get_slot_info) (self);
1034 265 : g_return_val_if_fail (original, CKR_GENERAL_ERROR);
1035 :
1036 265 : memcpy (info, original, sizeof (CK_SLOT_INFO));
1037 :
1038 : /* Extend all the strings appropriately */
1039 265 : extend_space_string (info->manufacturerID, sizeof (info->manufacturerID));
1040 265 : extend_space_string (info->slotDescription, sizeof (info->slotDescription));
1041 :
1042 265 : return CKR_OK;
1043 : }
1044 :
1045 : CK_RV
1046 108 : gkm_module_C_GetTokenInfo (GkmModule *self, CK_SLOT_ID id, CK_TOKEN_INFO_PTR info)
1047 : {
1048 : const CK_TOKEN_INFO *original;
1049 : GkmModuleClass *klass;
1050 :
1051 108 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
1052 :
1053 108 : if (id != GKM_SLOT_ID)
1054 0 : return CKR_SLOT_ID_INVALID;
1055 108 : if (info == NULL)
1056 0 : return CKR_ARGUMENTS_BAD;
1057 :
1058 : /* Any slot ID is valid for partitioned module */
1059 :
1060 108 : klass = GKM_MODULE_GET_CLASS (self);
1061 108 : g_return_val_if_fail (klass, CKR_GENERAL_ERROR);
1062 108 : g_return_val_if_fail (klass->get_token_info, CKR_GENERAL_ERROR);
1063 :
1064 108 : original = (klass->get_token_info) (self);
1065 108 : g_return_val_if_fail (original, CKR_GENERAL_ERROR);
1066 :
1067 108 : memcpy (info, original, sizeof (CK_TOKEN_INFO));
1068 :
1069 : /* Extend all the strings appropriately */
1070 108 : extend_space_string (info->label, sizeof (info->label));
1071 108 : extend_space_string (info->manufacturerID, sizeof (info->manufacturerID));
1072 108 : extend_space_string (info->model, sizeof (info->model));
1073 108 : extend_space_string (info->serialNumber, sizeof (info->serialNumber));
1074 :
1075 108 : return CKR_OK;
1076 : }
1077 :
1078 : CK_RV
1079 0 : gkm_module_C_GetMechanismList (GkmModule *self, CK_SLOT_ID id,
1080 : CK_MECHANISM_TYPE_PTR mech_list, CK_ULONG_PTR count)
1081 : {
1082 0 : const guint n_mechanisms = G_N_ELEMENTS (mechanism_list);
1083 : guint i;
1084 :
1085 0 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
1086 :
1087 0 : if (id != GKM_SLOT_ID)
1088 0 : return CKR_SLOT_ID_INVALID;
1089 0 : if (count == NULL)
1090 0 : return CKR_ARGUMENTS_BAD;
1091 :
1092 : /* Just want to get the count */
1093 0 : if (mech_list == NULL) {
1094 0 : *count = n_mechanisms;
1095 0 : return CKR_OK;
1096 : }
1097 :
1098 : /* Buffer too small? */
1099 0 : if (*count < n_mechanisms) {
1100 0 : *count = n_mechanisms;
1101 0 : return CKR_BUFFER_TOO_SMALL;
1102 : }
1103 :
1104 0 : *count = n_mechanisms;
1105 0 : for (i = 0; i < n_mechanisms; ++i)
1106 0 : mech_list[i] = mechanism_list[i].mechanism;
1107 :
1108 0 : return CKR_OK;
1109 : }
1110 :
1111 : CK_RV
1112 0 : gkm_module_C_GetMechanismInfo (GkmModule *self, CK_SLOT_ID id,
1113 : CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR info)
1114 : {
1115 0 : const guint n_mechanisms = G_N_ELEMENTS (mechanism_list);
1116 : guint index;
1117 :
1118 0 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
1119 :
1120 0 : if (id != GKM_SLOT_ID)
1121 0 : return CKR_SLOT_ID_INVALID;
1122 0 : if (info == NULL)
1123 0 : return CKR_ARGUMENTS_BAD;
1124 :
1125 0 : for (index = 0; index < n_mechanisms; ++index) {
1126 0 : if (mechanism_list[index].mechanism == type)
1127 0 : break;
1128 : }
1129 :
1130 0 : if (index == n_mechanisms)
1131 0 : return CKR_MECHANISM_INVALID;
1132 :
1133 0 : memcpy (info, &mechanism_list[index].info, sizeof (CK_MECHANISM_INFO));
1134 0 : return CKR_OK;
1135 : }
1136 :
1137 : CK_RV
1138 0 : gkm_module_C_InitToken (GkmModule *self, CK_SLOT_ID id, CK_UTF8CHAR_PTR pin,
1139 : CK_ULONG pin_len, CK_UTF8CHAR_PTR label)
1140 : {
1141 0 : return CKR_FUNCTION_NOT_SUPPORTED;
1142 : }
1143 :
1144 : CK_RV
1145 215 : gkm_module_C_OpenSession (GkmModule *self, CK_SLOT_ID id, CK_FLAGS flags, CK_VOID_PTR user_data,
1146 : CK_NOTIFY callback, CK_SESSION_HANDLE_PTR result)
1147 : {
1148 : CK_G_APPLICATION_PTR app;
1149 : CK_SESSION_HANDLE handle;
1150 : GkmSession *session;
1151 215 : Apartment *apt = NULL;
1152 :
1153 215 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
1154 :
1155 215 : if (APARTMENT_SLOT (id) != GKM_SLOT_ID)
1156 0 : return CKR_SLOT_ID_INVALID;
1157 215 : if (!result)
1158 0 : return CKR_ARGUMENTS_BAD;
1159 :
1160 215 : if (!(flags & CKF_SERIAL_SESSION))
1161 0 : return CKR_SESSION_PARALLEL_NOT_SUPPORTED;
1162 :
1163 : /*
1164 : * If they're calling us with the 'application' extension, then
1165 : * allocate or use our application identifier.
1166 : */
1167 215 : if (flags & CKF_G_APPLICATION_SESSION) {
1168 17 : app = user_data;
1169 17 : if (app == NULL)
1170 0 : return CKR_ARGUMENTS_BAD;
1171 17 : if (app->applicationId)
1172 0 : apt = lookup_apartment (self, APARTMENT_ID (id, app->applicationId));
1173 : } else {
1174 198 : app = NULL;
1175 198 : apt = lookup_apartment (self, APARTMENT_ID (id, 0));
1176 : }
1177 :
1178 : /* The first time this application is accessing, or closed all sessions, allocate new */
1179 215 : if (apt == NULL) {
1180 208 : apt = apartment_new (GKM_MODULE_GET_CLASS (self), id, app);
1181 208 : register_apartment (self, apt);
1182 : }
1183 :
1184 : /* Can't open read only session if SO login */
1185 215 : if (apt->logged_in == CKU_SO && !(flags & CKF_RW_SESSION))
1186 0 : return CKR_SESSION_READ_WRITE_SO_EXISTS;
1187 :
1188 : /* Make and register a new session */
1189 215 : handle = gkm_module_next_handle (self);
1190 215 : session = g_object_new (GKM_TYPE_SESSION, "slot-id", apt->slot_id, "apartment", apt->apt_id,
1191 : "flags", flags, "handle", handle, "module", self,
1192 : "manager", apt->session_manager, "logged-in", apt->logged_in, NULL);
1193 215 : apt->sessions = g_list_prepend (apt->sessions, session);
1194 :
1195 : /* Track the session by handle */
1196 430 : g_hash_table_insert (self->pv->sessions_by_handle,
1197 215 : gkm_util_ulong_alloc (handle),
1198 : g_object_ref (session));
1199 :
1200 215 : *result = handle;
1201 215 : return CKR_OK;
1202 : }
1203 :
1204 : CK_RV
1205 61 : gkm_module_C_CloseSession (GkmModule *self, CK_SESSION_HANDLE handle)
1206 : {
1207 : GkmSession *session;
1208 : CK_ULONG apt_id;
1209 : Apartment *apt;
1210 : GList *link;
1211 :
1212 61 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
1213 :
1214 61 : session = gkm_module_lookup_session (self, handle);
1215 61 : if (session == NULL)
1216 0 : return CKR_SESSION_HANDLE_INVALID;
1217 :
1218 : /* Calculate the virtual slot */
1219 61 : apt_id = gkm_session_get_apartment (session);
1220 61 : apt = lookup_apartment (self, apt_id);
1221 61 : g_return_val_if_fail (apt, CKR_GENERAL_ERROR);
1222 :
1223 61 : link = g_list_find (apt->sessions, session);
1224 61 : g_return_val_if_fail (link, CKR_GENERAL_ERROR);
1225 61 : apt->sessions = g_list_delete_link (apt->sessions, link);
1226 61 : g_object_unref (session);
1227 61 : if (!apt->sessions)
1228 54 : unregister_apartment (self, apt);
1229 :
1230 61 : if (!g_hash_table_remove (self->pv->sessions_by_handle, &handle))
1231 0 : g_assert_not_reached ();
1232 :
1233 61 : return CKR_OK;
1234 : }
1235 :
1236 : CK_RV
1237 0 : gkm_module_C_CloseAllSessions (GkmModule *self, CK_SLOT_ID id)
1238 : {
1239 : Apartment *apt;
1240 : CK_SESSION_HANDLE handle;
1241 : GList *l;
1242 :
1243 0 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
1244 :
1245 0 : if (APARTMENT_SLOT (id) != GKM_SLOT_ID)
1246 0 : return CKR_SLOT_ID_INVALID;
1247 :
1248 0 : apt = lookup_apartment (self, id);
1249 0 : if (apt == NULL)
1250 0 : return CKR_OK;
1251 :
1252 : /* Unregister all its sessions */
1253 0 : for (l = apt->sessions; l; l = g_list_next (l)) {
1254 0 : handle = gkm_session_get_handle (l->data);
1255 0 : if (!g_hash_table_remove (self->pv->sessions_by_handle, &handle))
1256 0 : g_assert_not_reached ();
1257 : }
1258 :
1259 0 : unregister_apartment (self, apt);
1260 0 : return CKR_OK;
1261 : }
1262 :
1263 : CK_RV
1264 4 : gkm_module_C_InitPIN (GkmModule* self, CK_SESSION_HANDLE handle,
1265 : CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
1266 : {
1267 : GkmSession *session;
1268 : Apartment *apt;
1269 : CK_ULONG apt_id;
1270 :
1271 4 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
1272 :
1273 4 : session = gkm_module_lookup_session (self, handle);
1274 4 : if (session == NULL)
1275 0 : return CKR_SESSION_HANDLE_INVALID;
1276 :
1277 : /* Calculate the virtual slot */
1278 4 : apt_id = gkm_session_get_apartment (session);
1279 4 : apt = lookup_apartment (self, apt_id);
1280 4 : g_return_val_if_fail (apt, CKR_GENERAL_ERROR);
1281 :
1282 4 : if (apt->logged_in != CKU_SO)
1283 0 : return CKR_USER_NOT_LOGGED_IN;
1284 :
1285 : /* Our InitPIN assumes an uninitialized PIN */
1286 4 : return gkm_module_login_change (self, apt_id, NULL, 0, pin, n_pin);
1287 : }
1288 :
1289 : CK_RV
1290 1 : gkm_module_C_SetPIN (GkmModule* self, CK_SESSION_HANDLE handle, CK_UTF8CHAR_PTR old_pin,
1291 : CK_ULONG old_pin_len, CK_UTF8CHAR_PTR new_pin, CK_ULONG new_pin_len)
1292 : {
1293 : GkmSession *session;
1294 : Apartment *apt;
1295 : CK_ULONG apt_id;
1296 :
1297 1 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
1298 :
1299 1 : session = gkm_module_lookup_session (self, handle);
1300 1 : if (session == NULL)
1301 0 : return CKR_SESSION_HANDLE_INVALID;
1302 :
1303 : /* Calculate the virtual slot */
1304 1 : apt_id = gkm_session_get_apartment (session);
1305 1 : apt = lookup_apartment (self, apt_id);
1306 1 : g_return_val_if_fail (apt, CKR_GENERAL_ERROR);
1307 :
1308 1 : return gkm_module_login_change (self, apt_id, old_pin, old_pin_len, new_pin, new_pin_len);
1309 : }
1310 :
1311 : CK_RV
1312 185 : gkm_module_C_Login (GkmModule *self, CK_SESSION_HANDLE handle, CK_USER_TYPE user_type,
1313 : CK_UTF8CHAR_PTR pin, CK_ULONG pin_len)
1314 : {
1315 : CK_ULONG apt_id;
1316 : GkmSession *session;
1317 : Apartment *apt;
1318 : GList *l;
1319 :
1320 185 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
1321 :
1322 185 : session = gkm_module_lookup_session (self, handle);
1323 185 : if (session == NULL)
1324 0 : return CKR_SESSION_HANDLE_INVALID;
1325 :
1326 : /* Pass off context specifc logins to appropriate place */
1327 185 : if (user_type == CKU_CONTEXT_SPECIFIC)
1328 0 : return gkm_session_login_context_specific (session, pin, pin_len);
1329 :
1330 : /* Some random crap... */
1331 185 : if (user_type != CKU_USER && user_type != CKU_SO)
1332 0 : return CKR_USER_TYPE_INVALID;
1333 :
1334 : /* Calculate the virtual slot */
1335 185 : apt_id = gkm_session_get_apartment (session);
1336 185 : apt = lookup_apartment (self, apt_id);
1337 185 : g_return_val_if_fail (apt, CKR_GENERAL_ERROR);
1338 :
1339 185 : if (apt->logged_in == user_type)
1340 2 : return CKR_USER_ALREADY_LOGGED_IN;
1341 183 : if (apt->logged_in != CKU_NONE)
1342 0 : return CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
1343 :
1344 183 : if (user_type == CKU_SO) {
1345 :
1346 : /* Can't login as SO if read-only sessions exist */
1347 8 : for (l = apt->sessions; l; l = g_list_next (l)) {
1348 4 : if (gkm_session_is_read_only (l->data))
1349 0 : return CKR_SESSION_READ_ONLY_EXISTS;
1350 : }
1351 :
1352 4 : return gkm_module_login_so (self, apt_id, pin, pin_len);
1353 :
1354 179 : } else if (user_type == CKU_USER) {
1355 179 : return gkm_module_login_user (self, apt_id, pin, pin_len);
1356 :
1357 : } else {
1358 0 : return CKR_USER_TYPE_INVALID;
1359 : }
1360 : }
1361 :
1362 : CK_RV
1363 0 : gkm_module_C_Logout (GkmModule *self, CK_SESSION_HANDLE handle)
1364 : {
1365 : CK_ULONG apt_id;
1366 : Apartment *apt;
1367 : GkmSession *session;
1368 :
1369 0 : g_return_val_if_fail (GKM_IS_MODULE (self), CKR_CRYPTOKI_NOT_INITIALIZED);
1370 :
1371 0 : session = gkm_module_lookup_session (self, handle);
1372 0 : if (session == NULL)
1373 0 : return CKR_SESSION_HANDLE_INVALID;
1374 :
1375 0 : apt_id = gkm_session_get_apartment (session);
1376 0 : apt = lookup_apartment (self, apt_id);
1377 0 : g_return_val_if_fail (apt, CKR_GENERAL_ERROR);
1378 :
1379 0 : if (apt->logged_in == CKU_NONE)
1380 0 : return CKR_USER_NOT_LOGGED_IN;
1381 :
1382 0 : else if (apt->logged_in == CKU_USER)
1383 0 : return gkm_module_logout_user (self, apt_id);
1384 :
1385 0 : else if (apt->logged_in == CKU_SO)
1386 0 : return gkm_module_logout_so (self, apt_id);
1387 :
1388 : else
1389 0 : g_return_val_if_reached (CKR_GENERAL_ERROR);
1390 : }
|