~ubuntu-branches/ubuntu/natty/gnome-keyring/natty

« back to all changes in this revision

Viewing changes to daemon/login/gkd-login.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2010-02-16 19:00:06 UTC
  • mfrom: (1.1.58 upstream)
  • Revision ID: james.westby@ubuntu.com-20100216190006-cqpnic4zxlkmmi0o
Tags: 2.29.90git20100218-0ubuntu1
Updated to a git snapshot version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * gnome-keyring
 
3
 *
 
4
 * Copyright (C) 2009 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, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
19
 * 02111-1307, USA.
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
 
 
24
#include "gkd-login.h"
 
25
 
 
26
#include "egg/egg-secure-memory.h"
 
27
 
 
28
#include "pkcs11/gkd-pkcs11.h"
 
29
#include "pkcs11/pkcs11i.h"
 
30
 
 
31
#include <glib/gi18n.h>
 
32
 
 
33
#include <string.h>
 
34
 
 
35
static gint unlock_failures = 0;
 
36
 
 
37
static void
 
38
note_that_unlock_failed (void)
 
39
{
 
40
        g_atomic_int_inc (&unlock_failures);
 
41
}
 
42
 
 
43
static void
 
44
note_that_unlock_succeeded (void)
 
45
{
 
46
        g_atomic_int_set (&unlock_failures, 0);
 
47
}
 
48
 
 
49
gboolean
 
50
gkd_login_did_unlock_fail (void)
 
51
{
 
52
        return g_atomic_int_get (&unlock_failures) ? TRUE : FALSE;
 
53
}
 
54
 
 
55
static GP11Module*
 
56
module_instance (void)
 
57
{
 
58
        GP11Module *module = gp11_module_new (gkd_pkcs11_get_base_functions ());
 
59
        gp11_module_set_pool_sessions (module, FALSE);
 
60
        gp11_module_set_auto_authenticate (module, FALSE);
 
61
        g_return_val_if_fail (module, NULL);
 
62
        return module;
 
63
}
 
64
 
 
65
static GP11Session*
 
66
open_and_login_session (GP11Slot *slot, CK_USER_TYPE user_type, GError **error)
 
67
{
 
68
        GP11Session *session;
 
69
        GError *err = NULL;
 
70
 
 
71
        g_return_val_if_fail (GP11_IS_SLOT (slot), NULL);
 
72
 
 
73
        if (!error)
 
74
                error = &err;
 
75
 
 
76
        session = gp11_slot_open_session (slot, CKF_RW_SESSION, error);
 
77
        if (session != NULL) {
 
78
                if (!gp11_session_login (session, user_type, NULL, 0, error)) {
 
79
                        if ((*error)->code != CKR_USER_ALREADY_LOGGED_IN) {
 
80
                                g_object_unref (session);
 
81
                                session = NULL;
 
82
                        }
 
83
                }
 
84
        }
 
85
 
 
86
        return session;
 
87
}
 
88
 
 
89
static GP11Session*
 
90
lookup_login_session (GP11Module *module)
 
91
{
 
92
        GP11Slot *slot = NULL;
 
93
        GError *error = NULL;
 
94
        GP11Session *session;
 
95
        GP11SlotInfo *info;
 
96
        GList *slots;
 
97
        GList *l;
 
98
 
 
99
        g_assert (GP11_IS_MODULE (module));
 
100
 
 
101
        /*
 
102
         * Find the right slot.
 
103
         *
 
104
         * TODO: This isn't necessarily the best way to do this.
 
105
         * A good function could be added to gp11 library.
 
106
         * But needs more thought on how to do this.
 
107
         */
 
108
        slots = gp11_module_get_slots (module, TRUE);
 
109
        for (l = slots; !slot && l; l = g_list_next (l)) {
 
110
                info = gp11_slot_get_info (l->data);
 
111
                if (g_ascii_strcasecmp ("Secret Store", info->slot_description) == 0)
 
112
                        slot = g_object_ref (l->data);
 
113
                gp11_slot_info_free (info);
 
114
        }
 
115
        gp11_list_unref_free (slots);
 
116
 
 
117
        g_return_val_if_fail (slot, NULL);
 
118
 
 
119
        session = open_and_login_session (slot, CKU_USER, &error);
 
120
        if (session == NULL) {
 
121
                g_warning ("couldn't open pkcs11 session for login: %s", error->message);
 
122
                g_clear_error (&error);
 
123
        }
 
124
 
 
125
        g_object_unref (slot);
 
126
 
 
127
        return session;
 
128
}
 
129
 
 
130
static GP11Object*
 
131
lookup_login_keyring (GP11Session *session)
 
132
{
 
133
        GError *error = NULL;
 
134
        GP11Object *login = NULL;
 
135
        GList *objects;
 
136
        guint length;
 
137
 
 
138
        g_return_val_if_fail (GP11_IS_SESSION (session), NULL);
 
139
 
 
140
        objects = gp11_session_find_objects (session, &error,
 
141
                                             CKA_CLASS, GP11_ULONG, CKO_G_COLLECTION,
 
142
                                             CKA_TOKEN, GP11_BOOLEAN, TRUE,
 
143
                                             CKA_ID, (gsize)5, "login",
 
144
                                             GP11_INVALID);
 
145
 
 
146
        if (error) {
 
147
                g_warning ("couldn't search for login keyring: %s", error->message);
 
148
                g_clear_error (&error);
 
149
                return NULL;
 
150
        }
 
151
 
 
152
        length = g_list_length (objects);
 
153
        if (length == 1) {
 
154
                login = g_object_ref (objects->data);
 
155
                gp11_object_set_session (login, session);
 
156
        } else if (length > 1) {
 
157
                g_warning ("more than one login keyring exists");
 
158
        }
 
159
 
 
160
        gp11_list_unref_free (objects);
 
161
        return login;
 
162
}
 
163
 
 
164
static GP11Object*
 
165
create_login_keyring (GP11Session *session, GP11Object *cred, GError **error)
 
166
{
 
167
        GP11Object *login;
 
168
        const gchar *label;
 
169
 
 
170
        g_return_val_if_fail (GP11_IS_SESSION (session), NULL);
 
171
        g_return_val_if_fail (GP11_IS_OBJECT (cred), NULL);
 
172
 
 
173
        /* TRANSLATORS: This is the display label for the login keyring */
 
174
        label = _("Login");
 
175
 
 
176
        login = gp11_session_create_object (session, error,
 
177
                                            CKA_CLASS, GP11_ULONG, CKO_G_COLLECTION,
 
178
                                            CKA_ID, (gsize)5, "login",
 
179
                                            CKA_LABEL, strlen (label), label,
 
180
                                            CKA_G_CREDENTIAL, GP11_ULONG, gp11_object_get_handle (cred),
 
181
                                            CKA_TOKEN, GP11_BOOLEAN, TRUE,
 
182
                                            GP11_INVALID);
 
183
 
 
184
        if (login != NULL)
 
185
                gp11_object_set_session (login, session);
 
186
        return login;
 
187
}
 
188
 
 
189
static GP11Object*
 
190
create_credential (GP11Session *session, GP11Object *object,
 
191
                   const gchar *secret, GError **error)
 
192
{
 
193
        GP11Attributes *attrs;
 
194
        GP11Object *cred;
 
195
 
 
196
        g_return_val_if_fail (GP11_IS_SESSION (session), NULL);
 
197
        g_return_val_if_fail (!object || GP11_IS_OBJECT (object), NULL);
 
198
 
 
199
        if (!secret)
 
200
                secret = "";
 
201
 
 
202
        attrs = gp11_attributes_newv (CKA_CLASS, GP11_ULONG, CKO_G_CREDENTIAL,
 
203
                                      CKA_VALUE, strlen (secret), secret,
 
204
                                      CKA_GNOME_TRANSIENT, GP11_BOOLEAN, TRUE,
 
205
                                      CKA_TOKEN, GP11_BOOLEAN, TRUE,
 
206
                                      GP11_INVALID);
 
207
 
 
208
        if (object)
 
209
                gp11_attributes_add_ulong (attrs, CKA_G_OBJECT,
 
210
                                           gp11_object_get_handle (object));
 
211
 
 
212
        cred = gp11_session_create_object_full (session, attrs, NULL, error);
 
213
        gp11_attributes_unref (attrs);
 
214
 
 
215
        if (cred != NULL)
 
216
                gp11_object_set_session (cred, session);
 
217
 
 
218
        return cred;
 
219
}
 
220
 
 
221
static gboolean
 
222
unlock_or_create_login (GP11Module *module, const gchar *master)
 
223
{
 
224
        GError *error = NULL;
 
225
        GP11Session *session;
 
226
        GP11Object *login;
 
227
        GP11Object *cred;
 
228
 
 
229
        g_return_val_if_fail (GP11_IS_MODULE (module), FALSE);
 
230
        g_return_val_if_fail (master, FALSE);
 
231
 
 
232
        /* Find the login object */
 
233
        session = lookup_login_session (module);
 
234
        login = lookup_login_keyring (session);
 
235
 
 
236
        /* Create credentials for login object */
 
237
        cred = create_credential (session, login, master, &error);
 
238
 
 
239
        /* Failure, bad password? */
 
240
        if (cred == NULL) {
 
241
                if (login && error->code == CKR_PIN_INCORRECT)
 
242
                        note_that_unlock_failed ();
 
243
                else
 
244
                        g_warning ("couldn't create login credential: %s", error->message);
 
245
                g_clear_error (&error);
 
246
 
 
247
        /* Non login keyring, create it */
 
248
        } else if (!login) {
 
249
                login = create_login_keyring (session, cred, &error);
 
250
                if (login == NULL) {
 
251
                        g_warning ("couldn't create login keyring: %s", error->message);
 
252
                        g_clear_error (&error);
 
253
                }
 
254
 
 
255
        /* The unlock succeeded yay */
 
256
        } else {
 
257
                note_that_unlock_succeeded ();
 
258
        }
 
259
 
 
260
        if (cred)
 
261
                g_object_unref (cred);
 
262
        if (login)
 
263
                g_object_unref (login);
 
264
        if (session)
 
265
                g_object_unref (session);
 
266
 
 
267
        return cred && login;
 
268
}
 
269
 
 
270
static gboolean
 
271
init_pin_for_uninitialized_slots (GP11Module *module, const gchar *master)
 
272
{
 
273
        GError *error = NULL;
 
274
        GList *slots, *l;
 
275
        gboolean initialize;
 
276
        GP11TokenInfo *info;
 
277
        GP11Session *session;
 
278
 
 
279
        g_return_val_if_fail (GP11_IS_MODULE (module), FALSE);
 
280
        g_return_val_if_fail (master, FALSE);
 
281
 
 
282
        slots = gp11_module_get_slots (module, TRUE);
 
283
        for (l = slots; l; l = g_list_next (l)) {
 
284
                info = gp11_slot_get_token_info (l->data);
 
285
                initialize = (info && !(info->flags & CKF_USER_PIN_INITIALIZED));
 
286
 
 
287
                if (initialize) {
 
288
                        session = open_and_login_session (l->data, CKU_SO, NULL);
 
289
                        if (session != NULL) {
 
290
                                if (gp11_session_init_pin (session, (const guchar*)master, strlen (master), &error)) {
 
291
                                        gkd_login_attach_secret (info->label, master,
 
292
                                                                 "manufacturer", info->manufacturer_id,
 
293
                                                                 "serial-number", info->serial_number,
 
294
                                                                 NULL);
 
295
                                } else {
 
296
                                        if (error->code != CKR_FUNCTION_NOT_SUPPORTED)
 
297
                                                g_warning ("couldn't initialize slot with master password: %s", error->message);
 
298
                                        g_clear_error (&error);
 
299
                                }
 
300
                                g_object_unref (session);
 
301
                        }
 
302
                }
 
303
 
 
304
                gp11_token_info_free (info);
 
305
        }
 
306
        gp11_list_unref_free (slots);
 
307
        return TRUE;
 
308
}
 
309
 
 
310
gboolean
 
311
gkd_login_unlock (const gchar *master)
 
312
{
 
313
        GP11Module *module;
 
314
        gboolean result;
 
315
 
 
316
        /* We don't support null or empty master passwords */
 
317
        if (!master || !master[0])
 
318
                return FALSE;
 
319
 
 
320
        module = module_instance ();
 
321
 
 
322
        result = unlock_or_create_login (module, master);
 
323
        if (result == TRUE)
 
324
                init_pin_for_uninitialized_slots (module, master);
 
325
 
 
326
        g_object_unref (module);
 
327
        return result;
 
328
}
 
329
 
 
330
static gboolean
 
331
change_or_create_login (GP11Module *module, const gchar *original, const gchar *master)
 
332
{
 
333
        GError *error = NULL;
 
334
        GP11Session *session;
 
335
        GP11Object *login = NULL;
 
336
        GP11Object *ocred = NULL;
 
337
        GP11Object *mcred = NULL;
 
338
        gboolean success = FALSE;
 
339
 
 
340
        g_return_val_if_fail (GP11_IS_MODULE (module), FALSE);
 
341
        g_return_val_if_fail (original, FALSE);
 
342
        g_return_val_if_fail (master, FALSE);
 
343
 
 
344
        /* Find the login object */
 
345
        session = lookup_login_session (module);
 
346
        login = lookup_login_keyring (session);
 
347
 
 
348
        /* Create the new credential we'll be changing to */
 
349
        mcred = create_credential (session, NULL, master, &error);
 
350
        if (mcred == NULL) {
 
351
                g_warning ("couldn't create new login credential: %s", error->message);
 
352
                g_clear_error (&error);
 
353
 
 
354
        /* Create original credentials */
 
355
        } else if (login) {
 
356
                ocred = create_credential (session, login, original, &error);
 
357
                if (ocred == NULL) {
 
358
                        if (error->code == CKR_PIN_INCORRECT) {
 
359
                                g_message ("couldn't change login master password, "
 
360
                                           "original password was wrong: %s", error->message);
 
361
                                note_that_unlock_failed ();
 
362
                        } else {
 
363
                                g_warning ("couldn't create original login credential: %s", error->message);
 
364
                        }
 
365
                        g_clear_error (&error);
 
366
                }
 
367
        }
 
368
 
 
369
        /* No keyring? try to create */
 
370
        if (!login && mcred) {
 
371
                login = create_login_keyring (session, mcred, &error);
 
372
                if (login == NULL) {
 
373
                        g_warning ("couldn't create login keyring: %s", error->message);
 
374
                        g_clear_error (&error);
 
375
                } else {
 
376
                        success = TRUE;
 
377
                }
 
378
 
 
379
        /* Change the master password */
 
380
        } else if (login && ocred && mcred) {
 
381
                if (!gp11_object_set (login, &error,
 
382
                                      CKA_G_CREDENTIAL, GP11_ULONG, gp11_object_get_handle (mcred),
 
383
                                      GP11_INVALID)) {
 
384
                        g_warning ("couldn't change login master password: %s", error->message);
 
385
                        g_clear_error (&error);
 
386
                } else {
 
387
                        success = TRUE;
 
388
                }
 
389
        }
 
390
 
 
391
        if (ocred) {
 
392
                gp11_object_destroy (ocred, NULL);
 
393
                g_object_unref (ocred);
 
394
        }
 
395
        if (mcred)
 
396
                g_object_unref (mcred);
 
397
        if (login)
 
398
                g_object_unref (login);
 
399
        if (session)
 
400
                g_object_unref (session);
 
401
 
 
402
        return success;
 
403
}
 
404
 
 
405
static gboolean
 
406
set_pin_for_any_slots (GP11Module *module, const gchar *original, const gchar *master)
 
407
{
 
408
        GError *error = NULL;
 
409
        GList *slots, *l;
 
410
        gboolean initialize;
 
411
        GP11TokenInfo *info;
 
412
        GP11Session *session;
 
413
 
 
414
        g_return_val_if_fail (GP11_IS_MODULE (module), FALSE);
 
415
        g_return_val_if_fail (original, FALSE);
 
416
        g_return_val_if_fail (master, FALSE);
 
417
 
 
418
        slots = gp11_module_get_slots (module, TRUE);
 
419
        for (l = slots; l; l = g_list_next (l)) {
 
420
 
 
421
                /* Set pin for any that are initialized, and not pap */
 
422
                info = gp11_slot_get_token_info (l->data);
 
423
                initialize = (info && (info->flags & CKF_USER_PIN_INITIALIZED));
 
424
 
 
425
                if (initialize) {
 
426
                        session = open_and_login_session (l->data, CKU_USER, NULL);
 
427
                        if (session != NULL) {
 
428
                                if (gp11_session_set_pin (session, (const guchar*)original, strlen (original),
 
429
                                                          (const guchar*)master, strlen (master), &error)) {
 
430
                                        gkd_login_attach_secret (info->label, master,
 
431
                                                                 "manufacturer", info->manufacturer_id,
 
432
                                                                 "serial-number", info->serial_number,
 
433
                                                                 NULL);
 
434
                                } else {
 
435
                                        if (error->code != CKR_PIN_INCORRECT && error->code != CKR_FUNCTION_NOT_SUPPORTED)
 
436
                                                g_warning ("couldn't change slot master password: %s", error->message);
 
437
                                        g_clear_error (&error);
 
438
                                }
 
439
                                g_object_unref (session);
 
440
                        }
 
441
                }
 
442
 
 
443
                gp11_token_info_free (info);
 
444
        }
 
445
        gp11_list_unref_free (slots);
 
446
        return TRUE;
 
447
}
 
448
 
 
449
gboolean
 
450
gkd_login_change_lock (const gchar *original, const gchar *master)
 
451
{
 
452
        GP11Module *module;
 
453
        gboolean result;
 
454
 
 
455
        /* We don't support null or empty master passwords */
 
456
        if (!master || !master[0])
 
457
                return FALSE;
 
458
        if (original == NULL)
 
459
                original = "";
 
460
 
 
461
        module = module_instance ();
 
462
 
 
463
        result = change_or_create_login (module, original, master);
 
464
        if (result == TRUE)
 
465
                set_pin_for_any_slots (module, original, master);
 
466
 
 
467
        g_object_unref (module);
 
468
        return result;
 
469
}
 
470
 
 
471
gboolean
 
472
gkd_login_is_usable (void)
 
473
{
 
474
        GP11Module *module;
 
475
        GP11Session *session;
 
476
        GP11Object *login;
 
477
        gboolean usable = FALSE;
 
478
        gpointer data;
 
479
        gsize n_data;
 
480
 
 
481
        module = module_instance ();
 
482
        if (!module)
 
483
                return FALSE;
 
484
 
 
485
        session = lookup_login_session (module);
 
486
        if (session) {
 
487
                login = lookup_login_keyring (session);
 
488
                if (login) {
 
489
                        data = gp11_object_get_data (login, CKA_G_LOCKED, &n_data, NULL);
 
490
                        usable = (data && n_data == sizeof (CK_BBOOL) && !*((CK_BBOOL*)data));
 
491
                        g_free (data);
 
492
                        g_object_unref (login);
 
493
                }
 
494
                g_object_unref (session);
 
495
        }
 
496
 
 
497
        g_object_unref (module);
 
498
        return usable;
 
499
}
 
500
 
 
501
static void
 
502
string_attribute_list_va (va_list args, const gchar *name, GP11Attribute *attr)
 
503
{
 
504
        GString *fields = g_string_sized_new(128);
 
505
        gsize length;
 
506
 
 
507
        while (name != NULL) {
 
508
                g_string_append (fields, name);
 
509
                g_string_append_c (fields, '\0');
 
510
                g_string_append (fields, va_arg (args, const gchar*));
 
511
                g_string_append_c (fields, '\0');
 
512
                name = va_arg (args, const gchar*);
 
513
        }
 
514
 
 
515
        length = fields->len;
 
516
        gp11_attribute_init (attr, CKA_G_FIELDS, g_string_free (fields, FALSE), length);
 
517
}
 
518
 
 
519
static GP11Object*
 
520
find_login_keyring_item (GP11Session *session, GP11Attribute *fields)
 
521
{
 
522
        GP11Object *search;
 
523
        GP11Object *item = NULL;
 
524
        GList *objects;
 
525
        GError *error = NULL;
 
526
        gpointer data;
 
527
        gsize n_data;
 
528
 
 
529
        g_return_val_if_fail (GP11_IS_SESSION (session), FALSE);
 
530
 
 
531
        /* Create a search object */
 
532
        search = gp11_session_create_object (session, &error,
 
533
                                             CKA_CLASS, GP11_ULONG, CKO_G_SEARCH,
 
534
                                             CKA_G_COLLECTION, (gsize)5, "login",
 
535
                                             CKA_TOKEN, GP11_BOOLEAN, FALSE,
 
536
                                             CKA_G_FIELDS, fields->length, fields->value,
 
537
                                             GP11_INVALID);
 
538
 
 
539
        if (!search) {
 
540
                g_warning ("couldn't create search for login keyring: %s", error->message);
 
541
                g_clear_error (&error);
 
542
                return NULL;
 
543
        }
 
544
 
 
545
        /* Get the data from the search */
 
546
        gp11_object_set_session (search, session);
 
547
        data = gp11_object_get_data (search, CKA_G_MATCHED, &n_data, &error);
 
548
        gp11_object_destroy (search, NULL);
 
549
        g_object_unref (search);
 
550
 
 
551
        if (data == NULL) {
 
552
                g_warning ("couldn't read search in login keyring: %s", error->message);
 
553
                g_clear_error (&error);
 
554
                return NULL;
 
555
        }
 
556
 
 
557
        n_data /= sizeof (CK_OBJECT_HANDLE);
 
558
        objects = gp11_objects_from_handle_array (gp11_session_get_slot (session), data,
 
559
                                                  MIN (sizeof (CK_OBJECT_HANDLE), n_data));
 
560
        g_free (data);
 
561
 
 
562
        if (objects) {
 
563
                item = g_object_ref (objects->data);
 
564
                gp11_object_set_session (item, session);
 
565
        }
 
566
 
 
567
        gp11_list_unref_free (objects);
 
568
        return item;
 
569
}
 
570
 
 
571
void
 
572
gkd_login_attach_secret (const gchar *label, const gchar *secret,
 
573
                         const gchar *first, ...)
 
574
{
 
575
        GError *error = NULL;
 
576
        GP11Attribute fields;
 
577
        GP11Session *session;
 
578
        GP11Module *module;
 
579
        gchar *display_name;
 
580
        GP11Object* item;
 
581
        va_list va;
 
582
 
 
583
        if (label == NULL)
 
584
                label = _("Unnamed");
 
585
        if (secret == NULL)
 
586
                secret = "";
 
587
 
 
588
        module = module_instance ();
 
589
        session = lookup_login_session (module);
 
590
 
 
591
        va_start(va, first);
 
592
        gp11_attribute_init_empty (&fields, CKA_G_FIELDS);
 
593
        string_attribute_list_va (va, first, &fields);
 
594
        va_end(va);
 
595
 
 
596
        display_name = g_strdup_printf (_("Unlock password for: %s"), label);
 
597
 
 
598
        item = find_login_keyring_item (session, &fields);
 
599
        if (item) {
 
600
                gp11_object_set (item, &error,
 
601
                                 CKA_LABEL, strlen (display_name), display_name,
 
602
                                 CKA_VALUE, strlen (secret), secret,
 
603
                                 GP11_INVALID);
 
604
        } else {
 
605
                item = gp11_session_create_object (session, &error,
 
606
                                                   CKA_TOKEN, GP11_BOOLEAN, TRUE,
 
607
                                                   CKA_CLASS, GP11_ULONG, CKO_SECRET_KEY,
 
608
                                                   CKA_LABEL, strlen (display_name), display_name,
 
609
                                                   CKA_VALUE, strlen (secret), secret,
 
610
                                                   CKA_G_COLLECTION, (gsize)5, "login",
 
611
                                                   CKA_G_FIELDS, fields.length, fields.value,
 
612
                                                   GP11_INVALID);
 
613
        }
 
614
 
 
615
        if (error != NULL) {
 
616
                g_warning ("couldn't store secret in login keyring: %s", error->message);
 
617
                g_clear_error (&error);
 
618
        }
 
619
 
 
620
        if (item)
 
621
                g_object_unref (item);
 
622
        g_free (display_name);
 
623
        gp11_attribute_clear (&fields);
 
624
        g_object_unref (session);
 
625
        g_object_unref (module);
 
626
}
 
627
 
 
628
gchar*
 
629
gkd_login_lookup_secret (const gchar *first, ...)
 
630
{
 
631
        GP11Attribute fields;
 
632
        GP11Session *session;
 
633
        GP11Module *module;
 
634
        GP11Object* item;
 
635
        gpointer data = NULL;
 
636
        gsize n_data;
 
637
        va_list va;
 
638
 
 
639
        module = module_instance ();
 
640
        session = lookup_login_session (module);
 
641
 
 
642
        va_start(va, first);
 
643
        gp11_attribute_init_empty (&fields, CKA_G_FIELDS);
 
644
        string_attribute_list_va (va, first, &fields);
 
645
        va_end(va);
 
646
 
 
647
        item = find_login_keyring_item (session, &fields);
 
648
        if (item != NULL) {
 
649
                data = gp11_object_get_data_full (item, CKA_VALUE, egg_secure_realloc, NULL, &n_data, NULL);
 
650
                if (data && !g_utf8_validate (data, n_data, NULL)) {
 
651
                        g_warning ("expected string, but found binary secret in login keyring");
 
652
                        egg_secure_clear (data, n_data);
 
653
                        egg_secure_free (data);
 
654
                        data = NULL;
 
655
                }
 
656
                g_object_unref (item);
 
657
        }
 
658
 
 
659
        g_object_unref (session);
 
660
        g_object_unref (module);
 
661
 
 
662
        /* Memory returned from gp11_object_get_data is null terminated */
 
663
        return data;
 
664
}
 
665
 
 
666
void
 
667
gkd_login_remove_secret (const gchar *first, ...)
 
668
{
 
669
        GError *error = NULL;
 
670
        GP11Attribute fields;
 
671
        GP11Session *session;
 
672
        GP11Module *module;
 
673
        GP11Object* item;
 
674
        va_list va;
 
675
 
 
676
        module = module_instance ();
 
677
        session = lookup_login_session (module);
 
678
 
 
679
        va_start(va, first);
 
680
        gp11_attribute_init_empty (&fields, CKA_G_FIELDS);
 
681
        string_attribute_list_va (va, first, &fields);
 
682
        va_end(va);
 
683
 
 
684
        item = find_login_keyring_item (session, &fields);
 
685
        if (item != NULL) {
 
686
                if (!gp11_object_destroy (item, &error)) {
 
687
                        if (error->code != CKR_OBJECT_HANDLE_INVALID)
 
688
                                g_warning ("couldn't remove stored secret from login keyring: %s", error->message);
 
689
                        g_clear_error (&error);
 
690
                }
 
691
                g_object_unref (item);
 
692
        }
 
693
 
 
694
        g_object_unref (session);
 
695
        g_object_unref (module);
 
696
}
 
697
 
 
698
GP11Attributes*
 
699
gkd_login_attributes_for_secret (const gchar *first, ...)
 
700
{
 
701
        GP11Attributes *attrs;
 
702
        GP11Attribute *fields;
 
703
        va_list va;
 
704
 
 
705
        attrs = gp11_attributes_newv (CKA_CLASS, GP11_ULONG, CKO_SECRET_KEY,
 
706
                                      CKA_G_COLLECTION, (gsize)5, "login",
 
707
                                      GP11_INVALID);
 
708
 
 
709
        va_start(va, first);
 
710
        fields = gp11_attributes_add_empty (attrs, CKA_G_FIELDS);
 
711
        string_attribute_list_va (va, first, fields);
 
712
        va_end(va);
 
713
 
 
714
        return attrs;
 
715
}