LCOV - code coverage report
Current view: top level - daemon/login - gkd-login.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 27.2 % 393 107
Test Date: 2024-04-08 13:24:42 Functions: 40.9 % 22 9

            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 "gkd-login.h"
      24              : 
      25              : #include "daemon/gkd-pkcs11.h"
      26              : 
      27              : #include "egg/egg-error.h"
      28              : #include "egg/egg-secure-memory.h"
      29              : 
      30              : #include "pkcs11/pkcs11i.h"
      31              : #include "pkcs11/wrap-layer/gkm-wrap-layer.h"
      32              : 
      33              : #include <gck/gck.h>
      34              : #include <gcr/gcr-unlock-options.h>
      35              : 
      36              : #include <glib/gi18n.h>
      37              : 
      38              : #include <string.h>
      39              : 
      40            0 : EGG_SECURE_DECLARE (gkd_login);
      41              : 
      42              : static GList*
      43            2 : module_instances (void)
      44              : {
      45              :         CK_FUNCTION_LIST_PTR funcs;
      46              :         GckModule *module;
      47              : 
      48            2 :         funcs = gkd_pkcs11_get_base_functions ();
      49            2 :         g_return_val_if_fail (funcs != NULL && "instances", NULL);
      50              : 
      51            2 :         module = gck_module_new (funcs);
      52            2 :         g_return_val_if_fail (module, NULL);
      53            2 :         return g_list_append (NULL, module);
      54              : }
      55              : 
      56              : static GckSession*
      57            6 : open_and_login_session (GckSlot *slot, CK_USER_TYPE user_type, GError **error)
      58              : {
      59              :         GckSession *session;
      60            6 :         GError *err = NULL;
      61              : 
      62            6 :         g_return_val_if_fail (GCK_IS_SLOT (slot), NULL);
      63              : 
      64            6 :         if (!error)
      65            4 :                 error = &err;
      66              : 
      67            6 :         session = gck_slot_open_session (slot, GCK_SESSION_READ_WRITE, NULL, error);
      68            6 :         if (session != NULL) {
      69            6 :                 if (!gck_session_login (session, user_type, NULL, 0, NULL, error)) {
      70            2 :                         if (g_error_matches (*error, GCK_ERROR, CKR_USER_ALREADY_LOGGED_IN)) {
      71            2 :                                 g_clear_error (error);
      72              :                         } else {
      73            0 :                                 g_object_unref (session);
      74            0 :                                 session = NULL;
      75              :                         }
      76              :                 }
      77              :         }
      78              : 
      79            6 :         return session;
      80              : }
      81              : 
      82              : static GckSession*
      83            2 : lookup_login_session (GList *modules)
      84              : {
      85            2 :         GckSlot *slot = NULL;
      86            2 :         GError *error = NULL;
      87              :         GckSession *session;
      88            2 :         GList *owned = NULL;
      89              : 
      90            2 :         if (modules == NULL)
      91            0 :                 modules = owned = module_instances ();
      92              : 
      93            2 :         slot = gck_modules_token_for_uri (modules, "pkcs11:token=Secret%20Store", &error);
      94            2 :         if (!slot) {
      95            0 :                 if (error) {
      96            0 :                         g_warning ("couldn't find secret store module: %s", egg_error_message (error));
      97            0 :                         g_error_free (error);
      98              :                 }
      99            0 :                 g_list_free_full (owned, g_object_unref);
     100            0 :                 return NULL;
     101              :         }
     102              : 
     103            2 :         session = open_and_login_session (slot, CKU_USER, &error);
     104            2 :         if (error) {
     105            0 :                 g_warning ("couldn't open pkcs11 session for login: %s", egg_error_message (error));
     106            0 :                 g_clear_error (&error);
     107              :         }
     108              : 
     109            2 :         g_object_unref (slot);
     110            2 :         g_list_free_full (owned, g_object_unref);
     111              : 
     112            2 :         return session;
     113              : }
     114              : 
     115              : static GckObject*
     116            2 : lookup_login_keyring (GckSession *session)
     117              : {
     118            2 :         GckBuilder builder = GCK_BUILDER_INIT;
     119            2 :         GError *error = NULL;
     120            2 :         GckObject *login = NULL;
     121              :         GList *objects;
     122              :         guint length;
     123              : 
     124            2 :         g_return_val_if_fail (GCK_IS_SESSION (session), NULL);
     125              : 
     126            2 :         gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);
     127            2 :         gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
     128            2 :         gck_builder_add_string (&builder, CKA_ID, "login");
     129              : 
     130            2 :         objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
     131              : 
     132            2 :         if (error) {
     133            0 :                 g_warning ("couldn't search for login keyring: %s", egg_error_message (error));
     134            0 :                 g_clear_error (&error);
     135            0 :                 return NULL;
     136              :         }
     137              : 
     138            2 :         length = g_list_length (objects);
     139            2 :         if (length == 1)
     140            0 :                 login = g_object_ref (objects->data);
     141            2 :         else if (length > 1)
     142            0 :                 g_warning ("more than one login keyring exists");
     143              : 
     144            2 :         gck_list_unref_free (objects);
     145            2 :         return login;
     146              : }
     147              : 
     148              : static GckObject*
     149            2 : create_login_keyring (GckSession *session, GckObject *cred, GError **error)
     150              : {
     151            2 :         GckBuilder builder = GCK_BUILDER_INIT;
     152              : 
     153            2 :         g_return_val_if_fail (GCK_IS_SESSION (session), NULL);
     154            2 :         g_return_val_if_fail (GCK_IS_OBJECT (cred), NULL);
     155              : 
     156            2 :         gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);
     157            2 :         gck_builder_add_string (&builder, CKA_ID, "login");
     158            2 :         gck_builder_add_ulong (&builder, CKA_G_CREDENTIAL, gck_object_get_handle (cred));
     159            2 :         gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
     160              : 
     161              :         /* TRANSLATORS: This is the display label for the login keyring */
     162            2 :         gck_builder_add_string (&builder, CKA_LABEL, _("Login"));
     163              : 
     164            2 :         return gck_session_create_object (session, gck_builder_end (&builder), NULL, error);
     165              : }
     166              : 
     167              : static GckObject*
     168            2 : create_credential (GckSession *session, GckObject *object,
     169              :                    const gchar *secret, GError **error)
     170              : {
     171            2 :         GckBuilder builder = GCK_BUILDER_INIT;
     172              : 
     173            2 :         g_return_val_if_fail (GCK_IS_SESSION (session), NULL);
     174            2 :         g_return_val_if_fail (!object || GCK_IS_OBJECT (object), NULL);
     175              : 
     176            2 :         if (!secret)
     177            0 :                 secret = "";
     178              : 
     179            2 :         gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_CREDENTIAL);
     180            2 :         gck_builder_add_string (&builder, CKA_VALUE, secret);
     181            2 :         gck_builder_add_boolean (&builder, CKA_GNOME_TRANSIENT, TRUE);
     182            2 :         gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
     183              : 
     184            2 :         if (object)
     185            0 :                 gck_builder_add_ulong (&builder, CKA_G_OBJECT,
     186              :                                        gck_object_get_handle (object));
     187              : 
     188            2 :         return gck_session_create_object (session, gck_builder_end (&builder), NULL, error);
     189              : }
     190              : 
     191              : static gboolean
     192            2 : unlock_or_create_login (GList *modules, const gchar *master)
     193              : {
     194            2 :         GError *error = NULL;
     195              :         GckSession *session;
     196              :         GckObject *login;
     197              :         GckObject *cred;
     198              : 
     199            2 :         g_return_val_if_fail (master, FALSE);
     200              : 
     201              :         /* Find the login object */
     202            2 :         session = lookup_login_session (modules);
     203            2 :         login = lookup_login_keyring (session);
     204              : 
     205              :         /* Create credentials for login object */
     206            2 :         cred = create_credential (session, login, master, &error);
     207              : 
     208              :         /* Failure, bad password? */
     209            2 :         if (cred == NULL) {
     210            0 :                 if (login && g_error_matches (error, GCK_ERROR, CKR_PIN_INCORRECT))
     211            0 :                         gkm_wrap_layer_mark_login_unlock_failure (master);
     212              :                 else
     213            0 :                         g_warning ("couldn't create login credential: %s", egg_error_message (error));
     214            0 :                 g_clear_error (&error);
     215              : 
     216              :         /* Non login keyring, create it */
     217            2 :         } else if (!login) {
     218            2 :                 login = create_login_keyring (session, cred, &error);
     219            2 :                 if (login == NULL && error) {
     220            0 :                         g_warning ("couldn't create login keyring: %s", egg_error_message (error));
     221            0 :                         g_clear_error (&error);
     222              :                 }
     223              : 
     224              :         /* The unlock succeeded yay */
     225              :         } else {
     226            0 :                 gkm_wrap_layer_mark_login_unlock_success ();
     227              :         }
     228              : 
     229            2 :         if (cred)
     230            2 :                 g_object_unref (cred);
     231            2 :         if (login)
     232            2 :                 g_object_unref (login);
     233            2 :         if (session)
     234            2 :                 g_object_unref (session);
     235              : 
     236            2 :         return cred && login;
     237              : }
     238              : 
     239              : static gboolean
     240            2 : init_pin_for_uninitialized_slots (GList *modules, const gchar *master)
     241              : {
     242            2 :         GError *error = NULL;
     243              :         GList *slots, *l;
     244              :         gboolean initialize;
     245              :         GckTokenInfo *info;
     246              :         GckSession *session;
     247              : 
     248            2 :         g_return_val_if_fail (master, FALSE);
     249              : 
     250            2 :         slots = gck_modules_get_slots (modules, TRUE);
     251           10 :         for (l = slots; l; l = g_list_next (l)) {
     252            8 :                 info = gck_slot_get_token_info (l->data);
     253            8 :                 initialize = (info && !(info->flags & CKF_USER_PIN_INITIALIZED));
     254              : 
     255            8 :                 if (initialize) {
     256            4 :                         session = open_and_login_session (l->data, CKU_SO, NULL);
     257            4 :                         if (session != NULL) {
     258            4 :                                 if (!gck_session_init_pin (session, (const guchar*)master, strlen (master), NULL, &error)) {
     259            2 :                                         if (!g_error_matches (error, GCK_ERROR, CKR_FUNCTION_NOT_SUPPORTED))
     260            0 :                                                 g_warning ("couldn't initialize slot with master password: %s",
     261              :                                                            egg_error_message (error));
     262            2 :                                         g_clear_error (&error);
     263              :                                 }
     264            4 :                                 g_object_unref (session);
     265              :                         }
     266              :                 }
     267              : 
     268            8 :                 gck_token_info_free (info);
     269              :         }
     270            2 :         gck_list_unref_free (slots);
     271            2 :         return TRUE;
     272              : }
     273              : 
     274              : gboolean
     275            2 : gkd_login_unlock (const gchar *master)
     276              : {
     277              :         GList *modules;
     278              :         gboolean result;
     279              : 
     280              :         /* We don't support null as master password */
     281            2 :         if (!master)
     282            0 :                 return FALSE;
     283              : 
     284            2 :         modules = module_instances ();
     285              : 
     286            2 :         result = unlock_or_create_login (modules, master);
     287            2 :         if (result == TRUE)
     288            2 :                 init_pin_for_uninitialized_slots (modules, master);
     289              : 
     290            2 :         gck_list_unref_free (modules);
     291            2 :         return result;
     292              : }
     293              : 
     294              : static gboolean
     295            0 : change_or_create_login (GList *modules, const gchar *original, const gchar *master)
     296              : {
     297            0 :         GckBuilder builder = GCK_BUILDER_INIT;
     298            0 :         GError *error = NULL;
     299              :         GckSession *session;
     300            0 :         GckObject *login = NULL;
     301            0 :         GckObject *ocred = NULL;
     302            0 :         GckObject *mcred = NULL;
     303            0 :         gboolean success = FALSE;
     304              : 
     305            0 :         g_return_val_if_fail (original, FALSE);
     306            0 :         g_return_val_if_fail (master, FALSE);
     307              : 
     308              :         /* Find the login object */
     309            0 :         session = lookup_login_session (modules);
     310            0 :         login = lookup_login_keyring (session);
     311              : 
     312              :         /* Create the new credential we'll be changing to */
     313            0 :         mcred = create_credential (session, NULL, master, &error);
     314            0 :         if (mcred == NULL) {
     315            0 :                 g_warning ("couldn't create new login credential: %s", egg_error_message (error));
     316            0 :                 g_clear_error (&error);
     317              : 
     318              :         /* Create original credentials */
     319            0 :         } else if (login) {
     320            0 :                 ocred = create_credential (session, login, original, &error);
     321            0 :                 if (ocred == NULL) {
     322            0 :                         if (g_error_matches (error, GCK_ERROR, CKR_PIN_INCORRECT)) {
     323            0 :                                 g_message ("couldn't change login master password, "
     324              :                                            "original password was wrong: %s",
     325              :                                            egg_error_message (error));
     326              :                         } else {
     327            0 :                                 g_warning ("couldn't create original login credential: %s",
     328              :                                            egg_error_message (error));
     329              :                         }
     330            0 :                         g_clear_error (&error);
     331              :                 }
     332              :         }
     333              : 
     334              :         /* No keyring? try to create */
     335            0 :         if (!login && mcred) {
     336            0 :                 login = create_login_keyring (session, mcred, &error);
     337            0 :                 if (login == NULL) {
     338            0 :                         g_warning ("couldn't create login keyring: %s", egg_error_message (error));
     339            0 :                         g_clear_error (&error);
     340              :                 } else {
     341            0 :                         success = TRUE;
     342              :                 }
     343              : 
     344              :         /* Change the master password */
     345            0 :         } else if (login && ocred && mcred) {
     346            0 :                 gck_builder_add_ulong (&builder, CKA_G_CREDENTIAL, gck_object_get_handle (mcred));
     347            0 :                 if (!gck_object_set (login, gck_builder_end (&builder), NULL, &error)) {
     348            0 :                         g_warning ("couldn't change login master password: %s", egg_error_message (error));
     349            0 :                         g_clear_error (&error);
     350              :                 } else {
     351            0 :                         success = TRUE;
     352              :                 }
     353              :         }
     354              : 
     355            0 :         if (ocred) {
     356            0 :                 gck_object_destroy (ocred, NULL, NULL);
     357            0 :                 g_object_unref (ocred);
     358              :         }
     359            0 :         if (mcred)
     360            0 :                 g_object_unref (mcred);
     361            0 :         if (login)
     362            0 :                 g_object_unref (login);
     363            0 :         if (session)
     364            0 :                 g_object_unref (session);
     365              : 
     366            0 :         return success;
     367              : }
     368              : 
     369              : static gboolean
     370            0 : set_pin_for_any_slots (GList *modules, const gchar *original, const gchar *master)
     371              : {
     372            0 :         GError *error = NULL;
     373              :         GList *slots, *l;
     374              :         gboolean initialize;
     375              :         GckTokenInfo *info;
     376              :         GckSession *session;
     377              : 
     378            0 :         g_return_val_if_fail (original, FALSE);
     379            0 :         g_return_val_if_fail (master, FALSE);
     380              : 
     381            0 :         slots = gck_modules_get_slots (modules, TRUE);
     382            0 :         for (l = slots; l; l = g_list_next (l)) {
     383              : 
     384              :                 /* Set pin for any that are initialized, and not pap */
     385            0 :                 info = gck_slot_get_token_info (l->data);
     386            0 :                 initialize = (info && (info->flags & CKF_USER_PIN_INITIALIZED));
     387              : 
     388            0 :                 if (initialize) {
     389            0 :                         session = open_and_login_session (l->data, CKU_USER, NULL);
     390            0 :                         if (session != NULL) {
     391            0 :                                 if (!gck_session_set_pin (session, (const guchar*)original, strlen (original),
     392              :                                                           (const guchar*)master, strlen (master), NULL, &error)) {
     393            0 :                                         if (!g_error_matches (error, GCK_ERROR, CKR_PIN_INCORRECT) &&
     394            0 :                                             !g_error_matches (error, GCK_ERROR, CKR_FUNCTION_NOT_SUPPORTED))
     395            0 :                                                 g_warning ("couldn't change slot master password: %s",
     396              :                                                            egg_error_message (error));
     397            0 :                                         g_clear_error (&error);
     398              :                                 }
     399            0 :                                 g_object_unref (session);
     400              :                         }
     401              :                 }
     402              : 
     403            0 :                 gck_token_info_free (info);
     404              :         }
     405            0 :         gck_list_unref_free (slots);
     406            0 :         return TRUE;
     407              : }
     408              : 
     409              : gboolean
     410            0 : gkd_login_change_lock (const gchar *original, const gchar *master)
     411              : {
     412              :         GList *modules;
     413              :         gboolean result;
     414              : 
     415              :         /* We don't support null or empty master passwords */
     416            0 :         if (!master || !master[0])
     417            0 :                 return FALSE;
     418            0 :         if (original == NULL)
     419            0 :                 original = "";
     420              : 
     421            0 :         modules = module_instances ();
     422              : 
     423            0 :         result = change_or_create_login (modules, original, master);
     424            0 :         if (result == TRUE)
     425            0 :                 set_pin_for_any_slots (modules, original, master);
     426              : 
     427            0 :         gck_list_unref_free (modules);
     428            0 :         return result;
     429              : }
     430              : 
     431              : gboolean
     432            0 : gkd_login_available (GckSession *session)
     433              : {
     434            0 :         GckBuilder builder = GCK_BUILDER_INIT;
     435            0 :         gboolean available = FALSE;
     436            0 :         GError *error = NULL;
     437              :         GList *objects;
     438              : 
     439            0 :         if (!session)
     440            0 :                 session = lookup_login_session (NULL);
     441              :         else
     442            0 :                 g_object_ref (session);
     443              : 
     444            0 :         if (session) {
     445            0 :                 gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);
     446            0 :                 gck_builder_add_string (&builder, CKA_ID, "login");
     447            0 :                 gck_builder_add_boolean (&builder, CKA_G_LOCKED, FALSE);
     448              : 
     449              :                 /* Check if the login keyring is usable */
     450            0 :                 objects = gck_session_find_objects (session, gck_builder_end (&builder), NULL, &error);
     451            0 :                 if (error) {
     452            0 :                         g_warning ("couldn't lookup login keyring: %s", error->message);
     453            0 :                         g_clear_error (&error);
     454            0 :                 } else if (objects) {
     455            0 :                         available = TRUE;
     456              :                 }
     457            0 :                 g_list_free_full (objects, g_object_unref);
     458            0 :                 g_object_unref (session);
     459              :         }
     460              : 
     461            0 :         return available;
     462              : }
     463              : 
     464              : static GList *
     465            0 : find_saved_items (GckSession *session,
     466              :                   GckAttributes *attrs)
     467              : {
     468            0 :         GckBuilder builder = GCK_BUILDER_INIT;
     469            0 :         GError *error = NULL;
     470              :         const GckAttribute *attr;
     471              :         GckObject *search;
     472              :         GList *results;
     473              :         gpointer data;
     474              :         gsize n_data;
     475              : 
     476            0 :         gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_SEARCH);
     477            0 :         gck_builder_add_boolean (&builder, CKA_TOKEN, FALSE);
     478              : 
     479            0 :         attr = gck_attributes_find (attrs, CKA_G_COLLECTION);
     480            0 :         if (attr != NULL)
     481            0 :                 gck_builder_add_attribute (&builder, attr);
     482              : 
     483            0 :         attr = gck_attributes_find (attrs, CKA_G_FIELDS);
     484            0 :         g_return_val_if_fail (attr != NULL, NULL);
     485            0 :         gck_builder_add_attribute (&builder, attr);
     486              : 
     487            0 :         search = gck_session_create_object (session, gck_builder_end (&builder), NULL, &error);
     488            0 :         if (search == NULL) {
     489            0 :                 g_warning ("couldn't perform search for stored passphrases: %s",
     490              :                            egg_error_message (error));
     491            0 :                 g_clear_error (&error);
     492            0 :                 return NULL;
     493              :         }
     494              : 
     495            0 :         data = gck_object_get_data (search, CKA_G_MATCHED, NULL, &n_data, &error);
     496            0 :         gck_object_destroy (search, NULL, NULL);
     497            0 :         g_object_unref (search);
     498              : 
     499            0 :         if (data == NULL) {
     500            0 :                 g_warning ("couldn't retrieve list of stored passphrases: %s",
     501              :                            egg_error_message (error));
     502            0 :                 g_clear_error (&error);
     503            0 :                 return NULL;
     504              :         }
     505              : 
     506            0 :         results = gck_objects_from_handle_array (session, data, n_data / sizeof (CK_ULONG));
     507              : 
     508            0 :         g_free (data);
     509            0 :         return results;
     510              : }
     511              : 
     512              : static gboolean
     513            0 : fields_to_attribute (GckBuilder *builder,
     514              :                      GHashTable *fields)
     515              : {
     516            0 :         GString *concat = g_string_sized_new (128);
     517              :         const gchar *field;
     518              :         const gchar *value;
     519              :         GList *keys, *l;
     520              : 
     521            0 :         keys = g_hash_table_get_keys (fields);
     522            0 :         for (l = g_list_sort (keys, (GCompareFunc) g_strcmp0); l; l = l->next) {
     523            0 :                 field = l->data;
     524            0 :                 value = g_hash_table_lookup (fields, field);
     525            0 :                 g_return_val_if_fail (value != NULL, FALSE);
     526              : 
     527              :                 g_string_append (concat, field);
     528              :                 g_string_append_c (concat, '\0');
     529              :                 g_string_append (concat, value);
     530              :                 g_string_append_c (concat, '\0');
     531              :         }
     532              : 
     533            0 :         gck_builder_add_data (builder, CKA_G_FIELDS, (const guchar *)concat->str, concat->len);
     534            0 :         g_string_free (concat, TRUE);
     535            0 :         return TRUE;
     536              : }
     537              : 
     538              : gchar *
     539            0 : gkd_login_lookup_password (GckSession *session,
     540              :                            const gchar *field,
     541              :                            ...)
     542              : {
     543              :         GHashTable *fields;
     544              :         const gchar *value;
     545              :         gchar *result;
     546              :         va_list va;
     547              : 
     548            0 :         fields = g_hash_table_new (g_str_hash, g_str_equal);
     549              : 
     550            0 :         va_start (va, field);
     551            0 :         while (field) {
     552            0 :                 value = va_arg (va, const gchar *);
     553            0 :                 g_hash_table_insert (fields, (gpointer)field, (gpointer)value);
     554            0 :                 field = va_arg (va, const gchar *);
     555              :         }
     556            0 :         va_end (va);
     557              : 
     558            0 :         result = gkd_login_lookup_passwordv (session, fields);
     559            0 :         g_hash_table_unref (fields);
     560            0 :         return result;
     561              : }
     562              : 
     563              : gchar *
     564            0 : gkd_login_lookup_passwordv (GckSession *session,
     565              :                             GHashTable *fields)
     566              : {
     567            0 :         GckBuilder builder = GCK_BUILDER_INIT;
     568              :         GckAttributes *attrs;
     569              :         GList *objects, *l;
     570            0 :         GError *error = NULL;
     571            0 :         gpointer data = NULL;
     572              :         gsize length;
     573              : 
     574            0 :         if (!session)
     575            0 :                 session = lookup_login_session (NULL);
     576              :         else
     577            0 :                 session = g_object_ref (session);
     578            0 :         if (!session)
     579            0 :                 return NULL;
     580              : 
     581            0 :         gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
     582              : 
     583            0 :         if (!fields_to_attribute (&builder, fields))
     584            0 :                 g_return_val_if_reached (FALSE);
     585              : 
     586            0 :         attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
     587            0 :         objects = find_saved_items (session, attrs);
     588            0 :         gck_attributes_unref (attrs);
     589              : 
     590              :         /* Return first password */
     591            0 :         data = NULL;
     592            0 :         for (l = objects; l; l = g_list_next (l)) {
     593            0 :                 data = gck_object_get_data_full (l->data, CKA_VALUE, egg_secure_realloc, NULL, &length, &error);
     594            0 :                 if (error) {
     595            0 :                         if (!g_error_matches (error, GCK_ERROR, CKR_USER_NOT_LOGGED_IN))
     596            0 :                                 g_warning ("couldn't lookup password: %s", egg_error_message (error));
     597            0 :                         g_clear_error (&error);
     598            0 :                         data = NULL;
     599              :                 } else {
     600            0 :                         break;
     601              :                 }
     602              :         }
     603              : 
     604            0 :         g_list_free_full (objects, g_object_unref);
     605            0 :         g_object_unref (session);
     606              : 
     607              :         /* Data is null terminated */
     608            0 :         return data;
     609              : }
     610              : 
     611              : void
     612            0 : gkd_login_clear_password (GckSession *session,
     613              :                           const gchar *field,
     614              :                           ...)
     615              : {
     616              :         GHashTable *fields;
     617              :         const gchar *value;
     618              :         va_list va;
     619              : 
     620            0 :         fields = g_hash_table_new (g_str_hash, g_str_equal);
     621              : 
     622            0 :         va_start (va, field);
     623            0 :         while (field) {
     624            0 :                 value = va_arg (va, const gchar *);
     625            0 :                 g_hash_table_insert (fields, (gpointer)field, (gpointer)value);
     626            0 :                 field = va_arg (va, const gchar *);
     627              :         }
     628            0 :         va_end (va);
     629              : 
     630            0 :         gkd_login_clear_passwordv (session, fields);
     631            0 :         g_hash_table_unref (fields);
     632            0 : }
     633              : 
     634              : void
     635            0 : gkd_login_clear_passwordv (GckSession *session,
     636              :                            GHashTable *fields)
     637              : {
     638            0 :         GckBuilder builder = GCK_BUILDER_INIT;
     639              :         GckAttributes *attrs;
     640              :         GList *objects, *l;
     641            0 :         GError *error = NULL;
     642              : 
     643            0 :         if (!session)
     644            0 :                 session = lookup_login_session (NULL);
     645              :         else
     646            0 :                 session = g_object_ref (session);
     647            0 :         if (!session)
     648            0 :                 return;
     649              : 
     650            0 :         gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
     651              : 
     652            0 :         if (!fields_to_attribute (&builder, fields))
     653            0 :                 g_return_if_reached ();
     654              : 
     655            0 :         attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
     656            0 :         objects = find_saved_items (session, attrs);
     657            0 :         gck_attributes_unref (attrs);
     658              : 
     659              :         /* Delete first item */
     660            0 :         for (l = objects; l; l = g_list_next (l)) {
     661            0 :                 if (gck_object_destroy (l->data, NULL, &error))
     662            0 :                         break; /* Only delete the first item */
     663            0 :                 g_warning ("couldn't clear password: %s", error->message);
     664            0 :                 g_clear_error (&error);
     665              :         }
     666              : 
     667            0 :         g_list_free_full (objects, g_object_unref);
     668            0 :         g_object_unref (session);
     669              : }
     670              : 
     671              : gboolean
     672            0 : gkd_login_store_password (GckSession *session,
     673              :                           const gchar *password,
     674              :                           const gchar *label,
     675              :                           const gchar *method,
     676              :                           gint lifetime,
     677              :                           const gchar *field,
     678              :                           ...)
     679              : {
     680              :         GHashTable *fields;
     681              :         const gchar *value;
     682              :         gboolean result;
     683              :         va_list va;
     684              : 
     685            0 :         fields = g_hash_table_new (g_str_hash, g_str_equal);
     686              : 
     687            0 :         va_start (va, field);
     688            0 :         while (field) {
     689            0 :                 value = va_arg (va, const gchar *);
     690            0 :                 g_hash_table_insert (fields, (gpointer)field, (gpointer)value);
     691            0 :                 field = va_arg (va, const gchar *);
     692              :         }
     693            0 :         va_end (va);
     694              : 
     695            0 :         result = gkd_login_store_passwordv (session, password, label, method, lifetime, fields);
     696            0 :         g_hash_table_unref (fields);
     697            0 :         return result;
     698              : }
     699              : 
     700              : gboolean
     701            0 : gkd_login_store_passwordv (GckSession *session,
     702              :                            const gchar *password,
     703              :                            const gchar *label,
     704              :                            const gchar *method,
     705              :                            gint lifetime,
     706              :                            GHashTable *fields)
     707              : {
     708            0 :         GckBuilder builder = GCK_BUILDER_INIT;
     709              :         GckAttributes *attrs;
     710              :         guchar *identifier;
     711              :         GList *previous;
     712            0 :         gboolean ret = FALSE;
     713              :         GckObject *item;
     714            0 :         GError *error = NULL;
     715              :         gsize length;
     716              : 
     717            0 :         if (!method)
     718            0 :                 method = GCR_UNLOCK_OPTION_SESSION;
     719              : 
     720            0 :         if (!session)
     721            0 :                 session = lookup_login_session (NULL);
     722              :         else
     723            0 :                 session = g_object_ref (session);
     724            0 :         if (!session)
     725            0 :                 return FALSE;
     726              : 
     727            0 :         if (!fields_to_attribute (&builder, fields))
     728            0 :                 g_return_val_if_reached (FALSE);
     729              : 
     730            0 :         if (g_str_equal (method, GCR_UNLOCK_OPTION_ALWAYS)) {
     731            0 :                 gck_builder_add_string (&builder, CKA_G_COLLECTION, "login");
     732              : 
     733              :         } else {
     734            0 :                 if (g_str_equal (method, GCR_UNLOCK_OPTION_IDLE)) {
     735            0 :                         gck_builder_add_boolean (&builder, CKA_GNOME_TRANSIENT, TRUE);
     736            0 :                         gck_builder_add_ulong (&builder, CKA_G_DESTRUCT_IDLE, lifetime);
     737              : 
     738            0 :                 } else if (g_str_equal (method, GCR_UNLOCK_OPTION_TIMEOUT)) {
     739            0 :                         gck_builder_add_boolean (&builder, CKA_GNOME_TRANSIENT, TRUE);
     740            0 :                         gck_builder_add_ulong (&builder, CKA_G_DESTRUCT_AFTER, lifetime);
     741              : 
     742            0 :                 } else if (!g_str_equal (method, GCR_UNLOCK_OPTION_SESSION)) {
     743            0 :                         g_message ("Unsupported gpg-cache-method setting: %s", method);
     744              :                 }
     745            0 :                 gck_builder_add_string (&builder, CKA_G_COLLECTION, "session");
     746              :         }
     747              : 
     748            0 :         gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
     749            0 :         gck_builder_add_ulong (&builder, CKA_CLASS, CKO_SECRET_KEY);
     750              : 
     751              :         /* Find a previously stored object like this, and replace if so */
     752            0 :         attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
     753            0 :         previous = find_saved_items (session, attrs);
     754            0 :         if (previous) {
     755            0 :                 identifier = gck_object_get_data (previous->data, CKA_ID, NULL, &length, NULL);
     756            0 :                 if (identifier != NULL)
     757            0 :                         gck_builder_add_data (&builder, CKA_ID, identifier, length);
     758            0 :                 g_free (identifier);
     759            0 :                 g_list_free_full (previous, g_object_unref);
     760              :         }
     761              : 
     762              :         /* Put in the remainder of the attributes */
     763            0 :         gck_builder_add_all (&builder, attrs);
     764            0 :         gck_builder_add_string (&builder, CKA_VALUE, password);
     765            0 :         gck_builder_add_string (&builder, CKA_LABEL, label);
     766            0 :         gck_attributes_unref (attrs);
     767              : 
     768            0 :         item = gck_session_create_object (session, gck_builder_end (&builder), NULL, &error);
     769            0 :         if (item == NULL) {
     770            0 :                 g_warning ("couldn't store password: %s", egg_error_message (error));
     771            0 :                 g_clear_error (&error);
     772            0 :                 ret = FALSE;
     773              :         } else {
     774            0 :                 g_object_unref (item);
     775            0 :                 ret = TRUE;
     776              :         }
     777              : 
     778            0 :         g_object_unref (session);
     779            0 :         return ret;
     780              : }
        

Generated by: LCOV version 2.0-1