LCOV - code coverage report
Current view: top level - pkcs11/secret-store - gkm-secret-search.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 84.3 % 229 193
Test Date: 2024-04-08 13:24:42 Functions: 87.5 % 24 21

            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-fields.h"
      25              : #include "gkm-secret-item.h"
      26              : #include "gkm-secret-search.h"
      27              : 
      28              : #include "gkm/gkm-attributes.h"
      29              : #include "gkm/gkm-manager.h"
      30              : #include "gkm/gkm-module.h"
      31              : #include "gkm/gkm-session.h"
      32              : #include "gkm/gkm-transaction.h"
      33              : #include "gkm/gkm-util.h"
      34              : 
      35              : #include "pkcs11i.h"
      36              : 
      37              : #include <glib/gi18n.h>
      38              : 
      39              : enum {
      40              :         PROP_0,
      41              :         PROP_COLLECTION_ID,
      42              :         PROP_FIELDS,
      43              :         PROP_SCHEMA_NAME
      44              : };
      45              : 
      46              : struct _GkmSecretSearch {
      47              :         GkmObject parent;
      48              :         gchar *collection_id;
      49              :         GHashTable *fields;
      50              :         gchar *schema_name;
      51              :         GList *managers;
      52              :         GHashTable *objects;
      53              : };
      54              : 
      55         2577 : G_DEFINE_TYPE (GkmSecretSearch, gkm_secret_search, GKM_TYPE_OBJECT);
      56              : 
      57              : static gboolean
      58         2109 : match_object_against_criteria (GkmSecretSearch *self, GkmObject *object)
      59              : {
      60              :         GkmSecretCollection *collection;
      61              :         GkmSecretItem *item;
      62              :         GHashTable *fields;
      63              :         const gchar *identifier;
      64              :         const gchar *schema;
      65              : 
      66         2109 :         if (!GKM_IS_SECRET_ITEM (object))
      67           22 :                 return FALSE;
      68              : 
      69         2087 :         item = GKM_SECRET_ITEM (object);
      70              : 
      71              :         /* Collection should match unless any collection allowed */
      72         2087 :         if (self->collection_id) {
      73         2064 :                 collection = gkm_secret_item_get_collection (item);
      74         2064 :                 g_return_val_if_fail (collection, FALSE);
      75         2064 :                 identifier = gkm_secret_object_get_identifier (GKM_SECRET_OBJECT (collection));
      76         2064 :                 g_return_val_if_fail (identifier, FALSE);
      77         2064 :                 if (!g_str_equal (identifier, self->collection_id))
      78           43 :                         return FALSE;
      79              :         }
      80              : 
      81         2044 :         fields = gkm_secret_item_get_fields (item);
      82              : 
      83              :         /* Match the schema, if we have one */
      84         2044 :         if (self->schema_name) {
      85           12 :                 schema = gkm_secret_item_get_schema (item);
      86              : 
      87              :                 /* Does the item has a schema set from the item type? */
      88           12 :                 if (schema != NULL) {
      89           12 :                         if (!g_str_equal (schema, self->schema_name))
      90            8 :                                 return FALSE;
      91              : 
      92              :                 /* See if the item has a schema set in the attributes */
      93              :                 } else {
      94            0 :                         if (!gkm_secret_fields_match_one (fields, GKM_SECRET_FIELD_SCHEMA, self->schema_name))
      95            0 :                                 return FALSE;
      96              :                 }
      97              :         }
      98              : 
      99              :         /* Fields should match using our special algorithm */
     100         2036 :         return gkm_secret_fields_match (fields, self->fields);
     101              : }
     102              : 
     103              : static void
     104         2107 : on_manager_added_object (GkmManager *manager, GkmObject *object, gpointer user_data)
     105              : {
     106         2107 :         GkmSecretSearch *self = user_data;
     107              : 
     108         2107 :         g_return_if_fail (GKM_IS_SECRET_SEARCH (self));
     109              : 
     110         2107 :         g_return_if_fail (g_hash_table_lookup (self->objects, object) == NULL);
     111              : 
     112         2107 :         if (match_object_against_criteria (self, object)) {
     113         2011 :                 g_hash_table_replace (self->objects, g_object_ref (object), "unused");
     114         2011 :                 gkm_object_notify_attribute (GKM_OBJECT (self), CKA_G_MATCHED);
     115              :         }
     116              : }
     117              : 
     118              : static void
     119          148 : on_manager_removed_object (GkmManager *manager, GkmObject *object, gpointer user_data)
     120              : {
     121          148 :         GkmSecretSearch *self = user_data;
     122              : 
     123          148 :         g_return_if_fail (GKM_IS_SECRET_SEARCH (self));
     124              : 
     125          148 :         if (g_hash_table_remove (self->objects, object))
     126            0 :                 gkm_object_notify_attribute (GKM_OBJECT (self), CKA_G_MATCHED);
     127              : }
     128              : 
     129              : static void
     130            4 : on_manager_changed_object (GkmManager *manager, GkmObject *object,
     131              :                            CK_ATTRIBUTE_TYPE type, gpointer user_data)
     132              : {
     133            4 :         GkmSecretSearch *self = user_data;
     134              :         CK_OBJECT_HANDLE handle;
     135              : 
     136            4 :         if (type != CKA_G_FIELDS)
     137            2 :                 return;
     138              : 
     139            2 :         g_return_if_fail (GKM_IS_SECRET_SEARCH (self));
     140              : 
     141            2 :         handle = gkm_object_get_handle (object);
     142            2 :         g_return_if_fail (handle);
     143              : 
     144              :         /* Should we have this object? */
     145            2 :         if (match_object_against_criteria (self, object)) {
     146            1 :                 if (g_hash_table_lookup (self->objects, object) == NULL) {
     147            1 :                         g_hash_table_replace (self->objects, g_object_ref (object), "unused");
     148            1 :                         gkm_object_notify_attribute (GKM_OBJECT (self), CKA_G_MATCHED);
     149              :                 }
     150              : 
     151              :         /* Should we not have this object? */
     152              :         } else {
     153            1 :                 if (g_hash_table_remove (self->objects, object))
     154            1 :                         gkm_object_notify_attribute (GKM_OBJECT (self), CKA_G_MATCHED);
     155              :         }
     156              : }
     157              : 
     158              : static void
     159            0 : on_manager_gone_away (gpointer user_data, GObject *where_the_object_was)
     160              : {
     161            0 :         GkmSecretSearch *self = GKM_SECRET_SEARCH (user_data);
     162              :         GList *l;
     163              : 
     164            0 :         g_return_if_fail (self);
     165              : 
     166            0 :         l = g_list_find (self->managers, where_the_object_was);
     167            0 :         g_return_if_fail (l != NULL);
     168            0 :         self->managers = g_list_delete_link (self->managers, l);
     169              : }
     170              : 
     171              : static void
     172           40 : populate_search_from_manager (GkmSecretSearch *self, GkmSession *session, GkmManager *manager)
     173              : {
     174              :         GList *objects, *o;
     175              : 
     176           40 :         self->managers = g_list_append (self->managers, manager);
     177              : 
     178              :         /* Add in all the objects */
     179           40 :         objects = gkm_manager_find_by_class (manager, session, CKO_SECRET_KEY);
     180         2127 :         for (o = objects; o; o = g_list_next (o))
     181         2087 :                 on_manager_added_object (manager, o->data, self);
     182           40 :         g_list_free (objects);
     183              : 
     184              :         /* Track this manager */
     185           40 :         g_object_weak_ref (G_OBJECT (manager), on_manager_gone_away, self);
     186              : 
     187              :         /* Watch for further events of objects */
     188           40 :         g_signal_connect (manager, "object-added", G_CALLBACK (on_manager_added_object), self);
     189           40 :         g_signal_connect (manager, "object-removed", G_CALLBACK (on_manager_removed_object), self);
     190           40 :         g_signal_connect (manager, "attribute-changed", G_CALLBACK (on_manager_changed_object), self);
     191           40 : }
     192              : 
     193              : static GkmObject*
     194           22 : factory_create_search (GkmSession *session, GkmTransaction *transaction,
     195              :                        CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
     196              : {
     197              :         GkmManager *s_manager, *m_manager;
     198              :         GkmSecretSearch *search;
     199           22 :         gchar *identifier = NULL;
     200              :         CK_ATTRIBUTE *attr;
     201              :         GHashTable *fields;
     202              :         gchar *schema_name;
     203              :         GkmModule *module;
     204              :         CK_RV rv;
     205              : 
     206           22 :         g_return_val_if_fail (GKM_IS_TRANSACTION (transaction), NULL);
     207           22 :         g_return_val_if_fail (attrs || !n_attrs, NULL);
     208              : 
     209              :         /* Find the fields being requested */
     210           22 :         attr = gkm_attributes_find (attrs, n_attrs, CKA_G_FIELDS);
     211           22 :         if (attr == NULL) {
     212            1 :                 gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
     213            1 :                 return NULL;
     214              :         }
     215              : 
     216              :         /* Parse the fields, into our internal representation */
     217           21 :         rv = gkm_secret_fields_parse (attr, &fields, &schema_name);
     218           21 :         gkm_attribute_consume (attr);
     219           21 :         if (rv != CKR_OK) {
     220            1 :                 gkm_transaction_fail (transaction, rv);
     221            1 :                 return NULL;
     222              :         }
     223              : 
     224              :         /* Remove the schema name from the search fields, handle that separately */
     225           20 :         g_hash_table_remove (fields, GKM_SECRET_FIELD_SCHEMA);
     226              : 
     227           20 :         s_manager = gkm_session_get_manager (session);
     228           20 :         module = gkm_session_get_module (session);
     229           20 :         m_manager = gkm_module_get_manager (module);
     230              : 
     231              :         /* See if a collection attribute was specified, not present means all collections */
     232           20 :         attr = gkm_attributes_find (attrs, n_attrs, CKA_G_COLLECTION);
     233           20 :         if (attr) {
     234           15 :                 rv = gkm_attribute_get_string (attr, &identifier);
     235           15 :                 if (rv != CKR_OK) {
     236            0 :                         g_free (schema_name);
     237            0 :                         g_hash_table_unref (fields);
     238            0 :                         gkm_transaction_fail (transaction, rv);
     239            0 :                         return NULL;
     240              :                 }
     241              :         }
     242              : 
     243           20 :         search = g_object_new (GKM_TYPE_SECRET_SEARCH,
     244              :                                "module", module,
     245              :                                "manager", s_manager,
     246              :                                "fields", fields,
     247              :                                "schema-name", schema_name,
     248              :                                "collection-id", identifier,
     249              :                                NULL);
     250           20 :         g_free (identifier);
     251              : 
     252              :         /* Load any new items or collections */
     253           20 :         gkm_module_refresh_token (module);
     254              : 
     255           20 :         populate_search_from_manager (search, session, s_manager);
     256           20 :         populate_search_from_manager (search, session, m_manager);
     257              : 
     258           20 :         gkm_session_complete_object_creation (session, transaction, GKM_OBJECT (search),
     259              :                                               TRUE, attrs, n_attrs);
     260              : 
     261           20 :         g_hash_table_unref (fields);
     262           20 :         g_free (schema_name);
     263              : 
     264           20 :         return GKM_OBJECT (search);
     265              : }
     266              : 
     267              : static gint
     268        19362 : on_matched_sort_modified (gconstpointer a,
     269              :                           gconstpointer b)
     270              : {
     271              :         glong modified_a;
     272              :         glong modified_b;
     273              : 
     274              :         /* Sorting in reverse order */
     275              : 
     276        19362 :         modified_a = gkm_secret_object_get_modified (GKM_SECRET_OBJECT (a));
     277        19362 :         modified_b = gkm_secret_object_get_modified (GKM_SECRET_OBJECT (b));
     278              : 
     279        19362 :         if (modified_a < modified_b)
     280         9718 :                 return 1;
     281         9644 :         if (modified_a > modified_b)
     282         9644 :                 return -1;
     283              : 
     284            0 :         return 0;
     285              : }
     286              : 
     287              : static CK_RV
     288           42 : attribute_set_handles (GHashTable *objects,
     289              :                        CK_ATTRIBUTE_PTR attr)
     290              : {
     291              :         GList *list, *l;
     292              :         GArray *array;
     293              :         gulong handle;
     294              :         CK_RV rv;
     295              : 
     296           42 :         g_assert (objects);
     297           42 :         g_assert (attr);
     298              : 
     299              :         /* Want the length */
     300           42 :         if (!attr->pValue) {
     301           21 :                 attr->ulValueLen = sizeof (CK_OBJECT_HANDLE) * g_hash_table_size (objects);
     302           21 :                 return CKR_OK;
     303              :         }
     304              : 
     305              :         /* Get the actual values */
     306           21 :         list = g_list_sort (g_hash_table_get_keys (objects), on_matched_sort_modified);
     307           21 :         array = g_array_new (FALSE, TRUE, sizeof (CK_OBJECT_HANDLE));
     308              : 
     309         2033 :         for (l = list; l != NULL; l = g_list_next (l)) {
     310         2012 :                 handle = gkm_object_get_handle (l->data);
     311         2012 :                 g_array_append_val (array, handle);
     312              :         }
     313              : 
     314           21 :         rv = gkm_attribute_set_data (attr, array->data, array->len * sizeof (CK_OBJECT_HANDLE));
     315           21 :         g_array_free (array, TRUE);
     316           21 :         g_list_free (list);
     317              : 
     318           21 :         return rv;
     319              : }
     320              : 
     321              : /* -----------------------------------------------------------------------------
     322              :  * OBJECT
     323              :  */
     324              : 
     325              : static CK_RV
     326          131 : gkm_secret_search_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE_PTR attr)
     327              : {
     328          131 :         GkmSecretSearch *self = GKM_SECRET_SEARCH (base);
     329              : 
     330          131 :         switch (attr->type) {
     331           47 :         case CKA_CLASS:
     332           47 :                 return gkm_attribute_set_ulong (attr, CKO_G_SEARCH);
     333            1 :         case CKA_MODIFIABLE:
     334            1 :                 return gkm_attribute_set_bool (attr, CK_TRUE); /* TODO: This is needed for deleting? */
     335           19 :         case CKA_G_COLLECTION:
     336           19 :                 if (!self->collection_id)
     337            2 :                         return gkm_attribute_set_empty (attr);
     338           17 :                 return gkm_attribute_set_string (attr, self->collection_id);
     339            2 :         case CKA_G_FIELDS:
     340            2 :                 return gkm_secret_fields_serialize (attr, self->fields, self->schema_name);
     341           42 :         case CKA_G_MATCHED:
     342           42 :                 return attribute_set_handles (self->objects, attr);
     343              :         }
     344              : 
     345           20 :         return GKM_OBJECT_CLASS (gkm_secret_search_parent_class)->get_attribute (base, session, attr);
     346              : }
     347              : 
     348              : 
     349              : static void
     350           20 : gkm_secret_search_init (GkmSecretSearch *self)
     351              : {
     352           20 :         self->objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
     353           20 : }
     354              : 
     355              : static GObject*
     356           20 : gkm_secret_search_constructor (GType type, guint n_props, GObjectConstructParam *props)
     357              : {
     358           20 :         GkmSecretSearch *self = GKM_SECRET_SEARCH (G_OBJECT_CLASS (gkm_secret_search_parent_class)->constructor(type, n_props, props));
     359           20 :         g_return_val_if_fail (self, NULL);
     360              : 
     361           20 :         g_return_val_if_fail (self->fields, NULL);
     362              : 
     363           20 :         return G_OBJECT (self);
     364              : }
     365              : 
     366              : static void
     367           60 : gkm_secret_search_set_property (GObject *obj, guint prop_id, const GValue *value,
     368              :                                     GParamSpec *pspec)
     369              : {
     370           60 :         GkmSecretSearch *self = GKM_SECRET_SEARCH (obj);
     371           60 :         switch (prop_id) {
     372           20 :         case PROP_COLLECTION_ID:
     373           20 :                 g_return_if_fail (!self->collection_id);
     374           20 :                 self->collection_id = g_value_dup_string (value);
     375           20 :                 break;
     376           20 :         case PROP_FIELDS:
     377           20 :                 g_return_if_fail (!self->fields);
     378           20 :                 self->fields = g_value_dup_boxed (value);
     379           20 :                 g_return_if_fail (self->fields);
     380           20 :                 break;
     381           20 :         case PROP_SCHEMA_NAME:
     382           20 :                 g_return_if_fail (self->schema_name == NULL);
     383           20 :                 self->schema_name = g_value_dup_string (value);
     384           20 :                 break;
     385            0 :         default:
     386            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     387            0 :                 break;
     388              :         }
     389              : }
     390              : 
     391              : static void
     392            0 : gkm_secret_search_get_property (GObject *obj, guint prop_id, GValue *value,
     393              :                                     GParamSpec *pspec)
     394              : {
     395            0 :         GkmSecretSearch *self = GKM_SECRET_SEARCH (obj);
     396            0 :         switch (prop_id) {
     397            0 :         case PROP_COLLECTION_ID:
     398            0 :                 g_value_set_string (value, self->collection_id);
     399            0 :                 break;
     400            0 :         case PROP_FIELDS:
     401            0 :                 g_return_if_fail (self->fields);
     402            0 :                 g_value_set_boxed (value, gkm_secret_search_get_fields (self));
     403            0 :                 break;
     404            0 :         case PROP_SCHEMA_NAME:
     405            0 :                 g_value_set_string (value, self->schema_name);
     406            0 :                 break;
     407            0 :         default:
     408            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     409            0 :                 break;
     410              :         }
     411              : }
     412              : 
     413              : static void
     414           40 : gkm_secret_search_dispose (GObject *obj)
     415              : {
     416           40 :         GkmSecretSearch *self = GKM_SECRET_SEARCH (obj);
     417              :         GList *l;
     418              : 
     419           80 :         for (l = self->managers; l; l = g_list_next (l)) {
     420           40 :                 g_signal_handlers_disconnect_by_func (l->data, on_manager_added_object, self);
     421           40 :                 g_signal_handlers_disconnect_by_func (l->data, on_manager_removed_object, self);
     422           40 :                 g_signal_handlers_disconnect_by_func (l->data, on_manager_changed_object, self);
     423           40 :                 g_object_weak_unref (G_OBJECT (l->data), on_manager_gone_away, self);
     424              :         }
     425           40 :         g_list_free (self->managers);
     426           40 :         self->managers = NULL;
     427              : 
     428           40 :         g_free (self->collection_id);
     429           40 :         self->collection_id = NULL;
     430              : 
     431           40 :         g_hash_table_remove_all (self->objects);
     432              : 
     433           40 :         G_OBJECT_CLASS (gkm_secret_search_parent_class)->dispose (obj);
     434           40 : }
     435              : 
     436              : static void
     437           20 : gkm_secret_search_finalize (GObject *obj)
     438              : {
     439           20 :         GkmSecretSearch *self = GKM_SECRET_SEARCH (obj);
     440              : 
     441           20 :         g_assert (!self->managers);
     442              : 
     443           20 :         g_free (self->schema_name);
     444           20 :         self->schema_name = NULL;
     445              : 
     446           20 :         if (self->fields)
     447           20 :                 g_hash_table_destroy (self->fields);
     448           20 :         self->fields = NULL;
     449              : 
     450           20 :         g_hash_table_destroy (self->objects);
     451              : 
     452           20 :         G_OBJECT_CLASS (gkm_secret_search_parent_class)->finalize (obj);
     453           20 : }
     454              : 
     455              : static void
     456            6 : gkm_secret_search_class_init (GkmSecretSearchClass *klass)
     457              : {
     458            6 :         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     459            6 :         GkmObjectClass *gkm_class = GKM_OBJECT_CLASS (klass);
     460              : 
     461            6 :         gkm_secret_search_parent_class = g_type_class_peek_parent (klass);
     462              : 
     463            6 :         gobject_class->constructor = gkm_secret_search_constructor;
     464            6 :         gobject_class->dispose = gkm_secret_search_dispose;
     465            6 :         gobject_class->finalize = gkm_secret_search_finalize;
     466            6 :         gobject_class->set_property = gkm_secret_search_set_property;
     467            6 :         gobject_class->get_property = gkm_secret_search_get_property;
     468              : 
     469            6 :         gkm_class->get_attribute = gkm_secret_search_get_attribute;
     470              : 
     471            6 :         g_object_class_install_property (gobject_class, PROP_COLLECTION_ID,
     472              :                    g_param_spec_string ("collection-id", "Collection ID", "Item's Collection's Identifier",
     473              :                                         NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
     474              : 
     475            6 :         g_object_class_install_property (gobject_class, PROP_FIELDS,
     476              :                    g_param_spec_boxed ("fields", "Fields", "Item's fields",
     477              :                                        GKM_BOXED_SECRET_FIELDS, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
     478              : 
     479            6 :         g_object_class_install_property (gobject_class, PROP_SCHEMA_NAME,
     480              :                    g_param_spec_string ("schema_name", "Schema Name", "Schema name to match",
     481              :                                         NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
     482            6 : }
     483              : 
     484              : /* -----------------------------------------------------------------------------
     485              :  * PUBLIC
     486              :  */
     487              : 
     488              : GkmFactory*
     489          125 : gkm_secret_search_get_factory (void)
     490              : {
     491              :         static CK_OBJECT_CLASS klass = CKO_G_SEARCH;
     492              :         static CK_BBOOL token = CK_FALSE;
     493              : 
     494              :         static CK_ATTRIBUTE attributes[] = {
     495              :                 { CKA_CLASS, &klass, sizeof (klass) },
     496              :                 { CKA_TOKEN, &token, sizeof (token) },
     497              :         };
     498              : 
     499              :         static GkmFactory factory = {
     500              :                 attributes,
     501              :                 G_N_ELEMENTS (attributes),
     502              :                 factory_create_search
     503              :         };
     504              : 
     505          125 :         return &factory;
     506              : }
     507              : 
     508              : GHashTable*
     509            1 : gkm_secret_search_get_fields (GkmSecretSearch *self)
     510              : {
     511            1 :         g_return_val_if_fail (GKM_IS_SECRET_SEARCH (self), NULL);
     512            1 :         return self->fields;
     513              : }
     514              : 
     515              : const gchar *
     516            0 : gkm_secret_search_get_schema_name (GkmSecretSearch *self)
     517              : {
     518            0 :         g_return_val_if_fail (GKM_IS_SECRET_SEARCH (self), NULL);
     519            0 :         return self->schema_name;
     520              : }
     521              : 
     522              : const gchar*
     523            1 : gkm_secret_search_get_collection_id (GkmSecretSearch *self)
     524              : {
     525            1 :         g_return_val_if_fail (GKM_IS_SECRET_SEARCH (self), NULL);
     526            1 :         return self->collection_id;
     527              : }
        

Generated by: LCOV version 2.0-1