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 : }
|