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-attributes.h"
27 : #include "gkm-credential.h"
28 : #define DEBUG_FLAG GKM_DEBUG_OBJECT
29 : #include "gkm-debug.h"
30 : #include "gkm-manager.h"
31 : #include "gkm-object.h"
32 : #include "gkm-transaction.h"
33 : #include "gkm-session.h"
34 : #include "gkm-store.h"
35 : #include "gkm-timer.h"
36 : #include "gkm-util.h"
37 :
38 : enum {
39 : PROP_0,
40 : PROP_HANDLE,
41 : PROP_MODULE,
42 : PROP_MANAGER,
43 : PROP_STORE,
44 : PROP_UNIQUE,
45 : PROP_TRANSIENT
46 : };
47 :
48 : enum {
49 : EXPOSE_OBJECT,
50 : NOTIFY_ATTRIBUTE,
51 : LAST_SIGNAL
52 : };
53 :
54 : static guint signals[LAST_SIGNAL] = { 0 };
55 :
56 : typedef struct _GkmObjectTransient {
57 : GkmTimer *timer;
58 : gulong timed_after;
59 : gulong timed_idle;
60 : glong stamp_used;
61 : glong stamp_created;
62 : gulong uses_remaining;
63 : } GkmObjectTransient;
64 :
65 : struct _GkmObjectPrivate {
66 : CK_OBJECT_HANDLE handle;
67 : GkmModule *module;
68 : GkmManager *manager;
69 : GkmStore *store;
70 : gchar *unique;
71 : gboolean exposed;
72 : GkmObjectTransient *transient;
73 : };
74 :
75 155097 : G_DEFINE_TYPE_WITH_PRIVATE (GkmObject, gkm_object, G_TYPE_OBJECT);
76 :
77 : /* Private friend functions from the manager */
78 : void _gkm_manager_register_object (GkmManager *self, GkmObject *object);
79 : void _gkm_manager_unregister_object (GkmManager *self, GkmObject *object);
80 :
81 : /* -----------------------------------------------------------------------------
82 : * INTERNAL
83 : */
84 :
85 : static void
86 1 : self_destruct (GkmObject *self)
87 : {
88 : GkmTransaction *transaction;
89 : CK_RV rv;
90 :
91 1 : transaction = gkm_transaction_new ();
92 :
93 1 : gkm_object_destroy (self, transaction);
94 :
95 1 : gkm_transaction_complete (transaction);
96 1 : rv = gkm_transaction_get_result (transaction);
97 1 : g_object_unref (transaction);
98 1 : if (rv != CKR_OK)
99 0 : g_warning ("Unexpected failure to auto destruct object (code: %lu)", (gulong)rv);
100 1 : }
101 :
102 : static void
103 2 : timer_callback (GkmTimer *timer, gpointer user_data)
104 : {
105 2 : GkmObject *self = user_data;
106 : glong after, idle, offset;
107 : GkmObjectTransient *transient;
108 : gint64 now;
109 :
110 2 : g_return_if_fail (GKM_IS_OBJECT (self));
111 :
112 2 : g_object_ref (self);
113 :
114 2 : g_return_if_fail (self->pv->transient);
115 2 : transient = self->pv->transient;
116 2 : g_return_if_fail (timer == transient->timer);
117 2 : transient->timer = NULL;
118 :
119 2 : now = g_get_real_time () / G_USEC_PER_SEC;
120 2 : idle = after = G_MAXLONG;
121 :
122 : /* Are we supposed to be destroyed after a certain time? */
123 2 : if (transient->timed_after) {
124 2 : g_return_if_fail (transient->stamp_created);
125 2 : after = (transient->stamp_created + transient->timed_after) - now;
126 : }
127 :
128 : /* Are we supposed to be destroyed after an idle time? */
129 2 : if (transient->timed_idle) {
130 0 : g_return_if_fail (transient->stamp_used);
131 0 : idle = (transient->stamp_used + transient->timed_idle) - now;
132 : }
133 :
134 : /* Okay, time to destroy? */
135 2 : offset = MIN (after, idle);
136 2 : if (offset <= 0)
137 1 : self_destruct (self);
138 :
139 : /* Setup the next timer */
140 : else
141 1 : transient->timer = gkm_timer_start (self->pv->module, offset, timer_callback, self);
142 :
143 2 : g_object_unref (self);
144 : }
145 :
146 : static gboolean
147 1 : start_callback (GkmTransaction *transaction, GObject *obj, gpointer user_data)
148 : {
149 1 : GkmObject *self = GKM_OBJECT (obj);
150 : GkmObjectTransient *transient;
151 : gint64 now;
152 :
153 1 : g_return_val_if_fail (GKM_IS_OBJECT (self), FALSE);
154 1 : g_return_val_if_fail (self->pv->transient, FALSE);
155 1 : transient = self->pv->transient;
156 1 : g_return_val_if_fail (!transient->timer, FALSE);
157 :
158 1 : now = g_get_real_time () / G_USEC_PER_SEC;
159 1 : transient->stamp_created = now;
160 1 : transient->stamp_used = now;
161 :
162 : /* Start the timer going */
163 1 : timer_callback (NULL, self);
164 1 : return TRUE;
165 : }
166 :
167 : static void
168 0 : module_went_away (gpointer data, GObject *old_module)
169 : {
170 0 : GkmObject *self = GKM_OBJECT (data);
171 0 : g_return_if_fail (self->pv->module);
172 0 : g_warning ("module destroyed before %s that module contained",
173 : G_OBJECT_TYPE_NAME (self));
174 0 : self->pv->module = NULL;
175 : }
176 :
177 : static gboolean
178 37 : complete_destroy (GkmTransaction *transaction, GObject *unused, gpointer user_data)
179 : {
180 37 : gkm_util_dispose_unref (user_data);
181 37 : return TRUE;
182 : }
183 :
184 : static gboolean
185 161 : complete_expose (GkmTransaction *transaction, GObject *obj, gpointer user_data)
186 : {
187 161 : GkmObject *self = GKM_OBJECT (obj);
188 161 : gboolean expose = GPOINTER_TO_UINT (user_data);
189 :
190 161 : if (gkm_transaction_get_failed (transaction))
191 1 : gkm_object_expose (self, !expose);
192 :
193 161 : return TRUE;
194 : }
195 :
196 : static gboolean
197 0 : find_credential (GkmCredential *cred, GkmObject *object, gpointer user_data)
198 : {
199 0 : CK_OBJECT_HANDLE *result = user_data;
200 0 : g_return_val_if_fail (!*result, FALSE);
201 0 : *result = gkm_object_get_handle (GKM_OBJECT (cred));
202 0 : return TRUE;
203 : }
204 :
205 : static void
206 133 : mark_object_transient (GkmObject *self)
207 : {
208 133 : if (!self->pv->transient)
209 133 : self->pv->transient = g_slice_new0 (GkmObjectTransient);
210 133 : }
211 :
212 : /* -----------------------------------------------------------------------------
213 : * OBJECT
214 : */
215 :
216 : static CK_RV
217 394 : gkm_object_real_get_attribute (GkmObject *self, GkmSession *session, CK_ATTRIBUTE* attr)
218 : {
219 394 : CK_OBJECT_HANDLE handle = 0;
220 : CK_RV rv;
221 :
222 394 : switch (attr->type)
223 : {
224 0 : case CKA_CLASS:
225 0 : g_warning ("Derived class should have overridden CKA_CLASS");
226 0 : return CKR_GENERAL_ERROR;
227 0 : case CKA_MODIFIABLE:
228 0 : return gkm_attribute_set_bool (attr, self->pv->store ? TRUE : FALSE);
229 0 : case CKA_PRIVATE:
230 0 : return gkm_attribute_set_bool (attr, FALSE);
231 39 : case CKA_TOKEN:
232 39 : return gkm_attribute_set_bool (attr, gkm_object_is_token (self));
233 0 : case CKA_G_CREDENTIAL:
234 0 : gkm_credential_for_each (session, GKM_OBJECT (self), find_credential, &handle);
235 0 : return gkm_attribute_set_ulong (attr, handle);
236 8 : case CKA_GNOME_UNIQUE:
237 8 : if (self->pv->unique)
238 0 : return gkm_attribute_set_string (attr, self->pv->unique);
239 8 : gkm_debug ("CKR_ATTRIBUTE_TYPE_INVALID: no CKA_GNOME_UNIQUE on object");
240 8 : return CKR_ATTRIBUTE_TYPE_INVALID;
241 4 : case CKA_GNOME_TRANSIENT:
242 4 : return gkm_attribute_set_bool (attr, self->pv->transient ? TRUE : FALSE);
243 1 : case CKA_G_DESTRUCT_AFTER:
244 2 : return gkm_attribute_set_ulong (attr, self->pv->transient ?
245 1 : self->pv->transient->timed_after : 0);
246 0 : case CKA_G_DESTRUCT_IDLE:
247 0 : return gkm_attribute_set_ulong (attr, self->pv->transient ?
248 0 : self->pv->transient->timed_idle : 0);
249 0 : case CKA_G_DESTRUCT_USES:
250 0 : return gkm_attribute_set_ulong (attr, self->pv->transient ?
251 0 : self->pv->transient->uses_remaining : 0);
252 : };
253 :
254 : /* Give store a shot */
255 342 : if (self->pv->store) {
256 133 : rv = gkm_store_get_attribute (self->pv->store, self, attr);
257 133 : if (rv != CKR_ATTRIBUTE_TYPE_INVALID)
258 1 : return rv;
259 : }
260 :
261 : /* Now some more defaults */
262 341 : switch (attr->type) {
263 0 : case CKA_LABEL:
264 0 : return gkm_attribute_set_data (attr, "", 0);
265 : }
266 :
267 341 : gkm_debug ("CKR_ATTRIBUTE_TYPE_INVALID: no %s attribute", gkm_log_attr_type (attr->type));
268 341 : return CKR_ATTRIBUTE_TYPE_INVALID;
269 : }
270 :
271 : static void
272 3 : gkm_object_real_set_attribute (GkmObject *self, GkmSession *session,
273 : GkmTransaction* transaction, CK_ATTRIBUTE* attr)
274 : {
275 : CK_ATTRIBUTE check;
276 : CK_RV rv;
277 :
278 3 : switch (attr->type) {
279 0 : case CKA_TOKEN:
280 : case CKA_PRIVATE:
281 : case CKA_MODIFIABLE:
282 : case CKA_CLASS:
283 0 : gkm_transaction_fail (transaction, CKR_ATTRIBUTE_READ_ONLY);
284 3 : return;
285 0 : case CKA_GNOME_UNIQUE:
286 0 : gkm_transaction_fail (transaction, self->pv->unique ?
287 : CKR_ATTRIBUTE_READ_ONLY :
288 : CKR_ATTRIBUTE_TYPE_INVALID);
289 0 : return;
290 : };
291 :
292 : /* Give store a shot */
293 3 : if (self->pv->store) {
294 3 : gkm_store_set_attribute (self->pv->store, transaction, self, attr);
295 3 : return;
296 : }
297 :
298 : /* Now some more defaults */
299 0 : switch (attr->type) {
300 0 : case CKA_LABEL:
301 0 : gkm_transaction_fail (transaction, CKR_ATTRIBUTE_READ_ONLY);
302 0 : return;
303 : }
304 :
305 : /* Check if this attribute exists */
306 0 : check.type = attr->type;
307 0 : check.pValue = 0;
308 0 : check.ulValueLen = 0;
309 0 : rv = gkm_object_get_attribute (self, session, &check);
310 0 : if (rv == CKR_ATTRIBUTE_TYPE_INVALID)
311 0 : gkm_transaction_fail (transaction, CKR_ATTRIBUTE_TYPE_INVALID);
312 : else
313 0 : gkm_transaction_fail (transaction, CKR_ATTRIBUTE_READ_ONLY);
314 : }
315 :
316 : static void
317 175 : gkm_object_real_create_attributes (GkmObject *self, GkmSession *session,
318 : GkmTransaction *transaction, CK_ATTRIBUTE *attrs, CK_ULONG n_attrs)
319 : {
320 : CK_ATTRIBUTE_PTR transient_attr;
321 175 : gboolean transient = FALSE;
322 175 : gulong after = 0;
323 175 : gulong idle = 0;
324 : CK_RV rv;
325 :
326 : /* Parse the transient attribute */
327 175 : transient_attr = gkm_attributes_find (attrs, n_attrs, CKA_GNOME_TRANSIENT);
328 175 : if (transient_attr) {
329 25 : rv = gkm_attribute_get_bool (transient_attr, &transient);
330 25 : if (rv != CKR_OK) {
331 1 : gkm_transaction_fail (transaction, rv);
332 2 : return;
333 : }
334 : }
335 :
336 : /* Parse the auto destruct attribute */
337 174 : if (!gkm_attributes_find_ulong (attrs, n_attrs, CKA_G_DESTRUCT_AFTER, &after))
338 172 : after = 0;
339 174 : if (!gkm_attributes_find_ulong (attrs, n_attrs, CKA_G_DESTRUCT_IDLE, &idle))
340 174 : idle = 0;
341 : /* Default for the transient attribute */
342 174 : if (!transient_attr && (idle || after))
343 1 : transient = TRUE;
344 :
345 : /* Used up these attributes */
346 174 : gkm_attributes_consume (attrs, n_attrs, CKA_G_DESTRUCT_AFTER,
347 : CKA_G_DESTRUCT_IDLE, CKA_GNOME_TRANSIENT, G_MAXULONG);
348 :
349 174 : if (transient) {
350 24 : mark_object_transient (self);
351 24 : self->pv->transient->timed_after = after;
352 24 : self->pv->transient->timed_idle = idle;
353 : }
354 :
355 174 : if (after || idle) {
356 2 : if (!self->pv->transient) {
357 1 : gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
358 1 : return;
359 : }
360 :
361 1 : gkm_transaction_add (transaction, self, start_callback, NULL);
362 : }
363 : }
364 :
365 : static CK_RV
366 0 : gkm_object_real_unlock (GkmObject *self, GkmCredential *cred)
367 : {
368 : /* A derived class should have overridden this */
369 0 : return CKR_FUNCTION_FAILED;
370 : }
371 :
372 : static void
373 5340 : gkm_object_real_expose_object (GkmObject *self, gboolean expose)
374 : {
375 5340 : g_return_if_fail (expose != self->pv->exposed);
376 5340 : g_return_if_fail (self->pv->manager);
377 :
378 5340 : self->pv->exposed = expose;
379 5340 : if (expose)
380 2670 : _gkm_manager_register_object (self->pv->manager, self);
381 : else
382 2670 : _gkm_manager_unregister_object (self->pv->manager, self);
383 : }
384 :
385 : static GObject*
386 2907 : gkm_object_constructor (GType type, guint n_props, GObjectConstructParam *props)
387 : {
388 2907 : GkmObject *self = GKM_OBJECT (G_OBJECT_CLASS (gkm_object_parent_class)->constructor(type, n_props, props));
389 :
390 2907 : g_return_val_if_fail (self, NULL);
391 2907 : g_return_val_if_fail (GKM_IS_MODULE (self->pv->module), NULL);
392 :
393 2907 : return G_OBJECT (self);
394 : }
395 :
396 : static void
397 2907 : gkm_object_init (GkmObject *self)
398 : {
399 2907 : self->pv = gkm_object_get_instance_private (self);
400 :
401 2907 : }
402 :
403 : static void
404 3316 : gkm_object_dispose (GObject *obj)
405 : {
406 3316 : GkmObject *self = GKM_OBJECT (obj);
407 : GkmObjectTransient *transient;
408 :
409 3316 : if (self->pv->manager) {
410 2757 : if (self->pv->exposed)
411 2569 : gkm_object_expose (self, FALSE);
412 2757 : g_return_if_fail (!self->pv->exposed);
413 2757 : g_object_remove_weak_pointer (G_OBJECT (self->pv->manager),
414 2757 : (gpointer*)&(self->pv->manager));
415 2757 : self->pv->manager = NULL;
416 : }
417 :
418 3316 : g_object_set (self, "store", NULL, NULL);
419 3316 : g_assert (self->pv->store == NULL);
420 :
421 3316 : if (self->pv->transient) {
422 283 : transient = self->pv->transient;
423 283 : if (transient->timer)
424 0 : gkm_timer_cancel (transient->timer);
425 283 : transient->timer = NULL;
426 : }
427 :
428 3316 : G_OBJECT_CLASS (gkm_object_parent_class)->dispose (obj);
429 : }
430 :
431 : static void
432 2907 : gkm_object_finalize (GObject *obj)
433 : {
434 2907 : GkmObject *self = GKM_OBJECT (obj);
435 :
436 2907 : g_assert (self->pv->manager == NULL);
437 2907 : g_free (self->pv->unique);
438 :
439 : /* This is done here, as an object must have a module even after dispose */
440 2907 : g_object_weak_unref (G_OBJECT (self->pv->module), module_went_away, self);
441 2907 : self->pv->module = NULL;
442 :
443 2907 : if (self->pv->transient) {
444 133 : g_slice_free (GkmObjectTransient, self->pv->transient);
445 133 : self->pv->transient = NULL;
446 : }
447 :
448 2907 : G_OBJECT_CLASS (gkm_object_parent_class)->finalize (obj);
449 2907 : }
450 :
451 : static void
452 15295 : gkm_object_set_property (GObject *obj, guint prop_id, const GValue *value,
453 : GParamSpec *pspec)
454 : {
455 15295 : GkmObject *self = GKM_OBJECT (obj);
456 : GkmStore *store;
457 :
458 15295 : switch (prop_id) {
459 0 : case PROP_HANDLE:
460 0 : gkm_object_set_handle (self, g_value_get_ulong (value));
461 0 : break;
462 2907 : case PROP_MODULE:
463 2907 : g_return_if_fail (!self->pv->module);
464 2907 : self->pv->module = g_value_get_object (value);
465 2907 : g_return_if_fail (GKM_IS_MODULE (self->pv->module));
466 2907 : g_object_weak_ref (G_OBJECT (self->pv->module), module_went_away, self);
467 2907 : break;
468 2907 : case PROP_MANAGER:
469 2907 : g_return_if_fail (!self->pv->manager);
470 2907 : self->pv->manager = g_value_get_object (value);
471 2907 : if (self->pv->manager) {
472 2757 : g_object_add_weak_pointer (G_OBJECT (self->pv->manager),
473 2757 : (gpointer*)&(self->pv->manager));
474 : }
475 2907 : break;
476 3667 : case PROP_STORE:
477 3667 : store = g_value_get_object (value);
478 3667 : if (self->pv->store) {
479 299 : g_return_if_fail (!store);
480 299 : g_object_remove_weak_pointer (G_OBJECT (self->pv->store),
481 299 : (gpointer*)&(self->pv->store));
482 : }
483 3667 : self->pv->store = store;
484 3667 : if (self->pv->store)
485 299 : g_object_add_weak_pointer (G_OBJECT (self->pv->store),
486 299 : (gpointer*)&(self->pv->store));
487 :
488 3667 : g_object_notify (G_OBJECT (self), "store");
489 3667 : break;
490 2907 : case PROP_UNIQUE:
491 2907 : g_return_if_fail (!self->pv->unique);
492 2907 : self->pv->unique = g_value_dup_string (value);
493 2907 : break;
494 2907 : case PROP_TRANSIENT:
495 2907 : g_return_if_fail (!self->pv->transient);
496 2907 : if (g_value_get_boolean (value))
497 109 : mark_object_transient (self);
498 2907 : break;
499 0 : default:
500 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
501 0 : break;
502 : }
503 : }
504 :
505 : static void
506 2670 : gkm_object_get_property (GObject *obj, guint prop_id, GValue *value,
507 : GParamSpec *pspec)
508 : {
509 2670 : GkmObject *self = GKM_OBJECT (obj);
510 :
511 2670 : switch (prop_id) {
512 2670 : case PROP_HANDLE:
513 2670 : g_value_set_ulong (value, gkm_object_get_handle (self));
514 2670 : break;
515 0 : case PROP_MODULE:
516 0 : g_return_if_fail (GKM_IS_MODULE (self->pv->module));
517 0 : g_value_set_object (value, gkm_object_get_module (self));
518 0 : break;
519 0 : case PROP_MANAGER:
520 0 : g_value_set_object (value, gkm_object_get_manager (self));
521 0 : break;
522 0 : case PROP_STORE:
523 0 : g_value_set_object (value, self->pv->store);
524 0 : break;
525 0 : case PROP_UNIQUE:
526 0 : g_value_set_string (value, gkm_object_get_unique (self));
527 0 : break;
528 0 : case PROP_TRANSIENT:
529 0 : g_value_set_boolean (value, gkm_object_is_transient (self));
530 0 : break;
531 0 : default:
532 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
533 0 : break;
534 : }
535 : }
536 :
537 : static void
538 45 : gkm_object_class_init (GkmObjectClass *klass)
539 : {
540 45 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
541 :
542 45 : gobject_class->constructor = gkm_object_constructor;
543 45 : gobject_class->dispose = gkm_object_dispose;
544 45 : gobject_class->finalize = gkm_object_finalize;
545 45 : gobject_class->set_property = gkm_object_set_property;
546 45 : gobject_class->get_property = gkm_object_get_property;
547 :
548 45 : klass->unlock = gkm_object_real_unlock;
549 45 : klass->get_attribute = gkm_object_real_get_attribute;
550 45 : klass->set_attribute = gkm_object_real_set_attribute;
551 45 : klass->create_attributes = gkm_object_real_create_attributes;
552 :
553 45 : klass->expose_object = gkm_object_real_expose_object;
554 :
555 45 : g_object_class_install_property (gobject_class, PROP_HANDLE,
556 : g_param_spec_ulong ("handle", "Handle", "Object handle",
557 : 0, G_MAXULONG, 0, G_PARAM_READWRITE));
558 :
559 45 : g_object_class_install_property (gobject_class, PROP_MODULE,
560 : g_param_spec_object ("module", "Module", "Object module",
561 : GKM_TYPE_MODULE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
562 :
563 45 : g_object_class_install_property (gobject_class, PROP_MANAGER,
564 : g_param_spec_object ("manager", "Manager", "Object manager",
565 : GKM_TYPE_MANAGER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
566 :
567 45 : g_object_class_install_property (gobject_class, PROP_STORE,
568 : g_param_spec_object ("store", "Store", "Object store",
569 : GKM_TYPE_STORE, G_PARAM_READWRITE));
570 :
571 45 : g_object_class_install_property (gobject_class, PROP_UNIQUE,
572 : g_param_spec_string ("unique", "Unique Identifer", "Machine unique identifier",
573 : NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
574 :
575 45 : g_object_class_install_property (gobject_class, PROP_TRANSIENT,
576 : g_param_spec_boolean ("transient", "Transient Object", "Transient Object",
577 : FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
578 :
579 45 : signals[EXPOSE_OBJECT] = g_signal_new ("expose-object", GKM_TYPE_OBJECT,
580 : G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GkmObjectClass, expose_object),
581 : NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN,
582 : G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
583 :
584 45 : signals[NOTIFY_ATTRIBUTE] = g_signal_new ("notify-attribute", GKM_TYPE_OBJECT,
585 : G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GkmObjectClass, notify_attribute),
586 : NULL, NULL, g_cclosure_marshal_VOID__ULONG,
587 : G_TYPE_NONE, 1, G_TYPE_ULONG);
588 45 : }
589 :
590 : /* -----------------------------------------------------------------------------
591 : * PUBLIC
592 : */
593 :
594 : CK_RV
595 12030 : gkm_object_get_attribute (GkmObject *self, GkmSession *session, CK_ATTRIBUTE_PTR attr)
596 : {
597 12030 : g_return_val_if_fail (GKM_IS_OBJECT (self), CKR_GENERAL_ERROR);
598 12030 : g_return_val_if_fail (attr, CKR_GENERAL_ERROR);
599 12030 : g_assert (GKM_OBJECT_GET_CLASS (self)->get_attribute);
600 12030 : return GKM_OBJECT_GET_CLASS (self)->get_attribute (self, session, attr);
601 : }
602 :
603 : void
604 268 : gkm_object_set_attribute (GkmObject *self, GkmSession *session,
605 : GkmTransaction *transaction, CK_ATTRIBUTE_PTR attr)
606 : {
607 268 : g_return_if_fail (GKM_IS_OBJECT (self));
608 268 : g_return_if_fail (GKM_IS_TRANSACTION (transaction));
609 268 : g_return_if_fail (!gkm_transaction_get_failed (transaction));
610 268 : g_return_if_fail (attr);
611 :
612 268 : g_assert (GKM_OBJECT_GET_CLASS (self)->set_attribute);
613 :
614 : /* Check that the value will actually change */
615 268 : if (!gkm_object_match (self, session, attr))
616 24 : GKM_OBJECT_GET_CLASS (self)->set_attribute (self, session, transaction, attr);
617 : }
618 :
619 : void
620 193 : gkm_object_create_attributes (GkmObject *self, GkmSession *session, GkmTransaction *transaction,
621 : CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
622 : {
623 193 : g_return_if_fail (GKM_IS_OBJECT (self));
624 193 : g_return_if_fail (GKM_IS_TRANSACTION (transaction));
625 193 : g_return_if_fail (!gkm_transaction_get_failed (transaction));
626 193 : g_return_if_fail (GKM_IS_SESSION (session));
627 193 : g_return_if_fail (attrs);
628 :
629 193 : g_assert (GKM_OBJECT_GET_CLASS (self)->create_attributes);
630 :
631 : /* Check that the value will actually change */
632 193 : GKM_OBJECT_GET_CLASS (self)->create_attributes (self, session, transaction, attrs, n_attrs);
633 : }
634 :
635 : void
636 4411 : gkm_object_notify_attribute (GkmObject *self, CK_ATTRIBUTE_TYPE attr_type)
637 : {
638 4411 : g_return_if_fail (GKM_IS_OBJECT (self));
639 4411 : g_signal_emit (self, signals[NOTIFY_ATTRIBUTE], 0, attr_type);
640 : }
641 :
642 : gboolean
643 827 : gkm_object_match (GkmObject *self, GkmSession *session, CK_ATTRIBUTE_PTR match)
644 : {
645 : CK_ATTRIBUTE attr;
646 827 : gboolean matched = FALSE;
647 : CK_RV rv;
648 :
649 827 : g_return_val_if_fail (GKM_IS_OBJECT (self), FALSE);
650 :
651 827 : if (!match->pValue)
652 0 : return FALSE;
653 :
654 827 : attr.type = match->type;
655 827 : attr.pValue = g_malloc0 (match->ulValueLen > 4 ? match->ulValueLen : 4);
656 827 : attr.ulValueLen = match->ulValueLen;
657 :
658 827 : matched = FALSE;
659 :
660 827 : rv = gkm_object_get_attribute (self, session, &attr);
661 1595 : matched = (rv == CKR_OK) &&
662 1551 : (match->ulValueLen == attr.ulValueLen) &&
663 724 : (memcmp (match->pValue, attr.pValue, attr.ulValueLen) == 0);
664 :
665 827 : g_free (attr.pValue);
666 827 : return matched;
667 : }
668 :
669 : gboolean
670 0 : gkm_object_match_all (GkmObject *self, GkmSession *session,
671 : CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
672 : {
673 : CK_ULONG i;
674 :
675 0 : g_return_val_if_fail (GKM_IS_OBJECT (self), FALSE);
676 :
677 0 : for (i = 0; i < n_attrs; ++i) {
678 0 : if (!gkm_object_match (self, session, &attrs[i]))
679 0 : return FALSE;
680 : }
681 :
682 0 : return TRUE;
683 : }
684 :
685 : CK_OBJECT_HANDLE
686 10940 : gkm_object_get_handle (GkmObject *self)
687 : {
688 10940 : g_return_val_if_fail (GKM_IS_OBJECT (self), 0);
689 10940 : return self->pv->handle;
690 : }
691 :
692 : void
693 2669 : gkm_object_set_handle (GkmObject *self, CK_OBJECT_HANDLE handle)
694 : {
695 2669 : g_return_if_fail (GKM_IS_OBJECT (self));
696 2669 : g_return_if_fail (handle != 0);
697 2669 : g_return_if_fail (self->pv->handle == 0);
698 :
699 2669 : self->pv->handle = handle;
700 2669 : g_object_notify (G_OBJECT (self), "handle");
701 : }
702 :
703 : GkmManager*
704 19532 : gkm_object_get_manager (GkmObject *self)
705 : {
706 19532 : g_return_val_if_fail (GKM_IS_OBJECT (self), NULL);
707 19532 : return self->pv->manager;
708 : }
709 :
710 : GkmModule*
711 2259 : gkm_object_get_module (GkmObject *self)
712 : {
713 2259 : g_return_val_if_fail (GKM_IS_OBJECT (self), NULL);
714 2259 : g_return_val_if_fail (GKM_IS_MODULE (self->pv->module), NULL);
715 2259 : return self->pv->module;
716 : }
717 :
718 : const gchar*
719 9 : gkm_object_get_unique (GkmObject *self)
720 : {
721 9 : g_return_val_if_fail (GKM_IS_OBJECT (self), NULL);
722 9 : return self->pv->unique;
723 : }
724 :
725 : gboolean
726 613 : gkm_object_is_token (GkmObject *self)
727 : {
728 613 : g_return_val_if_fail (GKM_IS_OBJECT (self), FALSE);
729 613 : if (!self->pv->manager)
730 0 : return FALSE;
731 613 : return gkm_manager_get_for_token (self->pv->manager);
732 : }
733 :
734 : gboolean
735 408 : gkm_object_is_transient (GkmObject *self)
736 : {
737 408 : g_return_val_if_fail (GKM_IS_OBJECT (self), FALSE);
738 408 : return self->pv->transient ? TRUE : FALSE;
739 : }
740 :
741 : void
742 36 : gkm_object_mark_used (GkmObject *self)
743 : {
744 : GkmObjectTransient *transient;
745 :
746 36 : g_return_if_fail (GKM_IS_OBJECT (self));
747 36 : transient = self->pv->transient;
748 :
749 36 : if (transient) {
750 12 : if (transient->timed_idle) {
751 0 : transient->stamp_used = g_get_real_time () / G_USEC_PER_SEC;
752 : }
753 12 : if (transient->uses_remaining) {
754 0 : --(transient->uses_remaining);
755 0 : if (transient->uses_remaining == 0)
756 0 : self_destruct (self);
757 : }
758 : }
759 : }
760 :
761 : CK_RV
762 157 : gkm_object_unlock (GkmObject *self, GkmCredential *cred)
763 : {
764 157 : g_return_val_if_fail (GKM_IS_OBJECT (self), CKR_GENERAL_ERROR);
765 157 : g_return_val_if_fail (GKM_OBJECT_GET_CLASS (self)->unlock, CKR_GENERAL_ERROR);
766 157 : return GKM_OBJECT_GET_CLASS (self)->unlock (self, cred);
767 : }
768 :
769 :
770 : gboolean
771 37 : gkm_object_get_attribute_boolean (GkmObject *self, GkmSession *session,
772 : CK_ATTRIBUTE_TYPE type, gboolean *value)
773 : {
774 : CK_ATTRIBUTE attr;
775 : CK_BBOOL bvalue;
776 :
777 37 : g_return_val_if_fail (GKM_IS_OBJECT (self), FALSE);
778 37 : g_return_val_if_fail (value, FALSE);
779 :
780 37 : attr.type = type;
781 37 : attr.ulValueLen = sizeof (CK_BBOOL);
782 37 : attr.pValue = &bvalue;
783 :
784 37 : if (gkm_object_get_attribute (self, session, &attr) != CKR_OK)
785 0 : return FALSE;
786 :
787 37 : *value = (bvalue == CK_TRUE) ? TRUE : FALSE;
788 37 : return TRUE;
789 : }
790 :
791 : gboolean
792 1 : gkm_object_get_attribute_ulong (GkmObject *self, GkmSession *session,
793 : CK_ATTRIBUTE_TYPE type, gulong *value)
794 : {
795 : CK_ATTRIBUTE attr;
796 : CK_ULONG uvalue;
797 :
798 1 : g_return_val_if_fail (GKM_IS_OBJECT (self), FALSE);
799 1 : g_return_val_if_fail (value, FALSE);
800 :
801 1 : attr.type = type;
802 1 : attr.ulValueLen = sizeof (CK_ULONG);
803 1 : attr.pValue = &uvalue;
804 :
805 1 : if (gkm_object_get_attribute (self, session, &attr) != CKR_OK)
806 0 : return FALSE;
807 :
808 1 : *value = uvalue;
809 1 : return TRUE;
810 : }
811 :
812 : void*
813 55 : gkm_object_get_attribute_data (GkmObject *self, GkmSession *session,
814 : CK_ATTRIBUTE_TYPE type, gsize *n_data)
815 : {
816 : CK_ATTRIBUTE attr;
817 :
818 55 : g_return_val_if_fail (GKM_IS_OBJECT (self), NULL);
819 55 : g_return_val_if_fail (n_data, NULL);
820 :
821 55 : attr.type = type;
822 55 : attr.ulValueLen = 0;
823 55 : attr.pValue = NULL;
824 :
825 55 : if (gkm_object_get_attribute (self, session, &attr) != CKR_OK)
826 3 : return NULL;
827 :
828 52 : if (attr.ulValueLen == 0)
829 8 : attr.ulValueLen = 1;
830 :
831 52 : attr.pValue = g_malloc0 (attr.ulValueLen);
832 :
833 52 : if (gkm_object_get_attribute (self, session, &attr) != CKR_OK) {
834 0 : g_free (attr.pValue);
835 0 : return NULL;
836 : }
837 :
838 52 : *n_data = attr.ulValueLen;
839 52 : return attr.pValue;
840 : }
841 :
842 : gboolean
843 21 : gkm_object_has_attribute_ulong (GkmObject *self, GkmSession *session,
844 : CK_ATTRIBUTE_TYPE type, gulong value)
845 : {
846 : gulong *data;
847 : gsize n_data, i;
848 :
849 21 : g_return_val_if_fail (GKM_IS_OBJECT (self), FALSE);
850 21 : g_return_val_if_fail (GKM_IS_SESSION (session), FALSE);
851 :
852 21 : data = gkm_object_get_attribute_data (self, session, type, &n_data);
853 21 : if (data == NULL)
854 0 : return FALSE;
855 :
856 21 : g_return_val_if_fail (n_data % sizeof (gulong) == 0, FALSE);
857 21 : for (i = 0; i < n_data / sizeof (gulong); ++i) {
858 21 : if (data[i] == value) {
859 21 : g_free (data);
860 21 : return TRUE;
861 : }
862 : }
863 :
864 0 : g_free (data);
865 0 : return FALSE;
866 : }
867 :
868 : gboolean
869 21 : gkm_object_has_attribute_boolean (GkmObject *self, GkmSession *session,
870 : CK_ATTRIBUTE_TYPE type, gboolean value)
871 : {
872 : gboolean data;
873 :
874 21 : g_return_val_if_fail (GKM_IS_OBJECT (self), FALSE);
875 21 : g_return_val_if_fail (GKM_IS_SESSION (session), FALSE);
876 :
877 21 : if (!gkm_object_get_attribute_boolean (self, session, type, &data))
878 0 : return FALSE;
879 21 : return data == value;
880 : }
881 :
882 : void
883 37 : gkm_object_destroy (GkmObject *self, GkmTransaction *transaction)
884 : {
885 : GkmSession *session;
886 : GkmManager *manager;
887 : GkmModule *module;
888 :
889 37 : g_return_if_fail (GKM_IS_OBJECT (self));
890 37 : g_return_if_fail (GKM_IS_TRANSACTION (transaction));
891 37 : g_return_if_fail (!gkm_transaction_get_failed (transaction));
892 37 : g_return_if_fail (self->pv->module);
893 :
894 37 : g_object_ref (self);
895 :
896 37 : session = gkm_session_for_session_object (self);
897 37 : if (session != NULL) {
898 21 : gkm_session_destroy_session_object (session, transaction, self);
899 : } else {
900 16 : manager = gkm_object_get_manager (self);
901 16 : module = gkm_object_get_module (self);
902 16 : if (manager == gkm_module_get_manager (module))
903 16 : gkm_module_remove_token_object (module, transaction, self);
904 : }
905 :
906 : /* Forcefully dispose of the object once the transaction completes */
907 37 : gkm_transaction_add (transaction, NULL, complete_destroy, g_object_ref (self));
908 :
909 37 : g_object_unref (self);
910 : }
911 :
912 : gboolean
913 2228 : gkm_object_is_exposed (GkmObject *self)
914 : {
915 2228 : g_return_val_if_fail (GKM_IS_OBJECT (self), FALSE);
916 2228 : return self->pv->exposed;
917 : }
918 :
919 : void
920 7497 : gkm_object_expose (GkmObject *self, gboolean expose)
921 : {
922 7497 : if (!expose && !self)
923 0 : return;
924 :
925 7497 : g_return_if_fail (GKM_IS_OBJECT (self));
926 :
927 7497 : if (self->pv->exposed != expose)
928 5340 : g_signal_emit (self, signals[EXPOSE_OBJECT], 0, expose);
929 : }
930 :
931 : void
932 2277 : gkm_object_expose_full (GkmObject *self, GkmTransaction *transaction, gboolean expose)
933 : {
934 2277 : if (!expose && !self)
935 0 : return;
936 :
937 2277 : g_return_if_fail (GKM_IS_OBJECT (self));
938 2277 : g_return_if_fail (!transaction || !gkm_transaction_get_failed (transaction));
939 :
940 2277 : if (self->pv->exposed != expose) {
941 2233 : if (transaction)
942 161 : gkm_transaction_add (transaction, self, complete_expose, GUINT_TO_POINTER (expose));
943 2233 : gkm_object_expose (self, expose);
944 : }
945 : }
|