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

« back to all changes in this revision

Viewing changes to daemon/keyrings/gkr-keyring.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
 
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
 
/* gkr-keyring.c - represents a keyring in memory, and functionality save/load
3
 
 
4
 
   Copyright (C) 2003 Red Hat, Inc
5
 
   Copyright (C) 2007 Stefan Walter
6
 
 
7
 
   Gnome keyring is free software; you can redistribute it and/or
8
 
   modify it under the terms of the GNU General Public License as
9
 
   published by the Free Software Foundation; either version 2 of the
10
 
   License, or (at your option) any later version.
11
 
  
12
 
   Gnome keyring is distributed in the hope that it will be useful,
13
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 
   General Public License for more details.
16
 
  
17
 
   You should have received a copy of the GNU General Public License
18
 
   along with this program; if not, write to the Free Software
19
 
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
 
 
21
 
   Author: Alexander Larsson <alexl@redhat.com>
22
 
   Author: Stef Walter <stef@memberwebs.com>
23
 
*/
24
 
 
25
 
#include "config.h"
26
 
 
27
 
#include "gkr-keyring.h"
28
 
#include "gkr-keyring-item.h"
29
 
#include "gkr-keyring-login.h"
30
 
#include "gkr-keyrings.h"
31
 
 
32
 
#include "egg/egg-buffer.h"
33
 
#include "egg/egg-secure-memory.h"
34
 
 
35
 
#include "library/gnome-keyring-private.h"
36
 
#include "library/gnome-keyring-proto.h"
37
 
 
38
 
#include "util/gkr-location.h"
39
 
 
40
 
#include <glib.h>
41
 
#include <glib/gi18n.h>
42
 
 
43
 
#include <gcrypt.h>
44
 
 
45
 
#include <sys/types.h>
46
 
#include <sys/stat.h>
47
 
#include <unistd.h>
48
 
#include <fcntl.h>
49
 
#include <errno.h>
50
 
#include <stdlib.h>
51
 
#include <stdio.h>
52
 
#include <string.h>
53
 
 
54
 
/* -----------------------------------------------------------------------------
55
 
 * DECLARATIONS
56
 
 */
57
 
 
58
 
enum {
59
 
    ITEM_ADDED,
60
 
    ITEM_REMOVED,
61
 
    LAST_SIGNAL
62
 
};
63
 
 
64
 
enum {
65
 
    PROP_0,
66
 
    PROP_NAME,
67
 
    PROP_LOCATION
68
 
};
69
 
 
70
 
static guint signals[LAST_SIGNAL] = { 0 };
71
 
 
72
 
G_DEFINE_TYPE (GkrKeyring, gkr_keyring, G_TYPE_OBJECT);
73
 
 
74
 
/* -----------------------------------------------------------------------------
75
 
 * HELPERS
76
 
 */
77
 
 
78
 
static int
79
 
write_all (int fd, const guchar *buf, size_t len)
80
 
{
81
 
        size_t bytes;
82
 
        int res;
83
 
 
84
 
        bytes = 0;
85
 
        while (bytes < len) {
86
 
                res = write (fd, buf + bytes, len - bytes);
87
 
                if (res < 0) {
88
 
                        if (errno != EINTR && errno != EAGAIN) {
89
 
                                perror ("write_all write failure:");
90
 
                                return -1;
91
 
                        }
92
 
                } else {
93
 
                        bytes += res;
94
 
                }
95
 
        }
96
 
        return 0;
97
 
}
98
 
 
99
 
static GQuark
100
 
get_default_location_for_name (GQuark volume, const char *keyring_name)
101
 
{
102
 
        gchar *path = NULL;
103
 
        gchar *base, *filename;
104
 
        int version;
105
 
        GQuark loc;
106
 
        
107
 
        g_assert (volume);
108
 
        g_assert (keyring_name && keyring_name[0]);
109
 
 
110
 
        base = g_filename_from_utf8 (keyring_name, -1, NULL, NULL, NULL);
111
 
        if (base == NULL)
112
 
                base = g_strdup ("keyring");
113
 
 
114
 
        version = 0;
115
 
        do {
116
 
                g_free (path);
117
 
                
118
 
                if (version == 0) 
119
 
                        filename = g_strdup_printf ("%s/keyrings/%s.keyring", 
120
 
                                                    g_quark_to_string (volume), base);
121
 
                else
122
 
                        filename = g_strdup_printf ("%s/keyrings/%s%d.keyring", 
123
 
                                                    g_quark_to_string (volume), base, version);
124
 
 
125
 
                loc = gkr_location_from_string (filename);
126
 
                g_free (filename);
127
 
                
128
 
                path = gkr_location_to_path (loc);
129
 
                g_return_val_if_fail (path, 0);
130
 
 
131
 
                version++;
132
 
        } while (g_file_test (path, G_FILE_TEST_EXISTS));
133
 
 
134
 
        g_free (base);
135
 
        
136
 
        loc = gkr_location_from_path (path);
137
 
        g_free (path);
138
 
        return loc;
139
 
}
140
 
 
141
 
/* -----------------------------------------------------------------------------
142
 
 * OBJECT
143
 
 */
144
 
 
145
 
static void
146
 
gkr_keyring_init (GkrKeyring *keyring)
147
 
{
148
 
        keyring->ctime = keyring->mtime = time (NULL);
149
 
 
150
 
        /* Default values: */
151
 
        keyring->lock_on_idle = FALSE;
152
 
        keyring->lock_timeout = 0;
153
 
}
154
 
 
155
 
static void
156
 
gkr_keyring_get_property (GObject *obj, guint prop_id, GValue *value, 
157
 
                          GParamSpec *pspec)
158
 
{
159
 
        GkrKeyring *keyring = GKR_KEYRING (obj);
160
 
 
161
 
        switch (prop_id) {
162
 
        case PROP_NAME:
163
 
                g_value_set_string (value, keyring->keyring_name);
164
 
                break;
165
 
        case PROP_LOCATION:
166
 
                g_value_set_uint (value, keyring->location);
167
 
                break;
168
 
        }
169
 
}
170
 
 
171
 
static void 
172
 
gkr_keyring_dispose (GObject *obj)
173
 
{
174
 
        GkrKeyring *keyring = GKR_KEYRING (obj);
175
 
        GkrKeyringItem *item;
176
 
        GList *l;
177
 
        
178
 
        /* Remove all references to items */
179
 
        for (l = keyring->items; l; l = g_list_next (l)) {
180
 
                item = GKR_KEYRING_ITEM (l->data);
181
 
                g_object_unref (item);
182
 
        }
183
 
        
184
 
        g_list_free (keyring->items);
185
 
        keyring->items = NULL;
186
 
        
187
 
        egg_secure_strfree (keyring->password);
188
 
        keyring->password = NULL;
189
 
 
190
 
        G_OBJECT_CLASS (gkr_keyring_parent_class)->dispose (obj);
191
 
}
192
 
 
193
 
static void
194
 
gkr_keyring_finalize (GObject *obj)
195
 
{
196
 
        GkrKeyring *keyring = GKR_KEYRING (obj);
197
 
 
198
 
        g_free (keyring->keyring_name);
199
 
        g_assert (keyring->password == NULL);
200
 
        
201
 
        G_OBJECT_CLASS (gkr_keyring_parent_class)->finalize (obj);
202
 
}
203
 
 
204
 
static void
205
 
gkr_keyring_class_init (GkrKeyringClass *klass)
206
 
{
207
 
        GObjectClass *gobject_class = (GObjectClass*)klass;
208
 
 
209
 
        gkr_keyring_parent_class  = g_type_class_peek_parent (klass);
210
 
        
211
 
        gobject_class->get_property = gkr_keyring_get_property;
212
 
        gobject_class->dispose = gkr_keyring_dispose;
213
 
        gobject_class->finalize = gkr_keyring_finalize;
214
 
        
215
 
        g_object_class_install_property (gobject_class, PROP_NAME,
216
 
                g_param_spec_string ("name", "Name", "Keyring Name",
217
 
                                     NULL, G_PARAM_READABLE));
218
 
                                     
219
 
        g_object_class_install_property (gobject_class, PROP_LOCATION,
220
 
                g_param_spec_uint ("location", "Location", "File Location",
221
 
                                   0, G_MAXUINT, 0, G_PARAM_READABLE));
222
 
        
223
 
        signals[ITEM_ADDED] = g_signal_new ("item-added", GKR_TYPE_KEYRING, 
224
 
                        G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GkrKeyringClass, item_added),
225
 
                        NULL, NULL, g_cclosure_marshal_VOID__OBJECT, 
226
 
                        G_TYPE_NONE, 1, GKR_TYPE_KEYRING_ITEM);
227
 
 
228
 
        signals[ITEM_REMOVED] = g_signal_new ("item-removed", GKR_TYPE_KEYRING, 
229
 
                        G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GkrKeyringClass, item_removed),
230
 
                        NULL, NULL, g_cclosure_marshal_VOID__OBJECT, 
231
 
                        G_TYPE_NONE, 1, GKR_TYPE_KEYRING_ITEM);
232
 
}
233
 
 
234
 
/* -----------------------------------------------------------------------------
235
 
 * PUBLIC
236
 
 */
237
 
 
238
 
GkrKeyring*
239
 
gkr_keyring_new (const char *name, GQuark location)
240
 
{
241
 
        GkrKeyring *keyring;
242
 
        
243
 
        /* TODO: This should be done using properties */
244
 
        
245
 
        keyring = g_object_new (GKR_TYPE_KEYRING, NULL);
246
 
        
247
 
        keyring->keyring_name = g_strdup (name);
248
 
        keyring->location = location;
249
 
 
250
 
        return keyring;
251
 
}
252
 
 
253
 
GkrKeyring*
254
 
gkr_keyring_create (GQuark location, const gchar *keyring_name, const gchar *password)
255
 
{
256
 
        GkrKeyring *keyring;
257
 
        
258
 
        if (!location)
259
 
                location = GKR_LOCATION_VOLUME_LOCAL;
260
 
        if (gkr_location_is_volume (location))
261
 
                location = get_default_location_for_name (location, keyring_name);
262
 
        
263
 
        keyring = gkr_keyring_new (keyring_name, 0);
264
 
        if (keyring != NULL) {
265
 
                keyring->location = location;
266
 
                keyring->locked = FALSE;
267
 
                keyring->password = egg_secure_strdup (password);
268
 
                keyring->salt_valid = FALSE;
269
 
                gkr_keyring_save_to_disk (keyring);
270
 
        }
271
 
        return keyring;
272
 
}
273
 
 
274
 
guint
275
 
gkr_keyring_get_new_id (GkrKeyring *keyring)
276
 
{
277
 
        GkrKeyringItem *item;
278
 
        GList *l;
279
 
        guint max;
280
 
 
281
 
        g_assert (GKR_IS_KEYRING (keyring));
282
 
 
283
 
        max = 0;
284
 
        for (l = keyring->items; l ; l = g_list_next (l)) {
285
 
                item = l->data;
286
 
                if (item->id >= max)
287
 
                        max = item->id;
288
 
        }
289
 
        /* Naive unique id lookup, but avoid rollaround at lest: */
290
 
        
291
 
        if (max == 0xffffffff)
292
 
                return 0;
293
 
        
294
 
        return max + 1;
295
 
}
296
 
 
297
 
GkrKeyringItem*
298
 
gkr_keyring_get_item (GkrKeyring *keyring, guint id)
299
 
{
300
 
        GkrKeyringItem *item;
301
 
        GList *l;
302
 
        
303
 
        for (l = keyring->items; l; l = g_list_next (l)) {
304
 
                item = GKR_KEYRING_ITEM (l->data);
305
 
                if (item->id == id)
306
 
                        return item;
307
 
        }
308
 
        
309
 
        return NULL;
310
 
}
311
 
 
312
 
GkrKeyringItem*  
313
 
gkr_keyring_find_item (GkrKeyring *keyring, GnomeKeyringItemType type, 
314
 
                       GnomeKeyringAttributeList *attrs, gboolean match_all)
315
 
{    
316
 
        GkrKeyringItem *item;
317
 
        GList *l;
318
 
        
319
 
        for (l = keyring->items; l; l = g_list_next (l)) {
320
 
                item = GKR_KEYRING_ITEM (l->data);
321
 
                if (gkr_keyring_item_match (item, type, attrs, match_all))
322
 
                        return item;
323
 
        }
324
 
        
325
 
        return NULL;
326
 
}
327
 
 
328
 
void
329
 
gkr_keyring_add_item (GkrKeyring* keyring, GkrKeyringItem* item)
330
 
{
331
 
        g_assert (GKR_IS_KEYRING (keyring));
332
 
        g_assert (GKR_IS_KEYRING_ITEM (item));
333
 
        
334
 
        /* Must not be added twice */
335
 
        g_assert (g_list_find (keyring->items, item) == NULL);
336
 
        
337
 
        keyring->items = g_list_append (keyring->items, item);
338
 
        g_object_ref (item);
339
 
        
340
 
        g_signal_emit (keyring, signals[ITEM_ADDED], 0, item);
341
 
 
342
 
}
343
 
 
344
 
void
345
 
gkr_keyring_remove_item (GkrKeyring* keyring, GkrKeyringItem* item)
346
 
{
347
 
        g_assert (GKR_IS_KEYRING (keyring));
348
 
        g_assert (GKR_IS_KEYRING_ITEM (item));
349
 
        
350
 
        if (g_list_find (keyring->items, item)) {
351
 
                keyring->items = g_list_remove (keyring->items, item);
352
 
 
353
 
                /* Must not be added twice */
354
 
                g_assert (g_list_find (keyring->items, item) == NULL);
355
 
                
356
 
                /* Keep the reference until after the signal */
357
 
                g_signal_emit (keyring, signals[ITEM_REMOVED], 0, item);
358
 
                
359
 
                g_object_unref (item);
360
 
        }
361
 
}
362
 
 
363
 
gboolean
364
 
gkr_keyring_update_from_disk (GkrKeyring *keyring)
365
 
{
366
 
        EggBuffer buffer;
367
 
        GError *err = NULL;
368
 
        guchar *contents = NULL;
369
 
        gsize len;
370
 
        gint result; 
371
 
 
372
 
        if (!keyring->location)
373
 
                return TRUE;
374
 
        
375
 
        if (!gkr_location_read_file (keyring->location, &contents, &len, &err)) {
376
 
                g_warning ("couldn't read keyring: %s", err && err->message ? err->message : "");
377
 
                g_clear_error (&err);
378
 
                return FALSE;
379
 
        }
380
 
        
381
 
        egg_buffer_init_static (&buffer, contents, len);
382
 
        
383
 
        result = gkr_keyring_binary_parse (keyring, &buffer);
384
 
        if (result == 0)
385
 
                result = gkr_keyring_textual_parse (keyring, &buffer);
386
 
                
387
 
        egg_buffer_uninit (&buffer);
388
 
        g_free (contents);
389
 
                
390
 
        if (result > 0)
391
 
                return TRUE;
392
 
                
393
 
        if (result == 0)
394
 
                g_warning ("keyring has unknown format");
395
 
        else if (result < 0)
396
 
                g_warning ("error parsing keyring");
397
 
        
398
 
        return FALSE;
399
 
}
400
 
 
401
 
gboolean 
402
 
gkr_keyring_remove_from_disk (GkrKeyring *keyring)
403
 
{
404
 
        gchar *file;
405
 
        int res;
406
 
 
407
 
        /* Cannot remove session or memory based keyring */
408
 
        if (!keyring->location)
409
 
                return FALSE;
410
 
                
411
 
        file = gkr_location_to_path (keyring->location);
412
 
        if (!file)
413
 
                return FALSE;
414
 
                
415
 
        res = unlink (file);
416
 
        g_free (file);
417
 
        
418
 
        return (res == 0);
419
 
}
420
 
 
421
 
gboolean
422
 
gkr_keyring_save_to_disk (GkrKeyring *keyring)
423
 
{
424
 
        struct stat statbuf;
425
 
        EggBuffer out;
426
 
        int fd;
427
 
        char *dirname;
428
 
        char *template;
429
 
        gboolean result;
430
 
        gboolean ret = TRUE;
431
 
        gchar *file = NULL;
432
 
        
433
 
        /* Can't save locked keyrings */
434
 
        if (keyring->locked)
435
 
                return FALSE;
436
 
 
437
 
        /* Not file backed */
438
 
        if (!keyring->location)
439
 
                return TRUE;
440
 
                
441
 
        file = gkr_location_to_path (keyring->location);
442
 
        if (!file)
443
 
                return FALSE;
444
 
        
445
 
        egg_buffer_init_full (&out, 4096, g_realloc);
446
 
 
447
 
        /* Generate it */       
448
 
        if (!keyring->password || !keyring->password[0])
449
 
                result = gkr_keyring_textual_generate (keyring, &out);
450
 
        else
451
 
                result = gkr_keyring_binary_generate (keyring, &out);
452
 
                
453
 
        /* And write it to disk */
454
 
        if (result) {
455
 
                dirname = g_path_get_dirname (file);
456
 
                if (g_mkdir_with_parents (dirname, S_IRWXU) < 0)
457
 
                        g_warning ("unable to create keyring dir");
458
 
                template = g_build_filename (dirname, ".keyringXXXXXX", NULL);
459
 
                
460
 
                fd = g_mkstemp (template);
461
 
                if (fd != -1) {
462
 
                        fchmod (fd, S_IRUSR | S_IWUSR);
463
 
                        if (write_all (fd, out.buf, out.len) == 0) {
464
 
#ifdef HAVE_FSYNC
465
 
                        fsync (fd);
466
 
#endif
467
 
                                close (fd);
468
 
                                if (rename (template, file) == 0) {
469
 
                                        if (stat (file, &statbuf) == 0)
470
 
                                                gkr_location_manager_note_mtime (NULL, 
471
 
                                                              keyring->location, statbuf.st_mtime);
472
 
                                } else {
473
 
                                        unlink (template);
474
 
                                }
475
 
                        } else {
476
 
                                close (fd);
477
 
                        }
478
 
                } else {
479
 
                        g_warning ("Can't open keyring save file %s", template);
480
 
                        perror ("mkstemp error: ");
481
 
                        ret = FALSE;
482
 
                }
483
 
                g_free (template);
484
 
                g_free (dirname);
485
 
        } else {
486
 
                g_warning ("Internal error: Unable to generate data for keyring %s\n", keyring->keyring_name);
487
 
                ret = FALSE;
488
 
        }
489
 
        
490
 
        egg_buffer_uninit (&out);
491
 
        g_free (file);
492
 
        return ret;
493
 
}
494
 
 
495
 
gboolean
496
 
gkr_keyring_lock (GkrKeyring *keyring)
497
 
{
498
 
        if (keyring->locked)
499
 
                return TRUE;
500
 
 
501
 
        /* Never lock the session keyring */
502
 
        if (!keyring->location)
503
 
                return TRUE;
504
 
 
505
 
        /* Password will be null for textual keyrings */
506
 
        if (keyring->password != NULL) {
507
 
                egg_secure_strfree (keyring->password);
508
 
                keyring->password = NULL;
509
 
        }
510
 
        
511
 
        if (!gkr_keyring_update_from_disk (keyring)) {
512
 
                /* Failed to re-read, remove the keyring */
513
 
                g_warning ("Couldn't re-read keyring %s\n", keyring->keyring_name);
514
 
                gkr_keyrings_remove (keyring);
515
 
        }
516
 
        
517
 
        return TRUE;
518
 
}
519
 
 
520
 
gboolean
521
 
gkr_keyring_unlock (GkrKeyring *keyring, const gchar *password)
522
 
{
523
 
        if (!keyring->locked)
524
 
                return TRUE;
525
 
                
526
 
        g_return_val_if_fail (keyring->password == NULL, FALSE);
527
 
                
528
 
        keyring->password = egg_secure_strdup (password);
529
 
        if (!gkr_keyring_update_from_disk (keyring)) {
530
 
                egg_secure_strfree (keyring->password);
531
 
                keyring->password = NULL;
532
 
        }
533
 
        if (keyring->locked) {
534
 
                g_assert (keyring->password == NULL);
535
 
                return FALSE;
536
 
        } else {
537
 
                g_assert (keyring->password != NULL);
538
 
                return TRUE;
539
 
        }
540
 
}
541
 
 
542
 
gboolean
543
 
gkr_keyring_is_insecure (GkrKeyring *keyring)
544
 
{
545
 
        /* It's locked, must have encryption */
546
 
        if (keyring->locked)
547
 
                return FALSE;
548
 
                
549
 
        /* Only in memory == secure */
550
 
        if (!keyring->location)
551
 
                return FALSE;
552
 
                
553
 
        /* No or empty password == insecure */
554
 
        if (!keyring->password || !keyring->password[0])
555
 
                return TRUE;
556
 
                
557
 
        return FALSE;
558
 
}
559
 
 
560
 
gboolean 
561
 
gkr_keyring_ask_check_unlock (GkrAskRequest* ask)
562
 
{
563
 
        GkrKeyring *keyring;
564
 
        const gchar *password;
565
 
        gchar *display;
566
 
        
567
 
        keyring = GKR_KEYRING (gkr_ask_request_get_object (ask));
568
 
        g_assert (GKR_IS_KEYRING (keyring));
569
 
 
570
 
        if (!keyring->locked) {
571
 
                ask->response = GKR_ASK_RESPONSE_ALLOW;
572
 
                return GKR_ASK_STOP_REQUEST;
573
 
        }
574
 
        
575
 
        /* If they typed a password, try it out */
576
 
        if (ask->response >= GKR_ASK_RESPONSE_ALLOW) {
577
 
                
578
 
                g_assert (ask->typed_password);
579
 
                if (!gkr_keyring_unlock (keyring, ask->typed_password)) {
580
 
                        /* Bad password, try again */
581
 
                        ask->response = GKR_ASK_RESPONSE_NONE;
582
 
                        return GKR_ASK_CONTINUE_REQUEST;
583
 
                }
584
 
                
585
 
                /* Did they ask us to remember the password? */
586
 
                if (ask->checked) {
587
 
                        display = g_strdup_printf (_("Unlock password for %s keyring"), 
588
 
                                                   keyring->keyring_name);
589
 
                        gkr_keyring_login_attach_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
590
 
                                                         display, ask->typed_password, 
591
 
                                                         "keyring", gkr_location_to_string (keyring->location), NULL);
592
 
                        g_free (display);
593
 
                }
594
 
        }
595
 
        
596
 
        /* 
597
 
         * We can automatically unlock keyrings that have their password
598
 
         * stored in the 'login' keyring.
599
 
         */
600
 
        password = gkr_keyring_login_lookup_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
601
 
                                                    "keyring", gkr_location_to_string (keyring->location), NULL);
602
 
        if (password) {
603
 
                if (gkr_keyring_unlock (keyring, password)) {
604
 
                        
605
 
                        /* A good password, unlocked, all done */
606
 
                        ask->response = GKR_ASK_RESPONSE_ALLOW;
607
 
                        return GKR_ASK_STOP_REQUEST;
608
 
                        
609
 
                } else {
610
 
                        
611
 
                        /* A bad internal password */
612
 
                        gkr_keyring_login_remove_secret (GNOME_KEYRING_ITEM_CHAINED_KEYRING_PASSWORD,
613
 
                                                         "keyring", gkr_location_to_string (keyring->location), NULL);
614
 
                }
615
 
        }       
616
 
 
617
 
        /* If the keyring is unlocked then no need to continue */
618
 
        if (!keyring->locked) {
619
 
                ask->response = GKR_ASK_RESPONSE_ALLOW;
620
 
                return GKR_ASK_STOP_REQUEST;
621
 
        }
622
 
        
623
 
        return GKR_ASK_DONT_CARE;
624
 
}