LCOV - code coverage report
Current view: top level - daemon/dbus - gkd-secret-prompt.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 58.4 % 185 108
Test Date: 2024-04-08 13:24:42 Functions: 60.0 % 30 18

            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-exchange.h"
      27              : #include "gkd-secret-service.h"
      28              : #include "gkd-secret-prompt.h"
      29              : #include "gkd-secret-objects.h"
      30              : #include "gkd-secret-secret.h"
      31              : #include "gkd-secret-session.h"
      32              : #include "gkd-secret-types.h"
      33              : #include "gkd-secret-util.h"
      34              : #include "gkd-secrets-generated.h"
      35              : 
      36              : #include "egg/egg-dh.h"
      37              : #include "egg/egg-error.h"
      38              : 
      39              : #include <string.h>
      40              : 
      41              : enum {
      42              :         PROP_0,
      43              :         PROP_CALLER,
      44              :         PROP_OBJECT_PATH,
      45              :         PROP_SERVICE
      46              : };
      47              : 
      48              : struct _GkdSecretPromptPrivate {
      49              :         gchar *object_path;
      50              :         GkdSecretService *service;
      51              :         GkdSecretExchange *exchange;
      52              :         GkdExportedPrompt *skeleton;
      53              :         GCancellable *cancellable;
      54              :         gboolean prompted;
      55              :         gboolean completed;
      56              :         gchar *caller;
      57              :         gchar *window_id;
      58              :         GList *objects;
      59              : };
      60              : 
      61              : static void gkd_secret_dispatch_iface (GkdSecretDispatchIface *iface);
      62           21 : G_DEFINE_TYPE_WITH_CODE (GkdSecretPrompt, gkd_secret_prompt, GCR_TYPE_SYSTEM_PROMPT,
      63              :                          G_ADD_PRIVATE (GkdSecretPrompt)
      64              :                          G_IMPLEMENT_INTERFACE (GKD_SECRET_TYPE_DISPATCH, gkd_secret_dispatch_iface));
      65              : 
      66              : static guint unique_prompt_number = 0;
      67              : 
      68              : static void
      69            1 : emit_completed (GkdSecretPrompt *self, gboolean dismissed)
      70              : {
      71              :         GVariant *variant;
      72              : 
      73            1 :         g_return_if_fail (GKD_SECRET_PROMPT_GET_CLASS (self)->encode_result);
      74            1 :         variant = GKD_SECRET_PROMPT_GET_CLASS (self)->encode_result (self);
      75              : 
      76              :         /* Emit signal manually, so that we can set the caller as destination */
      77            3 :         g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (self->pv->skeleton)),
      78            1 :                                        self->pv->caller,
      79            1 :                                        g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (self->pv->skeleton)),
      80              :                                        "org.freedesktop.Secret.Prompt", "Completed",
      81              :                                        g_variant_new ("(b@v)", dismissed, variant),
      82              :                                        NULL);
      83              : }
      84              : 
      85              : static void
      86            1 : on_system_prompt_inited (GObject *source,
      87              :                          GAsyncResult *result,
      88              :                          gpointer user_data)
      89              : {
      90            1 :         GkdSecretPrompt *self = GKD_SECRET_PROMPT (source);
      91              :         GkdSecretPromptClass *klass;
      92            1 :         GError *error = NULL;
      93              : 
      94            1 :         if (g_async_initable_init_finish (G_ASYNC_INITABLE (source), result, &error)) {
      95            1 :                 klass = GKD_SECRET_PROMPT_GET_CLASS (self);
      96            1 :                 g_assert (klass->prompt_ready);
      97            1 :                 (klass->prompt_ready) (self);
      98              :         } else {
      99            0 :                 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
     100            0 :                         g_message ("couldn't initialize prompt: %s", error->message);
     101            0 :                 g_error_free (error);
     102            0 :                 if (!self->pv->completed)
     103            0 :                         gkd_secret_prompt_dismiss (self);
     104              :         }
     105            1 : }
     106              : 
     107              : static gboolean
     108            1 : prompt_method_prompt (GkdExportedPrompt *skeleton,
     109              :                       GDBusMethodInvocation *invocation,
     110              :                       gchar *window_id,
     111              :                       GkdSecretPrompt *self)
     112              : {
     113            1 :         if (!gkd_dbus_invocation_matches_caller (invocation, self->pv->caller))
     114            0 :                 return FALSE;
     115              : 
     116              :         /* Act as if this object no longer exists */
     117            1 :         if (self->pv->completed)
     118            0 :                 return FALSE;
     119              : 
     120              :         /* Prompt can only be called once */
     121            1 :         if (self->pv->prompted) {
     122            0 :                 g_dbus_method_invocation_return_error_literal (invocation, GKD_SECRET_ERROR,
     123              :                                                                GKD_SECRET_ERROR_ALREADY_EXISTS,
     124              :                                                                "This prompt has already been shown.");
     125            0 :                 return TRUE;
     126              :         }
     127              : 
     128            1 :         self->pv->prompted = TRUE;
     129              : 
     130            1 :         gcr_prompt_set_caller_window (GCR_PROMPT (self), window_id);
     131              : 
     132            1 :         g_async_initable_init_async (G_ASYNC_INITABLE (self), G_PRIORITY_DEFAULT,
     133            1 :                                      self->pv->cancellable, on_system_prompt_inited, NULL);
     134              : 
     135            1 :         gkd_exported_prompt_complete_prompt (skeleton, invocation);
     136            1 :         return TRUE;
     137              : }
     138              : 
     139              : static gboolean
     140            0 : prompt_method_dismiss (GkdExportedPrompt *skeleton,
     141              :                        GDBusMethodInvocation *invocation,
     142              :                        GkdSecretPrompt *self)
     143              : {
     144            0 :         if (!gkd_dbus_invocation_matches_caller (invocation, self->pv->caller))
     145            0 :                 return FALSE;
     146              : 
     147              :         /* Act as if this object no longer exists */
     148            0 :         if (self->pv->completed)
     149            0 :                 return FALSE;
     150              : 
     151            0 :         gkd_secret_prompt_dismiss (self);
     152              : 
     153            0 :         gkd_exported_prompt_complete_dismiss (skeleton, invocation);
     154            0 :         return TRUE;
     155              : }
     156              : 
     157              : static void
     158            0 : gkd_secret_prompt_real_prompt_ready (GkdSecretPrompt *self)
     159              : {
     160              :         /* Default implementation, unused */
     161            0 :         g_return_if_reached ();
     162              : }
     163              : 
     164              : static GVariant *
     165            0 : gkd_secret_prompt_real_encode_result (GkdSecretPrompt *self)
     166              : {
     167              :         /* Default implementation, unused */
     168            0 :         g_return_val_if_reached (NULL);
     169              : }
     170              : 
     171              : static void
     172            1 : gkd_secret_prompt_constructed (GObject *obj)
     173              : {
     174            1 :         GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
     175            1 :         GError *error = NULL;
     176              : 
     177            1 :         G_OBJECT_CLASS (gkd_secret_prompt_parent_class)->constructed (obj);
     178              : 
     179            1 :         g_return_if_fail (self->pv->caller);
     180            1 :         g_return_if_fail (self->pv->service);
     181              : 
     182              :         /* Setup the path for the object */
     183            1 :         self->pv->object_path = g_strdup_printf (SECRET_PROMPT_PREFIX "/p%d", ++unique_prompt_number);
     184              : 
     185            1 :         self->pv->exchange = gkd_secret_exchange_new (self->pv->service, self->pv->caller);
     186              : 
     187              :         /* Set the exchange for the prompt */
     188            1 :         g_object_set (self, "secret-exchange", self->pv->exchange, NULL);
     189              : 
     190            1 :         self->pv->skeleton = gkd_exported_prompt_skeleton_new ();
     191            1 :         g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->pv->skeleton),
     192            1 :                                           gkd_secret_service_get_connection (self->pv->service), self->pv->object_path,
     193              :                                           &error);
     194              : 
     195            1 :         if (error != NULL) {
     196            0 :                 g_warning ("could not register secret prompt on session bus: %s", error->message);
     197            0 :                 g_error_free (error);
     198              :         }
     199              : 
     200            1 :         g_signal_connect (self->pv->skeleton, "handle-dismiss",
     201              :                           G_CALLBACK (prompt_method_dismiss), self);
     202            1 :         g_signal_connect (self->pv->skeleton, "handle-prompt",
     203              :                           G_CALLBACK (prompt_method_prompt), self);
     204              : }
     205              : 
     206              : void
     207            0 : gkd_secret_prompt_unexport (GkdSecretPrompt *self)
     208              : {
     209            0 :         g_return_if_fail (self->pv->skeleton != NULL);
     210            0 :         g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self->pv->skeleton));
     211            0 :         g_clear_object (&self->pv->skeleton);
     212              : }
     213              : 
     214              : static void
     215            1 : gkd_secret_prompt_init (GkdSecretPrompt *self)
     216              : {
     217            1 :         self->pv = gkd_secret_prompt_get_instance_private (self);
     218            1 :         self->pv->cancellable = g_cancellable_new ();
     219            1 : }
     220              : 
     221              : static void
     222            2 : gkd_secret_prompt_dispose (GObject *obj)
     223              : {
     224            2 :         GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
     225              : 
     226            2 :         g_cancellable_cancel (self->pv->cancellable);
     227              : 
     228            2 :         g_free (self->pv->object_path);
     229            2 :         self->pv->object_path = NULL;
     230              : 
     231            2 :         if (self->pv->service) {
     232            1 :                 g_object_remove_weak_pointer (G_OBJECT (self->pv->service),
     233            1 :                                               (gpointer*)&(self->pv->service));
     234            1 :                 self->pv->service = NULL;
     235              :         }
     236              : 
     237            2 :         g_clear_object (&self->pv->exchange);
     238              : 
     239            2 :         G_OBJECT_CLASS (gkd_secret_prompt_parent_class)->dispose (obj);
     240            2 : }
     241              : 
     242              : static void
     243            0 : gkd_secret_prompt_finalize (GObject *obj)
     244              : {
     245            0 :         GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
     246              : 
     247            0 :         g_assert (!self->pv->object_path);
     248            0 :         g_assert (!self->pv->service);
     249              : 
     250            0 :         g_free (self->pv->caller);
     251            0 :         self->pv->caller = NULL;
     252              : 
     253            0 :         g_clear_object (&self->pv->cancellable);
     254              : 
     255            0 :         G_OBJECT_CLASS (gkd_secret_prompt_parent_class)->finalize (obj);
     256            0 : }
     257              : 
     258              : static void
     259            2 : gkd_secret_prompt_set_property (GObject *obj, guint prop_id, const GValue *value,
     260              :                                 GParamSpec *pspec)
     261              : {
     262            2 :         GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
     263              : 
     264            2 :         switch (prop_id) {
     265            1 :         case PROP_CALLER:
     266            1 :                 g_return_if_fail (!self->pv->caller);
     267            1 :                 self->pv->caller = g_value_dup_string (value);
     268            1 :                 break;
     269            1 :         case PROP_SERVICE:
     270            1 :                 g_return_if_fail (!self->pv->service);
     271            1 :                 self->pv->service = g_value_get_object (value);
     272            1 :                 g_return_if_fail (self->pv->service);
     273            1 :                 g_object_add_weak_pointer (G_OBJECT (self->pv->service),
     274            1 :                                            (gpointer*)&(self->pv->service));
     275            1 :                 break;
     276            0 :         default:
     277            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     278            0 :                 break;
     279              :         }
     280              : }
     281              : 
     282              : static void
     283            2 : gkd_secret_prompt_get_property (GObject *obj, guint prop_id, GValue *value,
     284              :                                 GParamSpec *pspec)
     285              : {
     286            2 :         GkdSecretPrompt *self = GKD_SECRET_PROMPT (obj);
     287              : 
     288            2 :         switch (prop_id) {
     289            0 :         case PROP_CALLER:
     290            0 :                 g_value_set_string (value, gkd_secret_prompt_get_caller (self));
     291            0 :                 break;
     292            2 :         case PROP_OBJECT_PATH:
     293            2 :                 g_value_set_pointer (value, self->pv->object_path);
     294            2 :                 break;
     295            0 :         case PROP_SERVICE:
     296            0 :                 g_value_set_object (value, self->pv->service);
     297            0 :                 break;
     298            0 :         default:
     299            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     300            0 :                 break;
     301              :         }
     302            2 : }
     303              : 
     304              : static void
     305            1 : gkd_secret_prompt_class_init (GkdSecretPromptClass *klass)
     306              : {
     307            1 :         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     308              : 
     309            1 :         gobject_class->constructed = gkd_secret_prompt_constructed;
     310            1 :         gobject_class->dispose = gkd_secret_prompt_dispose;
     311            1 :         gobject_class->finalize = gkd_secret_prompt_finalize;
     312            1 :         gobject_class->set_property = gkd_secret_prompt_set_property;
     313            1 :         gobject_class->get_property = gkd_secret_prompt_get_property;
     314              : 
     315            1 :         klass->encode_result = gkd_secret_prompt_real_encode_result;
     316            1 :         klass->prompt_ready = gkd_secret_prompt_real_prompt_ready;
     317              : 
     318            1 :         g_object_class_install_property (gobject_class, PROP_CALLER,
     319              :                 g_param_spec_string ("caller", "Caller", "DBus caller name",
     320              :                                      NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY ));
     321              : 
     322            1 :         g_object_class_install_property (gobject_class, PROP_OBJECT_PATH,
     323              :                 g_param_spec_pointer ("object-path", "Object Path", "DBus Object Path",
     324              :                                       G_PARAM_READABLE));
     325              : 
     326            1 :         g_object_class_install_property (gobject_class, PROP_SERVICE,
     327              :                 g_param_spec_object ("service", "Service", "Service which owns this prompt",
     328              :                                      GKD_SECRET_TYPE_SERVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
     329            1 : }
     330              : 
     331              : static void
     332            1 : gkd_secret_dispatch_iface (GkdSecretDispatchIface *iface)
     333              : {
     334            1 : }
     335              : 
     336              : /* -----------------------------------------------------------------------------
     337              :  * PUBLIC
     338              :  */
     339              : 
     340              : const gchar*
     341            0 : gkd_secret_prompt_get_caller (GkdSecretPrompt *self)
     342              : {
     343            0 :         g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
     344            0 :         return self->pv->caller;
     345              : }
     346              : 
     347              : const gchar*
     348            0 : gkd_secret_prompt_get_window_id (GkdSecretPrompt *self)
     349              : {
     350            0 :         g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
     351            0 :         return self->pv->window_id;
     352              : }
     353              : 
     354              : GckSession*
     355            0 : gkd_secret_prompt_get_pkcs11_session (GkdSecretPrompt *self)
     356              : {
     357            0 :         g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
     358            0 :         g_return_val_if_fail (self->pv->service, NULL);
     359            0 :         return gkd_secret_service_get_pkcs11_session (self->pv->service, self->pv->caller);
     360              : }
     361              : 
     362              : GkdSecretService*
     363            1 : gkd_secret_prompt_get_service (GkdSecretPrompt *self)
     364              : {
     365            1 :         g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
     366            1 :         g_return_val_if_fail (self->pv->service, NULL);
     367            1 :         return self->pv->service;
     368              : }
     369              : 
     370              : GkdSecretObjects*
     371            0 : gkd_secret_prompt_get_objects (GkdSecretPrompt *self)
     372              : {
     373            0 :         g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
     374            0 :         g_return_val_if_fail (self->pv->service, NULL);
     375            0 :         return gkd_secret_service_get_objects (self->pv->service);
     376              : }
     377              : 
     378              : void
     379            1 : gkd_secret_prompt_complete (GkdSecretPrompt *self)
     380              : {
     381            1 :         g_return_if_fail (GKD_SECRET_IS_PROMPT (self));
     382            1 :         g_return_if_fail (!self->pv->completed);
     383            1 :         self->pv->completed = TRUE;
     384            1 :         emit_completed (self, FALSE);
     385              : 
     386              :         /* Make this object go away */
     387            1 :         g_object_run_dispose (G_OBJECT (self));
     388              : }
     389              : 
     390              : void
     391            0 : gkd_secret_prompt_dismiss (GkdSecretPrompt *self)
     392              : {
     393            0 :         g_return_if_fail (GKD_SECRET_IS_PROMPT (self));
     394            0 :         g_return_if_fail (!self->pv->completed);
     395            0 :         self->pv->completed = TRUE;
     396            0 :         emit_completed (self, TRUE);
     397              : 
     398              :         /* Make this object go away */
     399            0 :         g_object_run_dispose (G_OBJECT (self));
     400              : }
     401              : 
     402              : void
     403            0 : gkd_secret_prompt_dismiss_with_error (GkdSecretPrompt *self,
     404              :                                       GError *error)
     405              : {
     406            0 :         g_warning ("prompting failed: %s", egg_error_message (error));
     407            0 :         gkd_secret_prompt_dismiss (self);
     408            0 : }
     409              : 
     410              : GckObject*
     411            0 : gkd_secret_prompt_lookup_collection (GkdSecretPrompt *self, const gchar *path)
     412              : {
     413              :         GkdSecretObjects *objects;
     414              : 
     415            0 :         g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
     416            0 :         g_return_val_if_fail (path, NULL);
     417              : 
     418            0 :         objects = gkd_secret_prompt_get_objects (GKD_SECRET_PROMPT (self));
     419            0 :         return gkd_secret_objects_lookup_collection (objects, self->pv->caller, path);
     420              : }
     421              : 
     422              : GkdSecretSecret *
     423            1 : gkd_secret_prompt_take_secret (GkdSecretPrompt *self)
     424              : {
     425            1 :         g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
     426              : 
     427              :         /* ... instead it stashes away the raw cipher text, and makes it available here */
     428            1 :         return gkd_secret_exchange_take_last_secret (self->pv->exchange);
     429              : }
     430              : 
     431              : GCancellable *
     432            1 : gkd_secret_prompt_get_cancellable (GkdSecretPrompt *self)
     433              : {
     434            1 :         g_return_val_if_fail (GKD_SECRET_IS_PROMPT (self), NULL);
     435            1 :         return self->pv->cancellable;
     436              : }
        

Generated by: LCOV version 2.0-1