Line data Source code
1 : /*
2 : * gnome-keyring
3 : *
4 : * Copyright (C) 2009 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 "gkm-attributes.h"
24 : #include "gkm-credential.h"
25 : #include "gkm-secret.h"
26 : #include "gkm-session.h"
27 : #include "gkm-transaction.h"
28 :
29 : #include "pkcs11/pkcs11.h"
30 : #include "pkcs11/pkcs11i.h"
31 :
32 : enum {
33 : PROP_0,
34 : PROP_OBJECT,
35 : PROP_SECRET
36 : };
37 :
38 : struct _GkmCredentialPrivate {
39 :
40 : /* The object we authenticated */
41 : GkmObject *object;
42 :
43 : /* Secret which created this credential */
44 : GkmSecret *secret;
45 :
46 : /* Stored data */
47 : GType user_type;
48 : gpointer user_data;
49 : };
50 :
51 3521 : G_DEFINE_TYPE_WITH_PRIVATE (GkmCredential, gkm_credential, GKM_TYPE_OBJECT);
52 :
53 : /* -----------------------------------------------------------------------------
54 : * INTERNAL
55 : */
56 :
57 : static GkmObject*
58 69 : factory_create_credential (GkmSession *session, GkmTransaction *transaction,
59 : CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
60 : {
61 : CK_OBJECT_HANDLE handle;
62 : GkmCredential *cred;
63 : CK_ATTRIBUTE *attr;
64 : GkmManager *manager;
65 : GkmModule *module;
66 69 : GkmObject *object = NULL;
67 : CK_RV rv;
68 :
69 69 : g_return_val_if_fail (GKM_IS_TRANSACTION (transaction), NULL);
70 69 : g_return_val_if_fail (attrs || !n_attrs, NULL);
71 :
72 : /* The handle is optional */
73 69 : if (gkm_attributes_find_ulong (attrs, n_attrs, CKA_G_OBJECT, &handle)) {
74 24 : rv = gkm_session_lookup_readable_object (session, handle, &object);
75 24 : if (rv != CKR_OK) {
76 1 : gkm_transaction_fail (transaction, rv);
77 1 : return NULL;
78 : }
79 : } else {
80 45 : object = NULL;
81 : }
82 :
83 : /* The value is optional */
84 68 : attr = gkm_attributes_find (attrs, n_attrs, CKA_VALUE);
85 :
86 68 : gkm_attributes_consume (attrs, n_attrs, CKA_VALUE, CKA_G_OBJECT, G_MAXULONG);
87 :
88 68 : module = gkm_session_get_module (session);
89 68 : manager = gkm_manager_for_template (attrs, n_attrs, session);
90 68 : rv = gkm_credential_create (module, manager, object,
91 : attr ? attr->pValue : NULL,
92 : attr ? attr->ulValueLen : 0, &cred);
93 :
94 68 : if (rv == CKR_OK) {
95 64 : gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (cred),
96 : TRUE, attrs, n_attrs);
97 64 : return GKM_OBJECT (cred);
98 : } else {
99 4 : gkm_transaction_fail (transaction, rv);
100 4 : return NULL;
101 : }
102 : }
103 :
104 : static void
105 36 : self_destruct (GkmCredential *self)
106 : {
107 : GkmTransaction *transaction;
108 : CK_RV rv;
109 :
110 36 : g_assert (GKM_IS_CREDENTIAL (self));
111 :
112 36 : transaction = gkm_transaction_new ();
113 :
114 : /* Destroy ourselves */
115 36 : gkm_object_destroy (GKM_OBJECT (self), transaction);
116 :
117 36 : gkm_transaction_complete (transaction);
118 36 : rv = gkm_transaction_get_result (transaction);
119 36 : g_object_unref (transaction);
120 :
121 36 : if (rv != CKR_OK)
122 0 : g_warning ("Couldn't destroy credential object: (code %lu)", (gulong)rv);
123 36 : }
124 :
125 : static void
126 36 : object_went_away (gpointer data, GObject *old_object)
127 : {
128 36 : GkmCredential *self = data;
129 36 : g_return_if_fail (GKM_IS_CREDENTIAL (self));
130 36 : self->pv->object = NULL;
131 36 : self_destruct (self);
132 : }
133 :
134 : static void
135 478 : clear_data (GkmCredential *self)
136 : {
137 478 : if (!self->pv->user_data)
138 319 : return;
139 159 : if (G_TYPE_IS_BOXED (self->pv->user_type))
140 5 : g_boxed_free (self->pv->user_type, self->pv->user_data);
141 154 : else if (G_TYPE_IS_OBJECT (self->pv->user_type))
142 154 : g_object_unref (self->pv->user_data);
143 : else
144 0 : g_assert_not_reached ();
145 159 : self->pv->user_data = NULL;
146 159 : self->pv->user_type = 0;
147 : }
148 :
149 : /* -----------------------------------------------------------------------------
150 : * OBJECT
151 : */
152 :
153 : static CK_RV
154 943 : gkm_credential_real_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE *attr)
155 : {
156 943 : GkmCredential *self = GKM_CREDENTIAL (base);
157 : CK_OBJECT_HANDLE handle;
158 : gconstpointer value;
159 : gsize n_value;
160 :
161 943 : switch (attr->type) {
162 :
163 436 : case CKA_CLASS:
164 436 : return gkm_attribute_set_ulong (attr, CKO_G_CREDENTIAL);
165 :
166 0 : case CKA_PRIVATE:
167 0 : return gkm_attribute_set_bool (attr, TRUE);
168 :
169 313 : case CKA_G_OBJECT:
170 313 : handle = self->pv->object ? gkm_object_get_handle (self->pv->object) : 0;
171 313 : return gkm_attribute_set_ulong (attr, handle);
172 :
173 2 : case CKA_VALUE:
174 2 : if (gkm_session_is_for_application (session))
175 1 : return CKR_ATTRIBUTE_SENSITIVE;
176 1 : if (!self->pv->secret) {
177 0 : value = NULL;
178 0 : n_value = 0;
179 : } else {
180 1 : value = gkm_secret_get (self->pv->secret, &n_value);
181 : }
182 1 : return gkm_attribute_set_data (attr, value, n_value);
183 : };
184 :
185 192 : return GKM_OBJECT_CLASS (gkm_credential_parent_class)->get_attribute (base, session, attr);
186 : }
187 :
188 : static GObject*
189 205 : gkm_credential_constructor (GType type, guint n_props, GObjectConstructParam *props)
190 : {
191 205 : GkmCredential *self = GKM_CREDENTIAL (G_OBJECT_CLASS (gkm_credential_parent_class)->constructor(type, n_props, props));
192 205 : g_return_val_if_fail (self, NULL);
193 :
194 205 : return G_OBJECT (self);
195 : }
196 :
197 : static void
198 205 : gkm_credential_init (GkmCredential *self)
199 : {
200 205 : self->pv = gkm_credential_get_instance_private (self);
201 205 : }
202 :
203 : static void
204 318 : gkm_credential_dispose (GObject *obj)
205 : {
206 318 : GkmCredential *self = GKM_CREDENTIAL (obj);
207 :
208 318 : if (self->pv->object)
209 134 : g_object_weak_unref (G_OBJECT (self->pv->object), object_went_away, self);
210 318 : self->pv->object = NULL;
211 :
212 318 : if (self->pv->secret)
213 205 : g_object_unref (G_OBJECT (self->pv->secret));
214 318 : self->pv->secret = NULL;
215 :
216 318 : clear_data (self);
217 :
218 318 : G_OBJECT_CLASS (gkm_credential_parent_class)->dispose (obj);
219 318 : }
220 :
221 : static void
222 205 : gkm_credential_finalize (GObject *obj)
223 : {
224 205 : GkmCredential *self = GKM_CREDENTIAL (obj);
225 :
226 205 : g_assert (!self->pv->object);
227 205 : g_assert (!self->pv->user_type);
228 205 : g_assert (!self->pv->user_data);
229 :
230 205 : G_OBJECT_CLASS (gkm_credential_parent_class)->finalize (obj);
231 205 : }
232 :
233 : static void
234 410 : gkm_credential_set_property (GObject *obj, guint prop_id, const GValue *value,
235 : GParamSpec *pspec)
236 : {
237 410 : GkmCredential *self = GKM_CREDENTIAL (obj);
238 : GkmObject *object;
239 :
240 410 : switch (prop_id) {
241 205 : case PROP_OBJECT:
242 205 : object = g_value_get_object (value);
243 205 : if (object)
244 157 : gkm_credential_connect (self, object);
245 : else
246 48 : g_return_if_fail (!self->pv->object);
247 205 : break;
248 205 : case PROP_SECRET:
249 205 : gkm_credential_set_secret (self, g_value_get_object (value));
250 205 : break;
251 0 : default:
252 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
253 0 : break;
254 : }
255 : }
256 :
257 : static void
258 2 : gkm_credential_get_property (GObject *obj, guint prop_id, GValue *value,
259 : GParamSpec *pspec)
260 : {
261 2 : GkmCredential *self = GKM_CREDENTIAL (obj);
262 :
263 2 : switch (prop_id) {
264 1 : case PROP_OBJECT:
265 1 : g_value_set_object (value, gkm_credential_get_object (self));
266 1 : break;
267 1 : case PROP_SECRET:
268 1 : g_value_set_object (value, gkm_credential_get_secret (self));
269 1 : break;
270 0 : default:
271 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
272 0 : break;
273 : }
274 2 : }
275 :
276 : static void
277 36 : gkm_credential_class_init (GkmCredentialClass *klass)
278 : {
279 36 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
280 36 : GkmObjectClass *gkm_class = GKM_OBJECT_CLASS (klass);
281 :
282 36 : gobject_class->constructor = gkm_credential_constructor;
283 36 : gobject_class->dispose = gkm_credential_dispose;
284 36 : gobject_class->finalize = gkm_credential_finalize;
285 36 : gobject_class->set_property = gkm_credential_set_property;
286 36 : gobject_class->get_property = gkm_credential_get_property;
287 :
288 36 : gkm_class->get_attribute = gkm_credential_real_get_attribute;
289 :
290 36 : g_object_class_install_property (gobject_class, PROP_OBJECT,
291 : g_param_spec_object ("object", "Object", "Object authenticated",
292 : GKM_TYPE_OBJECT, G_PARAM_READWRITE));
293 :
294 36 : g_object_class_install_property (gobject_class, PROP_SECRET,
295 : g_param_spec_object ("secret", "Secret", "Optiontal secret",
296 : GKM_TYPE_SECRET, G_PARAM_READWRITE));
297 36 : }
298 :
299 : /* -----------------------------------------------------------------------------
300 : * PUBLIC
301 : */
302 :
303 : GkmFactory*
304 327 : gkm_credential_get_factory (void)
305 : {
306 : static CK_OBJECT_CLASS klass = CKO_G_CREDENTIAL;
307 :
308 : static CK_ATTRIBUTE attributes[] = {
309 : { CKA_CLASS, &klass, sizeof (klass) },
310 : };
311 :
312 : static GkmFactory factory = {
313 : attributes,
314 : G_N_ELEMENTS (attributes),
315 : factory_create_credential
316 : };
317 :
318 327 : return &factory;
319 : }
320 :
321 : CK_RV
322 205 : gkm_credential_create (GkmModule *module, GkmManager *manager, GkmObject *object,
323 : CK_UTF8CHAR_PTR pin, CK_ULONG n_pin, GkmCredential **result)
324 : {
325 : GkmCredential *cred;
326 205 : GkmSecret *secret = NULL;
327 : CK_RV rv;
328 :
329 205 : g_return_val_if_fail (GKM_IS_MODULE (module), CKR_GENERAL_ERROR);
330 205 : g_return_val_if_fail (!object || GKM_IS_OBJECT (object), CKR_GENERAL_ERROR);
331 205 : g_return_val_if_fail (!manager || GKM_IS_MANAGER (manager), CKR_GENERAL_ERROR);
332 205 : g_return_val_if_fail (result, CKR_GENERAL_ERROR);
333 :
334 205 : secret = gkm_secret_new_from_login (pin, n_pin);
335 205 : cred = g_object_new (GKM_TYPE_CREDENTIAL,
336 : "module", module,
337 : "manager", manager,
338 : "secret", secret,
339 : "object", object,
340 : NULL);
341 205 : g_object_unref (secret);
342 :
343 : /* If we have an object, the unlock must work */
344 205 : if (object) {
345 157 : rv = gkm_object_unlock (object, cred);
346 157 : if (rv == CKR_OK)
347 150 : *result = cred;
348 : else
349 7 : g_object_unref (cred);
350 :
351 : /* Created credentials without object */
352 : } else {
353 48 : *result = cred;
354 48 : rv = CKR_OK;
355 : }
356 :
357 205 : return rv;
358 : }
359 :
360 : void
361 170 : gkm_credential_connect (GkmCredential *self, GkmObject *object)
362 : {
363 170 : g_return_if_fail (GKM_IS_CREDENTIAL (self));
364 170 : g_return_if_fail (GKM_IS_OBJECT (object));
365 170 : g_return_if_fail (self->pv->object == NULL);
366 170 : g_return_if_fail (GKM_OBJECT (self) != object);
367 170 : self->pv->object = object;
368 170 : g_object_weak_ref (G_OBJECT (self->pv->object), object_went_away, self);
369 : }
370 :
371 : GkmSecret*
372 163 : gkm_credential_get_secret (GkmCredential *self)
373 : {
374 163 : g_return_val_if_fail (GKM_IS_CREDENTIAL (self), NULL);
375 163 : return self->pv->secret;
376 : }
377 :
378 : void
379 206 : gkm_credential_set_secret (GkmCredential *self, GkmSecret *secret)
380 : {
381 206 : g_return_if_fail (GKM_IS_CREDENTIAL (self));
382 :
383 206 : if (secret) {
384 206 : g_return_if_fail (GKM_IS_SECRET (secret));
385 206 : g_object_ref (secret);
386 : }
387 206 : if (self->pv->secret)
388 1 : g_object_unref (self->pv->secret);
389 206 : self->pv->secret = secret;
390 :
391 206 : g_object_notify (G_OBJECT (self), "secret");
392 : }
393 :
394 : const gchar*
395 9 : gkm_credential_get_password (GkmCredential *self, gsize *n_password)
396 : {
397 9 : g_return_val_if_fail (GKM_IS_CREDENTIAL (self), NULL);
398 9 : g_return_val_if_fail (n_password, NULL);
399 :
400 9 : if (!self->pv->secret) {
401 0 : *n_password = 0;
402 0 : return NULL;
403 : }
404 :
405 9 : return gkm_secret_get_password (self->pv->secret, n_password);
406 : }
407 :
408 : GkmObject*
409 18 : gkm_credential_get_object (GkmCredential *self)
410 : {
411 18 : g_return_val_if_fail (GKM_IS_CREDENTIAL (self), NULL);
412 18 : return self->pv->object;
413 : }
414 :
415 : gpointer
416 105 : gkm_credential_peek_data (GkmCredential *self, GType type)
417 : {
418 105 : g_return_val_if_fail (GKM_IS_CREDENTIAL (self), NULL);
419 105 : if (!self->pv->user_data)
420 6 : return NULL;
421 99 : g_return_val_if_fail (type == self->pv->user_type, NULL);
422 99 : return self->pv->user_data;
423 : }
424 :
425 : gpointer
426 26 : gkm_credential_pop_data (GkmCredential *self, GType type)
427 : {
428 26 : gpointer data = NULL;
429 26 : g_return_val_if_fail (GKM_IS_CREDENTIAL (self), NULL);
430 :
431 26 : if (self->pv->user_data) {
432 22 : g_return_val_if_fail (type == self->pv->user_type, NULL);
433 22 : if (G_TYPE_IS_BOXED (self->pv->user_type))
434 1 : data = g_boxed_copy (self->pv->user_type, self->pv->user_data);
435 21 : else if (G_TYPE_IS_OBJECT (self->pv->user_type))
436 21 : data = g_object_ref (self->pv->user_data);
437 : else
438 0 : g_assert_not_reached ();
439 : }
440 :
441 26 : gkm_object_mark_used (GKM_OBJECT (self));
442 26 : return data;
443 : }
444 :
445 : void
446 160 : gkm_credential_set_data (GkmCredential *self, GType type, gpointer data)
447 : {
448 160 : g_return_if_fail (GKM_IS_CREDENTIAL (self));
449 :
450 160 : if (data) {
451 159 : g_return_if_fail (type);
452 159 : g_return_if_fail (G_TYPE_IS_BOXED (type) || G_TYPE_IS_OBJECT (type));
453 : }
454 :
455 160 : clear_data (self);
456 :
457 160 : if (data) {
458 159 : self->pv->user_type = type;
459 159 : if (G_TYPE_IS_BOXED (type))
460 5 : self->pv->user_data = g_boxed_copy (type, data);
461 154 : else if (G_TYPE_IS_OBJECT (type))
462 154 : self->pv->user_data = g_object_ref (data);
463 : else
464 0 : g_assert_not_reached ();
465 : }
466 : }
467 :
468 : gboolean
469 183 : gkm_credential_for_each (GkmSession *session, GkmObject *object,
470 : GkmCredentialFunc func, gpointer user_data)
471 : {
472 : CK_OBJECT_HANDLE handle;
473 : CK_OBJECT_CLASS klass;
474 : CK_ATTRIBUTE attrs[2];
475 : GList *results, *l;
476 : GkmCredential *cred;
477 : gboolean ret;
478 :
479 183 : g_return_val_if_fail (GKM_IS_SESSION (session), FALSE);
480 183 : g_return_val_if_fail (GKM_IS_OBJECT (object), FALSE);
481 183 : g_return_val_if_fail (func, FALSE);
482 :
483 : /* Do we have one right on the session */
484 183 : cred = gkm_session_get_credential (session);
485 183 : if (cred && gkm_credential_get_object (cred) == object) {
486 0 : g_object_ref (cred);
487 0 : ret = (func) (cred, object, user_data);
488 0 : g_object_unref (cred);
489 0 : if (ret)
490 0 : return TRUE;
491 : }
492 :
493 183 : klass = CKO_G_CREDENTIAL;
494 183 : attrs[0].type = CKA_CLASS;
495 183 : attrs[0].pValue = &klass;
496 183 : attrs[0].ulValueLen = sizeof (klass);
497 :
498 183 : handle = gkm_object_get_handle (object);
499 183 : attrs[1].type = CKA_G_OBJECT;
500 183 : attrs[1].pValue = &handle;
501 183 : attrs[1].ulValueLen = sizeof (handle);
502 :
503 : /* Find any on the session */
504 183 : results = gkm_manager_find_by_attributes (gkm_session_get_manager (session),
505 : session, attrs, G_N_ELEMENTS (attrs));
506 :
507 191 : for (l = results; l; l = g_list_next (l)) {
508 27 : g_object_ref (l->data);
509 27 : ret = (func) (l->data, object, user_data);
510 27 : g_object_unref (l->data);
511 27 : if (ret)
512 19 : break;
513 : }
514 :
515 183 : g_list_free (results);
516 :
517 183 : if (l != NULL)
518 19 : return TRUE;
519 :
520 : /* Find any in the token */
521 164 : results = gkm_manager_find_by_attributes (gkm_module_get_manager (gkm_session_get_module (session)),
522 : session, attrs, G_N_ELEMENTS (attrs));
523 :
524 164 : for (l = results; l; l = g_list_next (l)) {
525 99 : g_object_ref (l->data);
526 99 : ret = (func) (l->data, object, user_data);
527 99 : g_object_unref (l->data);
528 99 : if (ret)
529 99 : break;
530 : }
531 :
532 164 : g_list_free (results);
533 :
534 164 : return (l != NULL);
535 : }
|