1 
2 /* Dump the  binary encrypted format of a keyring
3 
4    Build like this:
5 
6    $ gcc -o dump-keyring0-format $(pkg-config --cflags --libs glib-2.0) \
7         -lgcrypt dump-keyring0-format.c
8 
9    Copyright (C) 2003 Red Hat, Inc
10    Copyright (C) 2007, 2009 Stefan Walter
11    Copyright (C) 2013 Red Hat, Inc
12 
13    Gnome keyring is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of the
16    License, or (at your option) any later version.
17 
18    Gnome keyring is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    General Public License for more details.
22 
23    You should have received a copy of the GNU General Public License
24    along with this program; if not, write to the Free Software
25    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 
27    Author: Alexander Larsson <alexl@redhat.com>
28    Author: Stef Walter <stef@memberwebs.com>
29 */
30 
31 #include <glib.h>
32 
33 #include <gcrypt.h>
34 
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 
38 #include <ctype.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <unistd.h>
45 
46 enum {
47 	LOCK_ON_IDLE_FLAG = 1 << 0,
48 	LOCK_AFTER_FLAG = 1 << 1
49 };
50 
51 enum {
52 	ACCESS_READ = 1 << 0,
53 	ACCESS_WRITE = 1 << 1,
54 	ACCESS_REMOVE = 1 << 2
55 };
56 
57 #define KEYRING_FILE_HEADER "GnomeKeyring\n\r\0\n"
58 #define KEYRING_FILE_HEADER_LEN 16
59 
60 typedef gpointer (* BufferAllocator) (gpointer, gsize);
61 
62 #define DEFAULT_ALLOCATOR  ((BufferAllocator)realloc)
63 
64 typedef struct _Buffer {
65 	unsigned char *buf;
66 	gsize len;
67 	gsize allocated_len;
68 	int failures;
69 	BufferAllocator allocator;
70 } Buffer;
71 
72 #define BUFFER_EMPTY { NULL, 0, 0, 0, NULL }
73 
74 static gint
buffer_init_full(Buffer * buffer,gsize reserve,BufferAllocator allocator)75 buffer_init_full (Buffer *buffer,
76                   gsize reserve,
77                   BufferAllocator allocator)
78 {
79 	memset (buffer, 0, sizeof (*buffer));
80 
81 	if (!allocator)
82 		allocator = DEFAULT_ALLOCATOR;
83 	if (reserve == 0)
84 		reserve = 64;
85 
86 	buffer->buf = (allocator) (NULL, reserve);
87 	if (!buffer->buf) {
88 		buffer->failures++;
89 		return 0;
90 	}
91 
92 	buffer->len = 0;
93 	buffer->allocated_len = reserve;
94 	buffer->failures = 0;
95 	buffer->allocator = allocator;
96 
97 	return 1;
98 }
99 
100 static gint
buffer_init(Buffer * buffer,gsize reserve)101 buffer_init (Buffer *buffer,
102              gsize reserve)
103 {
104 	return buffer_init_full (buffer, reserve, NULL);
105 }
106 
107 
108 static void
buffer_init_static(Buffer * buffer,const guchar * buf,gsize len)109 buffer_init_static (Buffer* buffer,
110                     const guchar *buf,
111                     gsize len)
112 {
113 	memset (buffer, 0, sizeof (*buffer));
114 
115 	buffer->buf = (unsigned char*)buf;
116 	buffer->len = len;
117 	buffer->allocated_len = len;
118 	buffer->failures = 0;
119 
120 	/* A null allocator, and the buffer can't change in size */
121 	buffer->allocator = NULL;
122 }
123 
124 static void
buffer_uninit(Buffer * buffer)125 buffer_uninit (Buffer *buffer)
126 {
127 	if (!buffer)
128 		return;
129 
130 	/*
131 	 * Free the memory block using allocator. If no allocator,
132 	 * then this memory is ownerd elsewhere and not to be freed.
133 	 */
134 	if (buffer->buf && buffer->allocator)
135 		(buffer->allocator) (buffer->buf, 0);
136 
137 	memset (buffer, 0, sizeof (*buffer));
138 }
139 
140 static guint32
buffer_decode_uint32(guchar * ptr)141 buffer_decode_uint32 (guchar* ptr)
142 {
143 	guint32 val = ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
144 	return val;
145 }
146 
147 static int
buffer_get_uint32(Buffer * buffer,gsize offset,gsize * next_offset,guint32 * val)148 buffer_get_uint32 (Buffer *buffer,
149                    gsize offset,
150                    gsize *next_offset,
151                    guint32 *val)
152 {
153 	unsigned char *ptr;
154 	if (buffer->len < 4 || offset > buffer->len - 4) {
155 		buffer->failures++;
156 		return 0;
157 	}
158 	ptr = (unsigned char*)buffer->buf + offset;
159 	if (val != NULL)
160 		*val = buffer_decode_uint32 (ptr);
161 	if (next_offset != NULL)
162 		*next_offset = offset + 4;
163 	return 1;
164 }
165 
166 static gboolean
buffer_get_bytes(Buffer * buffer,gsize offset,gsize * next_offset,guchar * out,gsize n_bytes)167 buffer_get_bytes (Buffer *buffer,
168                   gsize offset,
169                   gsize *next_offset,
170                   guchar *out,
171                   gsize n_bytes)
172 {
173 	if (buffer->len < n_bytes || offset > buffer->len - n_bytes)
174 		return FALSE;
175 	memcpy (out, buffer->buf + offset, n_bytes);
176 	*next_offset = offset + n_bytes;
177 	return TRUE;
178 }
179 
180 static gboolean
buffer_get_time(Buffer * buffer,gsize offset,gsize * next_offset,time_t * time)181 buffer_get_time (Buffer *buffer,
182                  gsize offset,
183                  gsize *next_offset,
184                  time_t *time)
185 {
186 	guint32 a, b;
187 	guint64 val;
188 
189 	if (!buffer_get_uint32 (buffer, offset, &offset, &a) ||
190 	    !buffer_get_uint32 (buffer, offset, &offset, &b))
191 		return FALSE;
192 
193 	val = ((guint64)a) << 32 | b;
194 	*next_offset = offset;
195 	*time = (time_t) val;
196 	return TRUE;
197 }
198 
199 static int
buffer_get_string(Buffer * buffer,gsize offset,gsize * next_offset,gchar ** str_ret,BufferAllocator allocator)200 buffer_get_string (Buffer *buffer,
201                    gsize offset,
202                    gsize *next_offset,
203                    gchar **str_ret,
204                    BufferAllocator allocator)
205 {
206 	guint32 len;
207 
208 	if (!allocator)
209 		allocator = buffer->allocator;
210 	if (!allocator)
211 		allocator = DEFAULT_ALLOCATOR;
212 
213 	if (!buffer_get_uint32 (buffer, offset, &offset, &len)) {
214 		return 0;
215 	}
216 	if (len == 0xffffffff) {
217 		*next_offset = offset;
218 		*str_ret = NULL;
219 		return 1;
220 	} else if (len >= 0x7fffffff) {
221 		return 0;
222 	}
223 
224 	if (buffer->len < len ||
225 	    offset > buffer->len - len) {
226 		return 0;
227 	}
228 
229 	/* Make sure no null characters in string */
230 	if (memchr (buffer->buf + offset, 0, len) != NULL)
231 		return 0;
232 
233 	/* The passed allocator may be for non-pageable memory */
234 	*str_ret = (allocator) (NULL, len + 1);
235 	if (!*str_ret)
236 		return 0;
237 	memcpy (*str_ret, buffer->buf + offset, len);
238 
239 	/* Always zero terminate */
240 	(*str_ret)[len] = 0;
241 	*next_offset = offset + len;
242 
243 	return 1;
244 }
245 
246 static gboolean
buffer_get_utf8_string(Buffer * buffer,gsize offset,gsize * next_offset,char ** str_ret)247 buffer_get_utf8_string (Buffer *buffer,
248                         gsize offset,
249                         gsize *next_offset,
250                         char **str_ret)
251 {
252 	gsize len;
253 	char *str;
254 
255 	if (!buffer_get_string (buffer, offset, &offset, &str,
256 	                        (BufferAllocator)g_realloc))
257 		return FALSE;
258 	len = str ? strlen (str) : 0;
259 
260 	if (str != NULL) {
261 		if (!g_utf8_validate (str, len, NULL)) {
262 			g_free (str);
263 			return FALSE;
264 		}
265 	}
266 
267 	if (next_offset != NULL) {
268 		*next_offset = offset;
269 	}
270 	if (str_ret != NULL) {
271 		*str_ret = str;
272 	} else {
273 		g_free (str);
274 	}
275 	return TRUE;
276 }
277 
278 static gint
buffer_get_byte_array(Buffer * buffer,gsize offset,gsize * next_offset,const guchar ** val,gsize * vlen)279 buffer_get_byte_array (Buffer *buffer,
280                        gsize offset,
281                        gsize *next_offset,
282                        const guchar **val,
283                        gsize *vlen)
284 {
285 	guint32 len;
286 	if (!buffer_get_uint32 (buffer, offset, &offset, &len))
287 		return 0;
288 	if (len == 0xffffffff) {
289 		if (next_offset)
290 			*next_offset = offset;
291 		if (val)
292 			*val = NULL;
293 		if (vlen)
294 			*vlen = 0;
295 		return 1;
296 	} else if (len >= 0x7fffffff) {
297 		buffer->failures++;
298 		return 0;
299 	}
300 
301 	if (buffer->len < len || offset > buffer->len - len) {
302 		buffer->failures++;
303 		return 0;
304 	}
305 
306 	if (val)
307 		*val = buffer->buf + offset;
308 	if (vlen)
309 		*vlen = len;
310 	if (next_offset)
311 		*next_offset = offset + len;
312 
313 	return 1;
314 }
315 
316 
317 static gboolean
read_attributes(Buffer * buffer,gsize offset,gsize * next_offset,const gchar * identifier,GKeyFile * file)318 read_attributes (Buffer *buffer,
319                  gsize offset,
320                  gsize *next_offset,
321                  const gchar *identifier,
322                  GKeyFile *file)
323 {
324 	guint32 list_size;
325 	gchar *group = NULL;
326 	gboolean res = FALSE;
327 	char *name;
328 	guint32 type;
329 	char *str;
330 	guint32 val;
331 	int i;
332 
333 	if (!buffer_get_uint32 (buffer, offset, &offset, &list_size)) {
334 		g_message ("couldn't read number of attributes");
335 		goto bail;
336 	}
337 
338 	for (i = 0; i < list_size; i++) {
339 		g_free (group);
340 		group = g_strdup_printf ("%s:attribute%d", identifier, i);
341 
342 		if (!buffer_get_utf8_string (buffer, offset, &offset, &name)) {
343 			g_message ("couldn't read attribute name");
344 			goto bail;
345 		}
346 		if (file)
347 			g_key_file_set_string (file, group, "name", name);
348 		g_free (name);
349 
350 		if (!buffer_get_uint32 (buffer, offset, &offset, &type)) {
351 			g_message ("couldn't read attribute type");
352 			goto bail;
353 		}
354 		if (file)
355 			g_key_file_set_integer (file, group, "type", type);
356 
357 		switch (type) {
358 		case 0: /* A string */
359 			if (!buffer_get_utf8_string (buffer, offset, &offset, &str)) {
360 				g_message ("couldn't read string attribute value");
361 				goto bail;
362 			}
363 			if (file)
364 				g_key_file_set_string (file, group, "value", str);
365 			g_free (str);
366 			break;
367 
368 		case 1: /* A uint32 */
369 			if (!buffer_get_uint32 (buffer, offset, &offset, &val)) {
370 				g_message ("couldn't read number attribute value");
371 				goto bail;
372 			}
373 			if (file)
374 				g_key_file_set_int64 (file, group, "value", val);
375 			break;
376 		default:
377 			g_message ("invalid attribute type: %d", type);
378 			goto bail;
379 		}
380 	}
381 
382 	*next_offset = offset;
383 	res = TRUE;
384 
385 bail:
386 	return res;
387 }
388 
389 static gboolean
symkey_generate_simple(int cipher_algo,int hash_algo,const gchar * password,gssize n_password,const guchar * salt,gsize n_salt,int iterations,guchar ** key,guchar ** iv)390 symkey_generate_simple (int cipher_algo,
391                         int hash_algo,
392                         const gchar *password,
393                         gssize n_password,
394                         const guchar *salt,
395                         gsize n_salt,
396                         int iterations,
397                         guchar **key,
398                         guchar **iv)
399 {
400 	gcry_md_hd_t mdh;
401 	gcry_error_t gcry;
402 	guchar *digest;
403 	guchar *digested;
404 	guint n_digest;
405 	gint pass, i;
406 	gint needed_iv, needed_key;
407 	guchar *at_iv, *at_key;
408 
409 	g_assert (cipher_algo);
410 	g_assert (hash_algo);
411 
412 	g_return_val_if_fail (iterations >= 1, FALSE);
413 
414 	if (!password)
415 		n_password = 0;
416 	if (n_password == -1)
417 		n_password = strlen (password);
418 
419 	/*
420 	 * If cipher algo needs more bytes than hash algo has available
421 	 * then the entire hashing process is done again (with the previous
422 	 * hash bytes as extra input), and so on until satisfied.
423 	 */
424 
425 	needed_key = gcry_cipher_get_algo_keylen (cipher_algo);
426 	needed_iv = gcry_cipher_get_algo_blklen (cipher_algo);
427 
428 	gcry = gcry_md_open (&mdh, hash_algo, 0);
429 	if (gcry) {
430 		g_warning ("couldn't create '%s' hash context: %s",
431 			   gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
432 		return FALSE;
433 	}
434 
435 	n_digest = gcry_md_get_algo_dlen (hash_algo);
436 	g_return_val_if_fail (n_digest > 0, FALSE);
437 
438 	digest = g_malloc (n_digest);
439 	g_return_val_if_fail (digest, FALSE);
440 	if (key) {
441 		*key = g_malloc (needed_key);
442 		g_return_val_if_fail (*key, FALSE);
443 	}
444 	if (iv)
445 		*iv = g_new0 (guchar, needed_iv);
446 
447 	at_key = key ? *key : NULL;
448 	at_iv = iv ? *iv : NULL;
449 
450 	for (pass = 0; TRUE; ++pass) {
451 		gcry_md_reset (mdh);
452 
453 		/* Hash in the previous buffer on later passes */
454 		if (pass > 0)
455 			gcry_md_write (mdh, digest, n_digest);
456 
457 		if (password)
458 			gcry_md_write (mdh, password, n_password);
459 		if (salt && n_salt)
460 			gcry_md_write (mdh, salt, n_salt);
461 		gcry_md_final (mdh);
462 		digested = gcry_md_read (mdh, 0);
463 		g_return_val_if_fail (digested, FALSE);
464 		memcpy (digest, digested, n_digest);
465 
466 		for (i = 1; i < iterations; ++i) {
467 			gcry_md_reset (mdh);
468 			gcry_md_write (mdh, digest, n_digest);
469 			gcry_md_final (mdh);
470 			digested = gcry_md_read (mdh, 0);
471 			g_return_val_if_fail (digested, FALSE);
472 			memcpy (digest, digested, n_digest);
473 		}
474 
475 		/* Copy as much as possible into the destinations */
476 		i = 0;
477 		while (needed_key && i < n_digest) {
478 			if (at_key)
479 				*(at_key++) = digest[i];
480 			needed_key--;
481 			i++;
482 		}
483 		while (needed_iv && i < n_digest) {
484 			if (at_iv)
485 				*(at_iv++) = digest[i];
486 			needed_iv--;
487 			i++;
488 		}
489 
490 		if (needed_key == 0 && needed_iv == 0)
491 			break;
492 	}
493 
494 	g_free (digest);
495 	gcry_md_close (mdh);
496 
497 	return TRUE;
498 }
499 
500 static gboolean
decrypt_buffer(Buffer * buffer,const gchar * password,guchar salt[8],int iterations)501 decrypt_buffer (Buffer *buffer,
502                 const gchar *password,
503                 guchar salt[8],
504                 int iterations)
505 {
506 	gcry_cipher_hd_t cih;
507 	gcry_error_t gerr;
508 	guchar *key, *iv;
509 	gsize n_password = 0;
510 	gsize pos;
511 
512 	g_assert (buffer->len % 16 == 0);
513 	g_assert (16 == gcry_cipher_get_algo_blklen (GCRY_CIPHER_AES128));
514 	g_assert (16 == gcry_cipher_get_algo_keylen (GCRY_CIPHER_AES128));
515 
516 	/* No password is set, try an null password */
517 	if (password == NULL)
518 		n_password = 0;
519 	else
520 		n_password = strlen (password);
521 
522 	if (!symkey_generate_simple (GCRY_CIPHER_AES128, GCRY_MD_SHA256,
523 	                             password, n_password, salt, 8, iterations, &key, &iv))
524 		return FALSE;
525 
526 	gerr = gcry_cipher_open (&cih, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, 0);
527 	if (gerr) {
528 		g_warning ("couldn't create aes cipher context: %s",
529 		           gcry_strerror (gerr));
530 		g_free (key);
531 		g_free (iv);
532 		return FALSE;
533 	}
534 
535 	/* 16 = 128 bits */
536 	gerr = gcry_cipher_setkey (cih, key, 16);
537 	g_return_val_if_fail (!gerr, FALSE);
538 	g_free (key);
539 
540 	/* 16 = 128 bits */
541 	gerr = gcry_cipher_setiv (cih, iv, 16);
542 	g_return_val_if_fail (!gerr, FALSE);
543 	g_free (iv);
544 
545 	for (pos = 0; pos < buffer->len; pos += 16) {
546 		/* In place encryption */
547 		gerr = gcry_cipher_decrypt (cih, buffer->buf + pos, 16, NULL, 0);
548 		g_return_val_if_fail (!gerr, FALSE);
549 	}
550 
551 	gcry_cipher_close (cih);
552 
553 	return TRUE;
554 }
555 
556 static gboolean
verify_decrypted_buffer(Buffer * buffer)557 verify_decrypted_buffer (Buffer *buffer)
558 {
559 	guchar digest[16];
560 
561 	/* In case the world changes on us... */
562 	g_return_val_if_fail (gcry_md_get_algo_dlen (GCRY_MD_MD5) == sizeof (digest), 0);
563 
564 	gcry_md_hash_buffer (GCRY_MD_MD5, (void*)digest,
565 			     (guchar*)buffer->buf + 16, buffer->len - 16);
566 
567 	return memcmp (buffer->buf, digest, 16) == 0;
568 }
569 
570 static gboolean
read_acl(Buffer * buffer,gsize offset,gsize * offset_out,const gchar * identifier,GKeyFile * file)571 read_acl (Buffer *buffer,
572           gsize offset,
573           gsize *offset_out,
574           const gchar *identifier,
575           GKeyFile *file)
576 {
577 	gboolean res = FALSE;
578 	gchar *group = NULL;
579 	guint32 num_acs;
580 	guint32 x, y;
581 	int i;
582 	char *name, *path, *reserved;
583 
584 	if (!buffer_get_uint32 (buffer, offset, &offset, &num_acs)) {
585 		g_message ("couldn't read number of acls");
586 		return FALSE;
587 	}
588 
589 	for (i = 0; i < num_acs; i++) {
590 		g_free (group);
591 		group = g_strdup_printf ("%s:acl%d", identifier, i);
592 
593 		if (!buffer_get_uint32 (buffer, offset, &offset, &x)) {
594 			g_message ("couldn't read acl types allowed");
595 			goto bail;
596 		}
597 		g_key_file_set_boolean (file, group, "read-access", x & ACCESS_READ);
598 		g_key_file_set_boolean (file, group, "write-access", x & ACCESS_WRITE);
599 		g_key_file_set_boolean (file, group, "remove-access", x & ACCESS_REMOVE);
600 
601 		if (!buffer_get_utf8_string (buffer, offset, &offset, &name)) {
602 			g_message ("couldn't read acl application name");
603 			goto bail;
604 		}
605 		g_key_file_set_string (file, group, "display-name", name);
606 		g_free (name);
607 
608 		if (!buffer_get_utf8_string (buffer, offset, &offset, &path)) {
609 			g_message ("couldn't read acl application path");
610 			goto bail;
611 		}
612 		g_key_file_set_string (file, group, "path", path);
613 		g_free (path);
614 
615 		reserved = NULL;
616 		if (!buffer_get_utf8_string (buffer, offset, &offset, &reserved)) {
617 			g_message ("couldn't read acl reserved string");
618 			goto bail;
619 		}
620 		g_free (reserved);
621 
622 		if (!buffer_get_uint32 (buffer, offset, &offset, &y)) {
623 			g_message ("couldn't read acl reserved integer");
624 			goto bail;
625 		}
626 	}
627 
628 	*offset_out = offset;
629 	res = TRUE;
630 
631 bail:
632 	g_free (group);
633 	return res;
634 }
635 
636 static gboolean
read_hashed_item_info(Buffer * buffer,gsize * offset,guint n_items,GKeyFile * file,GPtrArray * items)637 read_hashed_item_info (Buffer *buffer,
638                        gsize *offset,
639                        guint n_items,
640                        GKeyFile *file,
641                        GPtrArray *items)
642 {
643 	gchar *identifier;
644 	guint type;
645 	guint id;
646 	gint i;
647 
648 	g_assert (buffer);
649 	g_assert (offset);
650 	g_assert (items);
651 
652 	for (i = 0; i < n_items; i++) {
653 		if (!buffer_get_uint32 (buffer, *offset, offset, &id)) {
654 			g_message ("couldn't read item id");
655 			return FALSE;
656 		}
657 		identifier = g_strdup_printf ("%u", id);
658 		g_ptr_array_add (items, identifier);
659 
660 		if (!buffer_get_uint32 (buffer, *offset, offset, &type)) {
661 			g_message ("couldn't read item type");
662 			return FALSE;
663 		}
664 		g_key_file_set_integer (file, identifier, "item-type", type);
665 
666 		/* NULL passed as file, so nothing gets written */
667 		if (!read_attributes (buffer, *offset, offset, identifier, NULL)) {
668 			g_message ("couldn't read hashed attributes");
669 			return FALSE;
670 		}
671 	}
672 
673 	return TRUE;
674 }
675 
676 static gboolean
read_full_item_info(Buffer * buffer,gsize * offset,guint n_items,GKeyFile * file,GPtrArray * items)677 read_full_item_info (Buffer *buffer,
678                      gsize *offset,
679                      guint n_items,
680                      GKeyFile *file,
681                      GPtrArray *items)
682 {
683 	const gchar *identifier;
684 	const unsigned char *ptr_secret;
685 	gsize n_secret;
686 	gchar *value;
687 	guint32 tmp;
688 	time_t ctime, mtime;
689 	gint i, j;
690 
691 	g_assert (buffer);
692 	g_assert (offset);
693 	g_assert (items->len == n_items);
694 
695 	for (i = 0; i < n_items; i++) {
696 		identifier = items->pdata[i];
697 
698 		/* The display name */
699 		if (!buffer_get_utf8_string (buffer, *offset, offset, &value)) {
700 			g_message ("couldn't read item display name");
701 			return FALSE;
702 		}
703 		g_key_file_set_string (file, identifier, "display-name", value);
704 		g_free (value);
705 
706 		/* The secret */
707 		if (!buffer_get_byte_array (buffer, *offset, offset, &ptr_secret, &n_secret)) {
708 			g_message ("couldn't read item secret");
709 			return FALSE;
710 		}
711 		if (g_utf8_validate ((gchar *)ptr_secret, n_secret, NULL))
712 			value = g_strndup ((gchar *)ptr_secret, n_secret);
713 		else
714 			value = g_base64_encode (ptr_secret, n_secret);
715 		g_key_file_set_string (file, identifier, "secret", value);
716 		g_free (value);
717 
718 		/* The item times */
719 		if (!buffer_get_time (buffer, *offset, offset, &ctime)) {
720 			g_message ("couldn't read item creation time");
721 			return FALSE;
722 		}
723 		g_key_file_set_int64 (file, identifier, "ctime", ctime);
724 
725 		if (!buffer_get_time (buffer, *offset, offset, &mtime)) {
726 			g_message ("couldn't read item modification time");
727 			return FALSE;
728 		}
729 		g_key_file_set_int64 (file, identifier, "mtime", mtime);
730 
731 		/* Reserved data */
732 		if (!buffer_get_utf8_string (buffer, *offset, offset, &value)) {
733 			g_message ("couldn't read item reserved string");
734 			return FALSE;
735 		}
736 		g_free (value);
737 		for (j = 0; j < 4; j++) {
738 			if (!buffer_get_uint32 (buffer, *offset, offset, &tmp)) {
739 				g_message ("couldn't read item reserved integer");
740 				return FALSE;
741 			}
742 		}
743 
744 		if (!read_attributes (buffer, *offset, offset, identifier, file))
745 			return FALSE;
746 
747 		/* The ACLs */
748 		if (!read_acl (buffer, *offset, offset, identifier, file))
749 			return FALSE;
750 	}
751 
752 	return TRUE;
753 }
754 
755 static gboolean
transform_keyring_binary_to_text(gconstpointer data,gsize n_data,const gchar * password,GKeyFile * file)756 transform_keyring_binary_to_text (gconstpointer data,
757                                   gsize n_data,
758                                   const gchar *password,
759                                   GKeyFile *file)
760 {
761 	Buffer to_decrypt = BUFFER_EMPTY;
762 	guchar major, minor, crypto, hash;
763 	guint32 flags;
764 	guint32 lock_timeout;
765 	time_t mtime, ctime;
766 	guint32 tmp;
767 	guint32 num_items;
768 	guint32 crypto_size;
769 	guint32 hash_iterations;
770 	guchar salt[8];
771 	Buffer buffer;
772 	GPtrArray *items = NULL;
773 	gboolean res = FALSE;
774 	gsize offset;
775 	gchar *value;
776 	int i;
777 
778 	/* The buffer we read from */
779 	buffer_init_static (&buffer, data, n_data);
780 
781 	if (buffer.len < KEYRING_FILE_HEADER_LEN ||
782 	    memcmp (buffer.buf, KEYRING_FILE_HEADER, KEYRING_FILE_HEADER_LEN) != 0) {
783 		buffer_uninit (&buffer);
784 		return FALSE;
785 	}
786 
787 	items = g_ptr_array_new_with_free_func (g_free);
788 	offset = KEYRING_FILE_HEADER_LEN;
789 	major = buffer.buf[offset++];
790 	minor = buffer.buf[offset++];
791 	crypto = buffer.buf[offset++];
792 	hash = buffer.buf[offset++];
793 
794 	value = g_strdup_printf ("version: %d.%d / crypto: %d / hash: %d",
795 	                         (gint)major, (gint)minor, (gint)crypto, (gint)hash);
796 	if (!g_key_file_set_comment (file, NULL, NULL, value, NULL))
797 		g_warn_if_reached ();
798 	g_free (value);
799 
800 	if (major != 0 || minor != 0) {
801 		g_message ("unknown version: %d.%d", (gint)major, (gint)minor);
802 		buffer_uninit (&buffer);
803 		return FALSE;
804 	}
805 
806 	if (!buffer_get_utf8_string (&buffer, offset, &offset, &value)) {
807 		g_message ("couldn't read keyring display name");
808 		goto bail;
809 	}
810 	g_key_file_set_string (file, "keyring", "display-name", value);
811 	g_free (value);
812 
813 	if (!buffer_get_time (&buffer, offset, &offset, &ctime)) {
814 		g_message ("couldn't read keyring creation time");
815 		goto bail;
816 	}
817 	g_key_file_set_int64 (file, "keyring", "ctime", ctime);
818 
819 	if (!buffer_get_time (&buffer, offset, &offset, &mtime)) {
820 		g_message ("couldn't read keyring modification time");
821 		goto bail;
822 	}
823 	g_key_file_set_int64 (file, "keyring", "mtime", mtime);
824 
825 	if (!buffer_get_uint32 (&buffer, offset, &offset, &flags)) {
826 		g_message ("couldn't read keyring flags");
827 		goto bail;
828 	}
829 	g_key_file_set_boolean (file, "keyring", "lock-on-idle", flags & LOCK_ON_IDLE_FLAG);
830 	g_key_file_set_boolean (file, "keyring", "lock-after", flags & LOCK_AFTER_FLAG);
831 
832 	if (!buffer_get_uint32 (&buffer, offset, &offset, &lock_timeout)) {
833 		g_message ("couldn't read lock timeout");
834 		goto bail;
835 	}
836 	g_key_file_set_integer (file, "keyring", "lock-timeout", lock_timeout);
837 
838 	if (!buffer_get_uint32 (&buffer, offset, &offset, &hash_iterations)) {
839 		g_message ("couldn't read hash iterations");
840 		goto bail;
841 	}
842 	g_key_file_set_integer (file, "keyring", "x-hash-iterations", hash_iterations);
843 
844 	if (!buffer_get_bytes (&buffer, offset, &offset, salt, 8)) {
845 		g_message ("couldn't read salt");
846 		goto bail;
847 	}
848 	value = g_base64_encode (salt, 8);
849 	g_key_file_set_string (file, "keyring", "x-salt", value);
850 	g_free (value);
851 
852 	for (i = 0; i < 4; i++) {
853 		if (!buffer_get_uint32 (&buffer, offset, &offset, &tmp))
854 			goto bail;
855 	}
856 
857 	if (!buffer_get_uint32 (&buffer, offset, &offset, &num_items)) {
858 		g_message ("couldn't read number of items");
859 		goto bail;
860 	}
861 	g_key_file_set_integer (file, "keyring", "x-num-items", num_items);
862 
863 	/* Hashed data, without secrets */
864 	if (!read_hashed_item_info (&buffer, &offset, num_items, file, items)) {
865 		g_message ("couldn't read hashed items");
866 		goto bail;
867 	}
868 
869 	if (!buffer_get_uint32 (&buffer, offset, &offset, &crypto_size)) {
870 		g_message ("couldn't read size of encrypted data");
871 		goto bail;
872 	}
873 	g_key_file_set_integer (file, "keyring", "x-crypto-size", crypto_size);
874 
875 	if (crypto_size > buffer.len - offset) {
876 		g_message ("encrypted data size is greater than file size, possibly truncated");
877 		crypto_size = buffer.len - offset;
878 	}
879 
880 	/* Make the crypted part is the right size */
881 	if (crypto_size % 16 != 0) {
882 		g_message ("encrypted data size is not a multiple of the encryption block size, possibly truncated");
883 		crypto_size = (crypto_size / 16) * 16;
884 	}
885 
886 	/* Copy the data into to_decrypt into non-pageable memory */
887 	buffer_init (&to_decrypt, crypto_size);
888 	memcpy (to_decrypt.buf, buffer.buf + offset, crypto_size);
889 	to_decrypt.len = crypto_size;
890 
891 	if (!decrypt_buffer (&to_decrypt, password, salt, hash_iterations))
892 		goto bail;
893 	if (!verify_decrypted_buffer (&to_decrypt))
894 		g_message ("encrypted data failed to verify, password wrong, or file corrupted");
895 	offset = 16; /* Skip hash */
896 	if (!read_full_item_info (&to_decrypt, &offset, num_items, file, items))
897 		goto bail;
898 
899 	res = TRUE;
900 
901 bail:
902 	g_ptr_array_free (items, TRUE);
903 	buffer_uninit (&to_decrypt);
904 	return res;
905 }
906 
907 
908 
909 int
main(int argc,char * argv[])910 main (int argc,
911       char *argv[])
912 {
913 	GError *error = NULL;
914 	const gchar *password;
915 	GKeyFile *file;
916 	gboolean ret;
917 	gchar *contents;
918 	gsize length;
919 
920 	g_set_prgname ("dump-keyring0-format");
921 	gcry_check_version (GCRYPT_VERSION);
922 
923 	if (argc < 2 || argc > 3) {
924 		g_printerr ("usage: %s file.keyring [output]\n", g_get_prgname ());
925 		return 2;
926 	}
927 
928 	if (!g_file_get_contents (argv[1], &contents, &length, &error)) {
929 		g_printerr ("%s: %s\n", g_get_prgname (), error->message);
930 		g_error_free (error);
931 		return 1;
932 	}
933 
934 	file = g_key_file_new ();
935 	password = getpass ("Password: ");
936 
937 	transform_keyring_binary_to_text (contents, length, password, file);
938 	g_free (contents);
939 
940 	contents = g_key_file_to_data (file, &length, &error);
941 	g_key_file_free (file);
942 
943 	if (contents == NULL) {
944 		g_printerr ("%s: couldn't encode: %s", g_get_prgname (), error->message);
945 		g_error_free (error);
946 		return 1;
947 	}
948 
949 	ret = TRUE;
950 	if (argc == 3)
951 		ret = g_file_set_contents (argv[2], contents, length, &error);
952 	else
953 		g_print ("%s", contents);
954 	g_free (contents);
955 
956 	if (!ret) {
957 		g_printerr ("%s: %s", g_get_prgname (), error->message);
958 		g_error_free (error);
959 		return 1;
960 	}
961 
962 	return 0;
963 }
964