LCOV - code coverage report
Current view: top level - kbx - keybox-dump.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 407 0.0 %
Date: 2015-11-05 17:10:59 Functions: 0 11 0.0 %

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

Generated by: LCOV version 1.11