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-secret-data.h"
24 : #include "gkm-secret-fields.h"
25 : #include "gkm-secret-item.h"
26 :
27 : #include "gkm/gkm-attributes.h"
28 : #include "gkm/gkm-module.h"
29 : #include "gkm/gkm-secret.h"
30 : #include "gkm/gkm-session.h"
31 : #include "gkm/gkm-transaction.h"
32 :
33 : #include "pkcs11/pkcs11i.h"
34 :
35 : #include <glib/gi18n.h>
36 :
37 : enum {
38 : PROP_0,
39 : PROP_COLLECTION,
40 : PROP_FIELDS,
41 : PROP_SCHEMA
42 : };
43 :
44 : struct _GkmSecretItem {
45 : GkmSecretObject parent;
46 : GHashTable *fields;
47 : gchar *schema;
48 : GkmSecretCollection *collection;
49 : };
50 :
51 32990 : G_DEFINE_TYPE (GkmSecretItem, gkm_secret_item, GKM_TYPE_SECRET_OBJECT);
52 :
53 : /* -----------------------------------------------------------------------------
54 : * INTERNAL
55 : */
56 :
57 : static gboolean
58 0 : complete_set_schema (GkmTransaction *transaction, GObject *obj, gpointer user_data)
59 : {
60 0 : GkmSecretItem *self = GKM_SECRET_ITEM (obj);
61 0 : gchar *old_schema = user_data;
62 :
63 0 : if (gkm_transaction_get_failed (transaction)) {
64 0 : g_free (self->schema);
65 0 : self->schema = old_schema;
66 : } else {
67 0 : gkm_object_notify_attribute (GKM_OBJECT (obj), CKA_G_SCHEMA);
68 0 : g_object_notify (G_OBJECT (obj), "schema");
69 0 : g_free (old_schema);
70 : }
71 :
72 0 : return TRUE;
73 : }
74 :
75 : static void
76 0 : begin_set_schema (GkmSecretItem *self, GkmTransaction *transaction, gchar *schema)
77 : {
78 0 : g_assert (GKM_IS_SECRET_OBJECT (self));
79 0 : g_assert (!gkm_transaction_get_failed (transaction));
80 :
81 0 : if (self->schema != schema) {
82 0 : gkm_secret_object_begin_modified (GKM_SECRET_OBJECT (self), transaction);
83 0 : gkm_transaction_add (transaction, self, complete_set_schema, self->schema);
84 0 : self->schema = schema;
85 : }
86 0 : }
87 :
88 : static gboolean
89 5 : complete_set_secret (GkmTransaction *transaction, GObject *obj, gpointer user_data)
90 : {
91 5 : if (!gkm_transaction_get_failed (transaction)) {
92 5 : gkm_object_notify_attribute (GKM_OBJECT (obj), CKA_VALUE);
93 : }
94 :
95 5 : return TRUE;
96 : }
97 :
98 : static gboolean
99 4 : complete_set_fields (GkmTransaction *transaction, GObject *obj, gpointer user_data)
100 : {
101 4 : GkmSecretItem *self = GKM_SECRET_ITEM (obj);
102 4 : GHashTable *old_fields = user_data;
103 :
104 4 : if (gkm_transaction_get_failed (transaction)) {
105 1 : if (self->fields)
106 1 : g_hash_table_unref (self->fields);
107 1 : self->fields = old_fields;
108 : } else {
109 3 : gkm_object_notify_attribute (GKM_OBJECT (obj), CKA_G_FIELDS);
110 3 : g_object_notify (G_OBJECT (obj), "fields");
111 3 : if (old_fields)
112 0 : g_hash_table_unref (old_fields);
113 : }
114 :
115 4 : return TRUE;
116 : }
117 :
118 : static void
119 4 : begin_set_fields (GkmSecretItem *self, GkmTransaction *transaction, GHashTable *fields)
120 : {
121 4 : g_assert (GKM_IS_SECRET_OBJECT (self));
122 4 : g_assert (!gkm_transaction_get_failed (transaction));
123 :
124 4 : gkm_secret_object_begin_modified (GKM_SECRET_OBJECT (self), transaction);
125 4 : gkm_transaction_add (transaction, self, complete_set_fields, self->fields);
126 4 : self->fields = fields;
127 4 : }
128 :
129 : static GkmObject*
130 8 : factory_create_item (GkmSession *session, GkmTransaction *transaction,
131 : CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
132 : {
133 8 : GkmSecretCollection *collection = NULL;
134 : GkmSecretItem *item;
135 : GkmManager *m_manager;
136 : GkmManager *s_manager;
137 : CK_ATTRIBUTE *attr;
138 : gboolean is_token;
139 8 : g_autofree gchar *identifier = NULL;
140 :
141 8 : g_return_val_if_fail (GKM_IS_TRANSACTION (transaction), NULL);
142 8 : g_return_val_if_fail (attrs || !n_attrs, NULL);
143 :
144 : /* See if a collection attribute was specified */
145 8 : attr = gkm_attributes_find (attrs, n_attrs, CKA_G_COLLECTION);
146 8 : if (attr == NULL) {
147 0 : gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
148 0 : return NULL;
149 : }
150 :
151 8 : m_manager = gkm_module_get_manager (gkm_session_get_module (session));
152 8 : s_manager = gkm_session_get_manager (session);
153 :
154 8 : gkm_attribute_consume (attr);
155 8 : if (!gkm_attributes_find_boolean (attrs, n_attrs, CKA_TOKEN, &is_token))
156 4 : collection = gkm_secret_collection_find (session, attr, m_manager, s_manager, NULL);
157 4 : else if (is_token)
158 4 : collection = gkm_secret_collection_find (session, attr, m_manager, NULL);
159 : else
160 0 : collection = gkm_secret_collection_find (session, attr, s_manager, NULL);
161 :
162 8 : if (!collection) {
163 0 : gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
164 0 : return NULL;
165 : }
166 :
167 : /* If an ID was specified, then try and see if that ID already exists */
168 8 : if (gkm_attributes_find_string (attrs, n_attrs, CKA_ID, &identifier)) {
169 2 : item = gkm_secret_collection_get_item (collection, identifier);
170 2 : if (item == NULL) {
171 0 : gkm_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
172 0 : return NULL;
173 : } else {
174 2 : gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (item),
175 : FALSE, attrs, n_attrs);
176 2 : return GKM_OBJECT (g_object_ref (item));
177 : }
178 : }
179 :
180 : /* Create a new collection which will own the item */
181 6 : item = gkm_secret_collection_create_item (collection, transaction);
182 6 : gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (item),
183 : TRUE, attrs, n_attrs);
184 6 : return GKM_OBJECT (g_object_ref (item));
185 : }
186 :
187 : /* -----------------------------------------------------------------------------
188 : * OBJECT
189 : */
190 :
191 : static gboolean
192 53 : gkm_secret_item_real_is_locked (GkmSecretObject *obj, GkmSession *session)
193 : {
194 53 : GkmSecretItem *self = GKM_SECRET_ITEM (obj);
195 53 : if (!self->collection)
196 1 : return TRUE;
197 52 : return gkm_secret_object_is_locked (GKM_SECRET_OBJECT (self->collection), session);
198 : }
199 :
200 : static CK_RV
201 8882 : gkm_secret_item_real_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE_PTR attr)
202 : {
203 8882 : GkmSecretItem *self = GKM_SECRET_ITEM (base);
204 : GkmSecretData *sdata;
205 : const gchar *identifier;
206 : const guchar *secret;
207 8882 : gsize n_secret = 0;
208 : CK_RV rv;
209 :
210 8882 : g_return_val_if_fail (self->collection, CKR_GENERAL_ERROR);
211 :
212 8882 : switch (attr->type) {
213 4256 : case CKA_CLASS:
214 4256 : return gkm_attribute_set_ulong (attr, CKO_SECRET_KEY);
215 :
216 12 : case CKA_VALUE:
217 12 : sdata = gkm_secret_collection_unlocked_use (self->collection, session);
218 12 : if (sdata == NULL)
219 2 : return CKR_USER_NOT_LOGGED_IN;
220 10 : identifier = gkm_secret_object_get_identifier (GKM_SECRET_OBJECT (self));
221 10 : secret = gkm_secret_data_get_raw (sdata, identifier, &n_secret);
222 10 : rv = gkm_attribute_set_data (attr, secret, n_secret);
223 10 : gkm_object_mark_used (base);
224 10 : g_object_unref (sdata);
225 10 : return rv;
226 :
227 142 : case CKA_G_COLLECTION:
228 142 : g_return_val_if_fail (self->collection, CKR_GENERAL_ERROR);
229 142 : identifier = gkm_secret_object_get_identifier (GKM_SECRET_OBJECT (self->collection));
230 142 : return gkm_attribute_set_string (attr, identifier);
231 :
232 11 : case CKA_G_FIELDS:
233 11 : if (!self->fields)
234 4 : return gkm_attribute_set_data (attr, NULL, 0);
235 7 : return gkm_secret_fields_serialize (attr, self->fields, self->schema);
236 :
237 2 : case CKA_G_SCHEMA:
238 2 : return gkm_attribute_set_string (attr, self->schema);
239 : }
240 :
241 4459 : return GKM_OBJECT_CLASS (gkm_secret_item_parent_class)->get_attribute (base, session, attr);
242 : }
243 :
244 : static void
245 16 : gkm_secret_item_real_set_attribute (GkmObject *base, GkmSession *session,
246 : GkmTransaction *transaction, CK_ATTRIBUTE_PTR attr)
247 : {
248 16 : GkmSecretItem *self = GKM_SECRET_ITEM (base);
249 : const gchar *identifier;
250 : GkmSecretData *sdata;
251 : GHashTable *fields;
252 : gchar *schema_name;
253 : GkmSecret *secret;
254 : gchar *schema;
255 : CK_RV rv;
256 :
257 16 : if (!self->collection) {
258 0 : gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
259 11 : g_return_if_reached ();
260 : }
261 :
262 : /* Check that the object is not locked */
263 16 : if (!gkm_secret_collection_unlocked_have (self->collection, session)) {
264 2 : gkm_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
265 2 : return;
266 : }
267 :
268 14 : switch (attr->type) {
269 5 : case CKA_VALUE:
270 5 : sdata = gkm_secret_collection_unlocked_use (self->collection, session);
271 5 : g_return_if_fail (sdata);
272 5 : identifier = gkm_secret_object_get_identifier (GKM_SECRET_OBJECT (self));
273 5 : secret = gkm_secret_new (attr->pValue, attr->ulValueLen);
274 5 : gkm_secret_data_set_transacted (sdata, transaction, identifier, secret);
275 5 : g_object_unref (secret);
276 5 : g_object_unref (sdata);
277 5 : gkm_secret_object_begin_modified (GKM_SECRET_OBJECT (self), transaction);
278 5 : if (!gkm_transaction_get_failed (transaction))
279 5 : gkm_transaction_add (transaction, self, complete_set_secret, NULL);
280 5 : return;
281 :
282 4 : case CKA_G_FIELDS:
283 4 : rv = gkm_secret_fields_parse (attr, &fields, &schema_name);
284 4 : if (rv != CKR_OK) {
285 0 : gkm_transaction_fail (transaction, rv);
286 : } else {
287 4 : begin_set_fields (self, transaction, fields);
288 4 : if (schema_name)
289 0 : begin_set_schema (self, transaction, schema_name);
290 : }
291 4 : return;
292 :
293 0 : case CKA_G_SCHEMA:
294 0 : rv = gkm_attribute_get_string (attr, &schema);
295 0 : if (rv != CKR_OK)
296 0 : gkm_transaction_fail (transaction, rv);
297 : else
298 0 : begin_set_schema (self, transaction, schema);
299 0 : return;
300 : }
301 :
302 5 : GKM_OBJECT_CLASS (gkm_secret_item_parent_class)->set_attribute (base, session, transaction, attr);
303 : }
304 :
305 : static void
306 2180 : gkm_secret_item_init (GkmSecretItem *self)
307 : {
308 :
309 2180 : }
310 :
311 : static GObject*
312 2180 : gkm_secret_item_constructor (GType type, guint n_props, GObjectConstructParam *props)
313 : {
314 2180 : GkmSecretItem *self = GKM_SECRET_ITEM (G_OBJECT_CLASS (gkm_secret_item_parent_class)->constructor(type, n_props, props));
315 2180 : g_return_val_if_fail (self, NULL);
316 :
317 2180 : g_return_val_if_fail (self->collection, NULL);
318 :
319 2180 : return G_OBJECT (self);
320 : }
321 :
322 : static void
323 2180 : gkm_secret_item_set_property (GObject *obj, guint prop_id, const GValue *value,
324 : GParamSpec *pspec)
325 : {
326 2180 : GkmSecretItem *self = GKM_SECRET_ITEM (obj);
327 :
328 2180 : switch (prop_id) {
329 2180 : case PROP_COLLECTION:
330 2180 : g_return_if_fail (!self->collection);
331 2180 : self->collection = g_value_get_object (value);
332 2180 : g_return_if_fail (self->collection);
333 2180 : g_object_add_weak_pointer (G_OBJECT (self->collection),
334 2180 : (gpointer*)&(self->collection));
335 2180 : break;
336 0 : case PROP_FIELDS:
337 0 : gkm_secret_item_set_fields (self, g_value_get_boxed (value));
338 0 : break;
339 0 : case PROP_SCHEMA:
340 0 : gkm_secret_item_set_schema (self, g_value_get_string (value));
341 0 : break;
342 0 : default:
343 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
344 0 : break;
345 : }
346 : }
347 :
348 : static void
349 0 : gkm_secret_item_get_property (GObject *obj, guint prop_id, GValue *value,
350 : GParamSpec *pspec)
351 : {
352 0 : GkmSecretItem *self = GKM_SECRET_ITEM (obj);
353 :
354 0 : switch (prop_id) {
355 0 : case PROP_COLLECTION:
356 0 : g_value_set_object (value, gkm_secret_item_get_collection (self));
357 0 : break;
358 0 : case PROP_FIELDS:
359 0 : g_value_set_boxed (value, gkm_secret_item_get_fields (self));
360 0 : break;
361 0 : case PROP_SCHEMA:
362 0 : g_value_set_string (value, gkm_secret_item_get_schema (self));
363 0 : break;
364 0 : default:
365 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
366 0 : break;
367 : }
368 0 : }
369 :
370 : static void
371 2180 : gkm_secret_item_dispose (GObject *obj)
372 : {
373 2180 : GkmSecretItem *self = GKM_SECRET_ITEM (obj);
374 :
375 2180 : if (self->collection)
376 172 : g_object_remove_weak_pointer (G_OBJECT (self->collection),
377 172 : (gpointer*)&(self->collection));
378 2180 : self->collection = NULL;
379 :
380 2180 : G_OBJECT_CLASS (gkm_secret_item_parent_class)->dispose (obj);
381 2180 : }
382 :
383 : static void
384 2180 : gkm_secret_item_finalize (GObject *obj)
385 : {
386 2180 : GkmSecretItem *self = GKM_SECRET_ITEM (obj);
387 :
388 2180 : g_assert (!self->collection);
389 :
390 2180 : if (self->fields)
391 2162 : g_hash_table_unref (self->fields);
392 2180 : self->fields = NULL;
393 :
394 2180 : g_free (self->schema);
395 2180 : self->schema = NULL;
396 :
397 2180 : G_OBJECT_CLASS (gkm_secret_item_parent_class)->finalize (obj);
398 2180 : }
399 :
400 : static void
401 29 : gkm_secret_item_class_init (GkmSecretItemClass *klass)
402 : {
403 29 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
404 29 : GkmObjectClass *gkm_class = GKM_OBJECT_CLASS (klass);
405 29 : GkmSecretObjectClass *secret_class = GKM_SECRET_OBJECT_CLASS (klass);
406 :
407 29 : gkm_secret_item_parent_class = g_type_class_peek_parent (klass);
408 :
409 29 : gobject_class->constructor = gkm_secret_item_constructor;
410 29 : gobject_class->dispose = gkm_secret_item_dispose;
411 29 : gobject_class->finalize = gkm_secret_item_finalize;
412 29 : gobject_class->set_property = gkm_secret_item_set_property;
413 29 : gobject_class->get_property = gkm_secret_item_get_property;
414 :
415 29 : gkm_class->get_attribute = gkm_secret_item_real_get_attribute;
416 29 : gkm_class->set_attribute = gkm_secret_item_real_set_attribute;
417 :
418 29 : secret_class->is_locked = gkm_secret_item_real_is_locked;
419 :
420 29 : g_object_class_install_property (gobject_class, PROP_COLLECTION,
421 : g_param_spec_object ("collection", "Collection", "Item's Collection",
422 : GKM_TYPE_SECRET_COLLECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
423 :
424 29 : g_object_class_install_property (gobject_class, PROP_FIELDS,
425 : g_param_spec_boxed ("fields", "Fields", "Item's fields",
426 : GKM_BOXED_SECRET_FIELDS, G_PARAM_READWRITE));
427 :
428 29 : g_object_class_install_property (gobject_class, PROP_SCHEMA,
429 : g_param_spec_string ("schema", "Schema", "Item's type or schema",
430 : NULL, G_PARAM_READWRITE));
431 29 : }
432 :
433 : /* -----------------------------------------------------------------------------
434 : * PUBLIC
435 : */
436 :
437 : GkmFactory*
438 111 : gkm_secret_item_get_factory (void)
439 : {
440 : static CK_OBJECT_CLASS klass = CKO_SECRET_KEY;
441 :
442 : static CK_ATTRIBUTE attributes[] = {
443 : { CKA_CLASS, &klass, sizeof (klass) },
444 : };
445 :
446 : static GkmFactory factory = {
447 : attributes,
448 : G_N_ELEMENTS (attributes),
449 : factory_create_item
450 : };
451 :
452 111 : return &factory;
453 : }
454 :
455 : GkmSecretCollection*
456 2077 : gkm_secret_item_get_collection (GkmSecretItem *self)
457 : {
458 2077 : g_return_val_if_fail (GKM_IS_SECRET_ITEM (self), NULL);
459 2077 : return self->collection;
460 : }
461 :
462 : GHashTable*
463 2110 : gkm_secret_item_get_fields (GkmSecretItem *self)
464 : {
465 2110 : g_return_val_if_fail (GKM_IS_SECRET_ITEM (self), NULL);
466 2110 : if (self->fields == NULL)
467 16 : self->fields = gkm_secret_fields_new ();
468 2110 : return self->fields;
469 : }
470 :
471 : void
472 2184 : gkm_secret_item_set_fields (GkmSecretItem *self, GHashTable *fields)
473 : {
474 2184 : g_return_if_fail (GKM_IS_SECRET_ITEM (self));
475 :
476 2184 : if (fields)
477 2184 : g_hash_table_ref (fields);
478 2184 : if (self->fields)
479 41 : g_hash_table_unref (self->fields);
480 2184 : self->fields = fields;
481 :
482 2184 : g_object_notify (G_OBJECT (self), "fields");
483 2184 : gkm_object_notify_attribute (GKM_OBJECT (self), CKA_G_FIELDS);
484 : }
485 :
486 : const gchar*
487 38 : gkm_secret_item_get_schema (GkmSecretItem *self)
488 : {
489 38 : g_return_val_if_fail (GKM_IS_SECRET_ITEM (self), NULL);
490 38 : return self->schema;
491 : }
492 :
493 : void
494 167 : gkm_secret_item_set_schema (GkmSecretItem *self, const gchar *schema)
495 : {
496 167 : g_return_if_fail (GKM_IS_SECRET_ITEM (self));
497 :
498 167 : if (schema != self->schema) {
499 167 : g_free (self->schema);
500 167 : self->schema = g_strdup (schema);
501 167 : g_object_notify (G_OBJECT (self), "schema");
502 167 : gkm_object_notify_attribute (GKM_OBJECT (self), CKA_G_SCHEMA);
503 : }
504 : }
|