LCOV - code coverage report
Current view: top level - daemon/dbus - gkd-secret-unlock.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 79.0 % 305 241
Test Date: 2024-04-08 13:24:42 Functions: 96.4 % 28 27

            Line data    Source code
       1              : /*
       2              :  * gnome-keyring
       3              :  *
       4              :  * Copyright (C) 2008 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-dbus.h"
      24              : #include "gkd-secret-dispatch.h"
      25              : #include "gkd-secret-error.h"
      26              : #include "gkd-secret-objects.h"
      27              : #include "gkd-secret-secret.h"
      28              : #include "gkd-secret-session.h"
      29              : #include "gkd-secret-service.h"
      30              : #include "gkd-secret-types.h"
      31              : #include "gkd-secret-unlock.h"
      32              : #include "gkd-secret-util.h"
      33              : #include "gkd-secrets-generated.h"
      34              : 
      35              : #include "egg/egg-error.h"
      36              : #include "egg/egg-secure-memory.h"
      37              : 
      38              : #include "daemon/login/gkd-login.h"
      39              : 
      40              : #include "pkcs11/pkcs11i.h"
      41              : 
      42              : #include <glib/gi18n.h>
      43              : 
      44              : #include <gck/gck.h>
      45              : 
      46              : #include <string.h>
      47              : 
      48              : /*
      49              :  * We try to serialize unlock requests, so the user doesn't get prompted
      50              :  * multiple times for the same thing. There are two queues:
      51              :  *  - self->queued: A queue of object paths per unlock requests.
      52              :  *  - unlock_prompt_queue: A queue of unlock requests ready to prompt.
      53              :  */
      54              : 
      55              : enum {
      56              :         PROP_0,
      57              :         PROP_CALLER,
      58              :         PROP_OBJECT_PATH,
      59              :         PROP_SERVICE
      60              : };
      61              : 
      62              : struct _GkdSecretUnlock {
      63              :         GObject parent;
      64              :         gchar *object_path;
      65              :         GkdSecretService *service;
      66              :         GkdExportedPrompt *skeleton;
      67              :         gchar *caller;
      68              :         gchar *window_id;
      69              :         GQueue *queued;
      70              :         gchar *current;
      71              :         GArray *results;
      72              :         gboolean prompted;
      73              :         gboolean completed;
      74              :         GCancellable *cancellable;
      75              : };
      76              : 
      77              : /* Forward declarations */
      78              : static void gkd_secret_dispatch_iface (GkdSecretDispatchIface *iface);
      79              : static void perform_next_unlock (GkdSecretUnlock *self);
      80              : 
      81           19 : G_DEFINE_TYPE_WITH_CODE (GkdSecretUnlock, gkd_secret_unlock, G_TYPE_OBJECT,
      82              :                          G_IMPLEMENT_INTERFACE (GKD_SECRET_TYPE_DISPATCH, gkd_secret_dispatch_iface));
      83              : 
      84              : static guint unique_prompt_number = 0;
      85              : static GQueue unlock_prompt_queue = G_QUEUE_INIT;
      86              : 
      87              : EGG_SECURE_DECLARE (secret_unlock);
      88              : 
      89              : /* -----------------------------------------------------------------------------
      90              :  * INTERNAL
      91              :  */
      92              : 
      93              : static GckObject*
      94            2 : lookup_collection (GkdSecretUnlock *self, const gchar *path)
      95              : {
      96            2 :         GkdSecretObjects *objects = gkd_secret_service_get_objects (self->service);
      97            2 :         return gkd_secret_objects_lookup_collection (objects, self->caller, path);
      98              : }
      99              : 
     100              : static void
     101            1 : emit_collection_unlocked (GkdSecretUnlock *self,
     102              :                           const gchar *path)
     103              : {
     104              :         GkdSecretObjects *objects;
     105              :         GckObject *collection;
     106              : 
     107            1 :         objects = gkd_secret_service_get_objects (self->service);
     108            1 :         collection = gkd_secret_objects_lookup_collection (objects, self->caller, path);
     109            1 :         if (collection != NULL) {
     110            1 :                 gkd_secret_objects_emit_collection_locked (objects, collection);
     111            1 :                 g_object_unref (collection);
     112              :         }
     113            1 : }
     114              : 
     115              : static gboolean
     116           17 : check_locked_collection (GckObject *collection, gboolean *locked)
     117              : {
     118           17 :         GError *error = NULL;
     119              :         gpointer value;
     120              :         gsize n_value;
     121              : 
     122           17 :         value = gck_object_get_data (collection, CKA_G_LOCKED, NULL, &n_value, &error);
     123           17 :         if (value == NULL) {
     124            0 :                 if (!g_error_matches (error, GCK_ERROR, CKR_OBJECT_HANDLE_INVALID))
     125            0 :                         g_warning ("couldn't check locked status of collection: %s",
     126              :                                    egg_error_message (error));
     127            0 :                 return FALSE;
     128              :         }
     129              : 
     130           17 :         *locked = (value && n_value == sizeof (CK_BBOOL) && *(CK_BBOOL*)value);
     131           17 :         g_free (value);
     132           17 :         return TRUE;
     133              : }
     134              : 
     135              : static void
     136           17 : common_unlock_attributes (GckBuilder *builder,
     137              :                           GckObject *collection)
     138              : {
     139           17 :         g_assert (builder != NULL);
     140           17 :         g_assert (GCK_IS_OBJECT (collection));
     141           17 :         gck_builder_add_ulong (builder, CKA_CLASS, CKO_G_CREDENTIAL);
     142           17 :         gck_builder_add_ulong (builder, CKA_G_OBJECT, gck_object_get_handle (collection));
     143           17 : }
     144              : 
     145              : static gboolean
     146            1 : mark_as_complete (GkdSecretUnlock *self, gboolean dismissed)
     147              : {
     148              :         GkdSecretUnlock *other;
     149              :         const char *value;
     150              :         gint i;
     151              :         GVariantBuilder builder;
     152              :         GVariant *variant;
     153              : 
     154            1 :         if (self->completed)
     155            0 :                 return FALSE;
     156            1 :         self->completed = TRUE;
     157              : 
     158            1 :         g_variant_builder_init (&builder, G_VARIANT_TYPE ("ao"));
     159            2 :         for (i = 0; i < self->results->len; ++i) {
     160            1 :                 value = g_array_index (self->results, gchar*, i);
     161            1 :                 g_variant_builder_add (&builder, "o", value);
     162              :         }
     163              : 
     164              :         /* Emit signal manually, so that we can set the caller as destination */
     165            1 :         variant = g_variant_new_variant (g_variant_builder_end (&builder));
     166            3 :         g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (self->skeleton)),
     167            1 :                                        self->caller,
     168            1 :                                        g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (self->skeleton)),
     169              :                                        "org.freedesktop.Secret.Prompt", "Completed",
     170              :                                        g_variant_new ("(b@v)", dismissed, variant),
     171              :                                        NULL);
     172              : 
     173              :         /* Fire off the next item in the unlock prompt queue */
     174            1 :         other = g_queue_pop_head (&unlock_prompt_queue);
     175            1 :         if (other != NULL) {
     176            0 :                 perform_next_unlock (other);
     177            0 :                 g_object_unref (other);
     178              :         }
     179              : 
     180            1 :         return TRUE;
     181              : }
     182              : 
     183              : static void
     184            1 : on_unlock_complete (GObject *object, GAsyncResult *res, gpointer user_data)
     185              : {
     186            1 :         GkdSecretUnlock *self = GKD_SECRET_UNLOCK (user_data);
     187              :         GkdSecretUnlock *other;
     188              :         GckObject *cred;
     189            1 :         GError *error = NULL;
     190              : 
     191              :         /* We should be at the front of the unlock queue, pop ourselves */
     192            1 :         other = g_queue_pop_head (&unlock_prompt_queue);
     193            1 :         if (other == self)
     194            1 :                 g_object_unref (other);
     195              :         else
     196            0 :                 g_warning ("unlock prompt queue is out of sync with prompts");
     197              : 
     198              :         /* Now process the results */
     199            1 :         cred = gck_session_create_object_finish (GCK_SESSION (object), res, &error);
     200              : 
     201              :         /* Successfully authentication */
     202            1 :         if (cred) {
     203            1 :                 g_object_unref (cred);
     204            1 :                 emit_collection_unlocked (self, self->current);
     205            1 :                 g_array_append_val (self->results, self->current);
     206            1 :                 self->current = NULL;
     207            1 :                 perform_next_unlock (self);
     208              : 
     209              :         /* The user cancelled the protected auth prompt */
     210            0 :         } else if (g_error_matches (error, GCK_ERROR, CKR_PIN_INCORRECT)) {
     211            0 :                 g_free (self->current);
     212            0 :                 self->current = NULL;
     213            0 :                 mark_as_complete (self, TRUE);
     214              : 
     215              :         /* The operation was cancelled via Dismiss call */
     216            0 :         } else if (g_error_matches (error, GCK_ERROR, CKR_CANCEL)) {
     217              :                 /* Should have been the result of a dismiss */
     218            0 :                 g_return_if_fail (self->completed);
     219              : 
     220              :         /* Another error, something's broken */
     221              :         } else {
     222            0 :                 g_warning ("couldn't create credential for collection: %s",
     223              :                            egg_error_message (error));
     224              :         }
     225              : 
     226            1 :         g_clear_error (&error);
     227              : 
     228              :         /* refed for async call */
     229            1 :         g_object_unref (self);
     230              : }
     231              : 
     232              : static void
     233            2 : perform_next_unlock (GkdSecretUnlock *self)
     234              : {
     235            2 :         GckBuilder builder = GCK_BUILDER_INIT;
     236              :         GckObject *collection;
     237              :         GckSession *session;
     238              :         gboolean locked;
     239              :         gboolean proceed;
     240              :         gchar *objpath;
     241              : 
     242              :         for (;;) {
     243            2 :                 g_assert (!self->current);
     244            2 :                 objpath = g_queue_pop_head (self->queued);
     245              : 
     246              :                 /* Nothing more to prompt for? */
     247            2 :                 if (!objpath) {
     248            1 :                         mark_as_complete (self, FALSE);
     249            1 :                         break;
     250              :                 }
     251              : 
     252              :                 /* Find the collection, make sure it's still around */
     253            1 :                 collection = lookup_collection (self, objpath);
     254            1 :                 if (collection == NULL) {
     255            0 :                         g_free (objpath);
     256            0 :                         continue;
     257              :                 }
     258              : 
     259            1 :                 if (!check_locked_collection (collection, &locked)) {
     260            0 :                         g_object_unref (collection);
     261            0 :                         g_free (objpath);
     262            0 :                         continue;
     263              : 
     264            1 :                 } else if (!locked) {
     265            0 :                         g_array_append_val (self->results, objpath);
     266            0 :                         g_object_unref (collection);
     267            0 :                         continue;
     268              :                 }
     269              : 
     270              :                 /* Add ourselves to the unlock prompt queue */
     271            1 :                 proceed = g_queue_is_empty (&unlock_prompt_queue);
     272            1 :                 g_queue_push_tail (&unlock_prompt_queue, g_object_ref (self));
     273              : 
     274              :                 /*
     275              :                  * Proceed with this unlock request. The on_unlock_complete callback
     276              :                  * pops us back off the unlock prompt queue
     277              :                  */
     278            1 :                 if (proceed) {
     279            1 :                         common_unlock_attributes (&builder, collection);
     280            1 :                         gck_builder_add_boolean (&builder, CKA_GNOME_TRANSIENT, TRUE);
     281            1 :                         gck_builder_add_data (&builder, CKA_VALUE, NULL, 0);
     282              : 
     283            1 :                         session = gkd_secret_service_get_pkcs11_session (self->service, self->caller);
     284            1 :                         gck_session_create_object_async (session, gck_builder_end (&builder),
     285              :                                                          self->cancellable, on_unlock_complete,
     286              :                                                          g_object_ref (self));
     287            1 :                         self->current = objpath;
     288            1 :                         break;
     289              :                 }
     290              : 
     291            0 :                 g_object_unref (collection);
     292              : 
     293              :                 /*
     294              :                  * Already have one unlock request going on. Just wait around
     295              :                  * and this function will be called again later.
     296              :                  */
     297            0 :                 if (!proceed) {
     298            0 :                         g_queue_push_head (self->queued, objpath);
     299            0 :                         break;
     300              :                 }
     301              :         }
     302            2 : }
     303              : 
     304              : /* -----------------------------------------------------------------------------
     305              :  * DBUS
     306              :  */
     307              : 
     308              : static gboolean
     309            1 : prompt_method_prompt (GkdExportedPrompt *skeleton,
     310              :                       GDBusMethodInvocation *invocation,
     311              :                       gchar *window_id,
     312              :                       GkdSecretUnlock *self)
     313              : {
     314            1 :         if (!gkd_dbus_invocation_matches_caller (invocation, self->caller))
     315            0 :                 return FALSE;
     316              : 
     317              :         /* Act as if this object no longer exists */
     318            1 :         if (self->completed)
     319            0 :                 return FALSE;
     320              : 
     321              :         /* Prompt can only be called once */
     322            1 :         if (self->prompted) {
     323            0 :                 g_dbus_method_invocation_return_error_literal (invocation,
     324              :                                                                GKD_SECRET_ERROR,
     325              :                                                                GKD_SECRET_ERROR_ALREADY_EXISTS,
     326              :                                                                "This prompt has already been shown.");
     327            0 :                 return TRUE;
     328              :         }
     329              : 
     330            1 :         gkd_secret_unlock_call_prompt (self, window_id);
     331              : 
     332            1 :         gkd_exported_prompt_complete_prompt (skeleton, invocation);
     333            1 :         return TRUE;
     334              : }
     335              : 
     336              : static gboolean
     337            0 : prompt_method_dismiss (GkdExportedPrompt *skeleton,
     338              :                        GDBusMethodInvocation *invocation,
     339              :                        GkdSecretUnlock *self)
     340              : {
     341            0 :         if (!gkd_dbus_invocation_matches_caller (invocation, self->caller))
     342            0 :                 return FALSE;
     343              : 
     344              :         /* Act as if this object no longer exists */
     345            0 :         if (self->completed)
     346            0 :                 return FALSE;
     347              : 
     348            0 :         g_cancellable_cancel (self->cancellable);
     349            0 :         mark_as_complete (self, TRUE);
     350              : 
     351            0 :         gkd_exported_prompt_complete_dismiss (skeleton, invocation);
     352            0 :         return TRUE;
     353              : }
     354              : 
     355              : /* -----------------------------------------------------------------------------
     356              :  * OBJECT
     357              :  */
     358              : 
     359              : static void
     360            1 : gkd_secret_unlock_init (GkdSecretUnlock *self)
     361              : {
     362            1 :         self->queued = g_queue_new ();
     363            1 :         self->results = g_array_new (TRUE, TRUE, sizeof (gchar*));
     364            1 :         self->cancellable = g_cancellable_new ();
     365            1 : }
     366              : 
     367              : static GObject*
     368            1 : gkd_secret_unlock_constructor (GType type, guint n_props, GObjectConstructParam *props)
     369              : {
     370            1 :         GkdSecretUnlock *self = GKD_SECRET_UNLOCK (G_OBJECT_CLASS (gkd_secret_unlock_parent_class)->constructor(type, n_props, props));
     371            1 :         GError *error = NULL;
     372              : 
     373            1 :         g_return_val_if_fail (self, NULL);
     374            1 :         g_return_val_if_fail (self->caller, NULL);
     375            1 :         g_return_val_if_fail (self->service, NULL);
     376              : 
     377              :         /* Setup the path for the object */
     378            1 :         if (!self->object_path)
     379            1 :                 self->object_path = g_strdup_printf (SECRET_PROMPT_PREFIX "/u%d", ++unique_prompt_number);
     380              : 
     381            1 :         self->skeleton = gkd_exported_prompt_skeleton_new ();
     382            1 :         g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->skeleton),
     383            1 :                                           gkd_secret_service_get_connection (self->service), self->object_path,
     384              :                                           &error);
     385              : 
     386            1 :         if (error != NULL) {
     387            0 :                 g_warning ("could not register secret unlock prompt on session bus: %s", error->message);
     388            0 :                 g_error_free (error);
     389              :         }
     390              : 
     391            1 :         g_signal_connect (self->skeleton, "handle-dismiss",
     392              :                           G_CALLBACK (prompt_method_dismiss), self);
     393            1 :         g_signal_connect (self->skeleton, "handle-prompt",
     394              :                           G_CALLBACK (prompt_method_prompt), self);
     395              : 
     396            1 :         return G_OBJECT (self);
     397              : }
     398              : 
     399              : static void
     400            2 : gkd_secret_unlock_dispose (GObject *obj)
     401              : {
     402            2 :         GkdSecretUnlock *self = GKD_SECRET_UNLOCK (obj);
     403              : 
     404            2 :         if (self->skeleton) {
     405            1 :                 g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self->skeleton));
     406            1 :                 g_clear_object (&self->skeleton);
     407              :         }
     408              : 
     409            2 :         if (self->service) {
     410            1 :                 g_object_remove_weak_pointer (G_OBJECT (self->service),
     411            1 :                                               (gpointer*)&(self->service));
     412            1 :                 self->service = NULL;
     413              :         }
     414              : 
     415            2 :         G_OBJECT_CLASS (gkd_secret_unlock_parent_class)->dispose (obj);
     416            2 : }
     417              : 
     418              : static void
     419            1 : gkd_secret_unlock_finalize (GObject *obj)
     420              : {
     421            1 :         GkdSecretUnlock *self = GKD_SECRET_UNLOCK (obj);
     422              : 
     423            1 :         g_free (self->object_path);
     424            1 :         self->object_path = NULL;
     425              : 
     426            1 :         if (g_queue_find (&unlock_prompt_queue, self))
     427            0 :                 g_warning ("unlock queue is not in sync with prompting");
     428              : 
     429            1 :         if (self->queued) {
     430            1 :                 while (!g_queue_is_empty (self->queued))
     431            0 :                         g_free (g_queue_pop_head (self->queued));
     432            1 :                 g_queue_free (self->queued);
     433            1 :                 self->queued = NULL;
     434              :         }
     435              : 
     436            1 :         if (self->results) {
     437            1 :                 gkd_secret_unlock_reset_results (self);
     438            1 :                 g_array_free (self->results, TRUE);
     439            1 :                 self->results = NULL;
     440              :         }
     441              : 
     442            1 :         g_free (self->current);
     443            1 :         self->current = NULL;
     444              : 
     445            1 :         g_object_unref (self->cancellable);
     446            1 :         self->cancellable = NULL;
     447              : 
     448            1 :         g_assert (!self->object_path);
     449            1 :         g_assert (!self->service);
     450              : 
     451            1 :         g_free (self->caller);
     452            1 :         self->caller = NULL;
     453              : 
     454            1 :         g_free (self->window_id);
     455            1 :         self->window_id = NULL;
     456              : 
     457            1 :         G_OBJECT_CLASS (gkd_secret_unlock_parent_class)->finalize (obj);
     458            1 : }
     459              : 
     460              : static void
     461            3 : gkd_secret_unlock_set_property (GObject *obj, guint prop_id, const GValue *value,
     462              :                                 GParamSpec *pspec)
     463              : {
     464            3 :         GkdSecretUnlock *self = GKD_SECRET_UNLOCK (obj);
     465              : 
     466            3 :         switch (prop_id) {
     467            1 :         case PROP_CALLER:
     468            1 :                 g_return_if_fail (!self->caller);
     469            1 :                 self->caller = g_value_dup_string (value);
     470            1 :                 break;
     471            1 :         case PROP_SERVICE:
     472            1 :                 g_return_if_fail (!self->service);
     473            1 :                 self->service = g_value_get_object (value);
     474            1 :                 g_return_if_fail (self->service);
     475            1 :                 g_object_add_weak_pointer (G_OBJECT (self->service),
     476            1 :                                            (gpointer*)&(self->service));
     477            1 :                 break;
     478            1 :         case PROP_OBJECT_PATH:
     479            1 :                 g_return_if_fail (!self->object_path);
     480            1 :                 self->object_path = g_strdup (g_value_get_pointer (value));
     481            1 :                 break;
     482            0 :         default:
     483            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     484            0 :                 break;
     485              :         }
     486              : }
     487              : 
     488              : static void
     489            2 : gkd_secret_unlock_get_property (GObject *obj, guint prop_id, GValue *value,
     490              :                                 GParamSpec *pspec)
     491              : {
     492            2 :         GkdSecretUnlock *self = GKD_SECRET_UNLOCK (obj);
     493              : 
     494            2 :         switch (prop_id) {
     495            0 :         case PROP_CALLER:
     496            0 :                 g_value_set_string (value, self->caller);
     497            0 :                 break;
     498            2 :         case PROP_OBJECT_PATH:
     499            2 :                 g_value_set_pointer (value, self->object_path);
     500            2 :                 break;
     501            0 :         case PROP_SERVICE:
     502            0 :                 g_value_set_object (value, self->service);
     503            0 :                 break;
     504            0 :         default:
     505            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     506            0 :                 break;
     507              :         }
     508            2 : }
     509              : 
     510              : 
     511              : static void
     512            1 : gkd_secret_unlock_class_init (GkdSecretUnlockClass *klass)
     513              : {
     514            1 :         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     515              : 
     516            1 :         gobject_class->constructor = gkd_secret_unlock_constructor;
     517            1 :         gobject_class->get_property = gkd_secret_unlock_get_property;
     518            1 :         gobject_class->set_property = gkd_secret_unlock_set_property;
     519            1 :         gobject_class->dispose = gkd_secret_unlock_dispose;
     520            1 :         gobject_class->finalize = gkd_secret_unlock_finalize;
     521              : 
     522            1 :         g_object_class_install_property (gobject_class, PROP_CALLER,
     523              :                 g_param_spec_string ("caller", "Caller", "DBus caller name",
     524              :                                      NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY ));
     525              : 
     526            1 :         g_object_class_install_property (gobject_class, PROP_OBJECT_PATH,
     527              :                 g_param_spec_pointer ("object-path", "Object Path", "DBus Object Path",
     528              :                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
     529              : 
     530            1 :         g_object_class_install_property (gobject_class, PROP_SERVICE,
     531              :                 g_param_spec_object ("service", "Service", "Service which owns this prompt",
     532              :                                      GKD_SECRET_TYPE_SERVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
     533            1 : }
     534              : 
     535              : static void
     536            1 : gkd_secret_dispatch_iface (GkdSecretDispatchIface *iface)
     537              : {
     538            1 : }
     539              : 
     540              : /* -----------------------------------------------------------------------------
     541              :  * PUBLIC
     542              :  */
     543              : 
     544              : GkdSecretUnlock*
     545            1 : gkd_secret_unlock_new (GkdSecretService *service, const gchar *caller,
     546              :                        const gchar *object_path)
     547              : {
     548            1 :         return g_object_new (GKD_SECRET_TYPE_UNLOCK,
     549              :                              "service", service,
     550              :                              "caller", caller,
     551              :                              "object-path", object_path,
     552              :                              NULL);
     553              : }
     554              : 
     555              : void
     556            1 : gkd_secret_unlock_queue (GkdSecretUnlock *self, const gchar *unlock_path)
     557              : {
     558            1 :         gboolean locked = TRUE;
     559              :         GckObject *coll;
     560              :         gchar *path;
     561              : 
     562            1 :         g_return_if_fail (GKD_SECRET_IS_UNLOCK (self));
     563            1 :         g_return_if_fail (unlock_path);
     564              : 
     565            1 :         coll = lookup_collection (self, unlock_path);
     566            1 :         if (coll == NULL)
     567            0 :                 return;
     568              : 
     569              :         /* Try to unlock with an empty password, which produces no prompt */
     570            1 :         if (gkd_secret_unlock_with_password (coll, (const guchar*)"", 0, NULL)) {
     571            0 :                 locked = FALSE;
     572              : 
     573              :         }
     574              : 
     575            1 :         path = g_strdup (unlock_path);
     576            1 :         if (locked)
     577            1 :                 g_queue_push_tail (self->queued, path);
     578              :         else
     579            0 :                 g_array_append_val (self->results, path);
     580              : 
     581            1 :         g_object_unref (coll);
     582              : }
     583              : 
     584              : gboolean
     585            1 : gkd_secret_unlock_have_queued (GkdSecretUnlock *self)
     586              : {
     587            1 :         g_return_val_if_fail (GKD_SECRET_IS_UNLOCK (self), FALSE);
     588            1 :         return !g_queue_is_empty (self->queued) || self->current;
     589              : }
     590              : 
     591              : gchar**
     592            1 : gkd_secret_unlock_get_results (GkdSecretUnlock *self, gint *n_results)
     593              : {
     594            1 :         g_return_val_if_fail (GKD_SECRET_IS_UNLOCK (self), NULL);
     595            1 :         g_return_val_if_fail (n_results, NULL);
     596            1 :         *n_results = self->results->len;
     597            1 :         return (gchar**)self->results->data;
     598              : }
     599              : 
     600              : void
     601            2 : gkd_secret_unlock_reset_results (GkdSecretUnlock *self)
     602              : {
     603              :         gint i;
     604              : 
     605            2 :         g_return_if_fail (GKD_SECRET_IS_UNLOCK (self));
     606              : 
     607            3 :         for (i = 0; i < self->results->len; ++i)
     608            1 :                 g_free (g_array_index (self->results, gchar*, i));
     609            2 :         g_array_set_size (self->results, 0);
     610              : }
     611              : 
     612              : void
     613            1 : gkd_secret_unlock_call_prompt (GkdSecretUnlock *self, const gchar *window_id)
     614              : {
     615            1 :         g_return_if_fail (GKD_SECRET_IS_UNLOCK (self));
     616            1 :         g_return_if_fail (!self->prompted);
     617              : 
     618            1 :         g_assert (!self->window_id);
     619            1 :         self->window_id = g_strdup (window_id);
     620              : 
     621            1 :         self->prompted = TRUE;
     622            1 :         perform_next_unlock (self);
     623              : }
     624              : 
     625              : gboolean
     626           15 : gkd_secret_unlock_with_secret (GckObject *collection,
     627              :                                GkdSecretSecret *master,
     628              :                                GError **error)
     629              : {
     630           15 :         GckBuilder builder = GCK_BUILDER_INIT;
     631              :         GckAttributes *attrs;
     632              :         GckObject *cred;
     633              :         gboolean locked;
     634              : 
     635           15 :         g_return_val_if_fail (GCK_IS_OBJECT (collection), FALSE);
     636           15 :         g_return_val_if_fail (master, FALSE);
     637              : 
     638              :         /* Shortcut if already unlocked */
     639           15 :         if (check_locked_collection (collection, &locked) && !locked)
     640            0 :                 return TRUE;
     641              : 
     642           15 :         common_unlock_attributes (&builder, collection);
     643           15 :         gck_builder_add_boolean (&builder, CKA_GNOME_TRANSIENT, TRUE);
     644           15 :         gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
     645           15 :         attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
     646              : 
     647           15 :         cred = gkd_secret_session_create_credential (master->session, NULL,
     648              :                                                      attrs, master, error);
     649              : 
     650           15 :         gck_attributes_unref (attrs);
     651              : 
     652           15 :         if (cred != NULL)
     653           15 :                 g_object_unref (cred);
     654           15 :         return (cred != NULL);
     655              : }
     656              : 
     657              : gboolean
     658            1 : gkd_secret_unlock_with_password (GckObject *collection, const guchar *password,
     659              :                                  gsize n_password, GError **error_out)
     660              : {
     661            1 :         GckBuilder builder = GCK_BUILDER_INIT;
     662            1 :         GError *error = NULL;
     663              :         GckSession *session;
     664              :         GckObject *cred;
     665              :         gboolean locked;
     666              : 
     667            1 :         g_return_val_if_fail (GCK_IS_OBJECT (collection), FALSE);
     668              : 
     669              :         /* Shortcut if already unlocked */
     670            1 :         if (check_locked_collection (collection, &locked) && !locked)
     671            0 :                 return TRUE;
     672              : 
     673            1 :         session = gck_object_get_session (collection);
     674            1 :         g_return_val_if_fail (session, FALSE);
     675              : 
     676            1 :         gck_builder_init_full (&builder, GCK_BUILDER_SECURE_MEMORY);
     677            1 :         common_unlock_attributes (&builder, collection);
     678            1 :         gck_builder_add_boolean (&builder, CKA_GNOME_TRANSIENT, TRUE);
     679            1 :         gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
     680            1 :         gck_builder_add_data (&builder, CKA_VALUE, password, n_password);
     681              : 
     682            1 :         cred = gck_session_create_object (session, gck_builder_end (&builder), NULL, &error);
     683            1 :         if (cred == NULL) {
     684            1 :                 if (g_error_matches (error, GCK_ERROR, CKR_PIN_INCORRECT)) {
     685            1 :                         g_set_error_literal (error_out, GKD_SECRET_DAEMON_ERROR,
     686              :                                              GKD_SECRET_DAEMON_ERROR_DENIED,
     687              :                                              "The password was incorrect.");
     688              :                 } else {
     689            0 :                         g_message ("couldn't create credential: %s", egg_error_message (error));
     690            0 :                         g_set_error_literal (error_out, G_DBUS_ERROR,
     691              :                                              G_DBUS_ERROR_FAILED,
     692              :                                              "Couldn't use credentials");
     693              :                 }
     694            1 :                 g_clear_error (&error);
     695            1 :                 return FALSE;
     696              :         }
     697              : 
     698            0 :         g_object_unref (cred);
     699            0 :         return TRUE;
     700              : }
        

Generated by: LCOV version 2.0-1