LCOV - code coverage report
Current view: top level - daemon/dbus - gkd-secret-create.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 54.6 % 205 112
Test Date: 2024-04-08 13:24:42 Functions: 76.2 % 21 16

            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-create.h"
      24              : #include "gkd-secret-dispatch.h"
      25              : #include "gkd-secret-error.h"
      26              : #include "gkd-secret-objects.h"
      27              : #include "gkd-secret-prompt.h"
      28              : #include "gkd-secret-secret.h"
      29              : #include "gkd-secret-service.h"
      30              : #include "gkd-secret-session.h"
      31              : #include "gkd-secret-types.h"
      32              : #include "gkd-secret-unlock.h"
      33              : #include "gkd-secret-util.h"
      34              : 
      35              : #include "egg/egg-error.h"
      36              : #include "egg/egg-secure-memory.h"
      37              : 
      38              : #include "pkcs11/pkcs11i.h"
      39              : 
      40              : #include <glib/gi18n.h>
      41              : 
      42              : #include <gck/gck.h>
      43              : 
      44              : #include <string.h>
      45              : 
      46              : enum {
      47              :         STATE_BEGIN,
      48              :         STATE_PROMPTING,
      49              :         STATE_PROMPTED
      50              : };
      51              : 
      52              : enum {
      53              :         PROP_0,
      54              :         PROP_PKCS11_ATTRIBUTES,
      55              :         PROP_ALIAS
      56              : };
      57              : 
      58              : struct _GkdSecretCreate {
      59              :         GkdSecretPrompt parent;
      60              :         GckAttributes *attributes;
      61              :         GkdSecretSecret *master;
      62              :         gchar *result_path;
      63              :         gchar *alias;
      64              :         gboolean confirmed;
      65              : };
      66              : 
      67              : static void    perform_prompting     (GkdSecretCreate *self);
      68              : 
      69            9 : G_DEFINE_TYPE (GkdSecretCreate, gkd_secret_create, GKD_SECRET_TYPE_PROMPT);
      70              : 
      71              : static void
      72            1 : setup_password_prompt (GkdSecretCreate *self)
      73              : {
      74              :         gchar *label;
      75              :         gchar *text;
      76              : 
      77            1 :         if (!gck_attributes_find_string (self->attributes, CKA_LABEL, &label))
      78            0 :                 label = g_strdup (_("Unnamed"));
      79              : 
      80            1 :         text = g_strdup_printf (_("An application wants to create a new keyring called ā€œ%sā€. "
      81              :                                   "Choose the password you want to use for it."), label);
      82            1 :         g_free (label);
      83              : 
      84            1 :         gcr_prompt_set_message (GCR_PROMPT (self), _("Choose password for new keyring"));
      85            1 :         gcr_prompt_set_description (GCR_PROMPT (self), text);
      86            1 :         gcr_prompt_set_password_new (GCR_PROMPT (self), TRUE);
      87              : 
      88            1 :         g_free (text);
      89            1 : }
      90              : 
      91              : static void
      92            0 : setup_confirmation_prompt (GkdSecretCreate *self)
      93              : {
      94            0 :         gcr_prompt_set_message (GCR_PROMPT (self), _("Store passwords unencrypted?"));
      95            0 :         gcr_prompt_set_description (GCR_PROMPT (self),
      96            0 :                                     _("By choosing to use a blank password, your stored passwords will not be safely encrypted. "
      97              :                                       "They will be accessible by anyone with access to your files."));
      98            0 : }
      99              : 
     100              : static gboolean
     101            1 : create_collection_with_secret (GkdSecretCreate *self, GkdSecretSecret *master)
     102              : {
     103            1 :         GError *error = NULL;
     104              :         GkdSecretService *service;
     105              :         gchar *identifier;
     106              : 
     107            1 :         g_assert (GKD_SECRET_IS_CREATE (self));
     108            1 :         g_assert (master);
     109            1 :         g_assert (!self->result_path);
     110              : 
     111            1 :         self->result_path = gkd_secret_create_with_secret (self->attributes, master, &error);
     112              : 
     113            1 :         if (!self->result_path) {
     114            0 :                 g_warning ("couldn't create new collection: %s", error->message);
     115            0 :                 g_error_free (error);
     116            0 :                 return FALSE;
     117              :         }
     118              : 
     119            1 :         service = gkd_secret_prompt_get_service (GKD_SECRET_PROMPT (self));
     120              : 
     121            1 :         if (self->alias) {
     122            0 :                 if (!gkd_secret_util_parse_path (self->result_path, &identifier, NULL))
     123            0 :                         g_assert_not_reached ();
     124            0 :                 gkd_secret_service_set_alias (service, self->alias, identifier);
     125            0 :                 g_free (identifier);
     126              :         }
     127              : 
     128              :         /* Notify the callers that a collection was created */
     129            1 :         gkd_secret_service_emit_collection_created (service, self->result_path);
     130              : 
     131            1 :         return TRUE;
     132              : }
     133              : 
     134              : static gboolean
     135            2 : locate_alias_collection_if_exists (GkdSecretCreate *self)
     136              : {
     137              :         GkdSecretService *service;
     138              :         GkdSecretObjects *objects;
     139              :         GckObject *collection;
     140              :         const gchar *identifier;
     141              :         const gchar *caller;
     142              :         gchar *path;
     143              : 
     144            2 :         if (!self->alias)
     145            2 :                 return FALSE;
     146              : 
     147            0 :         g_assert (!self->result_path);
     148              : 
     149            0 :         service = gkd_secret_prompt_get_service (GKD_SECRET_PROMPT (self));
     150            0 :         caller = gkd_secret_prompt_get_caller (GKD_SECRET_PROMPT (self));
     151            0 :         objects = gkd_secret_prompt_get_objects (GKD_SECRET_PROMPT (self));
     152              : 
     153            0 :         identifier = gkd_secret_service_get_alias (service, self->alias);
     154            0 :         if (!identifier)
     155            0 :                 return FALSE;
     156              : 
     157              :         /* Make sure it actually exists */
     158            0 :         path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, -1);
     159            0 :         collection = gkd_secret_objects_lookup_collection (objects, caller, path);
     160              : 
     161            0 :         if (collection) {
     162            0 :                 self->result_path = path;
     163            0 :                 g_object_unref (collection);
     164            0 :                 return TRUE;
     165              :         } else {
     166            0 :                 g_free (path);
     167            0 :                 return FALSE;
     168              :         }
     169              : }
     170              : 
     171              : static void
     172            0 : unlock_or_complete_this_prompt (GkdSecretCreate *self)
     173              : {
     174              :         GkdSecretUnlock *unlock;
     175              :         GkdSecretPrompt *prompt;
     176              : 
     177            0 :         g_object_ref (self);
     178            0 :         prompt = GKD_SECRET_PROMPT (self);
     179            0 :         gkd_secret_prompt_unexport (prompt);
     180              : 
     181            0 :         unlock = gkd_secret_unlock_new (gkd_secret_prompt_get_service (prompt),
     182              :                                         gkd_secret_prompt_get_caller (prompt),
     183            0 :                                         gkd_secret_dispatch_get_object_path (GKD_SECRET_DISPATCH (self)));
     184            0 :         gkd_secret_unlock_queue (unlock, self->result_path);
     185              : 
     186              :         /*
     187              :          * If any need to be unlocked, then replace this prompt
     188              :          * object with an unlock prompt object, and call the prompt
     189              :          * method.
     190              :          */
     191            0 :         if (gkd_secret_unlock_have_queued (unlock)) {
     192            0 :                 gkd_secret_service_publish_dispatch (gkd_secret_prompt_get_service (prompt),
     193              :                                                      gkd_secret_prompt_get_caller (prompt),
     194            0 :                                                      GKD_SECRET_DISPATCH (unlock));
     195            0 :                 gkd_secret_unlock_call_prompt (unlock, gkd_secret_prompt_get_window_id (prompt));
     196              :         }
     197              : 
     198            0 :         g_object_unref (unlock);
     199            0 :         g_object_unref (self);
     200            0 : }
     201              : 
     202              : static void
     203            1 : on_prompt_password_complete (GObject *source,
     204              :                              GAsyncResult *result,
     205              :                              gpointer user_data)
     206              : {
     207            1 :         GkdSecretCreate *self = GKD_SECRET_CREATE (source);
     208            1 :         GkdSecretPrompt *prompt = GKD_SECRET_PROMPT (source);
     209            1 :         GError *error = NULL;
     210              : 
     211            1 :         gcr_prompt_password_finish (GCR_PROMPT (source), result, &error);
     212              : 
     213            1 :         if (error != NULL) {
     214            0 :                 gkd_secret_prompt_dismiss_with_error (prompt, error);
     215            0 :                 g_error_free (error);
     216            0 :                 return;
     217              :         }
     218              : 
     219            1 :         self->master = gkd_secret_prompt_take_secret (prompt);
     220            1 :         if (self->master == NULL) {
     221            0 :                 gkd_secret_prompt_dismiss (prompt);
     222            0 :                 return;
     223              :         }
     224              : 
     225              :         /* If the password strength is greater than zero, then don't confirm */
     226            1 :         if (gcr_prompt_get_password_strength (GCR_PROMPT (source)) > 0)
     227            1 :                 self->confirmed = TRUE;
     228              : 
     229            1 :         perform_prompting (self);
     230              : }
     231              : 
     232              : static void
     233            0 : on_prompt_confirmation_complete (GObject *source,
     234              :                                  GAsyncResult *result,
     235              :                                  gpointer user_data)
     236              : {
     237            0 :         GkdSecretCreate *self = GKD_SECRET_CREATE (source);
     238            0 :         GkdSecretPrompt *prompt = GKD_SECRET_PROMPT (source);
     239            0 :         GError *error = NULL;
     240              : 
     241            0 :         self->confirmed = gcr_prompt_confirm_finish (GCR_PROMPT (source), result, &error);
     242            0 :         if (error != NULL) {
     243            0 :                 gkd_secret_prompt_dismiss_with_error (prompt, error);
     244            0 :                 g_error_free (error);
     245            0 :                 return;
     246              :         }
     247              : 
     248              :         /* If not confirmed, then prompt again */
     249            0 :         if (!self->confirmed) {
     250            0 :                 gkd_secret_secret_free (self->master);
     251            0 :                 self->master = NULL;
     252              :         }
     253              : 
     254            0 :         perform_prompting (self);
     255              : }
     256              : 
     257              : static void
     258            2 : perform_prompting (GkdSecretCreate *self)
     259              : {
     260            2 :         GkdSecretPrompt *prompt = GKD_SECRET_PROMPT (self);
     261              : 
     262              :         /* Does the alias exist? */
     263            2 :         if (locate_alias_collection_if_exists (self)) {
     264            0 :                 unlock_or_complete_this_prompt (self);
     265              : 
     266              :         /* Have we gotten a password yet? */
     267            2 :         } else if (self->master == NULL) {
     268            1 :                 setup_password_prompt (self);
     269            1 :                 gcr_prompt_password_async (GCR_PROMPT (self),
     270              :                                            gkd_secret_prompt_get_cancellable (prompt),
     271              :                                            on_prompt_password_complete, NULL);
     272              : 
     273              :         /* Check that the password is not empty */
     274            1 :         } else if (!self->confirmed) {
     275            0 :                 setup_confirmation_prompt (self);
     276            0 :                 gcr_prompt_confirm_async (GCR_PROMPT (self),
     277              :                                           gkd_secret_prompt_get_cancellable (prompt),
     278              :                                           on_prompt_confirmation_complete, NULL);
     279              : 
     280              :         /* Actually create the keyring */
     281            1 :         } else  if (create_collection_with_secret (self, self->master)) {
     282            1 :                 gkd_secret_prompt_complete (prompt);
     283              : 
     284              :         /* Failed */
     285              :         } else {
     286            0 :                 gkd_secret_prompt_dismiss (prompt);
     287              :         }
     288            2 : }
     289              : 
     290              : static void
     291            1 : gkd_secret_create_prompt_ready (GkdSecretPrompt *prompt)
     292              : {
     293            1 :         perform_prompting (GKD_SECRET_CREATE (prompt));
     294            1 : }
     295              : 
     296              : static GVariant *
     297            1 : gkd_secret_create_encode_result (GkdSecretPrompt *base)
     298              : {
     299            1 :         GkdSecretCreate *self = GKD_SECRET_CREATE (base);
     300              :         const gchar *path;
     301              : 
     302            1 :         path = self->result_path ? self->result_path : "/";
     303            1 :         return g_variant_new_variant (g_variant_new_object_path (path));
     304              : }
     305              : 
     306              : static void
     307            1 : gkd_secret_create_init (GkdSecretCreate *self)
     308              : {
     309            1 :         gcr_prompt_set_title (GCR_PROMPT (self), _("New Keyring Password"));
     310            1 : }
     311              : 
     312              : static void
     313            0 : gkd_secret_create_finalize (GObject *obj)
     314              : {
     315            0 :         GkdSecretCreate *self = GKD_SECRET_CREATE (obj);
     316              : 
     317            0 :         gkd_secret_secret_free (self->master);
     318            0 :         gck_attributes_unref (self->attributes);
     319            0 :         g_free (self->result_path);
     320            0 :         g_free (self->alias);
     321              : 
     322            0 :         G_OBJECT_CLASS (gkd_secret_create_parent_class)->finalize (obj);
     323            0 : }
     324              : 
     325              : static void
     326            2 : gkd_secret_create_set_property (GObject *obj, guint prop_id, const GValue *value,
     327              :                                 GParamSpec *pspec)
     328              : {
     329            2 :         GkdSecretCreate *self = GKD_SECRET_CREATE (obj);
     330              : 
     331            2 :         switch (prop_id) {
     332            1 :         case PROP_PKCS11_ATTRIBUTES:
     333            1 :                 g_return_if_fail (!self->attributes);
     334            1 :                 self->attributes = g_value_dup_boxed (value);
     335            1 :                 g_return_if_fail (self->attributes);
     336            1 :                 break;
     337            1 :         case PROP_ALIAS:
     338            1 :                 g_return_if_fail (!self->alias);
     339            1 :                 self->alias = g_value_dup_string (value);
     340            1 :                 break;
     341            0 :         default:
     342            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     343            0 :                 break;
     344              :         }
     345              : }
     346              : 
     347              : static void
     348            0 : gkd_secret_create_get_property (GObject *obj, guint prop_id, GValue *value,
     349              :                                 GParamSpec *pspec)
     350              : {
     351            0 :         GkdSecretCreate *self = GKD_SECRET_CREATE (obj);
     352              : 
     353            0 :         switch (prop_id) {
     354            0 :         case PROP_PKCS11_ATTRIBUTES:
     355            0 :                 g_value_set_boxed (value, self->attributes);
     356            0 :                 break;
     357            0 :         case PROP_ALIAS:
     358            0 :                 g_value_set_string (value, self->alias);
     359            0 :                 break;
     360            0 :         default:
     361            0 :                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
     362            0 :                 break;
     363              :         }
     364            0 : }
     365              : 
     366              : static void
     367            1 : gkd_secret_create_class_init (GkdSecretCreateClass *klass)
     368              : {
     369            1 :         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     370            1 :         GkdSecretPromptClass *prompt_class = GKD_SECRET_PROMPT_CLASS (klass);
     371              : 
     372            1 :         gobject_class->finalize = gkd_secret_create_finalize;
     373            1 :         gobject_class->get_property = gkd_secret_create_get_property;
     374            1 :         gobject_class->set_property = gkd_secret_create_set_property;
     375              : 
     376            1 :         prompt_class->prompt_ready = gkd_secret_create_prompt_ready;
     377            1 :         prompt_class->encode_result = gkd_secret_create_encode_result;
     378              : 
     379            1 :         g_object_class_install_property (gobject_class, PROP_PKCS11_ATTRIBUTES,
     380              :                 g_param_spec_boxed ("pkcs11-attributes", "PKCS11 Attributes", "PKCS11 Attributes",
     381              :                                      GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
     382              : 
     383            1 :         g_object_class_install_property (gobject_class, PROP_ALIAS,
     384              :                 g_param_spec_string ("alias", "Alias", "Collection Alias",
     385              :                                      NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
     386            1 : }
     387              : 
     388              : /* -----------------------------------------------------------------------------
     389              :  * PUBLIC
     390              :  */
     391              : 
     392              : GkdSecretCreate*
     393            1 : gkd_secret_create_new (GkdSecretService *service, const gchar *caller,
     394              :                        GckAttributes *attrs, const gchar *alias)
     395              : {
     396              :         const gchar *prompter_name;
     397              : 
     398            1 :         prompter_name = g_getenv ("GNOME_KEYRING_TEST_PROMPTER");
     399            1 :         return g_object_new (GKD_SECRET_TYPE_CREATE,
     400              :                              "service", service,
     401              :                              "caller", caller,
     402              :                              "pkcs11-attributes", attrs,
     403              :                              "alias", alias,
     404              :                              "bus-name", prompter_name,
     405              :                              NULL);
     406              : }
     407              : 
     408              : GckObject*
     409            2 : gkd_secret_create_with_credential (GckSession *session, GckAttributes *attrs,
     410              :                                    GckObject *cred, GError **error)
     411              : {
     412            2 :         GckBuilder builder = GCK_BUILDER_INIT;
     413              :         const GckAttribute *attr;
     414              :         gboolean token;
     415              : 
     416            2 :         gck_builder_add_ulong (&builder, CKA_G_CREDENTIAL, gck_object_get_handle (cred));
     417            2 :         gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_COLLECTION);
     418              : 
     419            2 :         attr = gck_attributes_find (attrs, CKA_LABEL);
     420            2 :         if (attr != NULL)
     421            2 :                 gck_builder_add_attribute (&builder, attr);
     422            2 :         if (!gck_attributes_find_boolean (attrs, CKA_TOKEN, &token))
     423            0 :                 token = FALSE;
     424            2 :         gck_builder_add_boolean (&builder, CKA_TOKEN, token);
     425              : 
     426            2 :         return gck_session_create_object (session, gck_builder_end (&builder), NULL, error);
     427              : }
     428              : 
     429              : gchar*
     430            2 : gkd_secret_create_with_secret (GckAttributes *attrs,
     431              :                                GkdSecretSecret *master,
     432              :                                GError **error)
     433              : {
     434            2 :         GckBuilder builder = GCK_BUILDER_INIT;
     435              :         GckAttributes *atts;
     436              :         GckObject *cred;
     437              :         GckObject *collection;
     438              :         GckSession *session;
     439              :         gpointer identifier;
     440              :         gsize n_identifier;
     441              :         gboolean token;
     442              :         gchar *path;
     443              : 
     444            2 :         if (!gck_attributes_find_boolean (attrs, CKA_TOKEN, &token))
     445            0 :                 token = FALSE;
     446              : 
     447            2 :         gck_builder_add_ulong (&builder, CKA_CLASS, CKO_G_CREDENTIAL);
     448            2 :         gck_builder_add_boolean (&builder, CKA_GNOME_TRANSIENT, TRUE);
     449            2 :         gck_builder_add_boolean (&builder, CKA_TOKEN, token);
     450              : 
     451            2 :         session = gkd_secret_session_get_pkcs11_session (master->session);
     452            2 :         g_return_val_if_fail (session, NULL);
     453              : 
     454              :         /* Create ourselves some credentials */
     455            2 :         atts = gck_attributes_ref_sink (gck_builder_end (&builder));
     456            2 :         cred = gkd_secret_session_create_credential (master->session, session,
     457              :                                                      atts, master, error);
     458            2 :         gck_attributes_unref (atts);
     459              : 
     460            2 :         if (cred == NULL)
     461            0 :                 return FALSE;
     462              : 
     463            2 :         collection = gkd_secret_create_with_credential (session, attrs, cred, error);
     464              : 
     465            2 :         g_object_unref (cred);
     466              : 
     467            2 :         if (collection == NULL)
     468            0 :                 return FALSE;
     469              : 
     470            2 :         identifier = gck_object_get_data (collection, CKA_ID, NULL, &n_identifier, error);
     471            2 :         g_object_unref (collection);
     472              : 
     473            2 :         if (!identifier)
     474            0 :                 return FALSE;
     475              : 
     476            2 :         path = gkd_secret_util_build_path (SECRET_COLLECTION_PREFIX, identifier, n_identifier);
     477            2 :         g_free (identifier);
     478            2 :         return path;
     479              : }
        

Generated by: LCOV version 2.0-1