LCOV - code coverage report
Current view: top level - pkcs11/secret-store - gkm-secret-textual.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 89.4 % 265 237
Test Date: 2024-04-08 13:24:42 Functions: 100.0 % 11 11

            Line data    Source code
       1              : /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
       2              : /* gkm-secret-textual.c - Textual non-encrypted format for the keyring
       3              : 
       4              :    Copyright (C) 2007, 2009 Stefan Walter
       5              : 
       6              :    The Gnome Keyring Library is free software; you can redistribute it and/or
       7              :    modify it under the terms of the GNU Library General Public License as
       8              :    published by the Free Software Foundation; either version 2 of the
       9              :    License, or (at your option) any later version.
      10              : 
      11              :    The Gnome Keyring Library is distributed in the hope that it will be useful,
      12              :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14              :    Library General Public License for more details.
      15              : 
      16              :    You should have received a copy of the GNU Library General Public
      17              :    License along with the Gnome Library; see the file COPYING.LIB.  If not,
      18              :    <http://www.gnu.org/licenses/>.
      19              : 
      20              :    Author: Stef Walter <stef@memberwebs.com>
      21              : */
      22              : 
      23              : #include "config.h"
      24              : 
      25              : #include "gkm-secret-collection.h"
      26              : #include "gkm-secret-compat.h"
      27              : #include "gkm-secret-data.h"
      28              : #include "gkm-secret-fields.h"
      29              : #include "gkm-secret-item.h"
      30              : #include "gkm-secret-textual.h"
      31              : 
      32              : #include "egg/egg-error.h"
      33              : #include "egg/egg-hex.h"
      34              : #include "egg/egg-secure-memory.h"
      35              : 
      36              : #include "gkm/gkm-secret.h"
      37              : 
      38              : #include <glib.h>
      39              : 
      40              : #include <sys/types.h>
      41              : 
      42              : #include <ctype.h>
      43              : #include <stdlib.h>
      44              : #include <string.h>
      45              : 
      46              : static void
      47           29 : key_file_set_uint64 (GKeyFile *file, const gchar *group,
      48              :                      const gchar *key, guint64 value)
      49              : {
      50              :         gchar buffer[64];
      51           29 :         g_snprintf (buffer, sizeof (buffer), "%llu",
      52              :                     (long long unsigned int)value);
      53           29 :         g_key_file_set_value (file, group, key, buffer);
      54           29 : }
      55              : 
      56              : static gboolean
      57          182 : key_file_get_uint64 (GKeyFile *file, const gchar *group,
      58              :                      const gchar *key, guint64 *value)
      59              : {
      60              :         gchar *str, *end;
      61              : 
      62          182 :         str = g_key_file_get_value (file, group, key, NULL);
      63          182 :         if (!str)
      64            1 :                 return FALSE;
      65              : 
      66          181 :         *value = g_ascii_strtoull (str, &end, 10);
      67          181 :         if (end[0]) {
      68            1 :                 g_free (str);
      69            1 :                 return FALSE;
      70              :         }
      71              : 
      72          180 :         g_free (str);
      73          180 :         return TRUE;
      74              : }
      75              : 
      76              : static void
      77            5 : generate_attributes (GKeyFile *file, GkmSecretItem *item)
      78              : {
      79              :         GHashTable *attributes;
      80              :         gchar *groupname;
      81              :         GList *names, *l;
      82              :         guint32 number;
      83            5 :         gint index = 0;
      84              : 
      85            5 :         attributes = gkm_secret_item_get_fields (item);
      86            5 :         g_return_if_fail (attributes);
      87              : 
      88            5 :         names = gkm_secret_fields_get_names (attributes);
      89           14 :         for (l = names; l; l = g_list_next (l)) {
      90            9 :                 groupname = g_strdup_printf ("%s:attribute%d",
      91            9 :                                              gkm_secret_object_get_identifier (GKM_SECRET_OBJECT (item)),
      92              :                                              index);
      93              : 
      94            9 :                 g_key_file_set_string (file, groupname, "name", l->data);
      95              : 
      96              :                 /*
      97              :                  * COMPATIBILITY:
      98              :                  *
      99              :                  * Our new Secrets API doesn't support integer attributes. However, to have
     100              :                  * compatibility with old keyring code reading this file, we need to set
     101              :                  * the type=uint32 attribute appropriately where expected.
     102              :                  *
     103              :                  * If there's an extra compat-uint32 attribute and the name of this attribute
     104              :                  * is contained in that list, then write as a uint32.
     105              :                  */
     106              : 
     107              :                 /* Determine if it's a uint32 compatible value, and store as such if it is */
     108            9 :                 if (gkm_secret_fields_get_compat_uint32 (attributes, l->data, &number)) {
     109            3 :                         g_key_file_set_string (file, groupname, "type", "uint32");
     110            3 :                         key_file_set_uint64 (file, groupname, "value", number);
     111              : 
     112              :                 /* A normal string attribute */
     113              :                 } else {
     114            6 :                         g_key_file_set_string (file, groupname, "type", "string");
     115            6 :                         g_key_file_set_string (file, groupname, "value", gkm_secret_fields_get (attributes, l->data));
     116              :                 }
     117              : 
     118            9 :                 g_free (groupname);
     119            9 :                 ++index;
     120              :         }
     121            5 :         g_list_free (names);
     122              : }
     123              : 
     124              : static void
     125           51 : parse_attributes (GKeyFile *file,
     126              :                   GkmSecretItem *item,
     127              :                   const gchar **groups,
     128              :                   gint compat_type)
     129              : {
     130              :         GHashTable *attributes;
     131              :         const gchar *identifier;
     132              :         const gchar **g;
     133              :         gchar *prefix;
     134              :         gchar *name, *type;
     135              :         guint64 number;
     136              :         const gchar *schema_name;
     137              : 
     138              :         /* Now do the attributes */
     139              : 
     140           51 :         identifier = gkm_secret_object_get_identifier (GKM_SECRET_OBJECT (item));
     141           51 :         prefix = g_strdup_printf ("%s:attribute", identifier);
     142           51 :         attributes = gkm_secret_fields_new ();
     143              : 
     144          512 :         for (g = groups; *g; ++g) {
     145          461 :                 if (!g_str_has_prefix (*g, prefix))
     146          356 :                         continue;
     147              : 
     148          105 :                 name = g_key_file_get_string (file, *g, "name", NULL);
     149          105 :                 if (!name)
     150            0 :                         continue;
     151              : 
     152          105 :                 type = g_key_file_get_string (file, *g, "type", NULL);
     153              : 
     154              :                 /* A uint32 type value */
     155          105 :                 if (type && g_str_equal (type, "uint32")) {
     156           28 :                         if (key_file_get_uint64 (file, *g, "value", &number))
     157           26 :                                 gkm_secret_fields_add_compat_uint32 (attributes, name, number);
     158           28 :                         g_free (name);
     159              : 
     160              :                 /* A string type value */
     161              :                 } else {
     162           77 :                         gkm_secret_fields_take (attributes, name,
     163              :                                                 g_key_file_get_string (file, *g, "value", NULL));
     164              :                 }
     165              : 
     166          105 :                 g_free (type);
     167              :         }
     168              : 
     169           51 :         gkm_secret_item_set_fields (item, attributes);
     170              : 
     171           51 :         schema_name = g_hash_table_lookup (attributes, GKM_SECRET_FIELD_SCHEMA);
     172           51 :         if (schema_name == NULL)
     173           50 :                 schema_name = gkm_secret_compat_format_item_type (compat_type);
     174           51 :         gkm_secret_item_set_schema (item, schema_name);
     175              : 
     176           51 :         g_hash_table_unref (attributes);
     177           51 :         g_free (prefix);
     178           51 : }
     179              : 
     180              : static void
     181            5 : generate_acl (GKeyFile *file, GkmSecretItem *item)
     182              : {
     183              :         const gchar *identifier;
     184              :         GkmSecretAccess *ac;
     185              :         gchar *groupname;
     186              :         GList *acl;
     187              :         gint i;
     188              : 
     189              :         /*
     190              :          * COMPATIBILITY: If we loaded ACLs and they're set on the item,
     191              :          * then store them back in.
     192              :          */
     193              : 
     194            5 :         identifier = gkm_secret_object_get_identifier (GKM_SECRET_OBJECT (item));
     195            5 :         acl = g_object_get_data (G_OBJECT (item), "compat-acl");
     196            5 :         for (i = 0; acl != NULL; acl = g_list_next (acl), ++i) {
     197            0 :                 ac = acl->data;
     198              : 
     199              :                 /* Build a group name */
     200            0 :                 groupname = g_strdup_printf ("%s:acl%d", identifier, i);
     201              : 
     202            0 :                 if (ac->display_name)
     203            0 :                         g_key_file_set_string (file, groupname, "display-name", ac->display_name);
     204            0 :                 if (ac->pathname)
     205            0 :                         g_key_file_set_string (file, groupname, "path", ac->pathname);
     206              : 
     207            0 :                 g_key_file_set_boolean (file, groupname, "read-access",
     208            0 :                                         ac->types_allowed & GKM_SECRET_ACCESS_READ);
     209            0 :                 g_key_file_set_boolean (file, groupname, "write-access",
     210            0 :                                         ac->types_allowed & GKM_SECRET_ACCESS_WRITE);
     211            0 :                 g_key_file_set_boolean (file, groupname, "remove-access",
     212            0 :                                         ac->types_allowed & GKM_SECRET_ACCESS_REMOVE);
     213              : 
     214            0 :                 g_free (groupname);
     215              :         }
     216            5 : }
     217              : 
     218              : static void
     219           51 : parse_acl (GKeyFile *file, GkmSecretItem *item, const gchar **groups)
     220              : {
     221              :         GkmSecretAccessType access_type;
     222              :         GkmSecretAccess *ac;
     223              :         const gchar *identifier;
     224              :         const gchar **g;
     225              :         gchar *prefix;
     226              :         gchar *path, *display;
     227           51 :         GError *err = NULL;
     228              :         GList *acl;
     229              : 
     230              :         /*
     231              :          * COMPATIBILITY: We don't actually use ACLs, but if we find them in the
     232              :          * file, then load them and save back later.
     233              :          */
     234              : 
     235           51 :         identifier = gkm_secret_object_get_identifier (GKM_SECRET_OBJECT (item));
     236           51 :         prefix = g_strdup_printf ("%s:acl", identifier);
     237           51 :         acl = NULL;
     238              : 
     239          512 :         for (g = groups; *g; ++g) {
     240          461 :                 if (!g_str_has_prefix (*g, prefix))
     241          415 :                         continue;
     242           46 :                 path = g_key_file_get_string (file, *g, "path", NULL);
     243           46 :                 if (!path)
     244            0 :                         continue;
     245              : 
     246           46 :                 display = g_key_file_get_string (file, *g, "display-name", NULL);
     247              : 
     248           46 :                 access_type = 0;
     249              : 
     250           46 :                 if (g_key_file_get_boolean (file, *g, "read-access", &err) && !err)
     251           46 :                         access_type |= GKM_SECRET_ACCESS_READ;
     252           46 :                 g_clear_error (&err);
     253              : 
     254           46 :                 if (g_key_file_get_boolean (file, *g, "write-access", &err) && !err)
     255           46 :                         access_type |= GKM_SECRET_ACCESS_WRITE;
     256           46 :                 g_clear_error (&err);
     257              : 
     258           46 :                 if (g_key_file_get_boolean (file, *g, "remove-access", &err) && !err)
     259           46 :                         access_type |= GKM_SECRET_ACCESS_REMOVE;
     260           46 :                 g_clear_error (&err);
     261              : 
     262           46 :                 ac = g_new0 (GkmSecretAccess, 1);
     263           46 :                 ac->display_name = display;
     264           46 :                 ac->pathname = path;
     265           46 :                 ac->types_allowed = access_type;
     266              : 
     267           46 :                 acl = g_list_prepend (acl, ac);
     268              :         }
     269              : 
     270           51 :         g_object_set_data_full (G_OBJECT (item), "compat-acl", acl, gkm_secret_compat_acl_free);
     271           51 :         g_free (prefix);
     272           51 : }
     273              : 
     274              : static void
     275            5 : generate_item (GKeyFile *file, GkmSecretItem *item, GkmSecretData *sdata)
     276              : {
     277              :         GkmSecretObject *obj;
     278              :         const gchar *value;
     279              :         const gchar *identifier;
     280              :         const guchar *secret;
     281              :         gsize n_secret;
     282              :         gchar *hex;
     283              : 
     284            5 :         g_assert (file);
     285            5 :         g_assert (GKM_IS_SECRET_ITEM (item));
     286            5 :         g_assert (GKM_IS_SECRET_DATA (sdata));
     287              : 
     288            5 :         obj = GKM_SECRET_OBJECT (item);
     289            5 :         identifier = gkm_secret_object_get_identifier (obj);
     290              : 
     291            5 :         value = gkm_secret_item_get_schema (item);
     292            5 :         g_key_file_set_integer (file, identifier, "item-type",
     293            5 :                                 gkm_secret_compat_parse_item_type (value));
     294              : 
     295            5 :         value = gkm_secret_object_get_label (obj);
     296            5 :         if (value != NULL)
     297            5 :                 g_key_file_set_string (file, identifier, "display-name", value);
     298              : 
     299            5 :         secret = gkm_secret_data_get_raw (sdata, identifier, &n_secret);
     300            5 :         if (secret != NULL) {
     301              :                 /* A textual secret. Note that secrets are always null-terminated. */
     302            3 :                 if (g_utf8_validate ((gchar*)secret, n_secret, NULL)) {
     303            2 :                         g_key_file_set_value (file, identifier, "secret", (gchar*)secret);
     304              : 
     305              :                 /* A non-textual secret */
     306              :                 } else {
     307            1 :                         hex = egg_hex_encode (secret, n_secret);
     308            1 :                         g_key_file_set_value (file, identifier, "binary-secret", hex);
     309            1 :                         g_free (hex);
     310              :                 }
     311              :         }
     312              : 
     313            5 :         key_file_set_uint64 (file, identifier, "mtime", gkm_secret_object_get_modified (obj));
     314            5 :         key_file_set_uint64 (file, identifier, "ctime", gkm_secret_object_get_created (obj));
     315              : 
     316            5 :         generate_attributes (file, item);
     317            5 :         generate_acl (file, item);
     318            5 : }
     319              : 
     320              : static void
     321           51 : parse_item (GKeyFile *file, GkmSecretItem *item, GkmSecretData *sdata,
     322              :             const gchar **groups)
     323              : {
     324              :         GkmSecretObject *obj;
     325              :         const gchar *identifier;
     326           51 :         GError *err = NULL;
     327              :         GkmSecret *secret;
     328              :         guchar *binary;
     329              :         gsize n_binary;
     330              :         gchar *val;
     331              :         guint64 num;
     332              :         gint type;
     333              : 
     334              :         /* First the main item data */
     335              : 
     336           51 :         obj = GKM_SECRET_OBJECT (item);
     337           51 :         identifier = gkm_secret_object_get_identifier (obj);
     338              : 
     339           51 :         type = g_key_file_get_integer (file, identifier, "item-type", &err);
     340           51 :         if (err) {
     341            0 :                 g_clear_error (&err);
     342            0 :                 type = 0;
     343              :         }
     344              : 
     345           51 :         val = g_key_file_get_string (file, identifier, "display-name", NULL);
     346           51 :         gkm_secret_object_set_label (obj, val);
     347           51 :         g_free (val);
     348              : 
     349           51 :         if (sdata) {
     350           13 :                 secret = NULL;
     351              : 
     352              :                 /* A textual secret */
     353           13 :                 val = g_key_file_get_string (file, identifier, "secret", NULL);
     354           13 :                 if (val != NULL) {
     355           12 :                         secret = gkm_secret_new_from_password (val);
     356           12 :                         g_free (val);
     357              : 
     358              :                 /* A binary secret */
     359              :                 } else {
     360            1 :                         val = g_key_file_get_string (file, identifier, "binary-secret", NULL);
     361            1 :                         if (val != NULL) {
     362            1 :                                 binary = egg_hex_decode (val, -1, &n_binary);
     363            1 :                                 secret = gkm_secret_new (binary, n_binary);
     364            1 :                                 g_free (binary);
     365            1 :                                 g_free (val);
     366              :                         }
     367              :                 }
     368              : 
     369              :                 /* Put the secret in the right place */
     370           13 :                 if (secret == NULL) {
     371            0 :                         gkm_secret_data_remove_secret (sdata, identifier);
     372              :                 } else {
     373           13 :                         gkm_secret_data_set_secret (sdata, identifier, secret);
     374           13 :                         g_object_unref (secret);
     375              :                 }
     376              :         }
     377              : 
     378           51 :         num = 0;
     379           51 :         if (key_file_get_uint64 (file, identifier, "mtime", &num))
     380           51 :                 gkm_secret_object_set_modified (obj, num);
     381           51 :         num = 0;
     382           51 :         if (key_file_get_uint64 (file, identifier, "ctime", &num))
     383           51 :                 gkm_secret_object_set_created (obj, num);
     384              : 
     385              :         /* Now the other stuff */
     386           51 :         parse_attributes (file, item, groups, type);
     387           51 :         parse_acl (file, item, groups);
     388           51 : }
     389              : 
     390              : GkmDataResult
     391            8 : gkm_secret_textual_write (GkmSecretCollection *collection, GkmSecretData *sdata,
     392              :                           gpointer *data, gsize *n_data)
     393              : {
     394              :         GkmSecretObject *obj;
     395              :         GList *items, *l;
     396              :         const gchar *value;
     397              :         GKeyFile *file;
     398            8 :         GError *err = NULL;
     399              :         gint idle_timeout;
     400              : 
     401            8 :         g_return_val_if_fail (GKM_IS_SECRET_COLLECTION (collection), GKM_DATA_FAILURE);
     402            8 :         g_return_val_if_fail (GKM_IS_SECRET_DATA (sdata), GKM_DATA_LOCKED);
     403            8 :         g_return_val_if_fail (data && n_data, GKM_DATA_FAILURE);
     404              : 
     405            8 :         obj = GKM_SECRET_OBJECT (collection);
     406            8 :         file = g_key_file_new ();
     407              : 
     408            8 :         value = gkm_secret_object_get_label (obj);
     409            8 :         if (value != NULL)
     410            8 :                 g_key_file_set_string (file, "keyring", "display-name", value);
     411              : 
     412            8 :         key_file_set_uint64 (file, "keyring", "ctime", gkm_secret_object_get_created (obj));
     413            8 :         key_file_set_uint64 (file, "keyring", "mtime", gkm_secret_object_get_modified (obj));
     414              : 
     415            8 :         idle_timeout = gkm_secret_collection_get_lock_idle (collection);
     416            8 :         g_key_file_set_boolean (file, "keyring", "lock-on-idle", idle_timeout > 0);
     417            8 :         if (idle_timeout)
     418            0 :                 g_key_file_set_integer (file, "keyring", "lock-timeout", idle_timeout);
     419            8 :         idle_timeout = gkm_secret_collection_get_lock_after (collection);
     420            8 :         g_key_file_set_boolean (file, "keyring", "lock-after", idle_timeout > 0);
     421            8 :         if (idle_timeout)
     422            0 :                 g_key_file_set_integer (file, "keyring", "lock-timeout", idle_timeout);
     423              : 
     424            8 :         items = gkm_secret_collection_get_items (collection);
     425           13 :         for (l = items; l; l = g_list_next (l))
     426            5 :                 generate_item (file, l->data, sdata);
     427            8 :         g_list_free (items);
     428              : 
     429            8 :         *data = (guchar*)g_key_file_to_data (file, n_data, &err);
     430            8 :         g_key_file_free (file);
     431              : 
     432            8 :         if (!*data) {
     433            0 :                 g_warning ("couldn't generate textual keyring file: %s", egg_error_message (err));
     434            0 :                 return GKM_DATA_FAILURE;
     435              :         }
     436              : 
     437            8 :         return GKM_DATA_SUCCESS;
     438              : }
     439              : 
     440              : static void
     441            3 : remove_unavailable_item (gpointer key, gpointer dummy, gpointer user_data)
     442              : {
     443              :         /* Called to remove items from a keyring that no longer exist */
     444              : 
     445            3 :         GkmSecretCollection *collection = GKM_SECRET_COLLECTION (user_data);
     446              :         GkmSecretItem *item;
     447              : 
     448            3 :         g_assert (GKM_IS_SECRET_COLLECTION (collection));
     449              : 
     450            3 :         item = gkm_secret_collection_get_item (collection, key);
     451            3 :         if (item != NULL)
     452            3 :                 gkm_secret_collection_remove_item (collection, item);
     453            3 : }
     454              : 
     455              : GkmDataResult
     456           27 : gkm_secret_textual_read (GkmSecretCollection *collection, GkmSecretData *sdata,
     457              :                          gconstpointer data, gsize n_data)
     458              : {
     459              :         GkmSecretObject *obj;
     460              :         GkmSecretItem *item;
     461              :         GList *items, *l;
     462           27 :         GError *err = NULL;
     463           27 :         GKeyFile *file = NULL;
     464           27 :         gchar **groups = NULL;
     465           27 :         GkmDataResult res = GKM_DATA_FAILURE;
     466           27 :         gchar *start = NULL;
     467              :         const gchar *identifier;
     468           27 :         GHashTable *checks = NULL;
     469              :         gint lock_timeout;
     470              :         gchar *value;
     471              :         guint64 num;
     472              :         gchar **g;
     473              : 
     474           27 :         g_return_val_if_fail (GKM_IS_SECRET_COLLECTION (collection), GKM_DATA_FAILURE);
     475           27 :         g_return_val_if_fail (!sdata || GKM_IS_SECRET_DATA (sdata), GKM_DATA_FAILURE);
     476              : 
     477           27 :         file = g_key_file_new ();
     478           27 :         obj = GKM_SECRET_OBJECT (collection);
     479              : 
     480           27 :         if (!n_data) {
     481            0 :                 res = GKM_DATA_UNRECOGNIZED;
     482            0 :                 goto done;
     483              :         }
     484              : 
     485           27 :         if (!g_key_file_load_from_data (file, (const gchar*)data, n_data, G_KEY_FILE_NONE, &err)) {
     486            1 :                 if (g_error_matches (err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE))
     487            1 :                         res = GKM_DATA_UNRECOGNIZED;
     488            1 :                 goto done;
     489              :         }
     490              : 
     491           26 :         start = g_key_file_get_start_group (file);
     492           26 :         if (!start || !g_str_equal (start, "keyring")) {
     493            0 :                 g_message ("invalid keyring file: wrong header group");
     494            0 :                 goto done;
     495              :         }
     496              : 
     497           26 :         value = g_key_file_get_string (file, "keyring", "display-name", NULL);
     498           26 :         gkm_secret_object_set_label (obj, value);
     499           26 :         g_free (value);
     500              : 
     501           26 :         num = 0;
     502           26 :         key_file_get_uint64 (file, "keyring", "ctime", &num);
     503           26 :         gkm_secret_object_set_created (obj, num);
     504              : 
     505           26 :         num = 0;
     506           26 :         key_file_get_uint64 (file, "keyring", "mtime", &num);
     507           26 :         gkm_secret_object_set_modified (obj, num);
     508              : 
     509              :         /* Not currently used :( */
     510           26 :         lock_timeout = g_key_file_get_integer (file, "keyring", "lock-timeout", NULL);
     511           26 :         if (g_key_file_get_boolean (file, "keyring", "lock-after", NULL))
     512            0 :                 gkm_secret_collection_set_lock_idle (collection, lock_timeout);
     513           26 :         else if (g_key_file_get_boolean (file, "keyring", "lock-on-idle", NULL))
     514            0 :                 gkm_secret_collection_set_lock_idle (collection, lock_timeout);
     515              : 
     516           26 :         g_object_set_data (G_OBJECT (collection), "lock-timeout", GINT_TO_POINTER (lock_timeout));
     517              : 
     518              :         /* Build a Hash table where we can track ids we haven't yet seen */
     519           26 :         checks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
     520           26 :         items = gkm_secret_collection_get_items (collection);
     521           36 :         for (l = items; l; l = g_list_next (l)) {
     522           10 :                 identifier = gkm_secret_object_get_identifier (l->data);
     523           10 :                 g_hash_table_replace (checks, g_strdup (identifier), "unused");
     524              :         }
     525           26 :         g_list_free (items);
     526              : 
     527           26 :         groups = g_key_file_get_groups (file, NULL);
     528          254 :         for (g = groups; *g; ++g) {
     529          228 :                 identifier = *g;
     530          228 :                 if (g_str_equal (identifier, "keyring") || strchr (identifier, ':'))
     531          177 :                         continue;
     532              : 
     533              :                 /* We've seen this id */
     534           51 :                 g_hash_table_remove (checks, identifier);
     535              : 
     536           51 :                 item = gkm_secret_collection_get_item (collection, identifier);
     537           51 :                 if (item == NULL)
     538           44 :                         item = gkm_secret_collection_new_item (collection, identifier);
     539           51 :                 parse_item (file, item, sdata, (const gchar**)groups);
     540              :         }
     541              : 
     542           26 :         g_hash_table_foreach (checks, (GHFunc)remove_unavailable_item, collection);
     543           26 :         res = GKM_DATA_SUCCESS;
     544              : 
     545           27 : done:
     546           27 :         if (checks)
     547           26 :                 g_hash_table_destroy (checks);
     548           27 :         if (file)
     549           27 :                 g_key_file_free (file);
     550           27 :         g_strfreev (groups);
     551           27 :         g_free (start);
     552           27 :         g_clear_error (&err);
     553              : 
     554           27 :         return res;
     555              : }
        

Generated by: LCOV version 2.0-1