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 "gkm-gnome2-file.h"
24 : #include "gkm-gnome2-private-key.h"
25 : #include "gkm-gnome2-public-key.h"
26 : #include "gkm-gnome2-storage.h"
27 :
28 : #include "gkm/gkm-certificate.h"
29 : #define DEBUG_FLAG GKM_DEBUG_STORAGE
30 : #include "gkm/gkm-debug.h"
31 : #include "gkm/gkm-data-asn1.h"
32 : #include "gkm/gkm-manager.h"
33 : #include "gkm/gkm-module.h"
34 : #include "gkm/gkm-secret.h"
35 : #include "gkm/gkm-serializable.h"
36 : #include "gkm/gkm-util.h"
37 :
38 : #include "egg/dotlock.h"
39 : #include "egg/egg-asn1x.h"
40 : #include "egg/egg-asn1-defs.h"
41 : #include "egg/egg-dn.h"
42 : #include "egg/egg-error.h"
43 : #include "egg/egg-hex.h"
44 :
45 : #include "pkcs11/pkcs11i.h"
46 :
47 : #include <glib/gstdio.h>
48 :
49 : #include <sys/file.h>
50 : #include <sys/stat.h>
51 : #include <errno.h>
52 : #include <fcntl.h>
53 : #include <unistd.h>
54 :
55 : enum {
56 : PROP_0,
57 : PROP_MODULE,
58 : PROP_DIRECTORY,
59 : PROP_MANAGER,
60 : PROP_LOGIN
61 : };
62 :
63 : struct _GkmGnome2Storage {
64 : GkmStore parent;
65 :
66 : GkmModule *module;
67 : GkmManager *manager;
68 :
69 : /* Information about file data */
70 : gchar *directory;
71 : gchar *filename;
72 : GkmGnome2File *file;
73 : time_t last_mtime;
74 : GkmSecret *login;
75 :
76 : /* Mapping of objects loaded */
77 : GHashTable *object_to_identifier;
78 : GHashTable *identifier_to_object;
79 :
80 : /* Valid when in write state */
81 : GkmTransaction *transaction;
82 : gchar *write_path;
83 : gint write_fd;
84 : gint read_fd;
85 : };
86 :
87 486 : G_DEFINE_TYPE (GkmGnome2Storage, gkm_gnome2_storage, GKM_TYPE_STORE);
88 :
89 : #define LOCK_TIMEOUT 4000 /*(4 seconds)*/
90 :
91 : #define UNWANTED_IDENTIFIER_CHARS ":/\\<>|\t\n\r\v "
92 :
93 : static gchar*
94 4 : name_for_subject (const guchar *subject,
95 : gsize n_subject)
96 : {
97 : GNode *asn;
98 : gchar *name;
99 : GBytes *bytes;
100 :
101 4 : g_assert (subject);
102 4 : g_assert (n_subject);
103 :
104 4 : bytes = g_bytes_new (subject, n_subject);
105 4 : asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Name", bytes);
106 4 : g_return_val_if_fail (asn != NULL, NULL);
107 4 : g_bytes_unref (bytes);
108 :
109 4 : name = egg_dn_read_part (egg_asn1x_node (asn, "rdnSequence", NULL), "CN");
110 4 : egg_asn1x_destroy (asn);
111 :
112 4 : return name;
113 : }
114 :
115 : static gchar*
116 5 : identifier_for_object (GkmObject *object)
117 : {
118 : GkmSerializableIface *serial;
119 : const gchar *ext;
120 : gchar *identifier;
121 5 : gchar *name = NULL;
122 : guchar *data;
123 : gsize n_data;
124 :
125 5 : g_assert (GKM_IS_OBJECT (object));
126 5 : g_assert (GKM_IS_SERIALIZABLE (object));
127 :
128 : /* Figure out the extension and prefix */
129 5 : serial = GKM_SERIALIZABLE_GET_INTERFACE (object);
130 5 : ext = serial->extension;
131 5 : g_return_val_if_fail (ext, NULL);
132 :
133 : /* First we try to use the CN of a subject */
134 5 : data = gkm_object_get_attribute_data (object, NULL, CKA_SUBJECT, &n_data);
135 5 : if (data && n_data)
136 4 : name = name_for_subject (data, n_data);
137 5 : g_free (data);
138 :
139 : /* Next we try hex encoding the ID */
140 5 : if (name == NULL) {
141 1 : data = gkm_object_get_attribute_data (object, NULL, CKA_ID, &n_data);
142 1 : if (data && n_data)
143 1 : name = egg_hex_encode (data, n_data);
144 1 : g_free (data);
145 : }
146 :
147 : /* Build up the identifier */
148 5 : identifier = g_strconcat (name, ext, NULL);
149 5 : g_strdelimit (identifier, UNWANTED_IDENTIFIER_CHARS, '_');
150 :
151 5 : g_free (name);
152 5 : return identifier;
153 : }
154 :
155 : static GType
156 4 : type_from_extension (const gchar *extension)
157 : {
158 4 : g_assert (extension);
159 :
160 4 : if (strcmp (extension, ".pkcs8") == 0)
161 0 : return GKM_TYPE_GNOME2_PRIVATE_KEY;
162 4 : else if (strcmp (extension, ".pub") == 0)
163 0 : return GKM_TYPE_GNOME2_PUBLIC_KEY;
164 4 : else if (strcmp (extension, ".cer") == 0)
165 4 : return GKM_TYPE_CERTIFICATE;
166 :
167 0 : return 0;
168 : }
169 :
170 :
171 : static GType
172 4 : type_from_identifier (const gchar *identifier)
173 : {
174 : const gchar *ext;
175 :
176 4 : g_assert (identifier);
177 :
178 4 : ext = strrchr (identifier, '.');
179 4 : if (ext == NULL)
180 0 : return 0;
181 :
182 4 : return type_from_extension (ext);
183 : }
184 :
185 : static dotlock_t
186 32 : lock_and_open_file (const gchar *filename,
187 : gint flags)
188 : {
189 : dotlock_t lockh;
190 32 : gint fd = -1;
191 :
192 : /*
193 : * In this function we don't actually put the object into a 'write' state,
194 : * that's the callers job if necessary.
195 : */
196 :
197 32 : fd = open (filename, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR);
198 32 : if (fd == -1) {
199 0 : g_message ("couldn't open store file: %s: %s",
200 : filename, g_strerror (errno));
201 0 : return NULL;
202 : }
203 :
204 32 : lockh = dotlock_create (filename, 0);
205 32 : if (!lockh) {
206 0 : g_message ("couldn't create lock for store file: %s: %s",
207 : filename, g_strerror (errno));
208 0 : close (fd);
209 0 : return NULL;
210 : }
211 :
212 32 : if (dotlock_take (lockh, LOCK_TIMEOUT)) {
213 0 : if (errno == EACCES)
214 0 : g_message ("couldn't write to store file:"
215 : " %s: file is locked", filename);
216 : else
217 0 : g_message ("couldn't lock store file: %s: %s",
218 : filename, g_strerror (errno));
219 0 : dotlock_destroy (lockh);
220 0 : close (fd);
221 0 : return NULL;
222 : }
223 :
224 : /* Successfully opened file */;
225 32 : dotlock_set_fd (lockh, fd);
226 32 : return lockh;
227 : }
228 :
229 : static gboolean
230 10 : complete_lock_file (GkmTransaction *transaction, GObject *object, gpointer data)
231 : {
232 10 : GkmGnome2Storage *self = GKM_GNOME2_STORAGE (object);
233 10 : dotlock_t lockh = data;
234 10 : int fd = dotlock_get_fd (lockh);
235 :
236 10 : gkm_debug ("closing: %s", self->filename);
237 :
238 : /*
239 : * Note that there is no error checking for release and
240 : * destroy. These functions will log errors anyway and we
241 : * can't do much else than logging those errors.
242 : */
243 10 : dotlock_release (lockh);
244 10 : dotlock_destroy (lockh);
245 10 : close (fd);
246 :
247 : /* Completed successfully */
248 10 : return TRUE;
249 : }
250 :
251 : static gint
252 10 : begin_lock_file (GkmGnome2Storage *self, GkmTransaction *transaction)
253 : {
254 : dotlock_t lockh;
255 :
256 : /*
257 : * In this function we don't actually put the object into a 'write' state,
258 : * that's the callers job if necessary.
259 : */
260 :
261 10 : g_assert (GKM_IS_GNOME2_STORAGE (self));
262 10 : g_assert (GKM_IS_TRANSACTION (transaction));
263 :
264 10 : g_return_val_if_fail (!gkm_transaction_get_failed (transaction), -1);
265 10 : gkm_debug ("modifying: %s", self->filename);
266 :
267 10 : lockh = lock_and_open_file (self->filename, O_RDONLY | O_CREAT);
268 10 : if (!lockh) {
269 0 : gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
270 0 : return -1;
271 : }
272 :
273 : /* Successfully opened file */;
274 10 : gkm_transaction_add (transaction, self, complete_lock_file, lockh);
275 10 : return dotlock_get_fd (lockh);
276 : }
277 :
278 : static gboolean
279 10 : complete_write_state (GkmTransaction *transaction, GObject *object, gpointer unused)
280 : {
281 10 : GkmGnome2Storage *self = GKM_GNOME2_STORAGE (object);
282 10 : gboolean ret = TRUE;
283 : struct stat sb;
284 :
285 10 : g_return_val_if_fail (GKM_IS_GNOME2_STORAGE (object), FALSE);
286 10 : g_return_val_if_fail (GKM_IS_TRANSACTION (transaction), FALSE);
287 10 : g_return_val_if_fail (self->transaction == transaction, FALSE);
288 :
289 10 : if (!gkm_transaction_get_failed (transaction)) {
290 : /* Transaction succeeded, overwrite the old with the new */
291 :
292 9 : if (g_rename (self->write_path, self->filename) == -1) {
293 0 : g_warning ("couldn't rename temporary store file: %s", self->write_path);
294 0 : ret = FALSE;
295 : } else {
296 9 : if (fstat (self->write_fd, &sb) >= 0)
297 9 : self->last_mtime = sb.st_mtime;
298 : }
299 : } else {
300 : /* Transaction failed, remove temporary file */
301 1 : if (g_unlink (self->write_path) == -1)
302 0 : g_warning ("couldn't delete temporary store file: %s", self->write_path);
303 : }
304 :
305 : /* read_fd is closed by complete_lock_file */
306 :
307 10 : if (self->write_fd != -1)
308 10 : close (self->write_fd);
309 10 : self->write_fd = -1;
310 :
311 10 : g_free (self->write_path);
312 10 : self->write_path = NULL;
313 :
314 10 : g_object_unref (self->transaction);
315 10 : self->transaction = NULL;
316 :
317 10 : return ret;
318 : }
319 :
320 : static gboolean
321 10 : begin_write_state (GkmGnome2Storage *self, GkmTransaction *transaction)
322 : {
323 10 : g_assert (GKM_IS_GNOME2_STORAGE (self));
324 10 : g_assert (GKM_IS_TRANSACTION (transaction));
325 :
326 10 : g_return_val_if_fail (!gkm_transaction_get_failed (transaction), FALSE);
327 :
328 : /* Already in write state for this transaction? */
329 10 : if (self->transaction != NULL) {
330 0 : g_return_val_if_fail (self->transaction == transaction, FALSE);
331 0 : return TRUE;
332 : }
333 :
334 : /* Lock file for the transaction */
335 10 : self->read_fd = begin_lock_file (self, transaction);
336 10 : if (self->read_fd == -1)
337 0 : return FALSE;
338 :
339 10 : gkm_transaction_add (transaction, self, complete_write_state, NULL);
340 10 : self->transaction = g_object_ref (transaction);
341 :
342 : /* Open the new file */
343 10 : g_assert (self->write_fd == -1);
344 10 : self->write_path = g_strdup_printf ("%s.XXXXXX", self->filename);
345 10 : self->write_fd = g_mkstemp (self->write_path);
346 10 : if (self->write_fd == -1) {
347 0 : g_message ("couldn't open new temporary store file: %s: %s", self->write_path, g_strerror (errno));
348 0 : gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
349 0 : return FALSE;
350 : }
351 :
352 10 : return TRUE;
353 : }
354 :
355 : static gboolean
356 6 : complete_modification_state (GkmTransaction *transaction, GObject *object, gpointer unused)
357 : {
358 6 : GkmGnome2Storage *self = GKM_GNOME2_STORAGE (object);
359 : GkmDataResult res;
360 :
361 6 : if (!gkm_transaction_get_failed (transaction)) {
362 5 : res = gkm_gnome2_file_write_fd (self->file, self->write_fd, self->login);
363 5 : switch(res) {
364 0 : case GKM_DATA_FAILURE:
365 : case GKM_DATA_UNRECOGNIZED:
366 0 : g_warning ("couldn't write to temporary store file: %s", self->write_path);
367 0 : return FALSE;
368 0 : case GKM_DATA_LOCKED:
369 0 : g_warning ("couldn't encrypt temporary store file: %s", self->write_path);
370 0 : return FALSE;
371 5 : case GKM_DATA_SUCCESS:
372 5 : break;
373 0 : default:
374 0 : g_assert_not_reached ();
375 : }
376 : }
377 :
378 6 : return TRUE;
379 : }
380 :
381 : static gboolean
382 9 : begin_modification_state (GkmGnome2Storage *self, GkmTransaction *transaction)
383 : {
384 : GkmDataResult res;
385 9 : CK_RV rv = CKR_OK;
386 :
387 : /* Already in write state for this transaction? */
388 9 : if (self->transaction != NULL) {
389 3 : g_return_val_if_fail (self->transaction == transaction, FALSE);
390 3 : return TRUE;
391 : }
392 :
393 6 : if (!begin_write_state (self, transaction))
394 0 : return FALSE;
395 :
396 : /* See if file needs updating */
397 6 : res = gkm_gnome2_file_read_fd (self->file, self->read_fd, self->login);
398 6 : switch (res) {
399 0 : case GKM_DATA_FAILURE:
400 0 : g_message ("failure updating user store file: %s", self->filename);
401 0 : rv = CKR_FUNCTION_FAILED;
402 0 : break;
403 0 : case GKM_DATA_LOCKED:
404 0 : rv = CKR_USER_NOT_LOGGED_IN;
405 0 : break;
406 0 : case GKM_DATA_UNRECOGNIZED:
407 0 : g_message ("unrecognized or invalid user store file: %s", self->filename);
408 0 : rv = CKR_FUNCTION_FAILED;
409 0 : break;
410 6 : case GKM_DATA_SUCCESS:
411 6 : rv = CKR_OK;
412 6 : break;
413 0 : default:
414 0 : g_assert_not_reached ();
415 : break;
416 : }
417 :
418 6 : if (rv != CKR_OK) {
419 0 : gkm_transaction_fail (transaction, rv);
420 0 : return FALSE;
421 : }
422 :
423 : /* Write out the data once completed with modifications */
424 6 : gkm_transaction_add (transaction, self, complete_modification_state, NULL);
425 :
426 6 : return TRUE;
427 : }
428 :
429 : static void
430 9 : take_object_ownership (GkmGnome2Storage *self, const gchar *identifier, GkmObject *object)
431 : {
432 : gchar *str;
433 :
434 9 : g_assert (GKM_IS_GNOME2_STORAGE (self));
435 9 : g_assert (GKM_IS_OBJECT (object));
436 :
437 9 : g_assert (g_hash_table_lookup (self->identifier_to_object, identifier) == NULL);
438 9 : g_assert (g_hash_table_lookup (self->object_to_identifier, object) == NULL);
439 :
440 9 : str = g_strdup (identifier);
441 9 : object = g_object_ref (object);
442 :
443 9 : g_hash_table_replace (self->identifier_to_object, str, object);
444 9 : g_hash_table_replace (self->object_to_identifier, object, str);;
445 :
446 9 : g_object_set (object, "store", self, NULL);
447 9 : gkm_object_expose (object, TRUE);
448 9 : }
449 :
450 : static gboolean
451 4 : check_object_hash (GkmGnome2Storage *self, const gchar *identifier, const guchar *data, gsize n_data)
452 : {
453 : gconstpointer value;
454 : GkmDataResult res;
455 : gboolean result;
456 : gsize n_value;
457 : gchar *digest;
458 :
459 4 : g_assert (GKM_IS_GNOME2_STORAGE (self));
460 4 : g_assert (identifier);
461 4 : g_assert (data);
462 :
463 4 : digest = g_compute_checksum_for_data (G_CHECKSUM_SHA1, data, n_data);
464 4 : g_return_val_if_fail (digest, FALSE);
465 :
466 4 : res = gkm_gnome2_file_read_value (self->file, identifier, CKA_GNOME_INTERNAL_SHA1, &value, &n_value);
467 4 : g_return_val_if_fail (res == GKM_DATA_SUCCESS, FALSE);
468 :
469 4 : result = (strlen (digest) == n_value && memcmp (digest, value, n_value) == 0);
470 4 : g_free (digest);
471 :
472 4 : return result;
473 : }
474 :
475 : static void
476 5 : store_object_hash (GkmGnome2Storage *self, GkmTransaction *transaction, const gchar *identifier,
477 : const guchar *data, gsize n_data)
478 : {
479 : GkmDataResult res;
480 : gchar *digest;
481 :
482 5 : g_assert (GKM_IS_GNOME2_STORAGE (self));
483 5 : g_assert (GKM_IS_TRANSACTION (transaction));
484 5 : g_assert (identifier);
485 5 : g_assert (data);
486 :
487 5 : digest = g_compute_checksum_for_data (G_CHECKSUM_SHA1, data, n_data);
488 5 : if (digest == NULL) {
489 0 : gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
490 0 : g_return_if_reached ();
491 : }
492 :
493 5 : res = gkm_gnome2_file_write_value (self->file, identifier, CKA_GNOME_INTERNAL_SHA1, digest, strlen (digest));
494 5 : g_free (digest);
495 :
496 5 : if (res != GKM_DATA_SUCCESS)
497 0 : gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
498 : }
499 :
500 : static void
501 4 : data_file_entry_added (GkmGnome2File *store, const gchar *identifier, GkmGnome2Storage *self)
502 : {
503 4 : GError *error = NULL;
504 : GkmObject *object;
505 : GBytes *bytes;
506 : gboolean ret;
507 : guchar *data;
508 : gsize n_data;
509 : GType type;
510 : gchar *path;
511 :
512 4 : g_return_if_fail (GKM_IS_GNOME2_STORAGE (self));
513 4 : g_return_if_fail (identifier);
514 :
515 : /* Already have this object? */
516 4 : object = g_hash_table_lookup (self->identifier_to_object, identifier);
517 4 : if (object != NULL)
518 0 : return;
519 :
520 : /* Figure out what type of object we're dealing with */
521 4 : type = type_from_identifier (identifier);
522 4 : if (type == 0) {
523 0 : g_warning ("don't know how to load file in user store: %s", identifier);
524 0 : return;
525 : }
526 :
527 : /* Read the file in */
528 4 : path = g_build_filename (self->directory, identifier, NULL);
529 4 : ret = g_file_get_contents (path, (gchar**)&data, &n_data, &error);
530 4 : g_free (path);
531 :
532 4 : if (ret == FALSE) {
533 0 : g_warning ("couldn't read file in user store: %s: %s", identifier,
534 : egg_error_message (error));
535 0 : g_clear_error (&error);
536 0 : return;
537 : }
538 :
539 : /* Make sure that the object wasn't tampered with */
540 4 : if (!check_object_hash (self, identifier, data, n_data)) {
541 0 : g_message ("file in user store doesn't match hash: %s", identifier);
542 0 : g_free (data);
543 0 : return;
544 : }
545 :
546 : /* Create a new object for this identifier */
547 4 : object = g_object_new (type, "unique", identifier, "module", self->module,
548 : "manager", gkm_module_get_manager (self->module), NULL);
549 4 : g_return_if_fail (GKM_IS_SERIALIZABLE (object));
550 4 : g_return_if_fail (GKM_SERIALIZABLE_GET_INTERFACE (object)->extension);
551 :
552 4 : bytes = g_bytes_new_take (data, n_data);
553 :
554 : /* And load the data into it */
555 4 : if (gkm_serializable_load (GKM_SERIALIZABLE (object), self->login, bytes))
556 4 : take_object_ownership (self, identifier, object);
557 : else
558 0 : g_message ("failed to load file in user store: %s", identifier);
559 :
560 4 : g_bytes_unref (bytes);
561 4 : g_object_unref (object);
562 : }
563 :
564 : static void
565 9 : data_file_entry_changed (GkmGnome2File *store, const gchar *identifier, CK_ATTRIBUTE_TYPE type, GkmGnome2Storage *self)
566 : {
567 : GkmObject *object;
568 :
569 9 : g_return_if_fail (GKM_IS_GNOME2_STORAGE (self));
570 9 : g_return_if_fail (identifier);
571 :
572 9 : object = g_hash_table_lookup (self->identifier_to_object, identifier);
573 9 : if (object != NULL)
574 4 : gkm_object_notify_attribute (object, type);
575 : }
576 :
577 : static void
578 0 : data_file_entry_removed (GkmGnome2File *store, const gchar *identifier, GkmGnome2Storage *self)
579 : {
580 : GkmObject *object;
581 :
582 0 : g_return_if_fail (GKM_IS_GNOME2_STORAGE (self));
583 0 : g_return_if_fail (identifier);
584 :
585 0 : object = g_hash_table_lookup (self->identifier_to_object, identifier);
586 0 : if (object != NULL) {
587 0 : g_object_set (object, "store", NULL, NULL);
588 :
589 : /* Unrefs and also disposes the object, which unregisters from manager*/
590 0 : g_hash_table_remove (self->identifier_to_object, identifier);
591 0 : g_hash_table_remove (self->object_to_identifier, object);
592 : }
593 : }
594 :
595 : static void
596 0 : relock_object (GkmGnome2Storage *self, GkmTransaction *transaction, const gchar *path,
597 : const gchar *identifier, GkmSecret *old_login, GkmSecret *new_login)
598 : {
599 0 : GError *error = NULL;
600 : GkmObject *object;
601 : GBytes *bytes;
602 : gpointer data;
603 : gsize n_data;
604 : GType type;
605 :
606 0 : g_assert (GKM_IS_GNOME2_STORAGE (self));
607 0 : g_assert (GKM_IS_TRANSACTION (transaction));
608 0 : g_assert (identifier);
609 0 : g_assert (path);
610 :
611 0 : g_assert (!gkm_transaction_get_failed (transaction));
612 :
613 : /* Figure out the type of object */
614 0 : type = type_from_identifier (identifier);
615 0 : if (type == 0) {
616 0 : g_warning ("don't know how to relock file in user store: %s", identifier);
617 0 : gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
618 0 : return;
619 : }
620 :
621 : /* Create a dummy object for this identifier */
622 0 : object = g_object_new (type, "unique", identifier, "module", self->module, NULL);
623 0 : if (!GKM_IS_SERIALIZABLE (object)) {
624 0 : g_warning ("cannot relock unserializable object for file in user store: %s", identifier);
625 0 : gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
626 0 : return;
627 : }
628 :
629 : /* Read in the data for the object */
630 0 : if (!g_file_get_contents (path, (gchar**)&data, &n_data, &error)) {
631 0 : g_message ("couldn't load file in user store in order to relock: %s: %s", identifier,
632 : egg_error_message (error));
633 0 : g_clear_error (&error);
634 0 : g_object_unref (object);
635 0 : gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
636 0 : return;
637 : }
638 :
639 : /* Make sure the data matches the hash */
640 0 : if (!check_object_hash (self, identifier, data, n_data)) {
641 0 : g_message ("file in data store doesn't match hash: %s", identifier);
642 0 : gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
643 0 : g_free (data);
644 0 : return;
645 : }
646 :
647 0 : bytes = g_bytes_new_take (data, n_data);
648 :
649 : /* Load it into our temporary object */
650 0 : if (!gkm_serializable_load (GKM_SERIALIZABLE (object), old_login, bytes)) {
651 0 : g_message ("unrecognized or invalid user store file: %s", identifier);
652 0 : gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
653 0 : g_bytes_unref (bytes);
654 0 : g_object_unref (object);
655 0 : return;
656 : }
657 :
658 0 : g_bytes_unref (bytes);
659 :
660 : /* Read it out of our temporary object */
661 0 : bytes = gkm_serializable_save (GKM_SERIALIZABLE (object), new_login);
662 0 : if (bytes == NULL) {
663 0 : g_warning ("unable to serialize data with new login: %s", identifier);
664 0 : gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
665 0 : g_object_unref (object);
666 0 : g_free (data);
667 0 : return;
668 : }
669 :
670 0 : g_object_unref (object);
671 :
672 : /* And write it back out to the file */
673 0 : gkm_transaction_write_file (transaction, path, data, n_data);
674 :
675 : /* Create and save the hash here */
676 0 : if (!gkm_transaction_get_failed (transaction))
677 0 : store_object_hash (self, transaction, identifier, data, n_data);
678 :
679 0 : g_bytes_unref (bytes);
680 : }
681 :
682 : typedef struct _RelockArgs {
683 : GkmGnome2Storage *self;
684 : GkmTransaction *transaction;
685 : GkmSecret *old_login;
686 : GkmSecret *new_login;
687 : } RelockArgs;
688 :
689 : static void
690 1 : relock_each_object (GkmGnome2File *file, const gchar *identifier, gpointer data)
691 : {
692 1 : RelockArgs *args = data;
693 : gchar *path;
694 : guint section;
695 :
696 1 : g_assert (GKM_IS_GNOME2_STORAGE (args->self));
697 1 : if (gkm_transaction_get_failed (args->transaction))
698 1 : return;
699 :
700 1 : if (!gkm_gnome2_file_lookup_entry (file, identifier, §ion))
701 0 : g_return_if_reached ();
702 :
703 : /* Only operate on private files */
704 1 : if (section != GKM_GNOME2_FILE_SECTION_PRIVATE)
705 1 : return;
706 :
707 0 : path = g_build_filename (args->self->directory, identifier, NULL);
708 0 : relock_object (args->self, args->transaction, path, identifier, args->old_login, args->new_login);
709 0 : g_free (path);
710 : }
711 :
712 : static CK_RV
713 22 : refresh_with_login (GkmGnome2Storage *self, GkmSecret *login)
714 : {
715 : GkmDataResult res;
716 : dotlock_t lockh;
717 : struct stat sb;
718 : CK_RV rv;
719 : int fd;
720 :
721 22 : g_assert (GKM_GNOME2_STORAGE (self));
722 22 : gkm_debug ("refreshing: %s", self->filename);
723 :
724 : /* Open the file for reading */
725 22 : lockh = lock_and_open_file (self->filename, O_RDONLY);
726 22 : if (!lockh) {
727 : /* No file, no worries */
728 0 : if (errno == ENOENT)
729 0 : return login ? CKR_USER_PIN_NOT_INITIALIZED : CKR_OK;
730 0 : g_message ("couldn't open store file: %s: %s", self->filename, g_strerror (errno));
731 0 : return CKR_FUNCTION_FAILED;
732 : }
733 :
734 22 : fd = dotlock_get_fd (lockh);
735 :
736 : /* Try and update the last read time */
737 22 : if (fstat (fd, &sb) >= 0)
738 22 : self->last_mtime = sb.st_mtime;
739 :
740 22 : res = gkm_gnome2_file_read_fd (self->file, fd, login);
741 22 : switch (res) {
742 0 : case GKM_DATA_FAILURE:
743 0 : g_message ("failure reading from file: %s", self->filename);
744 0 : rv = CKR_FUNCTION_FAILED;
745 0 : break;
746 0 : case GKM_DATA_LOCKED:
747 0 : rv = CKR_USER_NOT_LOGGED_IN;
748 0 : break;
749 0 : case GKM_DATA_UNRECOGNIZED:
750 0 : g_message ("unrecognized or invalid user store file: %s", self->filename);
751 0 : rv = CKR_FUNCTION_FAILED;
752 0 : break;
753 22 : case GKM_DATA_SUCCESS:
754 22 : rv = CKR_OK;
755 22 : break;
756 0 : default:
757 0 : g_assert_not_reached ();
758 : break;
759 : }
760 :
761 : /* Force a reread on next write */
762 22 : if (rv == CKR_FUNCTION_FAILED)
763 0 : self->last_mtime = 0;
764 :
765 22 : gkm_debug ("closing: %s", self->filename);
766 :
767 : /*
768 : * Note that there is no error checking for release and
769 : * destroy. These functions will log errors anyway and we
770 : * can't do much else than logging those errors.
771 : */
772 22 : dotlock_release (lockh);
773 22 : dotlock_destroy (lockh);
774 22 : close (fd);
775 :
776 22 : return rv;
777 : }
778 :
779 : /* -----------------------------------------------------------------------------
780 : * OBJECT
781 : */
782 :
783 : static CK_RV
784 3 : gkm_gnome2_storage_real_read_value (GkmStore *base, GkmObject *object, CK_ATTRIBUTE_PTR attr)
785 : {
786 3 : GkmGnome2Storage *self = GKM_GNOME2_STORAGE (base);
787 : const gchar *identifier;
788 : GkmDataResult res;
789 : gconstpointer value;
790 : gsize n_value;
791 : CK_RV rv;
792 :
793 3 : g_return_val_if_fail (GKM_IS_GNOME2_STORAGE (self), CKR_GENERAL_ERROR);
794 3 : g_return_val_if_fail (GKM_IS_OBJECT (object), CKR_GENERAL_ERROR);
795 3 : g_return_val_if_fail (attr, CKR_GENERAL_ERROR);
796 :
797 3 : if (self->last_mtime == 0) {
798 0 : rv = gkm_gnome2_storage_refresh (self);
799 0 : if (rv != CKR_OK)
800 0 : return rv;
801 : }
802 :
803 3 : identifier = g_hash_table_lookup (self->object_to_identifier, object);
804 3 : if (!identifier) {
805 0 : gkm_debug ("CKR_ATTRIBUTE_TYPE_INVALID: object not stored in gnome2 storage");
806 0 : return CKR_ATTRIBUTE_TYPE_INVALID;
807 : }
808 :
809 3 : res = gkm_gnome2_file_read_value (self->file, identifier, attr->type, &value, &n_value);
810 3 : switch (res) {
811 0 : case GKM_DATA_FAILURE:
812 0 : g_return_val_if_reached (CKR_GENERAL_ERROR);
813 1 : case GKM_DATA_UNRECOGNIZED:
814 1 : gkm_debug ("CKR_ATTRIBUTE_TYPE_INVALID: attribute %s not present",
815 : gkm_log_attr_type (attr->type));
816 1 : return CKR_ATTRIBUTE_TYPE_INVALID;
817 0 : case GKM_DATA_LOCKED:
818 0 : return CKR_USER_NOT_LOGGED_IN;
819 2 : case GKM_DATA_SUCCESS:
820 : /* Yes, we don't fill a buffer, just return pointer */
821 2 : attr->pValue = (CK_VOID_PTR)value;
822 2 : attr->ulValueLen = n_value;
823 2 : return CKR_OK;
824 0 : default:
825 0 : g_assert_not_reached ();
826 : }
827 : }
828 :
829 : static void
830 4 : gkm_gnome2_storage_real_write_value (GkmStore *base, GkmTransaction *transaction, GkmObject *object, CK_ATTRIBUTE_PTR attr)
831 : {
832 4 : GkmGnome2Storage *self = GKM_GNOME2_STORAGE (base);
833 : const gchar *identifier;
834 : GkmDataResult res;
835 : CK_RV rv;
836 :
837 4 : g_return_if_fail (GKM_IS_GNOME2_STORAGE (self));
838 4 : g_return_if_fail (GKM_IS_OBJECT (object));
839 4 : g_return_if_fail (GKM_IS_TRANSACTION (transaction));
840 4 : g_return_if_fail (!gkm_transaction_get_failed (transaction));
841 4 : g_return_if_fail (attr);
842 :
843 4 : if (!begin_modification_state (self, transaction))
844 0 : return;
845 :
846 4 : identifier = g_hash_table_lookup (self->object_to_identifier, object);
847 4 : if (!identifier) {
848 0 : gkm_transaction_fail (transaction, CKR_ATTRIBUTE_READ_ONLY);
849 0 : return;
850 : }
851 :
852 4 : res = gkm_gnome2_file_write_value (self->file, identifier, attr->type, attr->pValue, attr->ulValueLen);
853 4 : switch (res) {
854 0 : case GKM_DATA_FAILURE:
855 0 : rv = CKR_FUNCTION_FAILED;
856 0 : break;
857 0 : case GKM_DATA_UNRECOGNIZED:
858 0 : rv = CKR_ATTRIBUTE_READ_ONLY;
859 0 : break;
860 0 : case GKM_DATA_LOCKED:
861 0 : rv = CKR_USER_NOT_LOGGED_IN;
862 0 : break;
863 4 : case GKM_DATA_SUCCESS:
864 4 : rv = CKR_OK;
865 4 : break;
866 0 : default:
867 0 : g_assert_not_reached ();
868 : }
869 :
870 4 : if (rv != CKR_OK)
871 0 : gkm_transaction_fail (transaction, rv);
872 : }
873 :
874 : static GObject*
875 38 : gkm_gnome2_storage_constructor (GType type, guint n_props, GObjectConstructParam *props)
876 : {
877 38 : GkmGnome2Storage *self = GKM_GNOME2_STORAGE (G_OBJECT_CLASS (gkm_gnome2_storage_parent_class)->constructor(type, n_props, props));
878 : CK_ATTRIBUTE attr;
879 :
880 38 : g_return_val_if_fail (self, NULL);
881 :
882 38 : g_return_val_if_fail (self->directory, NULL);
883 38 : self->filename = g_build_filename (self->directory, "user.keystore", NULL);
884 :
885 38 : g_return_val_if_fail (self->manager, NULL);
886 38 : g_return_val_if_fail (self->module, NULL);
887 :
888 : /* Register store attributes */
889 38 : attr.type = CKA_LABEL;
890 38 : attr.pValue = "";
891 38 : attr.ulValueLen = 0;
892 :
893 38 : gkm_store_register_schema (GKM_STORE (self), &attr, NULL, 0);
894 :
895 38 : return G_OBJECT (self);
896 : }
897 :
898 : static void
899 38 : gkm_gnome2_storage_init (GkmGnome2Storage *self)
900 : {
901 38 : self->file = gkm_gnome2_file_new ();
902 38 : g_signal_connect (self->file, "entry-added", G_CALLBACK (data_file_entry_added), self);
903 38 : g_signal_connect (self->file, "entry-changed", G_CALLBACK (data_file_entry_changed), self);
904 38 : g_signal_connect (self->file, "entry-removed", G_CALLBACK (data_file_entry_removed), self);
905 :
906 : /* Each one owns the key and contains weak ref to other's key as its value */
907 38 : self->object_to_identifier = g_hash_table_new_full (g_direct_hash, g_direct_equal, gkm_util_dispose_unref, NULL);
908 38 : self->identifier_to_object = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
909 :
910 38 : self->read_fd = -1;
911 38 : self->write_fd = -1;
912 38 : }
913 :
914 : static void
915 38 : gkm_gnome2_storage_dispose (GObject *obj)
916 : {
917 38 : GkmGnome2Storage *self = GKM_GNOME2_STORAGE (obj);
918 :
919 38 : if (self->manager)
920 38 : g_object_unref (self->manager);
921 38 : self->manager = NULL;
922 :
923 38 : if (self->login)
924 1 : g_object_unref (self->login);
925 38 : self->login = NULL;
926 :
927 38 : g_signal_handlers_disconnect_by_func (self->file, data_file_entry_added, self);
928 38 : g_signal_handlers_disconnect_by_func (self->file, data_file_entry_changed, self);
929 38 : g_signal_handlers_disconnect_by_func (self->file, data_file_entry_removed, self);
930 :
931 38 : g_hash_table_remove_all (self->object_to_identifier);
932 38 : g_hash_table_remove_all (self->identifier_to_object);
933 :
934 38 : G_OBJECT_CLASS (gkm_gnome2_storage_parent_class)->dispose (obj);
935 38 : }
936 :
937 : static void
938 38 : gkm_gnome2_storage_finalize (GObject *obj)
939 : {
940 38 : GkmGnome2Storage *self = GKM_GNOME2_STORAGE (obj);
941 :
942 38 : g_assert (self->file);
943 38 : g_object_unref (self->file);
944 38 : self->file = NULL;
945 :
946 38 : g_free (self->filename);
947 38 : self->filename = NULL;
948 :
949 38 : g_assert (self->directory);
950 38 : g_free (self->directory);
951 38 : self->directory = NULL;
952 :
953 38 : g_assert (self->object_to_identifier);
954 38 : g_hash_table_destroy (self->object_to_identifier);
955 38 : g_hash_table_destroy (self->identifier_to_object);
956 :
957 38 : G_OBJECT_CLASS (gkm_gnome2_storage_parent_class)->finalize (obj);
958 38 : }
959 :
960 : static void
961 114 : gkm_gnome2_storage_set_property (GObject *obj, guint prop_id, const GValue *value,
962 : GParamSpec *pspec)
963 : {
964 114 : GkmGnome2Storage *self = GKM_GNOME2_STORAGE (obj);
965 :
966 114 : switch (prop_id) {
967 38 : case PROP_DIRECTORY:
968 38 : g_return_if_fail (!self->directory);
969 38 : self->directory = g_value_dup_string (value);
970 38 : g_return_if_fail (self->directory);
971 38 : break;
972 38 : case PROP_MODULE:
973 38 : g_return_if_fail (!self->module);
974 38 : self->module = g_value_get_object (value);
975 38 : break;
976 38 : case PROP_MANAGER:
977 38 : g_return_if_fail (!self->manager);
978 38 : self->manager = g_value_dup_object (value);
979 38 : g_return_if_fail (self->manager);
980 38 : break;
981 0 : default:
982 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
983 0 : break;
984 : }
985 : }
986 :
987 : static void
988 0 : gkm_gnome2_storage_get_property (GObject *obj, guint prop_id, GValue *value,
989 : GParamSpec *pspec)
990 : {
991 0 : GkmGnome2Storage *self = GKM_GNOME2_STORAGE (obj);
992 :
993 0 : switch (prop_id) {
994 0 : case PROP_DIRECTORY:
995 0 : g_value_set_string (value, gkm_gnome2_storage_get_directory (self));
996 0 : break;
997 0 : case PROP_MODULE:
998 0 : g_value_set_object (value, self->module);
999 0 : break;
1000 0 : case PROP_MANAGER:
1001 0 : g_value_set_object (value, gkm_gnome2_storage_get_manager (self));
1002 0 : break;
1003 0 : case PROP_LOGIN:
1004 0 : g_value_set_object (value, gkm_gnome2_storage_get_login (self));
1005 0 : break;
1006 0 : default:
1007 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1008 0 : break;
1009 : }
1010 0 : }
1011 :
1012 : static void
1013 30 : gkm_gnome2_storage_class_init (GkmGnome2StorageClass *klass)
1014 : {
1015 30 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1016 30 : GkmStoreClass *store_class = GKM_STORE_CLASS (klass);
1017 :
1018 30 : gobject_class->constructor = gkm_gnome2_storage_constructor;
1019 30 : gobject_class->dispose = gkm_gnome2_storage_dispose;
1020 30 : gobject_class->finalize = gkm_gnome2_storage_finalize;
1021 30 : gobject_class->set_property = gkm_gnome2_storage_set_property;
1022 30 : gobject_class->get_property = gkm_gnome2_storage_get_property;
1023 :
1024 30 : store_class->read_value = gkm_gnome2_storage_real_read_value;
1025 30 : store_class->write_value = gkm_gnome2_storage_real_write_value;
1026 :
1027 30 : g_object_class_install_property (gobject_class, PROP_DIRECTORY,
1028 : g_param_spec_string ("directory", "Storage Directory", "Directory for storage",
1029 : NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1030 :
1031 30 : g_object_class_install_property (gobject_class, PROP_MODULE,
1032 : g_param_spec_object ("module", "Module", "Module for objects",
1033 : GKM_TYPE_MODULE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1034 :
1035 30 : g_object_class_install_property (gobject_class, PROP_MANAGER,
1036 : g_param_spec_object ("manager", "Object Manager", "Object Manager",
1037 : GKM_TYPE_MANAGER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1038 :
1039 30 : g_object_class_install_property (gobject_class, PROP_LOGIN,
1040 : g_param_spec_object ("login", "Login", "Login used to unlock",
1041 : GKM_TYPE_SECRET, G_PARAM_READABLE));
1042 30 : }
1043 :
1044 : /* -----------------------------------------------------------------------------
1045 : * PUBLIC
1046 : */
1047 :
1048 : GkmGnome2Storage*
1049 38 : gkm_gnome2_storage_new (GkmModule *module, const gchar *directory)
1050 : {
1051 : GkmManager *manager;
1052 :
1053 38 : g_return_val_if_fail (GKM_IS_MODULE (module), NULL);
1054 38 : g_return_val_if_fail (directory, NULL);
1055 :
1056 38 : manager = gkm_module_get_manager (module);
1057 38 : g_return_val_if_fail (GKM_IS_MANAGER (manager), NULL);
1058 :
1059 38 : return g_object_new (GKM_TYPE_GNOME2_STORAGE,
1060 : "module", module,
1061 : "manager", manager,
1062 : "directory", directory,
1063 : NULL);
1064 : }
1065 :
1066 : CK_RV
1067 13 : gkm_gnome2_storage_refresh (GkmGnome2Storage *self)
1068 : {
1069 13 : g_return_val_if_fail (GKM_GNOME2_STORAGE (self), CKR_GENERAL_ERROR);
1070 13 : return refresh_with_login (self, self->login);
1071 : }
1072 :
1073 : void
1074 5 : gkm_gnome2_storage_create (GkmGnome2Storage *self, GkmTransaction *transaction, GkmObject *object)
1075 : {
1076 : gboolean is_private;
1077 : GkmDataResult res;
1078 : gchar *identifier;
1079 : GBytes *data;
1080 : gchar *path;
1081 :
1082 5 : g_return_if_fail (GKM_IS_GNOME2_STORAGE (self));
1083 5 : g_return_if_fail (GKM_IS_TRANSACTION (transaction));
1084 5 : g_return_if_fail (!gkm_transaction_get_failed (transaction));
1085 5 : g_return_if_fail (GKM_IS_OBJECT (object));
1086 :
1087 : /* Make sure we haven't already stored it */
1088 5 : identifier = g_hash_table_lookup (self->object_to_identifier, object);
1089 5 : g_return_if_fail (identifier == NULL);
1090 :
1091 : /* Double check that the object is in fact serializable */
1092 5 : if (!GKM_IS_SERIALIZABLE (object)) {
1093 0 : g_warning ("can't store object of type '%s' on token", G_OBJECT_TYPE_NAME (object));
1094 0 : gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
1095 0 : g_return_if_reached ();
1096 : }
1097 :
1098 : /* Figure out whether this is a private object */
1099 5 : if (!gkm_object_get_attribute_boolean (object, NULL, CKA_PRIVATE, &is_private))
1100 0 : is_private = FALSE;
1101 :
1102 : /* Can't serialize private if we're not unlocked */
1103 5 : if (is_private && !self->login) {
1104 0 : gkm_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
1105 0 : return;
1106 : }
1107 :
1108 : /* Hook ourselves into the transaction */
1109 5 : if (!begin_modification_state (self, transaction))
1110 0 : return;
1111 :
1112 : /* Create an identifier guaranteed unique by this transaction */
1113 5 : identifier = identifier_for_object (object);
1114 5 : if (gkm_gnome2_file_unique_entry (self->file, &identifier) != GKM_DATA_SUCCESS) {
1115 0 : gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
1116 0 : g_return_if_reached ();
1117 : }
1118 :
1119 : /* We don't want to get signals about this item being added */
1120 5 : g_signal_handlers_block_by_func (self->file, data_file_entry_added, self);
1121 5 : g_signal_handlers_block_by_func (self->file, data_file_entry_changed, self);
1122 :
1123 5 : res = gkm_gnome2_file_create_entry (self->file, identifier,
1124 5 : is_private ? GKM_GNOME2_FILE_SECTION_PRIVATE : GKM_GNOME2_FILE_SECTION_PUBLIC);
1125 :
1126 5 : g_signal_handlers_unblock_by_func (self->file, data_file_entry_added, self);
1127 5 : g_signal_handlers_unblock_by_func (self->file, data_file_entry_changed, self);
1128 :
1129 5 : switch(res) {
1130 0 : case GKM_DATA_FAILURE:
1131 : case GKM_DATA_UNRECOGNIZED:
1132 0 : g_free (identifier);
1133 0 : gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
1134 0 : return;
1135 0 : case GKM_DATA_LOCKED:
1136 0 : g_free (identifier);
1137 0 : gkm_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
1138 0 : return;
1139 5 : case GKM_DATA_SUCCESS:
1140 5 : break;
1141 0 : default:
1142 0 : g_assert_not_reached ();
1143 : }
1144 :
1145 : /* Serialize the object in question */
1146 5 : data = gkm_serializable_save (GKM_SERIALIZABLE (object), is_private ? self->login : NULL);
1147 :
1148 5 : if (data == NULL) {
1149 0 : gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
1150 0 : g_return_if_reached ();
1151 : }
1152 :
1153 5 : path = g_build_filename (self->directory, identifier, NULL);
1154 5 : gkm_transaction_write_file (transaction, path,
1155 : g_bytes_get_data (data, NULL),
1156 : g_bytes_get_size (data));
1157 :
1158 : /* Make sure we write in the object hash */
1159 5 : if (!gkm_transaction_get_failed (transaction))
1160 10 : store_object_hash (self, transaction, identifier,
1161 5 : g_bytes_get_data (data, NULL),
1162 : g_bytes_get_size (data));
1163 :
1164 : /* Now we decide to own the object */
1165 5 : if (!gkm_transaction_get_failed (transaction))
1166 5 : take_object_ownership (self, identifier, object);
1167 :
1168 5 : g_free (identifier);
1169 5 : g_free (path);
1170 5 : g_bytes_unref (data);
1171 : }
1172 :
1173 : void
1174 0 : gkm_gnome2_storage_destroy (GkmGnome2Storage *self, GkmTransaction *transaction, GkmObject *object)
1175 : {
1176 : GkmDataResult res;
1177 : gchar *identifier;
1178 : gchar *path;
1179 :
1180 0 : g_return_if_fail (GKM_IS_GNOME2_STORAGE (self));
1181 0 : g_return_if_fail (GKM_IS_TRANSACTION (transaction));
1182 0 : g_return_if_fail (!gkm_transaction_get_failed (transaction));
1183 0 : g_return_if_fail (object);
1184 :
1185 : /* Lookup the object identifier */
1186 0 : identifier = g_hash_table_lookup (self->object_to_identifier, object);
1187 0 : g_return_if_fail (identifier);
1188 :
1189 0 : if (!begin_modification_state (self, transaction))
1190 0 : return;
1191 :
1192 : /* First actually delete the file */
1193 0 : path = g_build_filename (self->directory, identifier, NULL);
1194 0 : gkm_transaction_remove_file (transaction, path);
1195 0 : g_free (path);
1196 :
1197 0 : if (gkm_transaction_get_failed (transaction))
1198 0 : return;
1199 :
1200 : /* Now delete the entry from our store */
1201 0 : res = gkm_gnome2_file_destroy_entry (self->file, identifier);
1202 0 : switch(res) {
1203 0 : case GKM_DATA_FAILURE:
1204 : case GKM_DATA_UNRECOGNIZED:
1205 0 : gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
1206 0 : return;
1207 0 : case GKM_DATA_LOCKED:
1208 0 : gkm_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
1209 0 : return;
1210 0 : case GKM_DATA_SUCCESS:
1211 0 : break;
1212 0 : default:
1213 0 : g_assert_not_reached ();
1214 : }
1215 :
1216 : /* Actual removal of object happened as a callback above */
1217 0 : g_return_if_fail (g_hash_table_lookup (self->object_to_identifier, object) == NULL);
1218 : }
1219 :
1220 : void
1221 4 : gkm_gnome2_storage_relock (GkmGnome2Storage *self, GkmTransaction *transaction,
1222 : GkmSecret *old_login, GkmSecret *new_login)
1223 : {
1224 : GkmGnome2File *file;
1225 : GkmDataResult res;
1226 : RelockArgs args;
1227 :
1228 4 : g_return_if_fail (GKM_IS_GNOME2_STORAGE (self));
1229 4 : g_return_if_fail (GKM_IS_TRANSACTION (transaction));
1230 :
1231 : /* Reload the file with the old password and start transaction */
1232 4 : if (!begin_write_state (self, transaction))
1233 0 : return;
1234 :
1235 4 : file = gkm_gnome2_file_new ();
1236 :
1237 : /* Read in from the old file */
1238 4 : res = gkm_gnome2_file_read_fd (file, self->read_fd, old_login);
1239 4 : switch(res) {
1240 0 : case GKM_DATA_FAILURE:
1241 : case GKM_DATA_UNRECOGNIZED:
1242 0 : gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
1243 0 : return;
1244 0 : case GKM_DATA_LOCKED:
1245 0 : gkm_transaction_fail (transaction, CKR_PIN_INCORRECT);
1246 0 : return;
1247 4 : case GKM_DATA_SUCCESS:
1248 4 : break;
1249 0 : default:
1250 0 : g_assert_not_reached ();
1251 : }
1252 :
1253 : /* Write out to new path as new file */
1254 4 : res = gkm_gnome2_file_write_fd (file, self->write_fd, new_login);
1255 4 : switch(res) {
1256 0 : case GKM_DATA_FAILURE:
1257 : case GKM_DATA_UNRECOGNIZED:
1258 0 : gkm_transaction_fail (transaction, CKR_FUNCTION_FAILED);
1259 0 : return;
1260 0 : case GKM_DATA_LOCKED:
1261 0 : gkm_transaction_fail (transaction, CKR_PIN_INCORRECT);
1262 0 : return;
1263 4 : case GKM_DATA_SUCCESS:
1264 4 : break;
1265 0 : default:
1266 0 : g_assert_not_reached ();
1267 : }
1268 :
1269 : /* Now go through all objects in the file, and load and reencode them */
1270 4 : args.transaction = transaction;
1271 4 : args.old_login = old_login;
1272 4 : args.new_login = new_login;
1273 4 : args.self = self;
1274 4 : gkm_gnome2_file_foreach_entry (file, relock_each_object, &args);
1275 :
1276 4 : if (!gkm_transaction_get_failed (transaction) && self->login) {
1277 0 : if (new_login)
1278 0 : g_object_ref (new_login);
1279 0 : g_object_unref (self->login);
1280 0 : self->login = new_login;
1281 0 : g_object_notify (G_OBJECT (self), "login");
1282 : }
1283 :
1284 4 : g_object_unref (file);
1285 : }
1286 :
1287 : CK_RV
1288 5 : gkm_gnome2_storage_unlock (GkmGnome2Storage *self, GkmSecret *login)
1289 : {
1290 : CK_RV rv;
1291 :
1292 5 : g_return_val_if_fail (GKM_IS_GNOME2_STORAGE (self), CKR_GENERAL_ERROR);
1293 5 : g_return_val_if_fail (!self->transaction, CKR_GENERAL_ERROR);
1294 :
1295 5 : if (self->login)
1296 0 : return CKR_USER_ALREADY_LOGGED_IN;
1297 :
1298 5 : self->login = login;
1299 :
1300 5 : rv = refresh_with_login (self, login);
1301 5 : if (rv == CKR_USER_NOT_LOGGED_IN)
1302 0 : rv = CKR_PIN_INCORRECT;
1303 :
1304 : /* Take on new login for good */
1305 5 : if (rv == CKR_OK) {
1306 5 : g_assert (self->login == login);
1307 5 : if (self->login)
1308 5 : g_object_ref (self->login);
1309 5 : g_object_notify (G_OBJECT (self), "login");
1310 :
1311 : /* Failed, so keep our previous NULL login */
1312 : } else {
1313 0 : self->login = NULL;
1314 : }
1315 :
1316 5 : return rv;
1317 : }
1318 :
1319 : CK_RV
1320 4 : gkm_gnome2_storage_lock (GkmGnome2Storage *self)
1321 : {
1322 : GkmSecret *prev;
1323 : CK_RV rv;
1324 :
1325 4 : g_return_val_if_fail (GKM_IS_GNOME2_STORAGE (self), CKR_GENERAL_ERROR);
1326 4 : g_return_val_if_fail (!self->transaction, CKR_GENERAL_ERROR);
1327 :
1328 4 : if (!self->login)
1329 0 : return CKR_USER_NOT_LOGGED_IN;
1330 :
1331 : /* While loading set new NULL login */
1332 4 : prev = self->login;
1333 4 : self->login = NULL;
1334 :
1335 4 : rv = refresh_with_login (self, NULL);
1336 :
1337 : /* Take on new login for good */
1338 4 : if (rv == CKR_OK) {
1339 4 : g_object_unref (prev);
1340 4 : g_assert (self->login == NULL);
1341 4 : g_object_notify (G_OBJECT (self), "login");
1342 :
1343 : /* Failed so revert to previous login */
1344 : } else {
1345 0 : self->login = prev;
1346 : }
1347 :
1348 4 : return rv;
1349 : }
1350 :
1351 : GkmManager*
1352 0 : gkm_gnome2_storage_get_manager (GkmGnome2Storage *self)
1353 : {
1354 0 : g_return_val_if_fail (GKM_IS_GNOME2_STORAGE (self), NULL);
1355 0 : return self->manager;
1356 : }
1357 :
1358 : const gchar*
1359 0 : gkm_gnome2_storage_get_directory (GkmGnome2Storage *self)
1360 : {
1361 0 : g_return_val_if_fail (GKM_IS_GNOME2_STORAGE (self), NULL);
1362 0 : return self->directory;
1363 : }
1364 :
1365 : GkmSecret*
1366 5 : gkm_gnome2_storage_get_login (GkmGnome2Storage *self)
1367 : {
1368 5 : g_return_val_if_fail (GKM_IS_GNOME2_STORAGE (self), NULL);
1369 5 : return self->login;
1370 : }
1371 :
1372 : gulong
1373 9 : gkm_gnome2_storage_token_flags (GkmGnome2Storage *self)
1374 : {
1375 9 : gulong flags = 0;
1376 : CK_RV rv;
1377 :
1378 : /* We don't changing SO logins, so always initialized */
1379 9 : flags |= CKF_TOKEN_INITIALIZED | CKF_LOGIN_REQUIRED;
1380 :
1381 : /* No file has been loaded yet? */
1382 9 : if (self->last_mtime == 0) {
1383 2 : rv = gkm_gnome2_storage_refresh (self);
1384 2 : if (rv == CKR_USER_PIN_NOT_INITIALIZED)
1385 0 : flags |= CKF_USER_PIN_TO_BE_CHANGED;
1386 2 : else if (rv != CKR_OK)
1387 0 : g_return_val_if_reached (flags);
1388 : }
1389 :
1390 : /* No private stuff in the file? */
1391 9 : if (gkm_gnome2_file_have_section (self->file, GKM_GNOME2_FILE_SECTION_PRIVATE))
1392 7 : flags |= CKF_USER_PIN_INITIALIZED;
1393 :
1394 9 : return flags;
1395 : }
|