LCOV - code coverage report
Current view: top level - pkcs11/wrap-layer - gkm-wrap-prompt.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 83.2 % 743 618
Test Date: 2024-04-08 13:24:42 Functions: 95.5 % 67 64

            Line data    Source code
       1              : /*
       2              :  * gnome-keyring
       3              :  *
       4              :  * Copyright (C) 2010 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 "gkm-wrap-login.h"
      24              : #include "gkm-wrap-prompt.h"
      25              : 
      26              : #include "egg/egg-error.h"
      27              : #include "egg/egg-secure-memory.h"
      28              : 
      29              : #include "gkm/gkm-attributes.h"
      30              : #include "gkm/gkm-log.h"
      31              : #include "gkm/gkm-util.h"
      32              : 
      33              : #include "pkcs11/pkcs11.h"
      34              : #include "pkcs11/pkcs11i.h"
      35              : 
      36              : #include <gcr/gcr-base.h>
      37              : 
      38              : #include <glib/gi18n.h>
      39              : 
      40              : #include <string.h>
      41              : 
      42            8 : EGG_SECURE_DECLARE (wrap_prompt);
      43              : 
      44              : #define GKM_TYPE_WRAP_PROMPT               (gkm_wrap_prompt_get_type ())
      45              : #define GKM_WRAP_PROMPT(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKM_TYPE_WRAP_PROMPT, GkmWrapPrompt))
      46              : #define GKM_WRAP_PROMPT_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GKM_TYPE_WRAP_PROMPT, GkmWrapPromptClass))
      47              : #define GKM_IS_WRAP_PROMPT(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKM_TYPE_WRAP_PROMPT))
      48              : #define GKM_IS_WRAP_PROMPT_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GKM_TYPE_WRAP_PROMPT))
      49              : #define GKM_WRAP_PROMPT_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GKM_TYPE_WRAP_PROMPT, GkmWrapPromptClass))
      50              : 
      51              : GType   gkm_wrap_prompt_get_type           (void);
      52              : 
      53              : typedef struct _GkmWrapPromptClass GkmWrapPromptClass;
      54              : 
      55              : struct _GkmWrapPromptClass {
      56              :         GcrSystemPromptClass parent_class;
      57              : };
      58              : 
      59              : struct _GkmWrapPrompt {
      60              :         GcrSystemPrompt parent;
      61              :         gboolean initialized;
      62              : 
      63              :         CK_FUNCTION_LIST_PTR module;
      64              :         CK_SESSION_HANDLE session;
      65              :         CK_OBJECT_HANDLE object;
      66              : 
      67              :         gpointer prompt_data;
      68              :         GDestroyNotify destroy_data;
      69              : 
      70              :         guint iteration;
      71              :         GQueue pool;
      72              : };
      73              : 
      74          625 : G_DEFINE_TYPE (GkmWrapPrompt, gkm_wrap_prompt, GCR_TYPE_SYSTEM_PROMPT);
      75              : 
      76              : static const gchar *the_prompter_name = NULL;
      77              : 
      78              : /* -----------------------------------------------------------------------------
      79              :  * UTILITIES
      80              :  */
      81              : 
      82              : static gpointer
      83          153 : pool_alloc (GkmWrapPrompt *self, gsize length)
      84              : {
      85          153 :         gpointer memory = g_malloc0 (length);
      86              : 
      87          153 :         g_assert (GKM_IS_WRAP_PROMPT (self));
      88          153 :         g_queue_push_tail (&self->pool, memory);
      89          153 :         return memory;
      90              : }
      91              : 
      92              : static gpointer
      93           53 : pool_dup (GkmWrapPrompt *self, gconstpointer original, gsize length)
      94              : {
      95           53 :         gpointer memory = pool_alloc (self, length);
      96           53 :         memcpy (memory, original, length);
      97           53 :         return memory;
      98              : }
      99              : 
     100              : /* -----------------------------------------------------------------------------
     101              :  * AUTO UNLOCK
     102              :  */
     103              : 
     104              : static gboolean
     105           17 : is_login_keyring (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
     106              : {
     107           17 :         gboolean is_login = FALSE;
     108           17 :         if (!gkm_attributes_find_boolean (attrs, n_attrs, CKA_G_LOGIN_COLLECTION, &is_login))
     109            1 :                 return FALSE;
     110           16 :         return is_login;
     111              : }
     112              : 
     113              : static gchar*
     114            7 : auto_unlock_keyring_location (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
     115              : {
     116              :         CK_ATTRIBUTE_PTR attr;
     117              : 
     118            7 :         if (is_login_keyring (attrs, n_attrs))
     119            0 :                 return NULL;
     120              : 
     121            7 :         attr = gkm_attributes_find (attrs, n_attrs, CKA_ID);
     122            7 :         if (attr == NULL)
     123            0 :                 return NULL;
     124              : 
     125              :         /*
     126              :          * COMPAT: Format it into a string. This is done this way for compatibility
     127              :          * with old gnome-keyring releases. In the future this may change.
     128              :          */
     129              : 
     130            7 :         return g_strdup_printf ("LOCAL:/keyrings/%s.keyring", (gchar*)attr->pValue);
     131              : }
     132              : 
     133              : static gchar*
     134           12 : auto_unlock_object_unique (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
     135              : {
     136              :         CK_ATTRIBUTE_PTR attr;
     137              : 
     138           12 :         attr = gkm_attributes_find (attrs, n_attrs, CKA_GNOME_UNIQUE);
     139           12 :         if (attr == NULL)
     140            0 :                 return NULL;
     141              : 
     142           12 :         return g_strndup (attr->pValue, attr->ulValueLen);
     143              : }
     144              : 
     145              : static void
     146            0 : convert_upper_case (gchar *str)
     147              : {
     148            0 :         for (; *str; ++str)
     149            0 :                 *str = g_ascii_toupper (*str);
     150            0 : }
     151              : 
     152              : static gchar*
     153            9 : auto_unlock_object_digest (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
     154              : {
     155              :         CK_ATTRIBUTE_PTR attr;
     156              :         gchar *result;
     157              : 
     158            9 :         attr = gkm_attributes_find (attrs, n_attrs, CKA_GNOME_INTERNAL_SHA1);
     159            9 :         if (attr == NULL)
     160            9 :                 return NULL;
     161              : 
     162            0 :         result = g_strndup (attr->pValue, attr->ulValueLen);
     163            0 :         convert_upper_case (result);
     164            0 :         return result;
     165              : }
     166              : 
     167              : static gchar*
     168            5 : auto_unlock_lookup_keyring (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
     169              : {
     170              :         gchar *location;
     171              :         gchar *password;
     172              : 
     173            5 :         location = auto_unlock_keyring_location (attrs, n_attrs);
     174            5 :         if (location == NULL)
     175            0 :                 return NULL;
     176              : 
     177            5 :         password = gkm_wrap_login_lookup_secret ("keyring", location, NULL);
     178            5 :         g_free (location);
     179            5 :         return password;
     180              : }
     181              : 
     182              : 
     183              : static gchar*
     184           14 : auto_unlock_lookup_object (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
     185              : {
     186              :         CK_OBJECT_CLASS klass;
     187              :         gchar *value;
     188              :         gchar *password;
     189              : 
     190           14 :         if (!gkm_attributes_find_ulong (attrs, n_attrs, CKA_CLASS, &klass))
     191            0 :                 return NULL;
     192              : 
     193           14 :         if (klass == CKO_G_COLLECTION)
     194            5 :                 return auto_unlock_lookup_keyring (attrs, n_attrs);
     195              : 
     196            9 :         value = auto_unlock_object_unique (attrs, n_attrs);
     197            9 :         if (value != NULL) {
     198            9 :                 password = gkm_wrap_login_lookup_secret ("unique", value, NULL);
     199            9 :                 g_free (value);
     200            9 :                 if (password)
     201            2 :                         return password;
     202              :         }
     203              : 
     204              :         /* COMPAT: Check old method of storing secrets for objects in login keyring */
     205            7 :         value = auto_unlock_object_digest (attrs, n_attrs);
     206            7 :         if (value != NULL) {
     207            0 :                 password = gkm_wrap_login_lookup_secret ("object-digest", value, NULL);
     208            0 :                 g_free (value);
     209            0 :                 if (password)
     210            0 :                         return password;
     211              :         }
     212              : 
     213            7 :         return NULL;
     214              : }
     215              : 
     216              : static gchar*
     217            6 : auto_unlock_lookup_token (CK_TOKEN_INFO_PTR info)
     218              : {
     219            6 :         gchar *password = NULL;
     220              :         gchar *manufacturer;
     221              :         gchar *serial;
     222              : 
     223            6 :         g_assert (info);
     224              : 
     225            6 :         manufacturer = g_strndup ((gchar*)info->manufacturerID, sizeof (info->manufacturerID));
     226            6 :         g_strchomp (manufacturer);
     227              : 
     228            6 :         serial = g_strndup ((gchar*)info->serialNumber, sizeof (info->serialNumber));
     229            6 :         g_strchomp (serial);
     230              : 
     231            6 :         if (!g_str_equal (manufacturer, "") && !g_str_equal (serial, ""))
     232            6 :                 password = gkm_wrap_login_lookup_secret ("manufacturer", manufacturer,
     233              :                                                          "serial-number", serial,
     234              :                                                          NULL);
     235              : 
     236            6 :         g_free (manufacturer);
     237            6 :         g_free (serial);
     238              : 
     239            6 :         return password;
     240              : }
     241              : 
     242              : static gboolean
     243           57 : auto_unlock_should_attach (GkmWrapPrompt *self)
     244              : {
     245           57 :         return gcr_prompt_get_choice_chosen (GCR_PROMPT (self));
     246              : }
     247              : 
     248              : static void
     249            1 : auto_unlock_attach_keyring (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, const gchar *password)
     250              : {
     251              :         gchar *location;
     252              :         gchar *label;
     253              : 
     254            1 :         if (!password)
     255            0 :                 return;
     256              : 
     257            1 :         location = auto_unlock_keyring_location (attrs, n_attrs);
     258            1 :         if (location == NULL)
     259            0 :                 return;
     260              : 
     261            1 :         if (!gkm_attributes_find_string (attrs, n_attrs, CKA_LABEL, &label))
     262            0 :                 if (!gkm_attributes_find_string (attrs, n_attrs, CKA_ID, &label))
     263            0 :                         label = g_strdup (location);
     264              : 
     265            1 :         gkm_wrap_login_attach_secret (label, password, "keyring", location, NULL);
     266            1 :         g_free (location);
     267            1 :         g_free (label);
     268              : }
     269              : 
     270              : static void
     271            2 : auto_unlock_attach_object (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, const gchar *password)
     272              : {
     273              :         CK_OBJECT_CLASS klass;
     274              :         gchar *label;
     275              :         gchar *unique;
     276              : 
     277            2 :         if (!password)
     278            1 :                 return;
     279              : 
     280            2 :         if (!gkm_attributes_find_ulong (attrs, n_attrs, CKA_CLASS, &klass))
     281            0 :                 return;
     282              : 
     283            2 :         if (klass == CKO_G_COLLECTION) {
     284            1 :                 auto_unlock_attach_keyring (attrs, n_attrs, password);
     285            1 :                 return;
     286              :         }
     287              : 
     288            1 :         unique = auto_unlock_object_unique (attrs, n_attrs);
     289            1 :         if (unique == NULL)
     290            0 :                 return;
     291              : 
     292            1 :         if (!gkm_attributes_find_string (attrs, n_attrs, CKA_LABEL, &label))
     293            0 :                 label = g_strdup (unique);
     294              : 
     295            1 :         gkm_wrap_login_attach_secret (label, password, "unique", unique, NULL);
     296            1 :         g_free (unique);
     297            1 :         g_free (label);
     298              : }
     299              : 
     300              : static void
     301            1 : auto_unlock_attach_token (CK_TOKEN_INFO_PTR info, const gchar *password)
     302              : {
     303              :         gchar *manufacturer;
     304              :         gchar *serial;
     305              :         gchar *label;
     306              : 
     307            1 :         g_assert (info);
     308              : 
     309            1 :         if (!password)
     310            0 :                 return;
     311              : 
     312            1 :         manufacturer = g_strndup ((gchar*)info->manufacturerID, sizeof (info->manufacturerID));
     313            1 :         g_strchomp (manufacturer);
     314              : 
     315            1 :         serial = g_strndup ((gchar*)info->serialNumber, sizeof (info->serialNumber));
     316            1 :         g_strchomp (serial);
     317              : 
     318            1 :         label = g_strndup ((gchar*)info->label, sizeof (info->label));
     319            1 :         g_strchomp (label);
     320              : 
     321            1 :         if (g_str_equal (label, "")) {
     322            0 :                 g_free (label);
     323            0 :                 label = g_strdup (manufacturer);
     324              :         }
     325              : 
     326            1 :         if (!g_str_equal (manufacturer, "") && !g_str_equal (serial, ""))
     327            1 :                 gkm_wrap_login_attach_secret (label, password,
     328              :                                               "manufacturer", manufacturer,
     329              :                                               "serial-number", serial,
     330              :                                               NULL);
     331              : 
     332            1 :         g_free (manufacturer);
     333            1 :         g_free (serial);
     334            1 :         g_free (label);
     335              : }
     336              : 
     337              : static void
     338            1 : auto_unlock_remove_keyring (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
     339              : {
     340              :         gchar *location;
     341              : 
     342            1 :         location = auto_unlock_keyring_location (attrs, n_attrs);
     343            1 :         if (location == NULL)
     344            0 :                 return;
     345              : 
     346            1 :         gkm_wrap_login_remove_secret ("keyring", location, NULL);
     347            1 :         g_free (location);
     348              : }
     349              : 
     350              : static void
     351            3 : auto_unlock_remove_object (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
     352              : {
     353              :         CK_OBJECT_CLASS klass;
     354              :         gchar *value;
     355              : 
     356            3 :         if (!gkm_attributes_find_ulong (attrs, n_attrs, CKA_CLASS, &klass))
     357            1 :                 return;
     358              : 
     359            3 :         if (klass == CKO_G_COLLECTION) {
     360            1 :                 auto_unlock_remove_keyring (attrs, n_attrs);
     361            1 :                 return;
     362              :         }
     363              : 
     364            2 :         value = auto_unlock_object_unique (attrs, n_attrs);
     365            2 :         if (value != NULL) {
     366            2 :                 gkm_wrap_login_remove_secret ("unique", value, NULL);
     367            2 :                 g_free (value);
     368              :         }
     369              : 
     370              :         /* COMPAT: Clear old method of storing secrets for objects in login keyring */
     371            2 :         value = auto_unlock_object_digest (attrs, n_attrs);
     372            2 :         if (value != NULL) {
     373            0 :                 gkm_wrap_login_remove_secret ("object-digest", value, NULL);
     374            0 :                 g_free (value);
     375              :         }
     376              : 
     377              : }
     378              : 
     379              : static void
     380            2 : auto_unlock_remove_token (CK_TOKEN_INFO_PTR info)
     381              : {
     382              :         gchar *manufacturer;
     383              :         gchar *serial;
     384              : 
     385            2 :         g_assert (info);
     386              : 
     387            2 :         manufacturer = g_strndup ((gchar*)info->manufacturerID, sizeof (info->manufacturerID));
     388            2 :         g_strchomp (manufacturer);
     389              : 
     390            2 :         serial = g_strndup ((gchar*)info->serialNumber, sizeof (info->serialNumber));
     391            2 :         g_strchomp (serial);
     392              : 
     393            2 :         if (!g_str_equal (manufacturer, "") && !g_str_equal (serial, ""))
     394            2 :                 gkm_wrap_login_remove_secret ("manufacturer", manufacturer,
     395              :                                               "serial-number", serial,
     396              :                                               NULL);
     397              : 
     398            2 :         g_free (manufacturer);
     399            2 :         g_free (serial);
     400            2 : }
     401              : 
     402              : /* -----------------------------------------------------------------------------------------
     403              :  * PROMPTING
     404              :  */
     405              : 
     406              : static void
     407            6 : set_unlock_options_on_object (GkmWrapPrompt *self, CK_ATTRIBUTE_PTR options, CK_ULONG n_options)
     408              : {
     409              :         CK_ATTRIBUTE attr;
     410              :         CK_RV rv;
     411              : 
     412            6 :         g_assert (GKM_IS_WRAP_PROMPT (self));
     413            6 :         g_assert (self->module);
     414            6 :         g_assert (options);
     415              : 
     416            6 :         attr.type = CKA_G_CREDENTIAL_TEMPLATE;
     417            6 :         attr.pValue = options;
     418            6 :         attr.ulValueLen = sizeof (CK_ATTRIBUTE) * n_options;
     419              : 
     420            6 :         rv = (self->module->C_SetAttributeValue) (self->session, self->object, &attr, 1);
     421            6 :         if (rv != CKR_OK && rv != CKR_ATTRIBUTE_TYPE_INVALID) {
     422            0 :                 if (rv != CKR_TOKEN_WRITE_PROTECTED)
     423            0 :                         g_warning ("Couldn't set credential template for prompt: %s",
     424              :                                    gkm_log_rv (rv));
     425              :         }
     426            6 : }
     427              : 
     428              : static CK_ATTRIBUTE_PTR
     429           14 : get_unlock_options_from_prompt (GkmWrapPrompt *self, CK_ULONG_PTR n_options)
     430              : {
     431              :         CK_ATTRIBUTE_PTR options;
     432              :         CK_BBOOL bval;
     433              : 
     434           14 :         g_assert (GKM_IS_WRAP_PROMPT (self));
     435           14 :         g_assert (n_options);
     436              : 
     437           14 :         *n_options = 2;
     438           14 :         options = pool_alloc (self, sizeof (CK_ATTRIBUTE) * (*n_options));
     439              : 
     440              :         /* CKA_TOKEN */
     441           14 :         bval = TRUE;
     442           14 :         options[0].type = CKA_TOKEN;
     443           14 :         options[0].pValue = pool_dup (self, &bval, sizeof (bval));
     444           14 :         options[0].ulValueLen = sizeof (bval);
     445              : 
     446              :         /* CKA_GNOME_TRANSIENT */
     447           14 :         bval = TRUE;
     448           14 :         options[1].type = CKA_GNOME_TRANSIENT;
     449           14 :         options[1].pValue = pool_dup (self, &bval, sizeof (bval));
     450           14 :         options[1].ulValueLen = sizeof (bval);
     451              : 
     452           14 :         return options;
     453              : }
     454              : 
     455              : static void
     456            7 : set_unlock_options_on_prompt (GkmWrapPrompt *self)
     457              : {
     458            7 :         gboolean chosen = FALSE;
     459              : 
     460            7 :         g_assert (GKM_IS_WRAP_PROMPT (self));
     461              : 
     462            7 :         gcr_prompt_set_choice_chosen (GCR_PROMPT (self), chosen);
     463            7 : }
     464              : 
     465              : static CK_ATTRIBUTE_PTR
     466           25 : get_attributes_from_object (GkmWrapPrompt *self, CK_ULONG *n_attrs)
     467              : {
     468              :         CK_ATTRIBUTE attrs[6];
     469              :         CK_ULONG i;
     470              :         CK_RV rv;
     471              : 
     472           25 :         g_assert (GKM_IS_WRAP_PROMPT (self));
     473           25 :         g_assert (n_attrs);
     474           25 :         g_assert (self->module);
     475              : 
     476           25 :         memset (attrs, 0, sizeof (attrs));
     477           25 :         attrs[0].type = CKA_LABEL;
     478           25 :         attrs[1].type = CKA_ID;
     479           25 :         attrs[2].type = CKA_CLASS;
     480           25 :         attrs[3].type = CKA_G_LOGIN_COLLECTION;
     481           25 :         attrs[4].type = CKA_GNOME_UNIQUE;
     482           25 :         attrs[5].type = CKA_GNOME_INTERNAL_SHA1;
     483              : 
     484           25 :         rv = (self->module->C_GetAttributeValue) (self->session, self->object, attrs, G_N_ELEMENTS (attrs));
     485           25 :         if (rv != CKR_OK && rv != CKR_ATTRIBUTE_TYPE_INVALID) {
     486            0 :                 g_warning ("Couldn't retrieve information about object to unlock: %s",
     487              :                            gkm_log_rv (rv));
     488            0 :                 return NULL;
     489              :         }
     490              : 
     491              :         /* Allocate for each value, note we're null terminating values */
     492          175 :         for (i = 0; i < G_N_ELEMENTS (attrs); ++i) {
     493          150 :                 if (attrs[i].ulValueLen != (CK_ULONG)-1)
     494           86 :                         attrs[i].pValue = pool_alloc (self, attrs[i].ulValueLen + 1);
     495              :         }
     496              : 
     497              :         /* Now get the actual values */
     498           25 :         rv = (self->module->C_GetAttributeValue) (self->session, self->object, attrs, G_N_ELEMENTS (attrs));
     499           25 :         if (rv != CKR_OK && rv != CKR_ATTRIBUTE_TYPE_INVALID) {
     500            0 :                 g_warning ("couldn't retrieve credential template for prompt: %s",
     501              :                            gkm_log_rv (rv));
     502            0 :                 return NULL;
     503              :         }
     504              : 
     505           25 :         *n_attrs = G_N_ELEMENTS (attrs);
     506           25 :         return pool_dup (self, attrs, sizeof (attrs));
     507              : 
     508              : }
     509              : 
     510              : static gboolean
     511           13 : get_info_for_token (GkmWrapPrompt *self, CK_TOKEN_INFO_PTR tinfo)
     512              : {
     513              :         CK_SESSION_INFO sinfo;
     514              : 
     515           25 :         return (self->module->C_GetSessionInfo) (self->session, &sinfo) == CKR_OK &&
     516           12 :                (self->module->C_GetTokenInfo) (sinfo.slotID, tinfo) == CKR_OK;
     517              : }
     518              : 
     519              : static void
     520            0 : setup_unlock_keyring_login (GkmWrapPrompt *self)
     521              : {
     522              :         GcrPrompt *prompt;
     523              :         const gchar *text;
     524              : 
     525            0 :         g_assert (GKM_IS_WRAP_PROMPT (self));
     526              : 
     527            0 :         prompt = GCR_PROMPT (self);
     528              : 
     529            0 :         gcr_prompt_set_title (prompt, _("Unlock Login Keyring"));
     530            0 :         gcr_prompt_set_message (prompt, _("Authentication required"));
     531              : 
     532            0 :         if (gkm_wrap_login_did_unlock_fail ())
     533            0 :                 text = _("The password you use to log in to your computer no longer matches that of your login keyring.");
     534              :         else
     535            0 :                 text = _("The login keyring did not get unlocked when you logged into your computer.");
     536            0 :         gcr_prompt_set_description (prompt, text);
     537              : 
     538            0 :         gcr_prompt_set_choice_label (prompt, NULL);
     539            0 :         gcr_prompt_set_continue_label (prompt, _("Unlock"));
     540            0 : }
     541              : 
     542              : static void
     543            4 : setup_unlock_keyring_other (GkmWrapPrompt *self,
     544              :                             const gchar *label)
     545              : {
     546              :         GcrPrompt *prompt;
     547              :         const gchar *choice;
     548              :         gchar *text;
     549              : 
     550            4 :         g_assert (GKM_IS_WRAP_PROMPT (self));
     551            4 :         prompt = GCR_PROMPT (self);
     552              : 
     553            4 :         gcr_prompt_set_title (prompt, _("Unlock Keyring"));
     554            4 :         gcr_prompt_set_message (prompt, _("Authentication required"));
     555              : 
     556            4 :         text = g_markup_printf_escaped (_("An application wants access to the keyring “%s”, but it is locked"), label);
     557            4 :         gcr_prompt_set_description (prompt, text);
     558            4 :         g_free (text);
     559              : 
     560            4 :         choice = NULL;
     561            4 :         if (gkm_wrap_login_is_usable ())
     562            2 :                 choice = _("Automatically unlock this keyring whenever I’m logged in");
     563            4 :         gcr_prompt_set_choice_label (prompt, choice);
     564            4 :         gcr_prompt_set_continue_label (prompt, _("Unlock"));
     565            4 : }
     566              : 
     567              : 
     568              : static const gchar*
     569           10 : calc_unlock_object_title (CK_OBJECT_CLASS klass)
     570              : {
     571           10 :         switch (klass) {
     572           10 :         case CKO_PRIVATE_KEY:
     573           10 :                 return _("Unlock private key");
     574            0 :         case CKO_CERTIFICATE:
     575            0 :                 return _("Unlock certificate");
     576            0 :         case CKO_PUBLIC_KEY:
     577            0 :                 return _("Unlock public key");
     578            0 :         default:
     579            0 :                 return _("Unlock");
     580              :         }
     581              : }
     582              : 
     583              : static const gchar *
     584            2 : calc_unlock_object_choice (CK_OBJECT_CLASS klass)
     585              : {
     586            2 :         switch (klass) {
     587            2 :         case CKO_PRIVATE_KEY:
     588              :         case CKO_PUBLIC_KEY:
     589            2 :                 return _("Automatically unlock this key whenever I’m logged in");
     590            0 :         case CKO_CERTIFICATE:
     591            0 :                 return _("Automatically unlock this certificate whenever I’m logged in");
     592            0 :         default:
     593            0 :                 return _("Automatically unlock whenever I’m logged in");
     594              :         }
     595              : }
     596              : 
     597              : static gchar*
     598           10 : calc_unlock_object_secondary (CK_OBJECT_CLASS klass,
     599              :                               const gchar *label)
     600              : {
     601           10 :         switch (klass) {
     602           10 :         case CKO_PRIVATE_KEY:
     603              :                 /* TRANSLATORS: The private key is locked */
     604           10 :                 return g_strdup_printf (_("An application wants access to the private key “%s”, but it is locked"), label);
     605            0 :         case CKO_CERTIFICATE:
     606              :                 /* TRANSLATORS: The certificate is locked */
     607            0 :                 return g_strdup_printf (_("An application wants access to the certificate “%s”, but it is locked"), label);
     608            0 :         case CKO_PUBLIC_KEY:
     609              :                 /* TRANSLATORS: The public key is locked */
     610            0 :                 return g_strdup_printf (_("An application wants access to the public key “%s”, but it is locked"), label);
     611            0 :         default:
     612              :                 /* TRANSLATORS: The object '%s' is locked */
     613            0 :                 return g_strdup_printf (_("An application wants access to “%s”, but it is locked"), label);
     614              :         }
     615              : }
     616              : 
     617              : static void
     618           10 : setup_unlock_object (GkmWrapPrompt *self,
     619              :                      const gchar *label,
     620              :                      CK_OBJECT_CLASS klass)
     621              : {
     622              :         GcrPrompt *prompt;
     623              :         const gchar *choice;
     624              :         gchar *text;
     625              : 
     626           10 :         g_assert (GKM_IS_WRAP_PROMPT (self));
     627           10 :         prompt = GCR_PROMPT (self);
     628              : 
     629           10 :         gcr_prompt_set_title (prompt, calc_unlock_object_title (klass));
     630           10 :         gcr_prompt_set_message (prompt, _("Authentication required"));
     631              : 
     632           10 :         text = calc_unlock_object_secondary (klass, label);
     633           10 :         gcr_prompt_set_description (prompt, text);
     634           10 :         g_free (text);
     635              : 
     636           10 :         choice = NULL;
     637           10 :         if (gkm_wrap_login_is_usable ())
     638            2 :                 choice = calc_unlock_object_choice (klass);
     639           10 :         gcr_prompt_set_choice_label (prompt, choice);
     640           10 :         gcr_prompt_set_continue_label (prompt, _("Unlock"));
     641           10 : }
     642              : 
     643              : static void
     644           14 : setup_unlock_prompt (GkmWrapPrompt *self,
     645              :                      CK_ATTRIBUTE_PTR attrs,
     646              :                      CK_ULONG n_attrs,
     647              :                      gboolean first)
     648              : {
     649              :         CK_ATTRIBUTE_PTR attr;
     650              :         GcrPrompt *prompt;
     651           14 :         const gchar *label = NULL;
     652              :         CK_OBJECT_CLASS klass;
     653              : 
     654           14 :         g_assert (GKM_IS_WRAP_PROMPT (self));
     655           14 :         prompt = GCR_PROMPT (self);
     656              : 
     657              :         /* Load up the object class */
     658           14 :         if (!gkm_attributes_find_ulong (attrs, n_attrs, CKA_CLASS, &klass))
     659            0 :                 klass = (CK_ULONG)-1;
     660              : 
     661              :         /* Load up its label */
     662           14 :         attr = gkm_attributes_find (attrs, n_attrs, CKA_LABEL);
     663           14 :         if (attr != NULL)
     664           14 :                 label = attr->pValue;
     665              : 
     666              :         /* Load up the identifier */
     667           14 :         attr = gkm_attributes_find (attrs, n_attrs, CKA_ID);
     668           14 :         if (attr != NULL && !label)
     669            0 :                 label = attr->pValue;
     670              : 
     671           14 :         if (!label)
     672            0 :                 label = _("Unnamed");
     673              : 
     674           14 :         if (klass == CKO_G_COLLECTION) {
     675            4 :                 if (is_login_keyring (attrs, n_attrs))
     676            0 :                         setup_unlock_keyring_login (self);
     677              :                 else
     678            4 :                         setup_unlock_keyring_other (self, label);
     679              :         } else {
     680           10 :                 setup_unlock_object (self, label, klass);
     681              :         }
     682              : 
     683           14 :         if (!first)
     684            1 :                 gcr_prompt_set_warning (prompt, _("The unlock password was incorrect"));
     685              : 
     686           14 :         gcr_prompt_set_continue_label (prompt, _("Unlock"));
     687           14 : }
     688              : 
     689              : static void
     690            6 : setup_unlock_token (GkmWrapPrompt *self,
     691              :                     CK_TOKEN_INFO_PTR tinfo)
     692              : {
     693              :         GcrPrompt *prompt;
     694              :         const gchar *choice;
     695              :         gchar *label;
     696              :         gchar *text;
     697              : 
     698            6 :         g_assert (GKM_IS_WRAP_PROMPT (self));
     699            6 :         prompt = GCR_PROMPT (self);
     700              : 
     701            6 :         label = g_strndup ((gchar*)tinfo->label, sizeof (tinfo->label));
     702            6 :         g_strchomp (label);
     703              : 
     704              :         /* Build up the prompt */
     705            6 :         gcr_prompt_set_title (prompt, _("Unlock certificate/key storage"));
     706            6 :         gcr_prompt_set_message (prompt, _("Authentication required"));
     707              : 
     708              :         /* TRANSLATORS: The storage is locked, and needs unlocking before the application can use it. */
     709            6 :         text = g_strdup_printf (_("An application wants access to the certificate/key storage “%s”, but it is locked"), label);
     710            6 :         gcr_prompt_set_description (prompt, text);
     711            6 :         g_free (text);
     712              : 
     713            6 :         choice = NULL;
     714            6 :         if (gkm_wrap_login_is_usable ())
     715            2 :                 choice = _("Automatically unlock whenever I’m logged in");
     716            6 :         gcr_prompt_set_choice_label (prompt, choice);
     717              : 
     718            6 :         gcr_prompt_set_continue_label (prompt, _("Unlock"));
     719              : 
     720            6 :         g_free (label);
     721            6 : }
     722              : 
     723              : static void
     724            0 : fix_login_keyring_if_unlock_failed (GkmWrapPrompt *self, const gchar *password)
     725              : {
     726            0 :         CK_OBJECT_CLASS klass = CKO_G_CREDENTIAL;
     727              :         CK_OBJECT_HANDLE cred;
     728            0 :         CK_BBOOL tval = CK_TRUE;
     729              :         CK_ATTRIBUTE attrs[4];
     730              :         gchar *failed;
     731              :         CK_RV rv;
     732              : 
     733            0 :         failed = gkm_wrap_login_steal_failed_password ();
     734              : 
     735              :         /* Do we have a failed unlock password? */
     736            0 :         if (!failed || !failed[0]) {
     737            0 :                 egg_secure_strfree (failed);
     738            0 :                 return;
     739              :         }
     740              : 
     741            0 :         attrs[0].type = CKA_CLASS;
     742            0 :         attrs[0].pValue = &klass;
     743            0 :         attrs[0].ulValueLen = sizeof (klass);
     744              : 
     745            0 :         attrs[1].type = CKA_VALUE;
     746            0 :         attrs[1].pValue = failed;
     747            0 :         attrs[1].ulValueLen = strlen (failed);
     748              : 
     749            0 :         attrs[2].type = CKA_GNOME_TRANSIENT;
     750            0 :         attrs[2].pValue = &tval;
     751            0 :         attrs[2].ulValueLen = sizeof (tval);
     752              : 
     753            0 :         attrs[3].type = CKA_TOKEN;
     754            0 :         attrs[3].pValue = &tval;
     755            0 :         attrs[3].ulValueLen = sizeof (tval);
     756              : 
     757              :         /* Create a credential object for the failed password */
     758            0 :         rv = (self->module->C_CreateObject) (self->session, attrs, G_N_ELEMENTS (attrs), &cred);
     759            0 :         egg_secure_strfree (failed);
     760              : 
     761            0 :         if (rv != CKR_OK) {
     762            0 :                 g_warning ("couldn't create credential to fix login password: %s",
     763              :                            gkm_log_rv (rv));
     764            0 :                 return;
     765              :         }
     766              : 
     767            0 :         attrs[0].type = CKA_G_CREDENTIAL;
     768            0 :         attrs[0].pValue = &cred;
     769            0 :         attrs[0].ulValueLen = sizeof (cred);
     770              : 
     771              :         /* Set the credential on the object */
     772            0 :         rv = (self->module->C_SetAttributeValue) (self->session, self->object, attrs, 1);
     773            0 :         if (rv != CKR_OK) {
     774            0 :                 g_warning ("couldn't change credential to fix login keyring password: %s",
     775              :                            gkm_log_rv (rv));
     776            0 :                 return;
     777              :         }
     778              : 
     779            0 :         g_message ("fixed login keyring password to match login password");
     780              : }
     781              : 
     782              : static gboolean
     783           23 : gkm_wrap_prompt_prepare (GkmWrapPrompt *self)
     784              : {
     785           23 :         GError *error = NULL;
     786              : 
     787           23 :         if (!self->initialized) {
     788           19 :                 if (!g_initable_init (G_INITABLE (self), NULL, &error)) {
     789            0 :                         g_warning ("couldn't create system prompt: %s", egg_error_message (error));
     790            0 :                         g_error_free (error);
     791            0 :                         return FALSE;
     792              :                 }
     793           19 :                 self->initialized = TRUE;
     794              :         }
     795              : 
     796           23 :         return TRUE;
     797              : }
     798              : 
     799              : static const gchar *
     800           23 : gkm_wrap_prompt_request_password (GkmWrapPrompt *self)
     801              : {
     802           23 :         GError *error = NULL;
     803              :         const gchar *password;
     804              : 
     805           23 :         g_assert (GKM_IS_WRAP_PROMPT (self));
     806              : 
     807           23 :         if (!gkm_wrap_prompt_prepare (self))
     808            0 :                 return NULL;
     809              : 
     810           23 :         password = gcr_prompt_password (GCR_PROMPT (self), NULL, &error);
     811           23 :         if (error != NULL) {
     812            0 :                 g_warning ("couldn't prompt for password: %s", egg_error_message (error));
     813            0 :                 g_error_free (error);
     814              :         }
     815              : 
     816           23 :         return password;
     817              : }
     818              : 
     819              : static void
     820           65 : gkm_wrap_prompt_init (GkmWrapPrompt *self)
     821              : {
     822           65 :         g_queue_init (&self->pool);
     823           65 : }
     824              : 
     825              : static void
     826           87 : gkm_wrap_prompt_clear_prompt_data (GkmWrapPrompt *self)
     827              : {
     828           87 :         if (self->destroy_data && self->prompt_data)
     829           13 :                 (self->destroy_data) (self->prompt_data);
     830           87 :         self->destroy_data = NULL;
     831           87 :         self->prompt_data = NULL;
     832           87 : }
     833              : 
     834              : static void
     835           22 : gkm_wrap_prompt_set_prompt_data (GkmWrapPrompt *self,
     836              :                                  gpointer prompt_data,
     837              :                                  GDestroyNotify destroy_data)
     838              : {
     839           22 :         gkm_wrap_prompt_clear_prompt_data (self);
     840           22 :         self->destroy_data = destroy_data;
     841           22 :         self->prompt_data = prompt_data;
     842           22 : }
     843              : 
     844              : static void
     845           65 : gkm_wrap_prompt_finalize (GObject *obj)
     846              : {
     847           65 :         GkmWrapPrompt *self = GKM_WRAP_PROMPT (obj);
     848              : 
     849           65 :         gkm_wrap_prompt_clear_prompt_data (self);
     850              : 
     851          218 :         while (!g_queue_is_empty(&self->pool))
     852          153 :                 g_free (g_queue_pop_head (&self->pool));
     853              : 
     854           65 :         G_OBJECT_CLASS (gkm_wrap_prompt_parent_class)->finalize (obj);
     855           65 : }
     856              : 
     857              : 
     858              : static void
     859           31 : gkm_wrap_prompt_class_init (GkmWrapPromptClass *klass)
     860              : {
     861           31 :         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     862           31 :         gobject_class->finalize = gkm_wrap_prompt_finalize;
     863           31 : }
     864              : 
     865              : /* -----------------------------------------------------------------------------
     866              :  * CREDENTIAL
     867              :  */
     868              : 
     869              : typedef struct _CredentialPrompt {
     870              :         GArray *template;
     871              :         CK_ULONG n_template;
     872              :         gchar *password;
     873              : } CredentialPrompt;
     874              : 
     875              : static void
     876            8 : credential_prompt_free (gpointer user_data)
     877              : {
     878            8 :         CredentialPrompt *data = user_data;
     879            8 :         g_array_free (data->template, TRUE);
     880            8 :         egg_secure_strfree (data->password);
     881            8 :         g_slice_free (CredentialPrompt, data);
     882            8 : }
     883              : 
     884              : GkmWrapPrompt*
     885            9 : gkm_wrap_prompt_for_credential (CK_FUNCTION_LIST_PTR module, CK_SESSION_HANDLE session,
     886              :                                 CK_ATTRIBUTE_PTR template, CK_ULONG n_template)
     887              : {
     888              :         CredentialPrompt *data;
     889              :         CK_ATTRIBUTE_PTR attr;
     890              :         CK_OBJECT_CLASS klass;
     891              :         CK_OBJECT_HANDLE object;
     892              :         GkmWrapPrompt *self;
     893              :         CK_ULONG i;
     894              : 
     895            9 :         g_return_val_if_fail (module, NULL);
     896            9 :         g_return_val_if_fail (session, NULL);
     897            9 :         g_return_val_if_fail (n_template || !template, NULL);
     898              : 
     899              :         /* Must be credential and have object for protected outh path */
     900           18 :         if (!gkm_attributes_find_ulong (template, n_template, CKA_CLASS, &klass) ||
     901            9 :             !gkm_attributes_find_ulong (template, n_template, CKA_G_OBJECT, &object) ||
     902            9 :             klass != CKO_G_CREDENTIAL || object == 0)
     903            0 :                 return NULL;
     904              : 
     905              :         /* Must have CKA_VALUE with pValue set to null for protected auth path */
     906            9 :         attr = gkm_attributes_find (template, n_template, CKA_VALUE);
     907            9 :         if (attr == NULL || attr->pValue != NULL)
     908            1 :                 return NULL;
     909              : 
     910            8 :         self = g_object_new (GKM_TYPE_WRAP_PROMPT,
     911              :                              "timeout-seconds", -1,
     912              :                              "bus-name", gkm_wrap_prompt_get_prompter_name (),
     913              :                              NULL);
     914              : 
     915              :         /* Build up the prompt */
     916            8 :         data = g_slice_new0 (CredentialPrompt);
     917            8 :         gkm_wrap_prompt_set_prompt_data (self, data, credential_prompt_free);
     918            8 :         self->module = module;
     919            8 :         self->session = session;
     920            8 :         self->object = object;
     921              : 
     922              :         /* Build up a copy of the template with CKA_VALUE first */
     923            8 :         data->template = g_array_new (FALSE, FALSE, sizeof (CK_ATTRIBUTE));
     924            8 :         g_array_append_val (data->template, *attr);
     925           34 :         for (i = 0; i < n_template; ++i) {
     926           26 :                 if (template[i].type != CKA_VALUE)
     927           18 :                         g_array_append_val (data->template, template[i]);
     928              :         }
     929              : 
     930            8 :         data->n_template = n_template;
     931              : 
     932            8 :         return self;
     933              : }
     934              : 
     935              : gboolean
     936           10 : gkm_wrap_prompt_do_credential (GkmWrapPrompt *self, CK_ATTRIBUTE_PTR *template,
     937              :                                CK_ULONG *n_template)
     938              : {
     939              :         CK_ATTRIBUTE_PTR options;
     940              :         CK_ATTRIBUTE_PTR attrs;
     941              :         CK_ATTRIBUTE_PTR attr;
     942              :         CK_ULONG n_attrs, n_options, i;
     943              :         CredentialPrompt *data;
     944           10 :         GError *error = NULL;
     945              : 
     946           10 :         g_return_val_if_fail (GKM_IS_WRAP_PROMPT (self), FALSE);
     947           10 :         g_return_val_if_fail (template, FALSE);
     948           10 :         g_return_val_if_fail (n_template, FALSE);
     949              : 
     950           10 :         g_assert (self->destroy_data == credential_prompt_free);
     951           10 :         data = self->prompt_data;
     952              : 
     953           10 :         attrs = get_attributes_from_object (self, &n_attrs);
     954           10 :         g_return_val_if_fail (attrs, FALSE);
     955              : 
     956           10 :         egg_secure_strfree (data->password);
     957           10 :         data->password = NULL;
     958              : 
     959           10 :         if (self->iteration == 0) {
     960            8 :                 ++(self->iteration);
     961            8 :                 data->password = auto_unlock_lookup_object (attrs, n_attrs);
     962              : 
     963            2 :         } else if (self->iteration == 1) {
     964            1 :                 auto_unlock_remove_object (attrs, n_attrs);
     965              :         }
     966              : 
     967           10 :         if (!data->password) {
     968              :                 const char *password;
     969            8 :                 setup_unlock_prompt (self, attrs, n_attrs, self->iteration == 1);
     970              : 
     971              :                 /* Now load up the unlock options into the prompt*/
     972            8 :                 if (self->iteration == 1)
     973            7 :                         set_unlock_options_on_prompt (self);
     974              : 
     975            8 :                 ++(self->iteration);
     976              : 
     977            8 :                 password = gkm_wrap_prompt_request_password (self);
     978            8 :                 if (password == NULL) {
     979            2 :                         if (error != NULL) {
     980            0 :                                 g_warning ("couldn't prompt for password: %s", egg_error_message (error));
     981            0 :                                 g_error_free (error);
     982              :                         }
     983            2 :                         return FALSE;
     984              :                 }
     985            6 :                 data->password = egg_secure_strdup (password);
     986              :         }
     987              : 
     988              :         /* Truncate any extra options off the end of template */
     989            8 :         g_assert (data->n_template > 0);
     990            8 :         g_assert (data->template->len >= data->n_template);
     991            8 :         g_array_set_size (data->template, data->n_template);
     992              : 
     993              :         /* Put the password into the template, always first */
     994            8 :         attr = &g_array_index (data->template, CK_ATTRIBUTE, 0);
     995            8 :         g_assert (attr->type == CKA_VALUE);
     996            8 :         attr->pValue = (gpointer)data->password;
     997            8 :         attr->ulValueLen = strlen (data->password);
     998              : 
     999              :         /* Tag any options onto the end of template */
    1000            8 :         options = get_unlock_options_from_prompt (self, &n_options);
    1001           24 :         for (i = 0; options && i < n_options; ++i)
    1002           16 :                 g_array_append_val (data->template, options[i]);
    1003              : 
    1004            8 :         *template = (CK_ATTRIBUTE_PTR)data->template->data;
    1005            8 :         *n_template = data->template->len;
    1006            8 :         return TRUE;
    1007              : }
    1008              : 
    1009              : void
    1010            8 : gkm_wrap_prompt_done_credential (GkmWrapPrompt *self, CK_RV call_result)
    1011              : {
    1012              :         CK_ATTRIBUTE_PTR options;
    1013              :         CK_ATTRIBUTE_PTR attrs;
    1014              :         CK_ULONG n_options, n_attrs;
    1015              :         CredentialPrompt *data;
    1016              : 
    1017            8 :         g_return_if_fail (GKM_IS_WRAP_PROMPT (self));
    1018              : 
    1019            8 :         g_assert (self->destroy_data == credential_prompt_free);
    1020            8 :         data = self->prompt_data;
    1021              : 
    1022              :         /* Save the options, and possibly auto unlock */
    1023            8 :         if (call_result == CKR_OK) {
    1024              : 
    1025            6 :                 attrs = get_attributes_from_object (self, &n_attrs);
    1026              : 
    1027              :                 /*
    1028              :                  * For the login keyring, we check for a previous unlock failure,
    1029              :                  * that would have come from PAM, and try to change the password to
    1030              :                  * the one that failed earlier.
    1031              :                  */
    1032            6 :                 if (is_login_keyring (attrs, n_attrs))
    1033            0 :                         fix_login_keyring_if_unlock_failed (self, data->password);
    1034              : 
    1035            6 :                 options = get_unlock_options_from_prompt (self, &n_options);
    1036            6 :                 if (options != NULL)
    1037            6 :                         set_unlock_options_on_object (self, options, n_options);
    1038              : 
    1039            6 :                 if (auto_unlock_should_attach (self))
    1040            1 :                         auto_unlock_attach_object (attrs, n_attrs, data->password);
    1041              :         }
    1042              : }
    1043              : 
    1044              : /* ------------------------------------------------------------------------------------
    1045              :  * INITPIN
    1046              :  */
    1047              : 
    1048              : static void
    1049            1 : setup_init_token (GkmWrapPrompt *self,
    1050              :                   CK_TOKEN_INFO_PTR tinfo)
    1051              : {
    1052              :         GcrPrompt *prompt;
    1053              :         const gchar *choice;
    1054              :         gchar *label;
    1055              :         gchar *text;
    1056              : 
    1057            1 :         g_assert (GKM_IS_WRAP_PROMPT (self));
    1058            1 :         g_assert (tinfo);
    1059              : 
    1060            1 :         prompt = GCR_PROMPT (self);
    1061              : 
    1062            1 :         label = g_strndup ((gchar*)tinfo->label, sizeof (tinfo->label));
    1063            1 :         g_strchomp (label);
    1064              : 
    1065              :         /* Build up the prompt */
    1066            1 :         gcr_prompt_set_password_new (prompt, TRUE);
    1067            1 :         gcr_prompt_set_title (prompt, _("New Password Required"));
    1068            1 :         gcr_prompt_set_message (prompt, _("New password required"));
    1069              : 
    1070            1 :         text = g_strdup_printf (_("In order to prepare “%s” for storage of certificates or keys, a password is required"), label);
    1071            1 :         gcr_prompt_set_description (prompt, text);
    1072            1 :         g_free (text);
    1073              : 
    1074            1 :         choice = NULL;
    1075            1 :         if (gkm_wrap_login_is_usable ())
    1076            0 :                 choice = _("Automatically unlock whenever I’m logged in");
    1077            1 :         gcr_prompt_set_choice_label (prompt, choice);
    1078              : 
    1079            1 :         gcr_prompt_set_continue_label (prompt, _("Continue"));
    1080              : 
    1081            1 :         g_free (label);
    1082            1 : }
    1083              : 
    1084              : GkmWrapPrompt*
    1085            1 : gkm_wrap_prompt_for_init_pin (CK_FUNCTION_LIST_PTR module, CK_SESSION_HANDLE session,
    1086              :                               CK_UTF8CHAR_PTR pin, CK_ULONG pin_len)
    1087              : {
    1088              :         GkmWrapPrompt *self;
    1089              : 
    1090            1 :         g_assert (module != NULL);
    1091              : 
    1092            1 :         if (pin != NULL || pin_len != 0)
    1093            0 :                 return NULL;
    1094              : 
    1095            1 :         self = g_object_new (GKM_TYPE_WRAP_PROMPT,
    1096              :                              "timeout-seconds", -1,
    1097              :                              "bus-name", gkm_wrap_prompt_get_prompter_name (),
    1098              :                              NULL);
    1099              : 
    1100              :         /* Build up the prompt */
    1101            1 :         self->module = module;
    1102            1 :         self->session = session;
    1103              : 
    1104            1 :         return self;
    1105              : }
    1106              : 
    1107              : gboolean
    1108            1 : gkm_wrap_prompt_do_init_pin (GkmWrapPrompt *self, CK_RV last_result,
    1109              :                              CK_UTF8CHAR_PTR *pin, CK_ULONG *n_pin)
    1110              : {
    1111              :         CK_TOKEN_INFO tinfo;
    1112              :         gchar *password;
    1113              : 
    1114            1 :         g_assert (GKM_IS_WRAP_PROMPT (self));
    1115            1 :         g_assert (self->module);
    1116            1 :         g_assert (pin);
    1117            1 :         g_assert (n_pin);
    1118              : 
    1119            1 :         if (!get_info_for_token (self, &tinfo))
    1120            0 :                 return FALSE;
    1121              : 
    1122            1 :         setup_init_token (self, &tinfo);
    1123              : 
    1124            1 :         password = (char *)gkm_wrap_prompt_request_password (self);
    1125            1 :         if (password == NULL)
    1126            0 :                 return FALSE;
    1127              : 
    1128            1 :         g_assert (self->destroy_data == NULL);
    1129            1 :         gkm_wrap_prompt_set_prompt_data (self, password, NULL);
    1130            1 :         *pin = (gpointer)password;
    1131            1 :         *n_pin = strlen (password);
    1132            1 :         return TRUE;
    1133              : }
    1134              : 
    1135              : void
    1136            1 : gkm_wrap_prompt_done_init_pin (GkmWrapPrompt *self, CK_RV call_result)
    1137              : {
    1138              :         CK_TOKEN_INFO tinfo;
    1139              : 
    1140            1 :         g_assert (GKM_IS_WRAP_PROMPT (self));
    1141            1 :         g_assert (self->destroy_data == NULL);
    1142              : 
    1143              :         /* Save auto auto unlock */
    1144            1 :         if (call_result == CKR_OK && auto_unlock_should_attach (self)) {
    1145            0 :                 if (get_info_for_token (self, &tinfo))
    1146            0 :                         auto_unlock_attach_token (&tinfo, self->prompt_data);
    1147              :         }
    1148            1 : }
    1149              : 
    1150              : /* ------------------------------------------------------------------------------------
    1151              :  * SETPIN
    1152              :  */
    1153              : 
    1154              : typedef struct _SetPinPrompt {
    1155              :         gchar *original;
    1156              :         gchar *password;
    1157              : } SetPinPrompt;
    1158              : 
    1159              : static void
    1160            1 : set_pin_prompt_free (gpointer user_data)
    1161              : {
    1162            1 :         SetPinPrompt *data = user_data;
    1163            1 :         egg_secure_strfree (data->original);
    1164            1 :         egg_secure_strfree (data->password);
    1165            1 :         g_slice_free (SetPinPrompt, data);
    1166            1 : }
    1167              : 
    1168              : static void
    1169            1 : setup_set_token_original (GkmWrapPrompt *self,
    1170              :                           CK_TOKEN_INFO_PTR tinfo)
    1171              : {
    1172              :         GcrPrompt *prompt;
    1173              :         gchar *label;
    1174              :         gchar *text;
    1175              : 
    1176            1 :         g_assert (GKM_IS_WRAP_PROMPT (self));
    1177            1 :         g_assert (tinfo != NULL);
    1178            1 :         prompt = GCR_PROMPT (self);
    1179              : 
    1180            1 :         label = g_strndup ((gchar*)tinfo->label, sizeof (tinfo->label));
    1181            1 :         g_strchomp (label);
    1182              : 
    1183              :         /* Build up the prompt */
    1184            1 :         gcr_prompt_set_password_new (prompt, FALSE);
    1185            1 :         gcr_prompt_set_title (prompt, _("Change Password"));
    1186            1 :         gcr_prompt_set_message (prompt, _("Authentication required"));
    1187              : 
    1188            1 :         text = g_strdup_printf (_("To change the password for “%s”, the original password is required"), label);
    1189            1 :         gcr_prompt_set_description (prompt, text);
    1190            1 :         g_free (text);
    1191              : 
    1192            1 :         gcr_prompt_set_continue_label (prompt, _("Continue"));
    1193            1 :         gcr_prompt_set_choice_label (prompt, NULL);
    1194            1 :         g_free (label);
    1195            1 : }
    1196              : 
    1197              : 
    1198              : static void
    1199            1 : setup_set_token_password (GkmWrapPrompt *self,
    1200              :                           CK_TOKEN_INFO_PTR tinfo)
    1201              : {
    1202              :         GcrPrompt *prompt;
    1203              :         const gchar *choice;
    1204              :         gchar *label;
    1205              :         gchar *text;
    1206              : 
    1207            1 :         g_assert (GKM_IS_WRAP_PROMPT (self));
    1208            1 :         g_assert (tinfo != NULL);
    1209            1 :         prompt = GCR_PROMPT (self);
    1210              : 
    1211            1 :         label = g_strndup ((gchar*)tinfo->label, sizeof (tinfo->label));
    1212            1 :         g_strchomp (label);
    1213              : 
    1214              :         /* Build up the prompt */
    1215            1 :         gcr_prompt_set_password_new (prompt, TRUE);
    1216            1 :         gcr_prompt_set_title (prompt, _("Change Password"));
    1217            1 :         gcr_prompt_set_message (prompt, _("Change password"));
    1218              : 
    1219            1 :         text = g_strdup_printf (_("Type a new password for “%s”"), label);
    1220            1 :         gcr_prompt_set_description (prompt, text);
    1221            1 :         g_free (text);
    1222              : 
    1223            1 :         choice = NULL;
    1224            1 :         if (gkm_wrap_login_is_usable ())
    1225            0 :                 choice = _("Automatically unlock whenever I’m logged in");
    1226              : 
    1227            1 :         gcr_prompt_set_continue_label (prompt, _("Continue"));
    1228            1 :         gcr_prompt_set_choice_label (prompt, choice);
    1229              : 
    1230            1 :         g_free (label);
    1231            1 : }
    1232              : 
    1233              : 
    1234              : GkmWrapPrompt*
    1235            1 : gkm_wrap_prompt_for_set_pin (CK_FUNCTION_LIST_PTR module, CK_SESSION_HANDLE session,
    1236              :                              CK_UTF8CHAR_PTR old_pin, CK_ULONG n_old_pin,
    1237              :                              CK_UTF8CHAR_PTR new_pin, CK_ULONG n_new_pin)
    1238              : {
    1239              :         GkmWrapPrompt *self;
    1240              : 
    1241            1 :         g_assert (module != NULL);
    1242              : 
    1243            1 :         if (new_pin != NULL || n_new_pin != 0)
    1244            0 :                 return NULL;
    1245              : 
    1246            1 :         self = g_object_new (GKM_TYPE_WRAP_PROMPT,
    1247              :                              "timeout-seconds", -1,
    1248              :                              "bus-name", gkm_wrap_prompt_get_prompter_name (),
    1249              :                              NULL);
    1250              : 
    1251              :         /* Build up the prompt */
    1252            1 :         self->module = module;
    1253            1 :         self->session = session;
    1254            1 :         gkm_wrap_prompt_set_prompt_data (self,
    1255              :                                          g_slice_new0 (SetPinPrompt),
    1256              :                                          set_pin_prompt_free);
    1257              : 
    1258            1 :         return self;
    1259              : }
    1260              : 
    1261              : gboolean
    1262            1 : gkm_wrap_prompt_do_set_pin (GkmWrapPrompt *self, CK_RV last_result,
    1263              :                             CK_UTF8CHAR_PTR *old_pin, CK_ULONG *n_old_pin,
    1264              :                             CK_UTF8CHAR_PTR *new_pin, CK_ULONG *n_new_pin)
    1265              : {
    1266            1 :         gboolean initializing = FALSE;
    1267              :         CK_TOKEN_INFO tinfo;
    1268              :         SetPinPrompt *data;
    1269              :         const gchar *password;
    1270              : 
    1271            1 :         g_assert (GKM_IS_WRAP_PROMPT (self));
    1272            1 :         g_assert (self->module);
    1273            1 :         g_assert (old_pin);
    1274            1 :         g_assert (n_old_pin);
    1275            1 :         g_assert (new_pin);
    1276            1 :         g_assert (n_new_pin);
    1277              : 
    1278            1 :         g_assert (self->destroy_data == set_pin_prompt_free);
    1279            1 :         data = self->prompt_data;
    1280              : 
    1281            1 :         if (!get_info_for_token (self, &tinfo))
    1282            0 :                 return FALSE;
    1283              : 
    1284            1 :         initializing = !(tinfo.flags & CKF_USER_PIN_INITIALIZED);
    1285              : 
    1286              :         /* Prompt for the original password */
    1287            1 :         if (!initializing || last_result != CKR_OK) {
    1288            1 :                 setup_set_token_original (self, &tinfo);
    1289            1 :                 password = gkm_wrap_prompt_request_password (self);
    1290            1 :                 if (password == NULL)
    1291            0 :                         return FALSE;
    1292            1 :                 egg_secure_strfree (data->original);
    1293            1 :                 data->original = egg_secure_strdup (password);
    1294              :         }
    1295              : 
    1296              :         /* Prompt for the new password */
    1297            1 :         if (data->password == NULL) {
    1298            1 :                 setup_set_token_password (self, &tinfo);
    1299            1 :                 password = gkm_wrap_prompt_request_password (self);
    1300            1 :                 if (password == NULL)
    1301            0 :                         return FALSE;
    1302            1 :                 data->password = egg_secure_strdup (password);
    1303              :         }
    1304              : 
    1305            1 :         *new_pin = (guchar *)data->password;
    1306            1 :         *n_new_pin = data->password ? strlen (data->password) : 0;
    1307            1 :         *old_pin = (guchar *)data->original;
    1308            1 :         *n_old_pin = data->original ? strlen (data->original) : 0;
    1309              : 
    1310            1 :         return TRUE;
    1311              : }
    1312              : 
    1313              : void
    1314            1 : gkm_wrap_prompt_done_set_pin (GkmWrapPrompt *self, CK_RV call_result)
    1315              : {
    1316              :         CK_TOKEN_INFO tinfo;
    1317              :         SetPinPrompt *data;
    1318              : 
    1319            1 :         g_assert (GKM_IS_WRAP_PROMPT (self));
    1320            1 :         g_assert (self->destroy_data == set_pin_prompt_free);
    1321            1 :         data = self->prompt_data;
    1322              : 
    1323              :         /* Save auto auto unlock */
    1324            1 :         if (call_result == CKR_OK && auto_unlock_should_attach (self)) {
    1325            0 :                 if (get_info_for_token (self, &tinfo))
    1326            0 :                         auto_unlock_attach_token (&tinfo, data->password);
    1327              :         }
    1328            1 : }
    1329              : 
    1330              : /* -----------------------------------------------------------------------------
    1331              :  * LOGIN
    1332              :  */
    1333              : 
    1334              : static GkmWrapPrompt*
    1335            6 : login_prompt_for_specific (CK_FUNCTION_LIST_PTR module, CK_SESSION_HANDLE session,
    1336              :                            CK_OBJECT_HANDLE object)
    1337              : {
    1338              :         GkmWrapPrompt *self;
    1339              :         CK_ATTRIBUTE attr;
    1340              :         CK_BBOOL always;
    1341              :         CK_RV rv;
    1342              : 
    1343            6 :         g_assert (module);
    1344              : 
    1345              :         /*
    1346              :          * Should have an object at this point, if none exists it's an
    1347              :          * indication of either a buggy PKCS#11 module, or bugs in this
    1348              :          * wrap-layer not stashing away the context specific object.
    1349              :          */
    1350            6 :         g_return_val_if_fail (object != 0, NULL);
    1351              : 
    1352              :         /* Find out if the object is CKA_ALWAYS_AUTHENTICATE */
    1353            6 :         always = CK_FALSE;
    1354            6 :         attr.type = CKA_ALWAYS_AUTHENTICATE;
    1355            6 :         attr.pValue = &always;
    1356            6 :         attr.ulValueLen = sizeof (always);
    1357              : 
    1358            6 :         rv = (module->C_GetAttributeValue) (session, object, &attr, 1);
    1359            6 :         if (rv != CKR_OK || always != CK_TRUE)
    1360            0 :                 return NULL;
    1361              : 
    1362            6 :         self = g_object_new (GKM_TYPE_WRAP_PROMPT,
    1363              :                              "timeout-seconds", -1,
    1364              :                              "bus-name", gkm_wrap_prompt_get_prompter_name (),
    1365              :                              NULL);
    1366              : 
    1367              :         /* Build up the prompt */
    1368            6 :         self->module = module;
    1369            6 :         self->session = session;
    1370            6 :         self->object = object;
    1371              : 
    1372            6 :         return self;
    1373              : }
    1374              : 
    1375              : static gboolean
    1376            8 : login_prompt_do_specific (GkmWrapPrompt *self, CK_RV last_result,
    1377              :                           CK_UTF8CHAR_PTR *pin, CK_ULONG *n_pin)
    1378              : {
    1379            8 :         gchar *password = NULL;
    1380              :         CK_ATTRIBUTE_PTR attrs;
    1381              :         CK_ULONG n_attrs;
    1382              : 
    1383            8 :         g_assert (GKM_IS_WRAP_PROMPT (self));
    1384            8 :         g_assert (pin);
    1385            8 :         g_assert (n_pin);
    1386            8 :         attrs = get_attributes_from_object (self, &n_attrs);
    1387            8 :         g_return_val_if_fail (attrs, FALSE);
    1388              : 
    1389            8 :         if (self->iteration == 0) {
    1390            6 :                 ++(self->iteration);
    1391            6 :                 password = auto_unlock_lookup_object (attrs, n_attrs);
    1392            6 :                 if (password)
    1393            2 :                         gkm_wrap_prompt_set_prompt_data (self, password,
    1394              :                                                          (GDestroyNotify)egg_secure_strfree);
    1395              : 
    1396            2 :         } else if (self->iteration == 1 && last_result == CKR_PIN_INCORRECT) {
    1397            2 :                 auto_unlock_remove_object (attrs, n_attrs);
    1398              :         }
    1399              : 
    1400            8 :         if (!password) {
    1401            6 :                 setup_unlock_prompt (self, attrs, n_attrs, self->iteration == 1);
    1402              : 
    1403            6 :                 password = (char *)gkm_wrap_prompt_request_password (self);
    1404            6 :                 if (password == NULL)
    1405            2 :                         return FALSE;
    1406            4 :                 gkm_wrap_prompt_set_prompt_data (self, password, NULL);
    1407              :         }
    1408              : 
    1409            6 :         *pin = (guchar *)password;
    1410            6 :         *n_pin = strlen (password);
    1411            6 :         return TRUE;
    1412              : }
    1413              : 
    1414              : static void
    1415            6 : login_prompt_done_specific (GkmWrapPrompt *self, CK_RV call_result)
    1416              : {
    1417              :         CK_ATTRIBUTE_PTR attrs;
    1418              :         CK_ULONG n_attrs;
    1419              : 
    1420            6 :         g_assert (GKM_IS_WRAP_PROMPT (self));
    1421            6 :         g_assert (self->destroy_data == NULL ||
    1422              :                   self->destroy_data == (GDestroyNotify)egg_secure_strfree);
    1423              : 
    1424              :         /* Possibly save away auto unlock */
    1425            6 :         if (call_result == CKR_OK && auto_unlock_should_attach (self)) {
    1426            1 :                 attrs = get_attributes_from_object (self, &n_attrs);
    1427            1 :                 auto_unlock_attach_object (attrs, n_attrs, self->prompt_data);
    1428              :         }
    1429            6 : }
    1430              : 
    1431              : static GkmWrapPrompt*
    1432           49 : login_prompt_for_user (CK_FUNCTION_LIST_PTR module, CK_SESSION_HANDLE session)
    1433              : {
    1434              :         GkmWrapPrompt *self;
    1435              : 
    1436           49 :         g_assert (module != NULL);
    1437              : 
    1438           49 :         self = g_object_new (GKM_TYPE_WRAP_PROMPT,
    1439              :                              "timeout-seconds", -1,
    1440              :                              "bus-name", gkm_wrap_prompt_get_prompter_name (),
    1441              :                              NULL);
    1442              : 
    1443              :         /* Build up the prompt */
    1444           49 :         self->module = module;
    1445           49 :         self->session = session;
    1446              : 
    1447           49 :         return self;
    1448              : }
    1449              : 
    1450              : static gboolean
    1451           10 : login_prompt_do_user (GkmWrapPrompt *self, CK_RV last_result,
    1452              :                        CK_UTF8CHAR_PTR *pin, CK_ULONG *n_pin)
    1453              : {
    1454              :         CK_TOKEN_INFO tinfo;
    1455           10 :         gchar *password = NULL;
    1456              : 
    1457           10 :         g_assert (GKM_IS_WRAP_PROMPT (self));
    1458           10 :         g_assert (self->module);
    1459           10 :         g_assert (pin);
    1460           10 :         g_assert (n_pin);
    1461              : 
    1462           10 :         if (!get_info_for_token (self, &tinfo))
    1463            2 :                 return FALSE;
    1464              : 
    1465            8 :         if (self->iteration == 0) {
    1466            6 :                 ++(self->iteration);
    1467            6 :                 password = auto_unlock_lookup_token (&tinfo);
    1468            6 :                 if (password)
    1469            2 :                         gkm_wrap_prompt_set_prompt_data (self, password,
    1470              :                                                          (GDestroyNotify)egg_secure_strfree);
    1471              : 
    1472            2 :         } else if (self->iteration == 1 && last_result == CKR_PIN_INCORRECT) {
    1473            2 :                 auto_unlock_remove_token (&tinfo);
    1474              :         }
    1475              : 
    1476            8 :         if (!password) {
    1477            6 :                 setup_unlock_token (self, &tinfo);
    1478              : 
    1479            6 :                 password = (char *)gkm_wrap_prompt_request_password (self);
    1480            6 :                 if (password == NULL)
    1481            2 :                         return FALSE;
    1482            4 :                 gkm_wrap_prompt_set_prompt_data (self, password, NULL);
    1483              :         }
    1484              : 
    1485            6 :         *pin = (guchar *)password;
    1486            6 :         *n_pin = strlen (password);
    1487            6 :         return TRUE;
    1488              : }
    1489              : 
    1490              : static void
    1491           49 : login_prompt_done_user (GkmWrapPrompt *self, CK_RV call_result)
    1492              : {
    1493              :         CK_TOKEN_INFO tinfo;
    1494              : 
    1495           49 :         g_assert (GKM_IS_WRAP_PROMPT (self));
    1496           49 :         g_assert (self->destroy_data == NULL ||
    1497              :                   self->destroy_data == (GDestroyNotify)egg_secure_strfree);
    1498              : 
    1499              :         /* Save the options, and possibly auto unlock */
    1500           49 :         if (call_result == CKR_OK && auto_unlock_should_attach (self)) {
    1501            1 :                 if (get_info_for_token (self, &tinfo))
    1502            1 :                         auto_unlock_attach_token (&tinfo, self->prompt_data);
    1503              :         }
    1504           49 : }
    1505              : 
    1506              : 
    1507              : GkmWrapPrompt*
    1508           59 : gkm_wrap_prompt_for_login (CK_FUNCTION_LIST_PTR module, CK_USER_TYPE user_type,
    1509              :                            CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object,
    1510              :                            CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
    1511              : {
    1512           59 :         g_return_val_if_fail (module, NULL);
    1513              : 
    1514           59 :         if (pin != NULL || n_pin != 0)
    1515            3 :                 return NULL;
    1516              : 
    1517           56 :         switch (user_type) {
    1518            6 :         case CKU_CONTEXT_SPECIFIC:
    1519            6 :                 return login_prompt_for_specific (module, session, object);
    1520           49 :         case CKU_USER:
    1521           49 :                 return login_prompt_for_user (module, session);
    1522            1 :         default:
    1523            1 :                 return NULL;
    1524              :         }
    1525              : }
    1526              : 
    1527              : gboolean
    1528           18 : gkm_wrap_prompt_do_login (GkmWrapPrompt *self, CK_USER_TYPE user_type, CK_RV last_result,
    1529              :                           CK_UTF8CHAR_PTR *pin, CK_ULONG *n_pin)
    1530              : {
    1531           18 :         g_return_val_if_fail (GKM_IS_WRAP_PROMPT (self), FALSE);
    1532           18 :         g_return_val_if_fail (pin, FALSE);
    1533           18 :         g_return_val_if_fail (n_pin, FALSE);
    1534              : 
    1535           18 :         switch (user_type) {
    1536            8 :         case CKU_CONTEXT_SPECIFIC:
    1537            8 :                 return login_prompt_do_specific (self, last_result, pin, n_pin);
    1538           10 :         case CKU_USER:
    1539           10 :                 return login_prompt_do_user (self, last_result, pin, n_pin);
    1540            0 :         default:
    1541            0 :                 return FALSE;
    1542              :         }
    1543              : }
    1544              : 
    1545              : void
    1546           55 : gkm_wrap_prompt_done_login (GkmWrapPrompt *self, CK_USER_TYPE user_type, CK_RV call_result)
    1547              : {
    1548           55 :         g_return_if_fail (GKM_IS_WRAP_PROMPT (self));
    1549              : 
    1550           55 :         switch (user_type) {
    1551            6 :         case CKU_CONTEXT_SPECIFIC:
    1552            6 :                 login_prompt_done_specific (self, call_result);
    1553            6 :                 break;
    1554           49 :         case CKU_USER:
    1555           49 :                 login_prompt_done_user (self, call_result);
    1556           49 :                 break;
    1557              :         }
    1558              : }
    1559              : 
    1560              : const gchar *
    1561           65 : gkm_wrap_prompt_get_prompter_name (void)
    1562              : {
    1563              :         const gchar *prompter_name;
    1564              : 
    1565           65 :         if (the_prompter_name)
    1566           22 :                 return the_prompter_name;
    1567              : 
    1568           43 :         prompter_name = g_getenv ("GNOME_KEYRING_TEST_PROMPTER");
    1569           43 :         if (prompter_name)
    1570           26 :                 return prompter_name;
    1571              : 
    1572           17 :         return NULL;
    1573              : }
    1574              : 
    1575              : void
    1576           18 : gkm_wrap_prompt_set_prompter_name (const gchar *prompter_name)
    1577              : {
    1578           18 :         the_prompter_name = g_intern_string (prompter_name);
    1579           18 : }
        

Generated by: LCOV version 2.0-1