LCOV - code coverage report
Current view: top level - pkcs11/gnome2-store - gkm-gnome2-storage.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 61.2 % 701 429
Test Date: 2024-12-15 20:37:51 Functions: 86.0 % 43 37

            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, &section))
     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              : }
        

Generated by: LCOV version 2.0-1