LCOV - code coverage report
Current view: top level - pkcs11/secret-store - gkm-secret-collection.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 76.5 % 477 365
Test Date: 2024-04-08 13:24:42 Functions: 87.8 % 49 43

            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-binary.h"
      24              : #include "gkm-secret-collection.h"
      25              : #include "gkm-secret-data.h"
      26              : #include "gkm-secret-item.h"
      27              : #include "gkm-secret-textual.h"
      28              : 
      29              : #include "egg/egg-error.h"
      30              : 
      31              : #include "gkm/gkm-attributes.h"
      32              : #include "gkm/gkm-credential.h"
      33              : #include "gkm/gkm-secret.h"
      34              : #include "gkm/gkm-session.h"
      35              : #include "gkm/gkm-transaction.h"
      36              : 
      37              : #include <glib/gi18n.h>
      38              : 
      39              : #include "pkcs11/pkcs11i.h"
      40              : 
      41              : enum {
      42              :         PROP_0,
      43              :         PROP_FILENAME
      44              : };
      45              : 
      46              : struct _GkmSecretCollection {
      47              :         GkmSecretObject parent;
      48              :         GkmSecretData *sdata;
      49              :         GHashTable *items;
      50              :         gchar *filename;
      51              :         guint32 watermark;
      52              :         GArray *template;
      53              : };
      54              : 
      55         9280 : G_DEFINE_TYPE (GkmSecretCollection, gkm_secret_collection, GKM_TYPE_SECRET_OBJECT);
      56              : 
      57              : /* Forward declarations */
      58              : static void add_item (GkmSecretCollection *, GkmTransaction *, GkmSecretItem *);
      59              : static void remove_item (GkmSecretCollection *, GkmTransaction *, GkmSecretItem *);
      60              : 
      61              : /* -----------------------------------------------------------------------------
      62              :  * INTERNAL
      63              :  */
      64              : 
      65              : static GkmDataResult
      66           97 : load_collection_and_secret_data (GkmSecretCollection *self, GkmSecretData *sdata,
      67              :                                  const gchar *path)
      68              : {
      69              :         GkmDataResult res;
      70           97 :         GError *error = NULL;
      71              :         guchar *data;
      72              :         gsize n_data;
      73              : 
      74              :         /* Read in the keyring */
      75           97 :         if (!g_file_get_contents (path, (gchar**)&data, &n_data, &error)) {
      76            0 :                 g_message ("problem reading keyring: %s: %s",
      77              :                            path, egg_error_message (error));
      78            0 :                 g_clear_error (&error);
      79            0 :                 return GKM_DATA_FAILURE;
      80              :         }
      81              : 
      82              :         /* Try to load from an encrypted file, and otherwise plain text */
      83           97 :         res = gkm_secret_binary_read (self, sdata, data, n_data);
      84           97 :         if (res == GKM_DATA_UNRECOGNIZED)
      85           20 :                 res = gkm_secret_textual_read (self, sdata, data, n_data);
      86              : 
      87           97 :         g_free (data);
      88              : 
      89           97 :         return res;
      90              : }
      91              : 
      92              : static GkmCredential*
      93           12 : lookup_unassociated_credential (GkmSession *session, CK_OBJECT_HANDLE handle)
      94              : {
      95              :         GkmObject *object;
      96              : 
      97           12 :         if (gkm_session_lookup_readable_object (session, handle, &object) != CKR_OK)
      98            0 :                 return NULL;
      99              : 
     100           12 :         if (gkm_credential_get_object (GKM_CREDENTIAL (object)) != NULL)
     101            0 :                 return NULL;
     102              : 
     103           12 :         return GKM_CREDENTIAL (object);
     104              : }
     105              : 
     106              : static gboolean
     107          101 : find_unlocked_credential (GkmCredential *cred, GkmObject *object, gpointer user_data)
     108              : {
     109          101 :         CK_OBJECT_HANDLE *result = user_data;
     110              : 
     111          101 :         g_return_val_if_fail (!*result, FALSE);
     112              : 
     113          101 :         if (gkm_credential_peek_data (cred, GKM_TYPE_SECRET_DATA)) {
     114           97 :                 *result = gkm_object_get_handle (GKM_OBJECT (cred));
     115           97 :                 return TRUE;
     116              :         }
     117              : 
     118            4 :         return FALSE;
     119              : }
     120              : 
     121              : static gboolean
     122           25 : find_unlocked_secret_data (GkmCredential *cred, GkmObject *object, gpointer user_data)
     123              : {
     124           25 :         GkmSecretCollection *self = GKM_SECRET_COLLECTION (object);
     125           25 :         GkmSecretData **result = user_data;
     126              : 
     127           25 :         g_return_val_if_fail (!*result, FALSE);
     128              : 
     129           25 :         *result = gkm_credential_pop_data (cred, GKM_TYPE_SECRET_DATA);
     130           25 :         if (*result) {
     131           21 :                 g_return_val_if_fail (*result == self->sdata, FALSE);
     132           21 :                 return TRUE;
     133              :         }
     134              : 
     135            4 :         return FALSE;
     136              : }
     137              : 
     138              : static void
     139          518 : track_secret_data (GkmSecretCollection *self, GkmSecretData *data)
     140              : {
     141          518 :         g_return_if_fail (GKM_IS_SECRET_COLLECTION (self));
     142              : 
     143          518 :         if (self->sdata)
     144           34 :                 g_object_remove_weak_pointer (G_OBJECT (self->sdata),
     145           34 :                                               (gpointer*)&(self->sdata));
     146          518 :         self->sdata = data;
     147          518 :         if (self->sdata)
     148          153 :                 g_object_add_weak_pointer (G_OBJECT (self->sdata),
     149          153 :                                            (gpointer*)&(self->sdata));
     150              : }
     151              : 
     152              : static void
     153          121 : each_value_to_list (gpointer key, gpointer value, gpointer user_data)
     154              : {
     155          121 :         GList **list = user_data;
     156          121 :         *list = g_list_prepend (*list, value);
     157          121 : }
     158              : 
     159              : static void
     160          119 : expose_each_item (gpointer key, gpointer value, gpointer user_data)
     161              : {
     162          119 :         gboolean expose = GPOINTER_TO_INT (user_data);
     163          119 :         gkm_object_expose (value, expose);
     164          119 : }
     165              : 
     166              : static gboolean
     167            8 : complete_add (GkmTransaction *transaction, GkmSecretCollection *self, GkmSecretItem *item)
     168              : {
     169            8 :         if (gkm_transaction_get_failed (transaction))
     170            1 :                 remove_item (self, NULL, item);
     171            8 :         g_object_unref (item);
     172            8 :         return TRUE;
     173              : }
     174              : 
     175              : static void
     176         2181 : add_item (GkmSecretCollection *self, GkmTransaction *transaction, GkmSecretItem *item)
     177              : {
     178              :         const gchar *identifier;
     179              :         guint32 number;
     180              : 
     181         2181 :         g_assert (GKM_IS_SECRET_COLLECTION (self));
     182         2181 :         g_assert (GKM_IS_SECRET_ITEM (item));
     183              : 
     184         2181 :         identifier = gkm_secret_object_get_identifier (GKM_SECRET_OBJECT (item));
     185         2181 :         g_return_if_fail (identifier);
     186              : 
     187              :         /* Make note of the highest numeric identifier, for later use */
     188         2181 :         number = strtoul (identifier, NULL, 10);
     189         2181 :         if (number > self->watermark)
     190          136 :                 self->watermark = number;
     191              : 
     192         4362 :         g_hash_table_replace (self->items, g_strdup (identifier), g_object_ref (item));
     193              : 
     194         2181 :         if (gkm_object_is_exposed (GKM_OBJECT (self)))
     195         2006 :                 gkm_object_expose_full (GKM_OBJECT (item), transaction, TRUE);
     196         2181 :         if (transaction)
     197            8 :                 gkm_transaction_add (transaction, self, (GkmTransactionFunc)complete_add,
     198              :                                      g_object_ref (item));
     199              : 
     200              : }
     201              : 
     202              : static gboolean
     203            4 : complete_remove (GkmTransaction *transaction, GkmSecretCollection *self, GkmSecretItem *item)
     204              : {
     205            4 :         if (gkm_transaction_get_failed (transaction))
     206            1 :                 add_item (self, NULL, item);
     207            4 :         g_object_unref (item);
     208            4 :         return TRUE;
     209              : }
     210              : 
     211              : static void
     212           12 : remove_item (GkmSecretCollection *self, GkmTransaction *transaction, GkmSecretItem *item)
     213              : {
     214              :         const gchar *identifier;
     215              : 
     216           12 :         g_assert (GKM_IS_SECRET_COLLECTION (self));
     217           12 :         g_assert (GKM_IS_SECRET_ITEM (item));
     218              : 
     219           12 :         identifier = gkm_secret_object_get_identifier (GKM_SECRET_OBJECT (item));
     220           12 :         g_return_if_fail (identifier);
     221              : 
     222           12 :         g_object_ref (item);
     223              : 
     224           12 :         g_hash_table_remove (self->items, identifier);
     225              : 
     226           12 :         gkm_object_expose_full (GKM_OBJECT (item), transaction, FALSE);
     227           12 :         if (transaction)
     228            4 :                 gkm_transaction_add (transaction, self, (GkmTransactionFunc)complete_remove,
     229              :                                      g_object_ref (item));
     230              : 
     231           12 :         g_object_unref (item);
     232              : }
     233              : 
     234              : static GkmObject*
     235           12 : factory_create_collection (GkmSession *session, GkmTransaction *transaction,
     236              :                            CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
     237              : {
     238           12 :         GkmSecretCollection *collection = NULL;
     239              :         CK_OBJECT_HANDLE handle;
     240              :         CK_ATTRIBUTE *attr;
     241              :         GkmManager *manager;
     242              :         GkmModule *module;
     243           12 :         gchar *identifier = NULL;
     244              :         GkmSecretData *sdata;
     245           12 :         gchar *label = NULL;
     246              :         GkmCredential *cred;
     247              :         gboolean is_token;
     248              :         CK_RV rv;
     249              : 
     250           12 :         g_return_val_if_fail (GKM_IS_TRANSACTION (transaction), NULL);
     251           12 :         g_return_val_if_fail (attrs || !n_attrs, NULL);
     252              : 
     253           12 :         manager = gkm_manager_for_template (attrs, n_attrs, session);
     254           12 :         module = gkm_session_get_module (session);
     255              : 
     256              :         /* Must have a credential, which is not associated with an object yet */
     257           12 :         if (!gkm_attributes_find_ulong (attrs, n_attrs, CKA_G_CREDENTIAL, &handle)) {
     258            0 :                 gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
     259            0 :                 return NULL;
     260              :         }
     261              : 
     262           12 :         cred = lookup_unassociated_credential (session, handle);
     263           12 :         if (cred == NULL) {
     264            0 :                 gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
     265            0 :                 return NULL;
     266              :         }
     267              : 
     268              :         /* The identifier */
     269           12 :         attr = gkm_attributes_find (attrs, n_attrs, CKA_ID);
     270           12 :         if (attr != NULL) {
     271            2 :                 gkm_attribute_consume (attr);
     272            2 :                 rv = gkm_attribute_get_string (attr, &identifier);
     273            2 :                 if (rv != CKR_OK) {
     274            0 :                         gkm_transaction_fail (transaction, rv);
     275            0 :                         return NULL;
     276              :                 }
     277              : 
     278              :                 /* Try to find the collection with that identifier */
     279            2 :                 if (!gkm_attributes_find_boolean (attrs, n_attrs, CKA_TOKEN, &is_token))
     280            0 :                         collection = gkm_secret_collection_find (session, attr,
     281              :                                                                  gkm_module_get_manager (module),
     282              :                                                                  gkm_session_get_manager (session), NULL);
     283            2 :                 else if (is_token)
     284            2 :                         collection = gkm_secret_collection_find (session, attr,
     285              :                                                                  gkm_module_get_manager (module), NULL);
     286              :                 else
     287            0 :                         collection = gkm_secret_collection_find (session, attr,
     288              :                                                                  gkm_session_get_manager (session), NULL);
     289              : 
     290              :                 /* Already have one with this identifier? Just return that */
     291            2 :                 if (collection != NULL) {
     292            0 :                         gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (collection),
     293              :                                                               FALSE, attrs, n_attrs);
     294            0 :                         return GKM_OBJECT (g_object_ref (collection));
     295              :                 }
     296              :         }
     297              : 
     298              :         /* The label  */
     299           12 :         attr = gkm_attributes_find (attrs, n_attrs, CKA_LABEL);
     300           12 :         if (attr != NULL) {
     301           11 :                 gkm_attribute_consume (attr);
     302           11 :                 rv = gkm_attribute_get_string (attr, &label);
     303           11 :                 if (rv != CKR_OK) {
     304            0 :                         gkm_transaction_fail (transaction, rv);
     305            0 :                         return NULL;
     306              :                 }
     307              : 
     308              :                 /* No identifier? Use label */
     309           11 :                 if (identifier == NULL)
     310           18 :                         identifier = g_strdup (label);
     311              :         }
     312              : 
     313           12 :         if (!identifier || !identifier[0]) {
     314            1 :                 g_free (identifier);
     315            1 :                 identifier = g_strdup ("unnamed");
     316              :         }
     317              : 
     318           12 :         if (!label || !label[0]) {
     319            1 :                 g_free (label);
     320            1 :                 if (identifier) {
     321            2 :                         label = g_strdup (identifier);
     322              :                 } else {
     323              :                         /* TRANSLATORS: This is the label for an keyring created without a label */
     324            0 :                         label = g_strdup (_("Unnamed"));
     325              :                 }
     326              :         }
     327              : 
     328           12 :         g_strdelimit (identifier, ":/\\<>|\t\n\r\v ", '_');
     329           12 :         collection = g_object_new (GKM_TYPE_SECRET_COLLECTION,
     330              :                                    "module", gkm_session_get_module (session),
     331              :                                    "identifier", identifier,
     332              :                                    "manager", manager,
     333              :                                    "label", label,
     334              :                                    NULL);
     335              : 
     336           12 :         gkm_secret_object_mark_created (GKM_SECRET_OBJECT (collection));
     337           12 :         g_free (identifier);
     338           12 :         g_free (label);
     339              : 
     340           12 :         gkm_credential_connect (cred, GKM_OBJECT (collection));
     341           12 :         sdata = g_object_new (GKM_TYPE_SECRET_DATA, NULL);
     342           12 :         gkm_credential_set_data (cred, GKM_TYPE_SECRET_DATA, sdata);
     343           12 :         gkm_secret_data_set_master (sdata, gkm_credential_get_secret (cred));
     344           12 :         track_secret_data (collection, sdata);
     345           12 :         g_object_unref (sdata);
     346              : 
     347           12 :         gkm_attributes_consume (attrs, n_attrs, CKA_G_CREDENTIAL, G_MAXULONG);
     348           12 :         gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (collection),
     349              :                                               TRUE, attrs, n_attrs);
     350           12 :         return GKM_OBJECT (collection);
     351              : }
     352              : 
     353              : static gboolean
     354            0 : complete_master_password (GkmTransaction *transaction, GObject *object, gpointer user_data)
     355              : {
     356            0 :         GkmSecretCollection *self = GKM_SECRET_COLLECTION (object);
     357            0 :         GkmSecret *previous = user_data;
     358              : 
     359            0 :         if (gkm_transaction_get_failed (transaction)) {
     360            0 :                 if (self->sdata)
     361            0 :                         gkm_secret_data_set_master (self->sdata, previous);
     362              :         }
     363              : 
     364            0 :         if (previous)
     365            0 :                 g_object_unref (previous);
     366              : 
     367            0 :         return TRUE;
     368              : }
     369              : 
     370              : static void
     371            0 : change_master_password (GkmSecretCollection *self, GkmTransaction *transaction,
     372              :                         GkmCredential *cred)
     373              : {
     374              :         GkmSecret *previous;
     375              : 
     376            0 :         g_assert (GKM_IS_SECRET_COLLECTION (self));
     377            0 :         g_assert (GKM_IS_TRANSACTION (transaction));
     378            0 :         g_assert (GKM_IS_CREDENTIAL (cred));
     379              : 
     380            0 :         if (!self->sdata) {
     381            0 :                 gkm_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
     382            0 :                 return;
     383              :         }
     384              : 
     385            0 :         previous = gkm_secret_data_get_master (self->sdata);
     386            0 :         if (previous != NULL)
     387            0 :                 g_object_ref (previous);
     388              : 
     389            0 :         gkm_credential_connect (cred, GKM_OBJECT (self));
     390            0 :         gkm_credential_set_data (cred, GKM_TYPE_SECRET_DATA, self->sdata);
     391            0 :         gkm_secret_data_set_master (self->sdata, gkm_credential_get_secret (cred));
     392              : 
     393            0 :         gkm_transaction_add (transaction, self, complete_master_password, previous);
     394              : }
     395              : 
     396              : /* -----------------------------------------------------------------------------
     397              :  * OBJECT
     398              :  */
     399              : 
     400              : static CK_RV
     401         1115 : gkm_secret_collection_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE_PTR attr)
     402              : {
     403         1115 :         GkmSecretCollection *self = GKM_SECRET_COLLECTION (base);
     404              :         const gchar *identifier;
     405              :         GkmSecret *master;
     406              : 
     407         1115 :         switch (attr->type) {
     408          416 :         case CKA_CLASS:
     409          416 :                 return gkm_attribute_set_ulong (attr, CKO_G_COLLECTION);
     410            2 :         case CKA_G_CREDENTIAL_TEMPLATE:
     411            2 :                 return gkm_attribute_set_template (attr, self->template);
     412           16 :         case CKA_G_LOGIN_COLLECTION:
     413           16 :                 identifier = gkm_secret_object_get_identifier (GKM_SECRET_OBJECT (base));
     414           16 :                 g_return_val_if_fail (identifier, CKR_GENERAL_ERROR);
     415           16 :                 return gkm_attribute_set_bool (attr, g_str_equal (identifier, "login"));
     416            0 :         case CKA_TRUSTED:
     417            0 :                 if (!self->sdata)
     418            0 :                         return gkm_attribute_set_bool (attr, CK_FALSE);
     419            0 :                 master = gkm_secret_data_get_master (self->sdata);
     420            0 :                 return gkm_attribute_set_bool (attr, (master && !gkm_secret_is_trivially_weak (master)));
     421              :         }
     422          681 :         return GKM_OBJECT_CLASS (gkm_secret_collection_parent_class)->get_attribute (base, session, attr);
     423              : }
     424              : 
     425              : static void
     426            3 : gkm_secret_collection_set_attribute (GkmObject *object, GkmSession *session,
     427              :                                      GkmTransaction *transaction, CK_ATTRIBUTE *attr)
     428              : {
     429            3 :         GkmSecretCollection *self = GKM_SECRET_COLLECTION (object);
     430            3 :         CK_OBJECT_HANDLE handle = 0;
     431              :         GkmCredential *cred;
     432              :         GArray *template;
     433              :         CK_RV rv;
     434              : 
     435            3 :         switch (attr->type) {
     436            0 :         case CKA_G_CREDENTIAL:
     437            0 :                 gkm_credential_for_each (session, GKM_OBJECT (self),
     438              :                                          find_unlocked_credential, &handle);
     439            0 :                 if (handle == 0) {
     440            0 :                         gkm_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
     441            2 :                         return;
     442              :                 }
     443            0 :                 rv = gkm_attribute_get_ulong (attr, &handle);
     444            0 :                 if (rv != CKR_OK) {
     445            0 :                         gkm_transaction_fail (transaction, rv);
     446            0 :                         return;
     447              :                 }
     448            0 :                 cred = lookup_unassociated_credential (session, handle);
     449            0 :                 if (cred == NULL) {
     450            0 :                         gkm_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
     451            0 :                         return;
     452              :                 }
     453            0 :                 change_master_password (self, transaction, cred);
     454            0 :                 return;
     455            2 :         case CKA_G_CREDENTIAL_TEMPLATE:
     456            2 :                 rv = gkm_attribute_get_template (attr, &template);
     457            2 :                 if (rv != CKR_OK) {
     458            0 :                         gkm_transaction_fail (transaction, rv);
     459            0 :                         return;
     460              :                 }
     461            2 :                 gkm_template_free (self->template);
     462            2 :                 self->template = template;
     463            2 :                 return;
     464              :         };
     465              : 
     466            1 :         GKM_OBJECT_CLASS (gkm_secret_collection_parent_class)->set_attribute (object, session, transaction, attr);
     467              : }
     468              : 
     469              : static CK_RV
     470          148 : gkm_secret_collection_real_unlock (GkmObject *obj, GkmCredential *cred)
     471              : {
     472          148 :         GkmSecretCollection *self = GKM_SECRET_COLLECTION (obj);
     473              :         GkmDataResult res;
     474              :         GkmSecretData *sdata;
     475              :         GkmSecret *master;
     476          148 :         CK_RV rv = CKR_GENERAL_ERROR;
     477              : 
     478          148 :         master = gkm_credential_get_secret (cred);
     479              : 
     480              :         /* Already unlocked, make sure pin matches */
     481          148 :         if (self->sdata) {
     482            2 :                 if (!gkm_secret_equal (gkm_secret_data_get_master (self->sdata), master))
     483            1 :                         return CKR_PIN_INCORRECT;
     484              : 
     485              :                 /* Credential now tracks our secret data */
     486            1 :                 gkm_credential_set_data (cred, GKM_TYPE_SECRET_DATA, self->sdata);
     487            1 :                 return CKR_OK;
     488              :         }
     489              : 
     490              :         /* New secret data object, setup master password */
     491          146 :         sdata = g_object_new (GKM_TYPE_SECRET_DATA, NULL);
     492          146 :         gkm_secret_data_set_master (sdata, master);
     493              : 
     494              :         /* Load the data from a file, and decrypt if necessary */
     495          146 :         if (self->filename) {
     496           29 :                 res = load_collection_and_secret_data (self, sdata, self->filename);
     497              : 
     498              :         /* No filename, password must be null */
     499              :         } else {
     500          117 :                 if (gkm_secret_equals (master, NULL, 0))
     501          116 :                         res = GKM_DATA_SUCCESS;
     502              :                 else
     503            1 :                         res = GKM_DATA_LOCKED;
     504              :         }
     505              : 
     506          146 :         switch (res) {
     507          141 :         case GKM_DATA_SUCCESS:
     508          141 :                 gkm_credential_set_data (cred, GKM_TYPE_SECRET_DATA, sdata);
     509          141 :                 track_secret_data (self, sdata);
     510          141 :                 rv = CKR_OK;
     511          141 :                 break;
     512            5 :         case GKM_DATA_LOCKED:
     513            5 :                 rv = CKR_PIN_INCORRECT;
     514            5 :                 break;
     515            0 :         case GKM_DATA_UNRECOGNIZED:
     516            0 :                 g_message ("unrecognized or invalid keyring: %s", self->filename);
     517            0 :                 rv = CKR_FUNCTION_FAILED;
     518            0 :                 break;
     519            0 :         case GKM_DATA_FAILURE:
     520            0 :                 g_message ("failed to read or parse keyring: %s", self->filename);
     521            0 :                 rv = CKR_GENERAL_ERROR;
     522            0 :                 break;
     523            0 :         default:
     524            0 :                 g_assert_not_reached ();
     525              :         }
     526              : 
     527          146 :         g_object_unref (sdata);
     528          146 :         return rv;
     529              : }
     530              : 
     531              : static void
     532          396 : gkm_secret_collection_expose (GkmObject *base, gboolean expose)
     533              : {
     534          396 :         GKM_OBJECT_CLASS (gkm_secret_collection_parent_class)->expose_object (base, expose);
     535          396 :         g_hash_table_foreach (GKM_SECRET_COLLECTION (base)->items, expose_each_item, GINT_TO_POINTER (expose));
     536          396 : }
     537              : 
     538              : static gboolean
     539          144 : gkm_secret_collection_real_is_locked (GkmSecretObject *obj, GkmSession *session)
     540              : {
     541          144 :         GkmSecretCollection *self = GKM_SECRET_COLLECTION (obj);
     542          144 :         return !gkm_secret_collection_unlocked_have (self, session);
     543              : }
     544              : 
     545              : static void
     546          252 : gkm_secret_collection_init (GkmSecretCollection *self)
     547              : {
     548          252 :         CK_ULONG idle = 0;
     549          252 :         CK_ULONG after = 0;
     550          252 :         CK_BBOOL token = CK_TRUE;
     551          252 :         CK_ATTRIBUTE attrs[] = {
     552              :                 { CKA_TOKEN, &token, sizeof (token) },
     553              :                 { CKA_GNOME_TRANSIENT, &token, sizeof (token) },
     554              :                 { CKA_G_DESTRUCT_IDLE, &idle, sizeof (idle) },
     555              :                 { CKA_G_DESTRUCT_AFTER, &after, sizeof (after) },
     556              :         };
     557              : 
     558          252 :         self->items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
     559          252 :         self->template = gkm_template_new (attrs, G_N_ELEMENTS (attrs));
     560          252 : }
     561              : 
     562              : static void
     563          252 : gkm_secret_collection_set_property (GObject *obj, guint prop_id, const GValue *value,
     564              :                                     GParamSpec *pspec)
     565              : {
     566          252 :         GkmSecretCollection *self = GKM_SECRET_COLLECTION (obj);
     567              : 
     568          252 :         switch (prop_id) {
     569          252 :         case PROP_FILENAME:
     570          252 :                 gkm_secret_collection_set_filename (self, g_value_get_string (value));
     571          252 :                 break;
     572            0 :         default:
     573            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     574            0 :                 break;
     575              :         }
     576          252 : }
     577              : 
     578              : static void
     579            0 : gkm_secret_collection_get_property (GObject *obj, guint prop_id, GValue *value,
     580              :                                     GParamSpec *pspec)
     581              : {
     582            0 :         GkmSecretCollection *self = GKM_SECRET_COLLECTION (obj);
     583              : 
     584            0 :         switch (prop_id) {
     585            0 :         case PROP_FILENAME:
     586            0 :                 g_value_set_string (value, gkm_secret_collection_get_filename (self));
     587            0 :                 break;
     588            0 :         default:
     589            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     590            0 :                 break;
     591              :         }
     592            0 : }
     593              : 
     594              : static void
     595          365 : gkm_secret_collection_dispose (GObject *obj)
     596              : {
     597          365 :         GkmSecretCollection *self = GKM_SECRET_COLLECTION (obj);
     598              : 
     599          365 :         track_secret_data (self, NULL);
     600          365 :         g_hash_table_remove_all (self->items);
     601              : 
     602          365 :         G_OBJECT_CLASS (gkm_secret_collection_parent_class)->dispose (obj);
     603          365 : }
     604              : 
     605              : static void
     606          252 : gkm_secret_collection_finalize (GObject *obj)
     607              : {
     608          252 :         GkmSecretCollection *self = GKM_SECRET_COLLECTION (obj);
     609              : 
     610          252 :         g_assert (self->sdata == NULL);
     611              : 
     612          252 :         g_hash_table_destroy (self->items);
     613          252 :         self->items = NULL;
     614              : 
     615          252 :         g_free (self->filename);
     616          252 :         self->filename = NULL;
     617              : 
     618          252 :         gkm_template_free (self->template);
     619          252 :         self->template = NULL;
     620              : 
     621          252 :         G_OBJECT_CLASS (gkm_secret_collection_parent_class)->finalize (obj);
     622          252 : }
     623              : 
     624              : static void
     625           34 : gkm_secret_collection_class_init (GkmSecretCollectionClass *klass)
     626              : {
     627           34 :         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     628           34 :         GkmObjectClass *gkm_class = GKM_OBJECT_CLASS (klass);
     629           34 :         GkmSecretObjectClass *secret_class = GKM_SECRET_OBJECT_CLASS (klass);
     630              : 
     631           34 :         gkm_secret_collection_parent_class = g_type_class_peek_parent (klass);
     632              : 
     633           34 :         gobject_class->set_property = gkm_secret_collection_set_property;
     634           34 :         gobject_class->get_property = gkm_secret_collection_get_property;
     635           34 :         gobject_class->dispose = gkm_secret_collection_dispose;
     636           34 :         gobject_class->finalize = gkm_secret_collection_finalize;
     637              : 
     638           34 :         gkm_class->get_attribute = gkm_secret_collection_get_attribute;
     639           34 :         gkm_class->set_attribute = gkm_secret_collection_set_attribute;
     640           34 :         gkm_class->unlock = gkm_secret_collection_real_unlock;
     641           34 :         gkm_class->expose_object = gkm_secret_collection_expose;
     642              : 
     643           34 :         secret_class->is_locked = gkm_secret_collection_real_is_locked;
     644              : 
     645           34 :         g_object_class_install_property (gobject_class, PROP_FILENAME,
     646              :                    g_param_spec_string ("filename", "Filename", "Collection filename (without path)",
     647              :                                         NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
     648              : 
     649           34 :         gkm_secret_object_class_unique_identifiers (secret_class);
     650           34 : }
     651              : 
     652              : /* -----------------------------------------------------------------------------
     653              :  * PUBLIC
     654              :  */
     655              : 
     656              : GkmFactory*
     657          117 : gkm_secret_collection_get_factory (void)
     658              : {
     659              :         static CK_OBJECT_CLASS klass = CKO_G_COLLECTION;
     660              : 
     661              :         static CK_ATTRIBUTE attributes[] = {
     662              :                 { CKA_CLASS, &klass, sizeof (klass) },
     663              :         };
     664              : 
     665              :         static GkmFactory factory = {
     666              :                 attributes,
     667              :                 G_N_ELEMENTS (attributes),
     668              :                 factory_create_collection
     669              :         };
     670              : 
     671          117 :         return &factory;
     672              : }
     673              : 
     674              : const gchar*
     675           71 : gkm_secret_collection_get_filename (GkmSecretCollection *self)
     676              : {
     677           71 :         g_return_val_if_fail (GKM_IS_SECRET_COLLECTION (self), NULL);
     678           71 :         return self->filename;
     679              : }
     680              : 
     681              : void
     682          273 : gkm_secret_collection_set_filename (GkmSecretCollection *self, const gchar *filename)
     683              : {
     684          273 :         g_return_if_fail (GKM_IS_SECRET_COLLECTION (self));
     685              : 
     686          273 :         if (self->filename == filename)
     687          192 :                 return;
     688           81 :         g_free (self->filename);
     689           81 :         self->filename = g_strdup (filename);
     690           81 :         g_object_notify (G_OBJECT (self), "filename");
     691              : }
     692              : 
     693              : GList*
     694          160 : gkm_secret_collection_get_items (GkmSecretCollection *self)
     695              : {
     696          160 :         GList *items = NULL;
     697          160 :         g_return_val_if_fail (GKM_IS_SECRET_COLLECTION (self), NULL);
     698          160 :         g_hash_table_foreach (self->items, each_value_to_list, &items);
     699          160 :         return items;
     700              : }
     701              : 
     702              : GkmSecretItem*
     703          195 : gkm_secret_collection_get_item (GkmSecretCollection *self, const gchar *identifier)
     704              : {
     705          195 :         g_return_val_if_fail (GKM_IS_SECRET_COLLECTION (self), NULL);
     706          195 :         g_return_val_if_fail (identifier, NULL);
     707          195 :         return g_hash_table_lookup (self->items, identifier);
     708              : }
     709              : 
     710              : gboolean
     711           22 : gkm_secret_collection_has_item (GkmSecretCollection *self, GkmSecretItem *item)
     712              : {
     713              :         const gchar *identifier;
     714              : 
     715           22 :         g_return_val_if_fail (GKM_IS_SECRET_COLLECTION (self), FALSE);
     716           22 :         g_return_val_if_fail (GKM_IS_SECRET_ITEM (item), FALSE);
     717              : 
     718           22 :         identifier = gkm_secret_object_get_identifier (GKM_SECRET_OBJECT (item));
     719           22 :         return g_hash_table_lookup (self->items, identifier) == item;
     720              : }
     721              : 
     722              : GkmSecretCollection*
     723           10 : gkm_secret_collection_find (GkmSession *session, CK_ATTRIBUTE_PTR attr, ...)
     724              : {
     725           10 :         CK_OBJECT_CLASS klass = CKO_G_COLLECTION;
     726           10 :         GkmSecretCollection *result = NULL;
     727              :         GkmManager *manager;
     728              :         CK_ATTRIBUTE attrs[2];
     729              :         GList *objects;
     730              :         va_list va;
     731              : 
     732           10 :         g_assert (attr);
     733              : 
     734           10 :         attrs[0].type = CKA_CLASS;
     735           10 :         attrs[0].ulValueLen = sizeof (klass);
     736           10 :         attrs[0].pValue = &klass;
     737           10 :         attrs[1].type = CKA_ID;
     738           10 :         attrs[1].ulValueLen = attr->ulValueLen;
     739           10 :         attrs[1].pValue = attr->pValue;
     740              : 
     741           10 :         va_start (va, attr);
     742           20 :         while (!result && (manager = va_arg (va, GkmManager*)) != NULL) {
     743           10 :                 objects = gkm_manager_find_by_attributes (manager, session, attrs, 2);
     744           10 :                 if (objects && GKM_IS_SECRET_COLLECTION (objects->data))
     745            8 :                         result = objects->data;
     746           10 :                 g_list_free (objects);
     747              :         }
     748           10 :         va_end (va);
     749              : 
     750           10 :         return result;
     751              : }
     752              : 
     753              : GkmSecretItem*
     754         2172 : gkm_secret_collection_new_item (GkmSecretCollection *self, const gchar *identifier)
     755              : {
     756              :         GkmSecretItem *item;
     757              : 
     758         2172 :         g_return_val_if_fail (GKM_IS_SECRET_COLLECTION (self), NULL);
     759         2172 :         g_return_val_if_fail (identifier, NULL);
     760         2172 :         g_return_val_if_fail (!g_hash_table_lookup (self->items, identifier), NULL);
     761              : 
     762         4344 :         item = g_object_new (GKM_TYPE_SECRET_ITEM,
     763         2172 :                              "module", gkm_object_get_module (GKM_OBJECT (self)),
     764         2172 :                              "manager", gkm_object_get_manager (GKM_OBJECT (self)),
     765              :                              "collection", self,
     766              :                              "identifier", identifier,
     767              :                              NULL);
     768              : 
     769         2172 :         add_item (self, NULL, item);
     770         2172 :         g_object_unref (item);
     771         2172 :         return item;
     772              : }
     773              : 
     774              : GkmSecretItem*
     775            8 : gkm_secret_collection_create_item (GkmSecretCollection *self, GkmTransaction *transaction)
     776              : {
     777              :         GkmSecretItem *item;
     778            8 :         gchar *identifier = NULL;
     779              : 
     780            8 :         g_return_val_if_fail (GKM_IS_SECRET_COLLECTION (self), NULL);
     781            8 :         g_return_val_if_fail (transaction, NULL);
     782            8 :         g_return_val_if_fail (!gkm_transaction_get_failed (transaction), NULL);
     783              : 
     784              :         do {
     785            8 :                 g_free (identifier);
     786            8 :                 identifier = g_strdup_printf ("%d", ++(self->watermark));
     787            8 :         } while (g_hash_table_lookup (self->items, identifier));
     788              : 
     789           16 :         item = g_object_new (GKM_TYPE_SECRET_ITEM,
     790            8 :                              "module", gkm_object_get_module (GKM_OBJECT (self)),
     791            8 :                              "manager", gkm_object_get_manager (GKM_OBJECT (self)),
     792              :                              "collection", self,
     793              :                              "identifier", identifier,
     794              :                              NULL);
     795              : 
     796            8 :         g_free (identifier);
     797            8 :         add_item (self, transaction, item);
     798            8 :         gkm_secret_object_mark_created (GKM_SECRET_OBJECT (item));
     799            8 :         g_object_unref (item);
     800            8 :         return item;
     801              : }
     802              : 
     803              : void
     804            7 : gkm_secret_collection_remove_item (GkmSecretCollection *self, GkmSecretItem *item)
     805              : {
     806            7 :         g_return_if_fail (GKM_IS_SECRET_COLLECTION (self));
     807            7 :         g_return_if_fail (GKM_IS_SECRET_ITEM (item));
     808            7 :         g_return_if_fail (gkm_secret_collection_has_item (self, item));
     809              : 
     810            7 :         remove_item (self, NULL, item);
     811              : }
     812              : 
     813              : void
     814            4 : gkm_secret_collection_destroy_item (GkmSecretCollection *self, GkmTransaction *transaction,
     815              :                                     GkmSecretItem *item)
     816              : {
     817            4 :         g_return_if_fail (GKM_IS_SECRET_COLLECTION (self));
     818            4 :         g_return_if_fail (GKM_IS_TRANSACTION (transaction));
     819            4 :         g_return_if_fail (GKM_IS_SECRET_ITEM (item));
     820            4 :         g_return_if_fail (gkm_secret_collection_has_item (self, item));
     821              : 
     822            4 :         remove_item (self, transaction, item);
     823              : }
     824              : 
     825              : gboolean
     826          160 : gkm_secret_collection_unlocked_have (GkmSecretCollection *self, GkmSession *session)
     827              : {
     828          160 :         CK_OBJECT_HANDLE handle = 0;
     829              : 
     830          160 :         g_return_val_if_fail (GKM_IS_SECRET_COLLECTION (self), FALSE);
     831          160 :         g_return_val_if_fail (GKM_IS_SESSION (session), FALSE);
     832              : 
     833              :         /*
     834              :          * Look for credential objects that this session has access
     835              :          * to, and use those to find the secret data. If a secret data is
     836              :          * found, it should match the one we are tracking in self->sdata.
     837              :          */
     838              : 
     839          160 :         gkm_credential_for_each (session, GKM_OBJECT (self), find_unlocked_credential, &handle);
     840          160 :         return handle != 0;
     841              : }
     842              : 
     843              : GkmSecretData*
     844           23 : gkm_secret_collection_unlocked_use (GkmSecretCollection *self, GkmSession *session)
     845              : {
     846           23 :         GkmSecretData *sdata = NULL;
     847              : 
     848           23 :         g_return_val_if_fail (GKM_IS_SECRET_COLLECTION (self), NULL);
     849           23 :         g_return_val_if_fail (GKM_IS_SESSION (session), NULL);
     850              : 
     851              :         /*
     852              :          * Look for credential objects that this session has access
     853              :          * to, and use those to find the secret data. If a secret data is
     854              :          * found, it should match the one we are tracking in self->sdata.
     855              :          */
     856              : 
     857           23 :         gkm_credential_for_each (session, GKM_OBJECT (self),
     858              :                                  find_unlocked_secret_data, &sdata);
     859              : 
     860           23 :         return sdata;
     861              : }
     862              : 
     863              : void
     864            0 : gkm_secret_collection_unlocked_clear (GkmSecretCollection *self)
     865              : {
     866              :         /*
     867              :          * TODO: This is a tough one to implement. I'm holding off and wondering
     868              :          * if we don't need it, perhaps? As it currently stands, what needs to happen
     869              :          * here is we need to find each and every credential that references the
     870              :          * secret data for this collection and completely delete those objects.
     871              :          */
     872            0 :         g_warning ("Clearing of secret data needs implementing");
     873            0 :         track_secret_data (self, NULL);
     874            0 : }
     875              : 
     876              : GkmDataResult
     877           70 : gkm_secret_collection_load (GkmSecretCollection *self)
     878              : {
     879           70 :         g_return_val_if_fail (GKM_IS_SECRET_COLLECTION (self), GKM_DATA_FAILURE);
     880              : 
     881           70 :         if (!self->filename)
     882            2 :                 return GKM_DATA_SUCCESS;
     883              : 
     884           68 :         return load_collection_and_secret_data (self, self->sdata, self->filename);
     885              : }
     886              : 
     887              : void
     888           22 : gkm_secret_collection_save (GkmSecretCollection *self, GkmTransaction *transaction)
     889              : {
     890              :         GkmSecret *master;
     891              :         GkmDataResult res;
     892              :         gpointer data;
     893              :         gsize n_data;
     894              : 
     895           22 :         g_return_if_fail (GKM_IS_SECRET_COLLECTION (self));
     896           22 :         g_return_if_fail (GKM_IS_TRANSACTION (transaction));
     897           22 :         g_return_if_fail (!gkm_transaction_get_failed (transaction));
     898              : 
     899              :         /* HACK: We can't save unless the secret data was loaded */
     900           22 :         if (!self->sdata) {
     901            0 :                 gkm_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
     902            0 :                 return;
     903              :         }
     904              : 
     905              :         /* Don't save ourselves if no filename */
     906           22 :         if (!self->filename)
     907            0 :                 return;
     908              : 
     909           22 :         master = gkm_secret_data_get_master (self->sdata);
     910           22 :         if (master == NULL || gkm_secret_equals (master, NULL, 0))
     911            7 :                 res = gkm_secret_textual_write (self, self->sdata, &data, &n_data);
     912              :         else
     913           15 :                 res = gkm_secret_binary_write (self, self->sdata, &data, &n_data);
     914              : 
     915           22 :         switch (res) {
     916            0 :         case GKM_DATA_FAILURE:
     917              :         case GKM_DATA_UNRECOGNIZED:
     918            0 :                 g_warning ("couldn't prepare to write out keyring: %s", self->filename);
     919            0 :                 gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
     920            0 :                 break;
     921            0 :         case GKM_DATA_LOCKED:
     922            0 :                 g_warning ("locked error while writing out keyring: %s", self->filename);
     923            0 :                 gkm_transaction_fail (transaction, CKR_GENERAL_ERROR);
     924            0 :                 break;
     925           22 :         case GKM_DATA_SUCCESS:
     926           22 :                 gkm_transaction_write_file (transaction, self->filename, data, n_data);
     927           22 :                 g_free (data);
     928           22 :                 break;
     929            0 :         default:
     930            0 :                 g_assert_not_reached ();
     931              :         };
     932              : }
     933              : 
     934              : void
     935            2 : gkm_secret_collection_destroy (GkmSecretCollection *self, GkmTransaction *transaction)
     936              : {
     937            2 :         g_return_if_fail (GKM_IS_SECRET_COLLECTION (self));
     938            2 :         g_return_if_fail (GKM_IS_TRANSACTION (transaction));
     939            2 :         g_return_if_fail (!gkm_transaction_get_failed (transaction));
     940              : 
     941            2 :         gkm_object_expose_full (GKM_OBJECT (self), transaction, FALSE);
     942            2 :         if (self->filename)
     943            2 :                 gkm_transaction_remove_file (transaction, self->filename);
     944              : }
     945              : 
     946              : gint
     947           24 : gkm_secret_collection_get_lock_idle (GkmSecretCollection *self)
     948              : {
     949              :         gulong value;
     950           24 :         g_return_val_if_fail (GKM_IS_SECRET_COLLECTION (self), 0);
     951           24 :         if (!gkm_template_find_ulong (self->template, CKA_G_DESTRUCT_IDLE, &value))
     952            3 :                 value = 0;
     953           24 :         return (gint)value;
     954              : }
     955              : 
     956              : void
     957            0 : gkm_secret_collection_set_lock_idle (GkmSecretCollection *self, gint lock_timeout)
     958              : {
     959            0 :         CK_ULONG value = (lock_timeout < 0) ? 0 : lock_timeout;
     960            0 :         CK_ATTRIBUTE attr = { CKA_G_DESTRUCT_IDLE, &value, sizeof (value) };
     961            0 :         g_return_if_fail (GKM_IS_SECRET_COLLECTION (self));
     962            0 :         gkm_template_set (self->template, &attr);
     963              : }
     964              : 
     965              : gint
     966           24 : gkm_secret_collection_get_lock_after (GkmSecretCollection *self)
     967              : {
     968              :         gulong value;
     969           24 :         g_return_val_if_fail (GKM_IS_SECRET_COLLECTION (self), 0);
     970           24 :         if (!gkm_template_find_ulong (self->template, CKA_G_DESTRUCT_AFTER, &value))
     971            3 :                 value = 0;
     972           24 :         return (gint)value;
     973              : }
     974              : 
     975              : void
     976            0 : gkm_secret_collection_set_lock_after (GkmSecretCollection *self, gint lock_timeout)
     977              : {
     978            0 :         CK_ULONG value = (lock_timeout < 0) ? 0 : lock_timeout;
     979            0 :         CK_ATTRIBUTE attr = { CKA_G_DESTRUCT_AFTER, &value, sizeof (value) };
     980            0 :         g_return_if_fail (GKM_IS_SECRET_COLLECTION (self));
     981            0 :         gkm_template_set (self->template, &attr);
     982              : }
        

Generated by: LCOV version 2.0-1