LCOV - code coverage report
Current view: top level - daemon/dbus - gkd-secret-change.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 243 0
Test Date: 2024-04-08 13:24:42 Functions: 0.0 % 21 0

            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-secret-change.h"
      24              : #include "gkd-secret-prompt.h"
      25              : #include "gkd-secret-secret.h"
      26              : #include "gkd-secret-service.h"
      27              : #include "gkd-secret-session.h"
      28              : #include "gkd-secret-types.h"
      29              : 
      30              : #include "egg/egg-error.h"
      31              : #include "egg/egg-secure-memory.h"
      32              : 
      33              : #include "pkcs11/pkcs11i.h"
      34              : 
      35              : #include <glib/gi18n.h>
      36              : 
      37              : #include <gck/gck.h>
      38              : #include <gcr/gcr-base.h>
      39              : 
      40              : #include <string.h>
      41              : 
      42              : enum {
      43              :         PROP_0,
      44              :         PROP_COLLECTION_PATH
      45              : };
      46              : 
      47              : struct _GkdSecretChange {
      48              :         GkdSecretPrompt parent;
      49              :         gchar *collection_path;
      50              :         GckSession *session;
      51              :         GkdSecretSecret *master;
      52              :         GckObject *ocred;
      53              :         gboolean unlocked;
      54              :         gboolean confirmed;
      55              : };
      56              : 
      57              : struct _GkdSecretChangeClass {
      58              :         GkdSecretPromptClass parent_class;
      59              : };
      60              : 
      61              : static void      perform_prompting     (GkdSecretChange *self,
      62              :                                         GckObject *collection);
      63              : 
      64            0 : G_DEFINE_TYPE (GkdSecretChange, gkd_secret_change, GKD_SECRET_TYPE_PROMPT);
      65              : 
      66              : static void
      67            0 : setup_original_prompt (GkdSecretChange *self,
      68              :                        GckObject *collection)
      69              : {
      70            0 :         GcrPrompt *prompt = GCR_PROMPT (self);
      71            0 :         GError *error = NULL;
      72              :         gpointer data;
      73              :         gsize n_data;
      74              :         gchar *label;
      75              :         gchar *text;
      76              : 
      77            0 :         data = gck_object_get_data (collection, CKA_LABEL, NULL, &n_data, &error);
      78            0 :         if (!data) {
      79            0 :                 g_warning ("couldn't get label for collection: %s", egg_error_message (error));
      80            0 :                 g_clear_error (&error);
      81              :         }
      82              : 
      83            0 :         if (!data || !n_data)
      84            0 :                 label = g_strdup (_("Unnamed"));
      85              :         else
      86            0 :                 label = g_strndup (data, n_data);
      87            0 :         g_free (data);
      88              : 
      89            0 :         text = g_strdup_printf (_("Enter the old password for the “%s” keyring"), label);
      90            0 :         gcr_prompt_set_message (prompt, text);
      91            0 :         g_free (text);
      92              : 
      93            0 :         text = g_strdup_printf (_("An application wants to change the password for the “%s” keyring. "
      94              :                                   "Enter the old password for it."), label);
      95            0 :         gcr_prompt_set_description (prompt, text);
      96            0 :         g_free (text);
      97              : 
      98            0 :         gcr_prompt_set_password_new (prompt, FALSE);
      99            0 :         gcr_prompt_set_continue_label (prompt, _("Continue"));
     100            0 : }
     101              : 
     102              : static void
     103            0 : setup_password_prompt (GkdSecretChange *self,
     104              :                        GckObject *collection)
     105              : {
     106            0 :         GcrPrompt *prompt = GCR_PROMPT (self);
     107            0 :         GError *error = NULL;
     108              :         gpointer data;
     109              :         gsize n_data;
     110              :         gchar *label;
     111              :         gchar *text;
     112              : 
     113            0 :         data = gck_object_get_data (collection, CKA_LABEL, NULL, &n_data, &error);
     114            0 :         if (!data) {
     115            0 :                 g_warning ("couldn't get label for collection: %s", egg_error_message (error));
     116            0 :                 g_clear_error (&error);
     117              :         }
     118              : 
     119            0 :         if (!data || !n_data)
     120            0 :                 label = g_strdup (_("Unnamed"));
     121              :         else
     122            0 :                 label = g_strndup (data, n_data);
     123            0 :         g_free (data);
     124              : 
     125            0 :         text = g_strdup_printf (_("Choose a new password for the “%s” keyring"), label);
     126            0 :         gcr_prompt_set_message (prompt, text);
     127            0 :         g_free (text);
     128              : 
     129            0 :         text = g_strdup_printf (_("An application wants to change the password for the “%s” keyring. "
     130              :                                   "Choose the new password you want to use for it."), label);
     131            0 :         gcr_prompt_set_description (prompt, text);
     132            0 :         g_free (text);
     133              : 
     134            0 :         gcr_prompt_set_password_new (prompt, TRUE);
     135            0 :         gcr_prompt_set_continue_label (prompt, _("Continue"));
     136            0 :         gcr_prompt_set_warning (prompt, NULL);
     137            0 : }
     138              : 
     139              : static void
     140            0 : setup_confirmation_prompt (GkdSecretChange *self)
     141              : {
     142            0 :         gcr_prompt_set_message (GCR_PROMPT (self), _("Store passwords unencrypted?"));
     143            0 :         gcr_prompt_set_description (GCR_PROMPT (self),
     144            0 :                                     _("By choosing to use a blank password, your stored passwords will not be safely encrypted. "
     145              :                                       "They will be accessible by anyone with access to your files."));
     146            0 :         gcr_prompt_set_continue_label (GCR_PROMPT (self), _("Continue"));
     147            0 : }
     148              : 
     149              : static void
     150            0 : set_warning_wrong (GkdSecretChange *self)
     151              : {
     152            0 :         gcr_prompt_set_warning (GCR_PROMPT (self), _("The original password was incorrect"));
     153            0 : }
     154              : 
     155              : static void
     156            0 : on_prompt_original_complete (GObject *source,
     157              :                              GAsyncResult *result,
     158              :                              gpointer user_data)
     159              : {
     160            0 :         GkdSecretChange *self = GKD_SECRET_CHANGE (source);
     161            0 :         GkdSecretPrompt *prompt = GKD_SECRET_PROMPT (source);
     162            0 :         GckBuilder builder = GCK_BUILDER_INIT;
     163            0 :         gboolean continue_prompting = TRUE;
     164              :         GkdSecretSecret *original;
     165              :         GckAttributes *attrs;
     166            0 :         GError *error = NULL;
     167              :         GckObject *collection;
     168              : 
     169            0 :         gcr_prompt_password_finish (GCR_PROMPT (source), result, &error);
     170            0 :         if (error != NULL) {
     171            0 :                 gkd_secret_prompt_dismiss_with_error (prompt, error);
     172            0 :                 g_error_free (error);
     173            0 :                 return;
     174              :         }
     175              : 
     176              :         /* The prompt was cancelled */
     177            0 :         original = gkd_secret_prompt_take_secret (prompt);
     178            0 :         if (original == NULL) {
     179            0 :                 gkd_secret_prompt_dismiss (prompt);
     180            0 :                 return;
     181              :         }
     182              : 
     183            0 :         collection = gkd_secret_prompt_lookup_collection (prompt, self->collection_path);
     184            0 :         if (collection != NULL) {
     185            0 :                 gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_CREDENTIAL);
     186            0 :                 gck_builder_add_boolean (&builder, CKA_TOKEN, FALSE);
     187            0 :                 gck_builder_add_ulong (&builder, CKA_G_OBJECT, gck_object_get_handle (collection));
     188              : 
     189            0 :                 attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
     190              : 
     191              :                 /* Create the original credential, in order to make sure we can unlock the collection */
     192            0 :                 self->ocred = gkd_secret_session_create_credential (original->session,
     193              :                                                                     self->session, attrs,
     194              :                                                                     original, &error);
     195              : 
     196            0 :                 gck_attributes_unref (attrs);
     197              : 
     198              :                 /* The unlock failed because password was bad */
     199            0 :                 if (g_error_matches (error, GCK_ERROR, CKR_PIN_INCORRECT)) {
     200            0 :                         set_warning_wrong (self);
     201            0 :                         g_error_free (error);
     202              : 
     203              :                 /* The unlock failed for some other reason */
     204            0 :                 } else if (error != NULL) {
     205            0 :                         continue_prompting = FALSE;
     206            0 :                         gkd_secret_prompt_dismiss_with_error (prompt, error);
     207            0 :                         g_error_free (error);
     208              : 
     209              :                 /* The unlock succeeded */
     210              :                 } else {
     211            0 :                         if (self->session == NULL)
     212            0 :                                 self->session = gck_object_get_session (self->ocred);
     213            0 :                         self->unlocked = TRUE;
     214              :                 }
     215              :         }
     216              : 
     217            0 :         if (continue_prompting)
     218            0 :                 perform_prompting (self, collection);
     219              : 
     220            0 :         gkd_secret_secret_free (original);
     221            0 :         g_clear_object (&collection);
     222              : }
     223              : 
     224              : static void
     225            0 : on_prompt_password_complete (GObject *source,
     226              :                              GAsyncResult *result,
     227              :                              gpointer user_data)
     228              : {
     229            0 :         GkdSecretChange *self = GKD_SECRET_CHANGE (source);
     230            0 :         GkdSecretPrompt *prompt = GKD_SECRET_PROMPT (source);
     231            0 :         GError *error = NULL;
     232              :         GckObject *collection;
     233              : 
     234            0 :         gcr_prompt_password_finish (GCR_PROMPT (source), result, &error);
     235            0 :         if (error != NULL) {
     236            0 :                 gkd_secret_prompt_dismiss_with_error (prompt, error);
     237            0 :                 g_error_free (error);
     238            0 :                 return;
     239              :         }
     240              : 
     241            0 :         self->master = gkd_secret_prompt_take_secret (prompt);
     242            0 :         if (self->master == NULL) {
     243            0 :                 gkd_secret_prompt_dismiss (prompt);
     244            0 :                 return;
     245              :         }
     246              : 
     247              :         /* If the password strength is greater than zero, then don't confirm */
     248            0 :         if (gcr_prompt_get_password_strength (GCR_PROMPT (source)) > 0)
     249            0 :                 self->confirmed = TRUE;
     250              : 
     251            0 :         collection = gkd_secret_prompt_lookup_collection (prompt, self->collection_path);
     252            0 :         perform_prompting (self, collection);
     253            0 :         g_clear_object (&collection);
     254              : }
     255              : 
     256              : static void
     257            0 : on_prompt_confirmation_complete (GObject *source,
     258              :                                  GAsyncResult *result,
     259              :                                  gpointer user_data)
     260              : {
     261            0 :         GkdSecretChange *self = GKD_SECRET_CHANGE (source);
     262            0 :         GkdSecretPrompt *prompt = GKD_SECRET_PROMPT (source);
     263            0 :         GError *error = NULL;
     264              :         GckObject *collection;
     265              : 
     266            0 :         self->confirmed = gcr_prompt_confirm_finish (GCR_PROMPT (source), result, &error);
     267            0 :         if (error != NULL) {
     268            0 :                 gkd_secret_prompt_dismiss_with_error (prompt, error);
     269            0 :                 g_error_free (error);
     270            0 :                 return;
     271              :         }
     272              : 
     273              :         /* If not confirmed, then prompt again */
     274            0 :         if (!self->confirmed) {
     275            0 :                 gkd_secret_secret_free (self->master);
     276            0 :                 self->master = NULL;
     277              :         }
     278              : 
     279            0 :         collection = gkd_secret_prompt_lookup_collection (prompt, self->collection_path);
     280            0 :         perform_prompting (self, collection);
     281            0 :         g_clear_object (&collection);
     282              : }
     283              : 
     284              : static void
     285            0 : perform_prompting (GkdSecretChange *self,
     286              :                    GckObject *collection)
     287              : {
     288            0 :         GkdSecretPrompt *prompt = GKD_SECRET_PROMPT (self);
     289            0 :         GError *error = NULL;
     290              : 
     291              :         /* Collection doesn't exist, just go away */
     292            0 :         if (collection == NULL) {
     293            0 :                 gkd_secret_prompt_dismiss (prompt);
     294              : 
     295              :         /* Get the original password and unlock */
     296            0 :         } else if (!self->unlocked) {
     297            0 :                 setup_original_prompt (self, collection);
     298            0 :                 gcr_prompt_password_async (GCR_PROMPT (self),
     299              :                                            gkd_secret_prompt_get_cancellable (prompt),
     300              :                                            on_prompt_original_complete, NULL);
     301              : 
     302              :         /* Get the new password */
     303            0 :         } else if (self->master == NULL) {
     304            0 :                 setup_password_prompt (self, collection);
     305            0 :                 gcr_prompt_password_async (GCR_PROMPT (self),
     306              :                                            gkd_secret_prompt_get_cancellable (prompt),
     307              :                                            on_prompt_password_complete, NULL);
     308              : 
     309              :         /* Check that the password is not empty */
     310            0 :         } else if (!self->confirmed) {
     311            0 :                 setup_confirmation_prompt (self);
     312            0 :                 gcr_prompt_confirm_async (GCR_PROMPT (self),
     313              :                                           gkd_secret_prompt_get_cancellable (prompt),
     314              :                                           on_prompt_confirmation_complete, NULL);
     315              : 
     316              :         /* Actually create the keyring */
     317            0 :         } else if (gkd_secret_change_with_secrets (collection, self->session,
     318              :                                                    NULL, self->master, &error)) {
     319            0 :                 gkd_secret_prompt_complete (prompt);
     320              : 
     321              :         /* Failed */
     322              :         } else {
     323            0 :                 gkd_secret_prompt_dismiss_with_error (prompt, error);
     324            0 :                 g_error_free (error);
     325              :         }
     326            0 : }
     327              : 
     328              : static void
     329            0 : gkd_secret_change_prompt_ready (GkdSecretPrompt *prompt)
     330              : {
     331            0 :         GkdSecretChange *self = GKD_SECRET_CHANGE (prompt);
     332              :         GckObject *collection;
     333              : 
     334            0 :         collection = gkd_secret_prompt_lookup_collection (prompt, self->collection_path);
     335            0 :         perform_prompting (self, collection);
     336            0 :         g_clear_object (&collection);
     337            0 : }
     338              : 
     339              : static GVariant *
     340            0 : gkd_secret_change_encode_result (GkdSecretPrompt *base)
     341              : {
     342            0 :         return g_variant_new_variant (g_variant_new_string (""));
     343              : }
     344              : 
     345              : static void
     346            0 : gkd_secret_change_init (GkdSecretChange *self)
     347              : {
     348            0 :         gcr_prompt_set_title (GCR_PROMPT (self), _("Change Keyring Password"));
     349            0 : }
     350              : 
     351              : static void
     352            0 : gkd_secret_change_dispose (GObject *obj)
     353              : {
     354            0 :         GkdSecretChange *self = GKD_SECRET_CHANGE (obj);
     355              : 
     356            0 :         if (self->ocred) {
     357            0 :                 gck_object_destroy (self->ocred, NULL, NULL);
     358            0 :                 g_object_unref (self->ocred);
     359            0 :                 self->ocred = NULL;
     360              :         }
     361              : 
     362            0 :         G_OBJECT_CLASS (gkd_secret_change_parent_class)->dispose (obj);
     363            0 : }
     364              : 
     365              : static void
     366            0 : gkd_secret_change_finalize (GObject *obj)
     367              : {
     368            0 :         GkdSecretChange *self = GKD_SECRET_CHANGE (obj);
     369              : 
     370            0 :         g_free (self->collection_path);
     371            0 :         if (self->master)
     372            0 :                 gkd_secret_secret_free (self->master);
     373            0 :         if (self->session)
     374            0 :                 g_object_unref (self->session);
     375              : 
     376            0 :         G_OBJECT_CLASS (gkd_secret_change_parent_class)->finalize (obj);
     377            0 : }
     378              : 
     379              : static void
     380            0 : gkd_secret_change_set_property (GObject *obj, guint prop_id, const GValue *value,
     381              :                                 GParamSpec *pspec)
     382              : {
     383            0 :         GkdSecretChange *self = GKD_SECRET_CHANGE (obj);
     384              : 
     385            0 :         switch (prop_id) {
     386            0 :         case PROP_COLLECTION_PATH:
     387            0 :                 g_return_if_fail (!self->collection_path);
     388            0 :                 self->collection_path = g_value_dup_string (value);
     389            0 :                 g_return_if_fail (self->collection_path);
     390            0 :                 break;
     391            0 :         default:
     392            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     393            0 :                 break;
     394              :         }
     395              : }
     396              : 
     397              : static void
     398            0 : gkd_secret_change_get_property (GObject *obj, guint prop_id, GValue *value,
     399              :                                 GParamSpec *pspec)
     400              : {
     401            0 :         GkdSecretChange *self = GKD_SECRET_CHANGE (obj);
     402              : 
     403            0 :         switch (prop_id) {
     404            0 :         case PROP_COLLECTION_PATH:
     405            0 :                 g_value_set_string (value, self->collection_path);
     406            0 :                 break;
     407            0 :         default:
     408            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     409            0 :                 break;
     410              :         }
     411            0 : }
     412              : 
     413              : static void
     414            0 : gkd_secret_change_class_init (GkdSecretChangeClass *klass)
     415              : {
     416            0 :         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     417            0 :         GkdSecretPromptClass *prompt_class = GKD_SECRET_PROMPT_CLASS (klass);
     418              : 
     419            0 :         gobject_class->dispose = gkd_secret_change_dispose;
     420            0 :         gobject_class->finalize = gkd_secret_change_finalize;
     421            0 :         gobject_class->get_property = gkd_secret_change_get_property;
     422            0 :         gobject_class->set_property = gkd_secret_change_set_property;
     423              : 
     424            0 :         prompt_class->prompt_ready = gkd_secret_change_prompt_ready;
     425            0 :         prompt_class->encode_result = gkd_secret_change_encode_result;
     426              : 
     427            0 :         g_object_class_install_property (gobject_class, PROP_COLLECTION_PATH,
     428              :                 g_param_spec_string ("collection-path", "Collection Path", "Collection Path",
     429              :                                      "/", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
     430            0 : }
     431              : 
     432              : /* -----------------------------------------------------------------------------
     433              :  * PUBLIC
     434              :  */
     435              : 
     436              : GkdSecretChange*
     437            0 : gkd_secret_change_new (GkdSecretService *service, const gchar *caller,
     438              :                        const gchar *path)
     439              : {
     440              :         const gchar *prompter_name;
     441              : 
     442            0 :         g_return_val_if_fail (GKD_SECRET_IS_SERVICE (service), NULL);
     443            0 :         g_return_val_if_fail (caller, NULL);
     444            0 :         g_return_val_if_fail (path, NULL);
     445              : 
     446            0 :         prompter_name = g_getenv ("GNOME_KEYRING_TEST_PROMPTER");
     447            0 :         return g_object_new (GKD_SECRET_TYPE_CHANGE,
     448              :                              "service", service,
     449              :                              "caller", caller,
     450              :                              "collection-path", path,
     451              :                              "bus-name", prompter_name,
     452              :                              NULL);
     453              : }
     454              : 
     455              : gboolean
     456            0 : gkd_secret_change_with_secrets (GckObject *collection,
     457              :                                 GckSession *session,
     458              :                                 GkdSecretSecret *original,
     459              :                                 GkdSecretSecret *master,
     460              :                                 GError **error)
     461              : {
     462            0 :         GckBuilder builder = GCK_BUILDER_INIT;
     463            0 :         GckAttributes *attrs = NULL;
     464            0 :         gboolean result = FALSE;
     465            0 :         GckObject *ocred = NULL;
     466            0 :         GckObject *mcred = NULL;
     467              : 
     468            0 :         g_assert (GCK_IS_OBJECT (collection));
     469            0 :         g_assert (session == NULL || GCK_IS_SESSION (session));
     470            0 :         g_assert (master != NULL);
     471            0 :         g_assert (error == NULL || *error == NULL);
     472              : 
     473              :         /* Create the new credential */
     474            0 :         gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_CREDENTIAL);
     475            0 :         gck_builder_add_boolean (&builder, CKA_TOKEN, FALSE);
     476            0 :         attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
     477            0 :         mcred = gkd_secret_session_create_credential (master->session, session, attrs, master, error);
     478            0 :         gck_builder_add_all (&builder, attrs);
     479            0 :         gck_attributes_unref (attrs);
     480              : 
     481            0 :         if (mcred == NULL)
     482            0 :                 goto cleanup;
     483              : 
     484              :         /* Create the original credential, in order to make sure we can the collection */
     485            0 :         if (original) {
     486            0 :                 gck_builder_add_ulong (&builder, CKA_G_OBJECT, gck_object_get_handle (collection));
     487            0 :                 attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
     488            0 :                 ocred = gkd_secret_session_create_credential (original->session, session, attrs, original, error);
     489            0 :                 gck_attributes_unref (attrs);
     490              : 
     491            0 :                 if (ocred == NULL)
     492            0 :                         goto cleanup;
     493              :         }
     494              : 
     495            0 :         gck_builder_clear (&builder);
     496            0 :         gck_builder_add_ulong (&builder, CKA_G_CREDENTIAL, gck_object_get_handle (mcred));
     497              : 
     498              :         /* Now set the collection credentials to the first one */
     499            0 :         result = gck_object_set (collection, gck_builder_end (&builder), NULL, error);
     500              : 
     501            0 : cleanup:
     502            0 :         if (ocred) {
     503              :                 /* Always destroy the original credential */
     504            0 :                 gck_object_destroy (ocred, NULL, NULL);
     505            0 :                 g_object_unref (ocred);
     506              :         }
     507            0 :         if (mcred) {
     508              :                 /* Always destroy the master credential */
     509            0 :                 gck_object_destroy (mcred, NULL, NULL);
     510            0 :                 g_object_unref (mcred);
     511              :         }
     512              : 
     513            0 :         gck_builder_clear (&builder);
     514            0 :         return result;
     515              : }
        

Generated by: LCOV version 2.0-1