Line data Source code
1 : /* keybox-dump.c - Debug helpers
2 : * Copyright (C) 2001, 2003 Free Software Foundation, Inc.
3 : *
4 : * This file is part of GnuPG.
5 : *
6 : * GnuPG is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * GnuPG is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include <config.h>
21 : #include <stdlib.h>
22 : #include <stdio.h>
23 : #include <string.h>
24 : #include <errno.h>
25 :
26 : #include "keybox-defs.h"
27 : #include <gcrypt.h>
28 : #include "host2net.h"
29 :
30 : /* Argg, we can't include ../common/util.h */
31 : char *bin2hexcolon (const void *buffer, size_t length, char *stringbuf);
32 :
33 : #define get32(a) buf32_to_ulong ((a))
34 : #define get16(a) buf16_to_ulong ((a))
35 :
36 :
37 : void
38 0 : print_string (FILE *fp, const byte *p, size_t n, int delim)
39 : {
40 0 : for ( ; n; n--, p++ )
41 : {
42 0 : if (*p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim)
43 : {
44 0 : putc('\\', fp);
45 0 : if( *p == '\n' )
46 0 : putc('n', fp);
47 0 : else if( *p == '\r' )
48 0 : putc('r', fp);
49 0 : else if( *p == '\f' )
50 0 : putc('f', fp);
51 0 : else if( *p == '\v' )
52 0 : putc('v', fp);
53 0 : else if( *p == '\b' )
54 0 : putc('b', fp);
55 0 : else if( !*p )
56 0 : putc('0', fp);
57 : else
58 0 : fprintf(fp, "x%02x", *p );
59 : }
60 : else
61 0 : putc(*p, fp);
62 : }
63 0 : }
64 :
65 :
66 : static int
67 0 : print_checksum (const byte *buffer, size_t length, size_t unhashed, FILE *fp)
68 : {
69 : const byte *p;
70 : int i;
71 : int hashlen;
72 : unsigned char digest[20];
73 :
74 0 : fprintf (fp, "Checksum: ");
75 0 : if (unhashed && unhashed < 20)
76 : {
77 0 : fputs ("[specified unhashed sized too short]\n", fp);
78 0 : return 0;
79 : }
80 0 : if (!unhashed)
81 : {
82 0 : unhashed = 16;
83 0 : hashlen = 16;
84 : }
85 : else
86 0 : hashlen = 20;
87 0 : if (length < 5+unhashed)
88 : {
89 0 : fputs ("[blob too short for a checksum]\n", fp);
90 0 : return 0;
91 : }
92 :
93 0 : p = buffer + length - hashlen;
94 0 : for (i=0; i < hashlen; p++, i++)
95 0 : fprintf (fp, "%02x", *p);
96 :
97 0 : if (hashlen == 16) /* Compatibility method. */
98 : {
99 0 : gcry_md_hash_buffer (GCRY_MD_MD5, digest, buffer, length - 16);
100 0 : if (!memcmp (buffer + length - 16, digest, 16))
101 0 : fputs (" [valid]\n", fp);
102 : else
103 0 : fputs (" [bad]\n", fp);
104 : }
105 : else
106 : {
107 0 : gcry_md_hash_buffer (GCRY_MD_SHA1, digest, buffer, length - unhashed);
108 0 : if (!memcmp (buffer + length - hashlen, digest, hashlen))
109 0 : fputs (" [valid]\n", fp);
110 : else
111 0 : fputs (" [bad]\n", fp);
112 : }
113 0 : return 0;
114 : }
115 :
116 :
117 : static int
118 0 : dump_header_blob (const byte *buffer, size_t length, FILE *fp)
119 : {
120 : unsigned long n;
121 :
122 0 : if (length < 32)
123 : {
124 0 : fprintf (fp, "[blob too short]\n");
125 0 : return -1;
126 : }
127 0 : fprintf (fp, "Version: %d\n", buffer[5]);
128 :
129 0 : n = get16 (buffer + 6);
130 0 : fprintf( fp, "Flags: %04lX", n);
131 0 : if (n)
132 : {
133 0 : int any = 0;
134 :
135 0 : fputs (" (", fp);
136 0 : if ((n & 2))
137 : {
138 0 : if (any)
139 0 : putc (',', fp);
140 0 : fputs ("openpgp", fp);
141 0 : any++;
142 : }
143 0 : putc (')', fp);
144 : }
145 0 : putc ('\n', fp);
146 :
147 0 : if ( memcmp (buffer+8, "KBXf", 4))
148 0 : fprintf (fp, "[Error: invalid magic number]\n");
149 :
150 0 : n = get32 (buffer+16);
151 0 : fprintf( fp, "created-at: %lu\n", n );
152 0 : n = get32 (buffer+20);
153 0 : fprintf( fp, "last-maint: %lu\n", n );
154 :
155 0 : return 0;
156 : }
157 :
158 :
159 : /* Dump one block to FP */
160 : int
161 0 : _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
162 : {
163 : const byte *buffer;
164 : size_t length;
165 : int type, i;
166 : ulong n, nkeys, keyinfolen;
167 : ulong nuids, uidinfolen;
168 : ulong nsigs, siginfolen;
169 : ulong rawdata_off, rawdata_len;
170 : ulong nserial;
171 : ulong unhashed;
172 : const byte *p;
173 :
174 0 : buffer = _keybox_get_blob_image (blob, &length);
175 :
176 0 : if (length < 32)
177 : {
178 0 : fprintf (fp, "[blob too short]\n");
179 0 : return -1;
180 : }
181 :
182 0 : n = get32( buffer );
183 0 : if (n > length)
184 0 : fprintf (fp, "[blob larger than length - output truncated]\n");
185 : else
186 0 : length = n; /* ignore the rest */
187 :
188 0 : fprintf (fp, "Length: %lu\n", n );
189 0 : type = buffer[4];
190 0 : switch (type)
191 : {
192 : case KEYBOX_BLOBTYPE_EMPTY:
193 0 : fprintf (fp, "Type: Empty\n");
194 0 : return 0;
195 :
196 : case KEYBOX_BLOBTYPE_HEADER:
197 0 : fprintf (fp, "Type: Header\n");
198 0 : return dump_header_blob (buffer, length, fp);
199 : case KEYBOX_BLOBTYPE_PGP:
200 0 : fprintf (fp, "Type: OpenPGP\n");
201 0 : break;
202 : case KEYBOX_BLOBTYPE_X509:
203 0 : fprintf (fp, "Type: X.509\n");
204 0 : break;
205 : default:
206 0 : fprintf (fp, "Type: %d\n", type);
207 0 : fprintf (fp, "[can't dump this blob type]\n");
208 0 : return 0;
209 : }
210 0 : fprintf (fp, "Version: %d\n", buffer[5]);
211 :
212 0 : if (length < 40)
213 : {
214 0 : fprintf (fp, "[blob too short]\n");
215 0 : return -1;
216 : }
217 :
218 0 : n = get16 (buffer + 6);
219 0 : fprintf( fp, "Blob-Flags: %04lX", n);
220 0 : if (n)
221 : {
222 0 : int any = 0;
223 :
224 0 : fputs (" (", fp);
225 0 : if ((n & 1))
226 : {
227 0 : fputs ("secret", fp);
228 0 : any++;
229 : }
230 0 : if ((n & 2))
231 : {
232 0 : if (any)
233 0 : putc (',', fp);
234 0 : fputs ("ephemeral", fp);
235 0 : any++;
236 : }
237 0 : putc (')', fp);
238 : }
239 0 : putc ('\n', fp);
240 :
241 0 : rawdata_off = get32 (buffer + 8);
242 0 : rawdata_len = get32 (buffer + 12);
243 :
244 0 : fprintf( fp, "Data-Offset: %lu\n", rawdata_off );
245 0 : fprintf( fp, "Data-Length: %lu\n", rawdata_len );
246 0 : if (rawdata_off > length || rawdata_len > length
247 0 : || rawdata_off+rawdata_len > length
248 0 : || rawdata_len + 4 > length
249 0 : || rawdata_off+rawdata_len + 4 > length)
250 0 : fprintf (fp, "[Error: raw data larger than blob]\n");
251 0 : unhashed = length - rawdata_off - rawdata_len;
252 0 : fprintf (fp, "Unhashed: %lu\n", unhashed);
253 :
254 0 : nkeys = get16 (buffer + 16);
255 0 : fprintf (fp, "Key-Count: %lu\n", nkeys );
256 0 : if (!nkeys)
257 0 : fprintf (fp, "[Error: no keys]\n");
258 0 : if (nkeys > 1 && type == KEYBOX_BLOBTYPE_X509)
259 0 : fprintf (fp, "[Error: only one key allowed for X509]\n");
260 :
261 0 : keyinfolen = get16 (buffer + 18 );
262 0 : fprintf (fp, "Key-Info-Length: %lu\n", keyinfolen);
263 : /* fixme: check bounds */
264 0 : p = buffer + 20;
265 0 : for (n=0; n < nkeys; n++, p += keyinfolen)
266 : {
267 : ulong kidoff, kflags;
268 :
269 0 : fprintf (fp, "Key-Fpr[%lu]: ", n );
270 0 : for (i=0; i < 20; i++ )
271 0 : fprintf (fp, "%02X", p[i]);
272 0 : kidoff = get32 (p + 20);
273 0 : fprintf (fp, "\nKey-Kid-Off[%lu]: %lu\n", n, kidoff );
274 0 : fprintf (fp, "Key-Kid[%lu]: ", n );
275 : /* fixme: check bounds */
276 0 : for (i=0; i < 8; i++ )
277 0 : fprintf (fp, "%02X", buffer[kidoff+i] );
278 0 : kflags = get16 (p + 24 );
279 0 : fprintf( fp, "\nKey-Flags[%lu]: %04lX\n", n, kflags);
280 : }
281 :
282 : /* serial number */
283 0 : fputs ("Serial-No: ", fp);
284 0 : nserial = get16 (p);
285 0 : p += 2;
286 0 : if (!nserial)
287 0 : fputs ("none", fp);
288 : else
289 : {
290 0 : for (; nserial; nserial--, p++)
291 0 : fprintf (fp, "%02X", *p);
292 : }
293 0 : putc ('\n', fp);
294 :
295 : /* user IDs */
296 0 : nuids = get16 (p);
297 0 : fprintf (fp, "Uid-Count: %lu\n", nuids );
298 0 : uidinfolen = get16 (p + 2);
299 0 : fprintf (fp, "Uid-Info-Length: %lu\n", uidinfolen);
300 : /* fixme: check bounds */
301 0 : p += 4;
302 0 : for (n=0; n < nuids; n++, p += uidinfolen)
303 : {
304 : ulong uidoff, uidlen, uflags;
305 :
306 0 : uidoff = get32( p );
307 0 : uidlen = get32( p+4 );
308 0 : if (type == KEYBOX_BLOBTYPE_X509 && !n)
309 : {
310 0 : fprintf (fp, "Issuer-Off: %lu\n", uidoff );
311 0 : fprintf (fp, "Issuer-Len: %lu\n", uidlen );
312 0 : fprintf (fp, "Issuer: \"");
313 : }
314 0 : else if (type == KEYBOX_BLOBTYPE_X509 && n == 1)
315 : {
316 0 : fprintf (fp, "Subject-Off: %lu\n", uidoff );
317 0 : fprintf (fp, "Subject-Len: %lu\n", uidlen );
318 0 : fprintf (fp, "Subject: \"");
319 : }
320 : else
321 : {
322 0 : fprintf (fp, "Uid-Off[%lu]: %lu\n", n, uidoff );
323 0 : fprintf (fp, "Uid-Len[%lu]: %lu\n", n, uidlen );
324 0 : fprintf (fp, "Uid[%lu]: \"", n );
325 : }
326 0 : print_string (fp, buffer+uidoff, uidlen, '\"');
327 0 : fputs ("\"\n", fp);
328 0 : uflags = get16 (p + 8);
329 0 : if (type == KEYBOX_BLOBTYPE_X509 && !n)
330 : {
331 0 : fprintf (fp, "Issuer-Flags: %04lX\n", uflags );
332 0 : fprintf (fp, "Issuer-Validity: %d\n", p[10] );
333 : }
334 0 : else if (type == KEYBOX_BLOBTYPE_X509 && n == 1)
335 : {
336 0 : fprintf (fp, "Subject-Flags: %04lX\n", uflags );
337 0 : fprintf (fp, "Subject-Validity: %d\n", p[10] );
338 : }
339 : else
340 : {
341 0 : fprintf (fp, "Uid-Flags[%lu]: %04lX\n", n, uflags );
342 0 : fprintf (fp, "Uid-Validity[%lu]: %d\n", n, p[10] );
343 : }
344 : }
345 :
346 0 : nsigs = get16 (p);
347 0 : fprintf (fp, "Sig-Count: %lu\n", nsigs );
348 0 : siginfolen = get16 (p + 2);
349 0 : fprintf (fp, "Sig-Info-Length: %lu\n", siginfolen );
350 : /* fixme: check bounds */
351 0 : p += 4;
352 : {
353 0 : int in_range = 0;
354 0 : ulong first = 0;
355 :
356 0 : for (n=0; n < nsigs; n++, p += siginfolen)
357 : {
358 : ulong sflags;
359 :
360 0 : sflags = get32 (p);
361 0 : if (!in_range && !sflags)
362 : {
363 0 : in_range = 1;
364 0 : first = n;
365 0 : continue;
366 : }
367 0 : if (in_range && !sflags)
368 0 : continue;
369 0 : if (in_range)
370 : {
371 0 : fprintf (fp, "Sig-Expire[%lu-%lu]: [not checked]\n", first, n-1);
372 0 : in_range = 0;
373 : }
374 :
375 0 : fprintf (fp, "Sig-Expire[%lu]: ", n );
376 0 : if (!sflags)
377 0 : fputs ("[not checked]", fp);
378 0 : else if (sflags == 1 )
379 0 : fputs ("[missing key]", fp);
380 0 : else if (sflags == 2 )
381 0 : fputs ("[bad signature]", fp);
382 0 : else if (sflags < 0x10000000)
383 0 : fprintf (fp, "[bad flag %0lx]", sflags);
384 0 : else if (sflags == (ulong)(-1))
385 0 : fputs ("[good - does not expire]", fp );
386 : else
387 0 : fprintf (fp, "[good - expires at %lu]", sflags);
388 0 : putc ('\n', fp );
389 : }
390 0 : if (in_range)
391 : {
392 0 : fprintf (fp, "Sig-Expire[%lu-%lu]: [not checked]\n", first, n-1);
393 0 : in_range = 0;
394 : }
395 : }
396 0 : fprintf (fp, "Ownertrust: %d\n", p[0] );
397 0 : fprintf (fp, "All-Validity: %d\n", p[1] );
398 0 : p += 4;
399 0 : n = get32 (p); p += 4;
400 0 : fprintf (fp, "Recheck-After: %lu\n", n );
401 0 : n = get32 (p ); p += 4;
402 0 : fprintf( fp, "Latest-Timestamp: %lu\n", n );
403 0 : n = get32 (p ); p += 4;
404 0 : fprintf (fp, "Created-At: %lu\n", n );
405 0 : n = get32 (p ); p += 4;
406 0 : fprintf (fp, "Reserved-Space: %lu\n", n );
407 :
408 0 : if (n >= 4 && unhashed >= 24)
409 : {
410 0 : n = get32 ( buffer + length - unhashed);
411 0 : fprintf (fp, "Storage-Flags: %08lx\n", n );
412 : }
413 0 : print_checksum (buffer, length, unhashed, fp);
414 0 : return 0;
415 : }
416 :
417 :
418 : /* Compute the SHA-1 checksum of the rawdata in BLOB and put it into
419 : DIGEST. */
420 : static int
421 0 : hash_blob_rawdata (KEYBOXBLOB blob, unsigned char *digest)
422 : {
423 : const unsigned char *buffer;
424 : size_t n, length;
425 : int type;
426 : ulong rawdata_off, rawdata_len;
427 :
428 0 : buffer = _keybox_get_blob_image (blob, &length);
429 :
430 0 : if (length < 32)
431 0 : return -1;
432 0 : n = get32 (buffer);
433 0 : if (n < length)
434 0 : length = n; /* Blob larger than length in header - ignore the rest. */
435 :
436 0 : type = buffer[4];
437 0 : switch (type)
438 : {
439 : case KEYBOX_BLOBTYPE_PGP:
440 : case KEYBOX_BLOBTYPE_X509:
441 0 : break;
442 :
443 : case KEYBOX_BLOBTYPE_EMPTY:
444 : case KEYBOX_BLOBTYPE_HEADER:
445 : default:
446 0 : memset (digest, 0, 20);
447 0 : return 0;
448 : }
449 :
450 0 : if (length < 40)
451 0 : return -1;
452 :
453 0 : rawdata_off = get32 (buffer + 8);
454 0 : rawdata_len = get32 (buffer + 12);
455 :
456 0 : if (rawdata_off > length || rawdata_len > length
457 0 : || rawdata_off+rawdata_off > length)
458 0 : return -1; /* Out of bounds. */
459 :
460 0 : gcry_md_hash_buffer (GCRY_MD_SHA1, digest, buffer+rawdata_off, rawdata_len);
461 0 : return 0;
462 : }
463 :
464 :
465 : struct file_stats_s
466 : {
467 : unsigned long too_short_blobs;
468 : unsigned long too_large_blobs;
469 : unsigned long total_blob_count;
470 : unsigned long empty_blob_count;
471 : unsigned long header_blob_count;
472 : unsigned long pgp_blob_count;
473 : unsigned long x509_blob_count;
474 : unsigned long unknown_blob_count;
475 : unsigned long non_flagged;
476 : unsigned long secret_flagged;
477 : unsigned long ephemeral_flagged;
478 : unsigned long skipped_long_blobs;
479 : };
480 :
481 : static int
482 0 : update_stats (KEYBOXBLOB blob, struct file_stats_s *s)
483 : {
484 : const unsigned char *buffer;
485 : size_t length;
486 : int type;
487 : unsigned long n;
488 :
489 0 : buffer = _keybox_get_blob_image (blob, &length);
490 0 : if (length < 32)
491 : {
492 0 : s->too_short_blobs++;
493 0 : return -1;
494 : }
495 :
496 0 : n = get32( buffer );
497 0 : if (n > length)
498 0 : s->too_large_blobs++;
499 : else
500 0 : length = n; /* ignore the rest */
501 :
502 0 : s->total_blob_count++;
503 0 : type = buffer[4];
504 0 : switch (type)
505 : {
506 : case KEYBOX_BLOBTYPE_EMPTY:
507 0 : s->empty_blob_count++;
508 0 : return 0;
509 : case KEYBOX_BLOBTYPE_HEADER:
510 0 : s->header_blob_count++;
511 0 : return 0;
512 : case KEYBOX_BLOBTYPE_PGP:
513 0 : s->pgp_blob_count++;
514 0 : break;
515 : case KEYBOX_BLOBTYPE_X509:
516 0 : s->x509_blob_count++;
517 0 : break;
518 : default:
519 0 : s->unknown_blob_count++;
520 0 : return 0;
521 : }
522 :
523 0 : if (length < 40)
524 : {
525 0 : s->too_short_blobs++;
526 0 : return -1;
527 : }
528 :
529 0 : n = get16 (buffer + 6);
530 0 : if (n)
531 : {
532 0 : if ((n & 1))
533 0 : s->secret_flagged++;
534 0 : if ((n & 2))
535 0 : s->ephemeral_flagged++;
536 : }
537 : else
538 0 : s->non_flagged++;
539 :
540 0 : return 0;
541 : }
542 :
543 :
544 :
545 : static FILE *
546 0 : open_file (const char **filename, FILE *outfp)
547 : {
548 : FILE *fp;
549 :
550 0 : if (!*filename)
551 : {
552 0 : *filename = "-";
553 0 : fp = stdin;
554 : }
555 : else
556 0 : fp = fopen (*filename, "rb");
557 0 : if (!fp)
558 : {
559 0 : int save_errno = errno;
560 0 : fprintf (outfp, "can't open '%s': %s\n", *filename, strerror(errno));
561 0 : gpg_err_set_errno (save_errno);
562 : }
563 0 : return fp;
564 : }
565 :
566 :
567 :
568 : int
569 0 : _keybox_dump_file (const char *filename, int stats_only, FILE *outfp)
570 : {
571 : FILE *fp;
572 : KEYBOXBLOB blob;
573 : int rc;
574 0 : unsigned long count = 0;
575 : struct file_stats_s stats;
576 :
577 0 : memset (&stats, 0, sizeof stats);
578 :
579 0 : if (!(fp = open_file (&filename, outfp)))
580 0 : return gpg_error_from_syserror ();
581 :
582 : for (;;)
583 : {
584 0 : rc = _keybox_read_blob (&blob, fp);
585 0 : if (gpg_err_code (rc) == GPG_ERR_TOO_LARGE
586 0 : && gpg_err_source (rc) == GPG_ERR_SOURCE_KEYBOX)
587 : {
588 0 : if (stats_only)
589 0 : stats.skipped_long_blobs++;
590 : else
591 : {
592 0 : fprintf (outfp, "BEGIN-RECORD: %lu\n", count );
593 0 : fprintf (outfp, "# Record too large\nEND-RECORD\n");
594 : }
595 0 : count++;
596 0 : continue;
597 : }
598 0 : if (rc)
599 0 : break;
600 :
601 0 : if (stats_only)
602 : {
603 0 : update_stats (blob, &stats);
604 : }
605 : else
606 : {
607 0 : fprintf (outfp, "BEGIN-RECORD: %lu\n", count );
608 0 : _keybox_dump_blob (blob, outfp);
609 0 : fprintf (outfp, "END-RECORD\n");
610 : }
611 0 : _keybox_release_blob (blob);
612 0 : count++;
613 0 : }
614 0 : if (rc == -1)
615 0 : rc = 0;
616 0 : if (rc)
617 0 : fprintf (outfp, "# error reading '%s': %s\n", filename, gpg_strerror (rc));
618 :
619 0 : if (fp != stdin)
620 0 : fclose (fp);
621 :
622 0 : if (stats_only)
623 : {
624 0 : fprintf (outfp,
625 : "Total number of blobs: %8lu\n"
626 : " header: %8lu\n"
627 : " empty: %8lu\n"
628 : " openpgp: %8lu\n"
629 : " x509: %8lu\n"
630 : " non flagged: %8lu\n"
631 : " secret flagged: %8lu\n"
632 : " ephemeral flagged: %8lu\n",
633 : stats.total_blob_count,
634 : stats.header_blob_count,
635 : stats.empty_blob_count,
636 : stats.pgp_blob_count,
637 : stats.x509_blob_count,
638 : stats.non_flagged,
639 : stats.secret_flagged,
640 : stats.ephemeral_flagged);
641 0 : if (stats.skipped_long_blobs)
642 0 : fprintf (outfp, " skipped long blobs: %8lu\n",
643 : stats.skipped_long_blobs);
644 0 : if (stats.unknown_blob_count)
645 0 : fprintf (outfp, " unknown blob types: %8lu\n",
646 : stats.unknown_blob_count);
647 0 : if (stats.too_short_blobs)
648 0 : fprintf (outfp, " too short blobs: %8lu (error)\n",
649 : stats.too_short_blobs);
650 0 : if (stats.too_large_blobs)
651 0 : fprintf (outfp, " too large blobs: %8lu (error)\n",
652 : stats.too_large_blobs);
653 : }
654 :
655 0 : return rc;
656 : }
657 :
658 :
659 :
660 : struct dupitem_s
661 : {
662 : unsigned long recno;
663 : unsigned char digest[20];
664 : };
665 :
666 :
667 : static int
668 0 : cmp_dupitems (const void *arg_a, const void *arg_b)
669 : {
670 0 : struct dupitem_s *a = (struct dupitem_s *)arg_a;
671 0 : struct dupitem_s *b = (struct dupitem_s *)arg_b;
672 :
673 0 : return memcmp (a->digest, b->digest, 20);
674 : }
675 :
676 :
677 : int
678 0 : _keybox_dump_find_dups (const char *filename, int print_them, FILE *outfp)
679 : {
680 : FILE *fp;
681 : KEYBOXBLOB blob;
682 : int rc;
683 0 : unsigned long recno = 0;
684 : unsigned char zerodigest[20];
685 : struct dupitem_s *dupitems;
686 : size_t dupitems_size, dupitems_count, lastn, n;
687 : char fprbuf[3*20+1];
688 :
689 : (void)print_them;
690 :
691 0 : memset (zerodigest, 0, sizeof zerodigest);
692 :
693 0 : if (!(fp = open_file (&filename, outfp)))
694 0 : return gpg_error_from_syserror ();
695 :
696 0 : dupitems_size = 1000;
697 0 : dupitems = malloc (dupitems_size * sizeof *dupitems);
698 0 : if (!dupitems)
699 : {
700 0 : gpg_error_t tmperr = gpg_error_from_syserror ();
701 0 : fprintf (outfp, "error allocating array for '%s': %s\n",
702 0 : filename, strerror(errno));
703 0 : return tmperr;
704 : }
705 0 : dupitems_count = 0;
706 :
707 0 : while ( !(rc = _keybox_read_blob (&blob, fp)) )
708 : {
709 : unsigned char digest[20];
710 :
711 0 : if (hash_blob_rawdata (blob, digest))
712 0 : fprintf (outfp, "error in blob %ld of '%s'\n", recno, filename);
713 0 : else if (memcmp (digest, zerodigest, 20))
714 : {
715 0 : if (dupitems_count >= dupitems_size)
716 : {
717 : struct dupitem_s *tmp;
718 :
719 0 : dupitems_size += 1000;
720 0 : tmp = realloc (dupitems, dupitems_size * sizeof *dupitems);
721 0 : if (!tmp)
722 : {
723 0 : gpg_error_t tmperr = gpg_error_from_syserror ();
724 0 : fprintf (outfp, "error reallocating array for '%s': %s\n",
725 0 : filename, strerror(errno));
726 0 : free (dupitems);
727 0 : return tmperr;
728 : }
729 0 : dupitems = tmp;
730 : }
731 0 : dupitems[dupitems_count].recno = recno;
732 0 : memcpy (dupitems[dupitems_count].digest, digest, 20);
733 0 : dupitems_count++;
734 : }
735 0 : _keybox_release_blob (blob);
736 0 : recno++;
737 : }
738 0 : if (rc == -1)
739 0 : rc = 0;
740 0 : if (rc)
741 0 : fprintf (outfp, "error reading '%s': %s\n", filename, gpg_strerror (rc));
742 0 : if (fp != stdin)
743 0 : fclose (fp);
744 :
745 0 : qsort (dupitems, dupitems_count, sizeof *dupitems, cmp_dupitems);
746 :
747 0 : for (lastn=0, n=1; n < dupitems_count; lastn=n, n++)
748 : {
749 0 : if (!memcmp (dupitems[lastn].digest, dupitems[n].digest, 20))
750 : {
751 0 : bin2hexcolon (dupitems[lastn].digest, 20, fprbuf);
752 0 : fprintf (outfp, "fpr=%s recno=%lu", fprbuf, dupitems[lastn].recno);
753 : do
754 0 : fprintf (outfp, " %lu", dupitems[n].recno);
755 : while (++n < dupitems_count
756 0 : && !memcmp (dupitems[lastn].digest, dupitems[n].digest, 20));
757 0 : putc ('\n', outfp);
758 0 : n--;
759 : }
760 : }
761 :
762 0 : free (dupitems);
763 :
764 0 : return rc;
765 : }
766 :
767 :
768 : /* Print records with record numbers FROM to TO to OUTFP. */
769 : int
770 0 : _keybox_dump_cut_records (const char *filename, unsigned long from,
771 : unsigned long to, FILE *outfp)
772 : {
773 : FILE *fp;
774 : KEYBOXBLOB blob;
775 : int rc;
776 0 : unsigned long recno = 0;
777 :
778 0 : if (!(fp = open_file (&filename, stderr)))
779 0 : return gpg_error_from_syserror ();
780 :
781 0 : while ( !(rc = _keybox_read_blob (&blob, fp)) )
782 : {
783 0 : if (recno > to)
784 0 : break; /* Ready. */
785 0 : if (recno >= from)
786 : {
787 0 : if ((rc = _keybox_write_blob (blob, outfp)))
788 : {
789 0 : fprintf (stderr, "error writing output: %s\n",
790 : gpg_strerror (rc));
791 0 : goto leave;
792 : }
793 : }
794 0 : _keybox_release_blob (blob);
795 0 : recno++;
796 : }
797 0 : if (rc == -1)
798 0 : rc = 0;
799 0 : if (rc)
800 0 : fprintf (stderr, "error reading '%s': %s\n", filename, gpg_strerror (rc));
801 : leave:
802 0 : if (fp != stdin)
803 0 : fclose (fp);
804 0 : return rc;
805 : }
|