LCOV - code coverage report
Current view: top level - pkcs11/secret-store - gkm-secret-module.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 86.5 % 208 180
Test Date: 2024-04-08 13:24:42 Functions: 100.0 % 26 26

            Line data    Source code
       1              : /*
       2              :  * gnome-keyring
       3              :  *
       4              :  * Copyright (C) 2009 Stefan Walter
       5              :  *
       6              :  * This program is free software; you can redistribute it and/or modify
       7              :  * it under the terms of the GNU Lesser General Public License as
       8              :  * published by the Free Software Foundation; either version 2.1 of
       9              :  * the License, or (at your option) any later version.
      10              :  *
      11              :  * This program is distributed in the hope that it will be useful, but
      12              :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14              :  * Lesser General Public License for more details.
      15              :  *
      16              :  * You should have received a copy of the GNU Lesser General Public
      17              :  * License along with this program; if not, see
      18              :  * <http://www.gnu.org/licenses/>.
      19              :  */
      20              : 
      21              : #include "config.h"
      22              : 
      23              : #include "gkm-secret-collection.h"
      24              : #include "gkm-secret-item.h"
      25              : #include "gkm-secret-module.h"
      26              : #include "gkm-secret-search.h"
      27              : #include "gkm-secret-store.h"
      28              : 
      29              : #include "gkm/gkm-credential.h"
      30              : #define DEBUG_FLAG GKM_DEBUG_STORAGE
      31              : #include "gkm/gkm-debug.h"
      32              : #include "gkm/gkm-transaction.h"
      33              : #include "gkm/gkm-util.h"
      34              : 
      35              : #include "egg/egg-file-tracker.h"
      36              : 
      37              : #include <glib/gstdio.h>
      38              : 
      39              : #include <errno.h>
      40              : #include <fcntl.h>
      41              : #include <string.h>
      42              : 
      43              : struct _GkmSecretModule {
      44              :         GkmModule parent;
      45              :         EggFileTracker *tracker;
      46              :         GHashTable *collections;
      47              :         gchar *directory;
      48              :         GkmCredential *session_credential;
      49              : };
      50              : 
      51              : static const CK_SLOT_INFO gkm_secret_module_slot_info = {
      52              :         "Secret Store",
      53              :         "Gnome Keyring",
      54              :         CKF_TOKEN_PRESENT,
      55              :         { 0, 0 },
      56              :         { 0, 0 }
      57              : };
      58              : 
      59              : static const CK_TOKEN_INFO gkm_secret_module_token_info = {
      60              :         "Secret Store",
      61              :         "Gnome Keyring",
      62              :         "1.0",
      63              :         "1:SECRET:MAIN", /* Unique serial number for manufacturer */
      64              :         CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED | CKF_LOGIN_REQUIRED,
      65              :         CK_EFFECTIVELY_INFINITE,
      66              :         CK_EFFECTIVELY_INFINITE,
      67              :         CK_EFFECTIVELY_INFINITE,
      68              :         CK_EFFECTIVELY_INFINITE,
      69              :         1024,
      70              :         1,
      71              :         CK_UNAVAILABLE_INFORMATION,
      72              :         CK_UNAVAILABLE_INFORMATION,
      73              :         CK_UNAVAILABLE_INFORMATION,
      74              :         CK_UNAVAILABLE_INFORMATION,
      75              :         { 0, 0 },
      76              :         { 0, 0 },
      77              :         ""
      78              : };
      79              : 
      80         1048 : G_DEFINE_TYPE (GkmSecretModule, gkm_secret_module, GKM_TYPE_MODULE);
      81              : 
      82              : GkmModule*  _gkm_secret_store_get_module_for_testing (void);
      83              : 
      84              : /* Forward declarations */
      85              : static void add_collection (GkmSecretModule *, GkmTransaction *, GkmSecretCollection *);
      86              : static void remove_collection (GkmSecretModule *, GkmTransaction *, GkmSecretCollection *);
      87              : 
      88              : /* -----------------------------------------------------------------------------
      89              :  * ACTUAL PKCS#11 Module Implementation
      90              :  */
      91              : 
      92              : /* Include all the module entry points */
      93              : #include "gkm/gkm-module-ep.h"
      94          109 : GKM_DEFINE_MODULE (gkm_secret_module, GKM_TYPE_SECRET_MODULE);
      95              : 
      96              : /* -----------------------------------------------------------------------------
      97              :  * INTERNAL
      98              :  */
      99              : 
     100              : static gboolean
     101            8 : complete_add (GkmTransaction *transaction, GObject *obj, gpointer user_data)
     102              : {
     103            8 :         GkmSecretCollection *collection = GKM_SECRET_COLLECTION (user_data);
     104            8 :         if (gkm_transaction_get_failed (transaction))
     105            0 :                 remove_collection (GKM_SECRET_MODULE (obj), NULL, collection);
     106            8 :         g_object_unref (collection);
     107            8 :         return TRUE;
     108              : }
     109              : 
     110              : static void
     111           67 : add_collection (GkmSecretModule *self, GkmTransaction *transaction, GkmSecretCollection  *collection)
     112              : {
     113              :         const gchar *filename;
     114              : 
     115           67 :         g_assert (GKM_IS_SECRET_MODULE(self));
     116           67 :         g_assert (GKM_IS_SECRET_COLLECTION (collection));
     117              : 
     118           67 :         filename = gkm_secret_collection_get_filename (collection);
     119           67 :         g_return_if_fail (filename);
     120              : 
     121          134 :         g_hash_table_replace (self->collections, g_strdup (filename), g_object_ref (collection));
     122              : 
     123           67 :         gkm_object_expose_full (GKM_OBJECT (collection), transaction, TRUE);
     124           67 :         if (transaction)
     125            8 :                 gkm_transaction_add (transaction, self, complete_add, g_object_ref (collection));
     126              : }
     127              : 
     128              : static gboolean
     129            2 : complete_remove (GkmTransaction *transaction, GObject *obj, gpointer user_data)
     130              : {
     131            2 :         GkmSecretCollection *collection = GKM_SECRET_COLLECTION (user_data);
     132            2 :         if (gkm_transaction_get_failed (transaction))
     133            0 :                 add_collection (GKM_SECRET_MODULE (obj), NULL, collection);
     134            2 :         g_object_unref (collection);
     135            2 :         return TRUE;
     136              : }
     137              : 
     138              : static void
     139            2 : remove_collection (GkmSecretModule *self, GkmTransaction *transaction, GkmSecretCollection *collection)
     140              : {
     141              :         const gchar *filename;
     142              : 
     143            2 :         g_assert (GKM_IS_SECRET_MODULE (self));
     144            2 :         g_assert (GKM_IS_SECRET_COLLECTION (collection));
     145              : 
     146            2 :         filename = gkm_secret_collection_get_filename (collection);
     147            2 :         g_return_if_fail (filename);
     148              : 
     149            2 :         g_hash_table_remove (self->collections, filename);
     150              : 
     151            2 :         gkm_object_expose_full (GKM_OBJECT (collection), transaction, FALSE);
     152            2 :         if (transaction)
     153            2 :                 gkm_transaction_add (transaction, self, complete_remove, g_object_ref (collection));
     154              : }
     155              : 
     156              : static gchar*
     157           59 : identifier_from_filename (GkmSecretModule *self, const gchar *filename)
     158              : {
     159              :         gchar *identifier;
     160              : 
     161              :         /* Do we have one for this path yet? */
     162           59 :         identifier = g_path_get_basename (filename);
     163              : 
     164              :         /* Remove the keyring suffix */
     165           59 :         if (g_str_has_suffix (identifier, ".keyring"))
     166           59 :                 identifier[strlen(identifier) - 8] = 0;
     167              : 
     168           59 :         return identifier;
     169              : }
     170              : 
     171              : static gchar*
     172            8 : identifier_to_new_filename (GkmSecretModule *self, const gchar *identifier)
     173              : {
     174              :         gchar *filename;
     175              :         gint i;
     176              :         int fd;
     177              : 
     178            8 :         for (i = 0; i < G_MAXINT; ++i) {
     179            8 :                 if (i == 0)
     180            8 :                         filename = g_strdup_printf ("%s/%s.keyring", self->directory, identifier);
     181              :                 else
     182            0 :                         filename = g_strdup_printf ("%s/%s_%d.keyring", self->directory, identifier, i);
     183              : 
     184              :                 /* Try to create the file, and check that it doesn't exist */
     185            8 :                 fd = g_open (filename, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
     186            8 :                 if (fd == -1) {
     187            0 :                         if (errno != EEXIST)
     188            0 :                                 break;
     189              :                 } else {
     190            8 :                         close (fd);
     191            8 :                         break;
     192              :                 }
     193              : 
     194            0 :                 g_free (filename);
     195              :         }
     196              : 
     197            8 :         return filename;
     198              : }
     199              : 
     200              : 
     201              : static void
     202           59 : on_file_load (EggFileTracker *tracker,
     203              :               const gchar *path,
     204              :               GkmSecretModule *self)
     205              : {
     206              :         GkmSecretCollection *collection;
     207              :         GkmManager *manager;
     208              :         GkmDataResult res;
     209              :         gboolean created;
     210              :         gchar *identifier;
     211              : 
     212           59 :         manager = gkm_module_get_manager (GKM_MODULE (self));
     213           59 :         g_return_if_fail (manager);
     214              : 
     215              :         /* Do we have one for this path yet? */
     216           59 :         identifier = identifier_from_filename (self, path);
     217           59 :         collection = g_hash_table_lookup (self->collections, path);
     218              : 
     219           59 :         if (collection == NULL) {
     220           59 :                 created = TRUE;
     221           59 :                 collection = g_object_new (GKM_TYPE_SECRET_COLLECTION,
     222              :                                            "module", self,
     223              :                                            "identifier", identifier,
     224              :                                            "filename", path,
     225              :                                            "manager", manager,
     226              :                                            NULL);
     227              :         } else {
     228            0 :                 created = FALSE;
     229            0 :                 g_object_ref (collection);
     230              :         }
     231              : 
     232           59 :         res = gkm_secret_collection_load (collection);
     233              : 
     234           59 :         switch (res) {
     235           59 :         case GKM_DATA_SUCCESS:
     236           59 :                 if (created)
     237           59 :                         add_collection (self, NULL, collection);
     238           59 :                 break;
     239            0 :         case GKM_DATA_LOCKED:
     240            0 :                 g_message ("master password for keyring changed without our knowledge: %s", path);
     241            0 :                 gkm_secret_collection_unlocked_clear (collection);
     242            0 :                 break;
     243            0 :         case GKM_DATA_UNRECOGNIZED:
     244            0 :                 g_message ("keyring was in an invalid or unrecognized format: %s", path);
     245            0 :                 break;
     246            0 :         case GKM_DATA_FAILURE:
     247            0 :                 g_message ("failed to parse keyring: %s", path);
     248            0 :                 break;
     249            0 :         default:
     250            0 :                 g_assert_not_reached ();
     251              :         }
     252              : 
     253           59 :         g_object_unref (collection);
     254           59 :         g_free (identifier);
     255              : }
     256              : 
     257              : static void
     258            1 : on_file_remove (EggFileTracker *tracker,
     259              :                 const gchar *path,
     260              :                 GkmSecretModule *self)
     261              : {
     262              :         GkmSecretCollection *collection;
     263              : 
     264            1 :         g_return_if_fail (path);
     265            1 :         g_return_if_fail (GKM_IS_SECRET_MODULE (self));
     266              : 
     267            1 :         collection = g_hash_table_lookup (self->collections, path);
     268            1 :         if (collection)
     269            0 :                 remove_collection (self, NULL, collection);
     270              : }
     271              : 
     272              : /* -----------------------------------------------------------------------------
     273              :  * OBJECT
     274              :  */
     275              : 
     276              : static const CK_SLOT_INFO*
     277           66 : gkm_secret_module_real_get_slot_info (GkmModule *self)
     278              : {
     279           66 :         return &gkm_secret_module_slot_info;
     280              : }
     281              : 
     282              : static const CK_TOKEN_INFO*
     283           92 : gkm_secret_module_real_get_token_info (GkmModule *self)
     284              : {
     285           92 :         return &gkm_secret_module_token_info;
     286              : }
     287              : 
     288              : static void
     289          109 : gkm_secret_module_real_parse_argument (GkmModule *base, const gchar *name, const gchar *value)
     290              : {
     291          109 :         GkmSecretModule *self = GKM_SECRET_MODULE (base);
     292          109 :         if (g_str_equal (name, "directory")) {
     293          109 :                 g_free (self->directory);
     294          109 :                 self->directory = g_strdup (value);
     295              :         }
     296          109 : }
     297              : 
     298              : static CK_RV
     299          209 : gkm_secret_module_real_refresh_token (GkmModule *base)
     300              : {
     301          209 :         GkmSecretModule *self = GKM_SECRET_MODULE (base);
     302          209 :         if (self->tracker)
     303          209 :                 egg_file_tracker_refresh (self->tracker, FALSE);
     304          209 :         return CKR_OK;
     305              : }
     306              : 
     307              : static void
     308           14 : gkm_secret_module_real_add_object (GkmModule *module, GkmTransaction *transaction,
     309              :                                    GkmObject *object)
     310              : {
     311           14 :         GkmSecretModule *self = GKM_SECRET_MODULE (module);
     312              :         GkmSecretCollection *collection;
     313              :         const gchar *identifier;
     314              :         gchar *filename;
     315              : 
     316           14 :         g_return_if_fail (!gkm_transaction_get_failed (transaction));
     317              : 
     318           14 :         if (GKM_IS_SECRET_COLLECTION (object)) {
     319            8 :                 collection = GKM_SECRET_COLLECTION (object);
     320              : 
     321              :                 /* Setup a filename for this collection */
     322            8 :                 identifier = gkm_secret_object_get_identifier (GKM_SECRET_OBJECT (collection));
     323            8 :                 filename = identifier_to_new_filename (self, identifier);
     324            8 :                 gkm_secret_collection_set_filename (collection, filename);
     325            8 :                 g_free (filename);
     326              : 
     327            8 :                 add_collection (self, transaction, collection);
     328              :         }
     329              : }
     330              : 
     331              : static void
     332           29 : gkm_secret_module_real_store_object (GkmModule *module, GkmTransaction *transaction,
     333              :                                      GkmObject *object)
     334              : {
     335           29 :         GkmSecretModule *self = GKM_SECRET_MODULE (module);
     336           29 :         GkmSecretCollection *collection = NULL;
     337              : 
     338              :         /* Store the item's collection */
     339           29 :         if (GKM_IS_SECRET_ITEM (object)) {
     340            9 :                 collection = gkm_secret_item_get_collection (GKM_SECRET_ITEM (object));
     341            9 :                 g_return_if_fail (GKM_IS_SECRET_COLLECTION (collection));
     342            9 :                 gkm_module_store_token_object (GKM_MODULE (self), transaction, GKM_OBJECT (collection));
     343              : 
     344              :         /* Storing a collection */
     345           20 :         } else if (GKM_IS_SECRET_COLLECTION (object)) {
     346           20 :                 collection = GKM_SECRET_COLLECTION (object);
     347           20 :                 gkm_secret_collection_save (collection, transaction);
     348              : 
     349              :         /* No other kind of token object */
     350              :         } else {
     351            0 :                 g_warning ("can't store object of type '%s' on secret token", G_OBJECT_TYPE_NAME (object));
     352            0 :                 gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
     353              :         }
     354              : }
     355              : 
     356              : static void
     357            4 : gkm_secret_module_real_remove_object (GkmModule *module, GkmTransaction *transaction,
     358              :                                       GkmObject *object)
     359              : {
     360            4 :         GkmSecretModule *self = GKM_SECRET_MODULE (module);
     361              :         GkmSecretCollection *collection;
     362              : 
     363              :         /* Ignore the session keyring credentials */
     364            8 :         if (self->session_credential != NULL &&
     365            4 :             GKM_OBJECT (self->session_credential) == object)
     366            0 :                 return;
     367              : 
     368              :         /* Removing an item */
     369            4 :         if (GKM_IS_SECRET_ITEM (object)) {
     370            2 :                 collection = gkm_secret_item_get_collection (GKM_SECRET_ITEM (object));
     371            2 :                 g_return_if_fail (GKM_IS_SECRET_COLLECTION (collection));
     372            2 :                 gkm_secret_collection_destroy_item (collection, transaction, GKM_SECRET_ITEM (object));
     373            2 :                 if (!gkm_transaction_get_failed (transaction))
     374            2 :                         gkm_secret_collection_save (collection, transaction);
     375              : 
     376              :         /* Removing a collection */
     377            2 :         } else if (GKM_IS_SECRET_COLLECTION (object)) {
     378            2 :                 collection = GKM_SECRET_COLLECTION (object);
     379            2 :                 gkm_secret_collection_destroy (collection, transaction);
     380            2 :                 if (!gkm_transaction_get_failed (transaction))
     381            2 :                         remove_collection (self, transaction, collection);
     382              : 
     383              :         /* No other token objects */
     384              :         } else {
     385            0 :                 g_warning ("Trying to remove token object of type '%s' from secret "
     386              :                            "module, but that type is not supported.", G_OBJECT_TYPE_NAME (object));
     387            0 :                 gkm_transaction_fail (transaction, CKR_FUNCTION_NOT_SUPPORTED);
     388              :         }
     389              : }
     390              : 
     391              : static GObject*
     392          109 : gkm_secret_module_constructor (GType type, guint n_props, GObjectConstructParam *props)
     393              : {
     394          109 :         GkmSecretModule *self = GKM_SECRET_MODULE (G_OBJECT_CLASS (gkm_secret_module_parent_class)->constructor(type, n_props, props));
     395              :         GkmManager *manager;
     396              :         GkmObject *collection;
     397              :         CK_RV rv;
     398              : 
     399          109 :         g_return_val_if_fail (self, NULL);
     400              : 
     401          109 :         if (!self->directory)
     402            0 :                 self->directory = gkm_util_locate_keyrings_directory ();
     403          109 :         gkm_debug ("secret store directory: %s", self->directory);
     404              : 
     405          109 :         self->tracker = egg_file_tracker_new (self->directory, "*.keyring", NULL);
     406          109 :         g_signal_connect (self->tracker, "file-added", G_CALLBACK (on_file_load), self);
     407          109 :         g_signal_connect (self->tracker, "file-changed", G_CALLBACK (on_file_load), self);
     408          109 :         g_signal_connect (self->tracker, "file-removed", G_CALLBACK (on_file_remove), self);
     409              : 
     410          109 :         manager = gkm_module_get_manager (GKM_MODULE (self));
     411              : 
     412          109 :         collection = g_object_new (GKM_TYPE_SECRET_COLLECTION,
     413              :                                    "module", self,
     414              :                                    "identifier", "session",
     415              :                                    "manager", manager,
     416              :                                    "transient", TRUE,
     417              :                                    NULL);
     418              : 
     419              :         /* Create the 'session' keyring, which is not stored to disk */
     420          109 :         g_return_val_if_fail (gkm_object_is_transient (collection), NULL);
     421          109 :         gkm_module_add_token_object (GKM_MODULE (self), NULL, collection);
     422          109 :         gkm_object_expose (collection, TRUE);
     423              : 
     424              :         /* Unlock the 'session' keyring */
     425          109 :         rv = gkm_credential_create (GKM_MODULE (self), manager, GKM_OBJECT (collection),
     426              :                                     NULL, 0, &self->session_credential);
     427          109 :         if (rv == CKR_OK)
     428          109 :                 gkm_object_expose (GKM_OBJECT (self->session_credential), TRUE);
     429              :         else
     430            0 :                 g_warning ("couldn't unlock the 'session' keyring");
     431              : 
     432          109 :         g_object_unref (collection);
     433          109 :         return G_OBJECT (self);
     434              : }
     435              : 
     436              : static void
     437          109 : gkm_secret_module_init (GkmSecretModule *self)
     438              : {
     439          109 :         self->collections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
     440          109 :         gkm_module_register_factory (GKM_MODULE (self), GKM_FACTORY_SECRET_SEARCH);
     441          109 :         gkm_module_register_factory (GKM_MODULE (self), GKM_FACTORY_SECRET_ITEM);
     442          109 :         gkm_module_register_factory (GKM_MODULE (self), GKM_FACTORY_SECRET_COLLECTION);
     443          109 : }
     444              : 
     445              : static void
     446          218 : gkm_secret_module_dispose (GObject *obj)
     447              : {
     448          218 :         GkmSecretModule *self = GKM_SECRET_MODULE (obj);
     449              : 
     450          218 :         if (self->tracker)
     451          109 :                 g_object_unref (self->tracker);
     452          218 :         self->tracker = NULL;
     453              : 
     454          218 :         if (self->session_credential)
     455          109 :                 g_object_unref (self->session_credential);
     456          218 :         self->session_credential = NULL;
     457              : 
     458          218 :         g_hash_table_remove_all (self->collections);
     459              : 
     460          218 :         G_OBJECT_CLASS (gkm_secret_module_parent_class)->dispose (obj);
     461          218 : }
     462              : 
     463              : static void
     464          109 : gkm_secret_module_finalize (GObject *obj)
     465              : {
     466          109 :         GkmSecretModule *self = GKM_SECRET_MODULE (obj);
     467              : 
     468          109 :         g_assert (self->tracker == NULL);
     469              : 
     470          109 :         g_hash_table_destroy (self->collections);
     471          109 :         self->collections = NULL;
     472              : 
     473          109 :         g_free (self->directory);
     474          109 :         self->directory = NULL;
     475              : 
     476          109 :         g_assert (!self->session_credential);
     477              : 
     478          109 :         G_OBJECT_CLASS (gkm_secret_module_parent_class)->finalize (obj);
     479          109 : }
     480              : 
     481              : static void
     482           34 : gkm_secret_module_class_init (GkmSecretModuleClass *klass)
     483              : {
     484           34 :         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     485           34 :         GkmModuleClass *module_class = GKM_MODULE_CLASS (klass);
     486              : 
     487           34 :         gobject_class->constructor = gkm_secret_module_constructor;
     488           34 :         gobject_class->dispose = gkm_secret_module_dispose;
     489           34 :         gobject_class->finalize = gkm_secret_module_finalize;
     490              : 
     491           34 :         module_class->get_slot_info = gkm_secret_module_real_get_slot_info;
     492           34 :         module_class->get_token_info = gkm_secret_module_real_get_token_info;
     493           34 :         module_class->parse_argument = gkm_secret_module_real_parse_argument;
     494           34 :         module_class->refresh_token = gkm_secret_module_real_refresh_token;
     495           34 :         module_class->add_token_object = gkm_secret_module_real_add_object;
     496           34 :         module_class->store_token_object = gkm_secret_module_real_store_object;
     497           34 :         module_class->remove_token_object = gkm_secret_module_real_remove_object;
     498           34 : }
     499              : 
     500              : /* ---------------------------------------------------------------------------------------
     501              :  * PUBLIC
     502              :  */
     503              : 
     504              : CK_FUNCTION_LIST_PTR
     505          191 : gkm_secret_store_get_functions (void)
     506              : {
     507          191 :         gkm_crypto_initialize ();
     508          191 :         return gkm_secret_module_function_list;
     509              : }
     510              : 
     511              : GkmModule*
     512          164 : _gkm_secret_store_get_module_for_testing (void)
     513              : {
     514          164 :         return pkcs11_module;
     515              : }
        

Generated by: LCOV version 2.0-1