1 /* keybox-update.c - keybox update operations
2  * Copyright (C) 2001, 2003, 2004, 2012 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 <https://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 #include <time.h>
26 #include <unistd.h>
27 #include <assert.h>
28 
29 #include "keybox-defs.h"
30 #include "../common/sysutils.h"
31 #include "../common/host2net.h"
32 #include "../common/utilproto.h"
33 
34 #define EXTSEP_S "."
35 
36 #define FILECOPY_INSERT 1
37 #define FILECOPY_DELETE 2
38 #define FILECOPY_UPDATE 3
39 
40 
41 #if !defined(HAVE_FSEEKO) && !defined(fseeko)
42 
43 #ifdef HAVE_LIMITS_H
44 # include <limits.h>
45 #endif
46 #ifndef LONG_MAX
47 # define LONG_MAX ((long) ((unsigned long) -1 >> 1))
48 #endif
49 #ifndef LONG_MIN
50 # define LONG_MIN (-1 - LONG_MAX)
51 #endif
52 
53 /****************
54  * A substitute for fseeko, for hosts that don't have it.
55  */
56 static int
fseeko(FILE * stream,off_t newpos,int whence)57 fseeko (FILE * stream, off_t newpos, int whence)
58 {
59   while (newpos != (long) newpos)
60     {
61       long pos = newpos < 0 ? LONG_MIN : LONG_MAX;
62       if (fseek (stream, pos, whence) != 0)
63 	return -1;
64       newpos -= pos;
65       whence = SEEK_CUR;
66     }
67   return fseek (stream, (long) newpos, whence);
68 }
69 #endif /* !defined(HAVE_FSEEKO) && !defined(fseeko) */
70 
71 
72 static int
create_tmp_file(const char * template,char ** r_bakfname,char ** r_tmpfname,estream_t * r_fp)73 create_tmp_file (const char *template,
74                  char **r_bakfname, char **r_tmpfname, estream_t *r_fp)
75 {
76   gpg_error_t err;
77 
78   err = keybox_tmp_names (template, 0, r_bakfname, r_tmpfname);
79   if (!err)
80     {
81       *r_fp = es_fopen (*r_tmpfname, "wb");
82       if (!*r_fp)
83         {
84           err = gpg_error_from_syserror ();
85           xfree (*r_tmpfname);
86           *r_tmpfname = NULL;
87           xfree (*r_bakfname);
88           *r_bakfname = NULL;
89         }
90     }
91 
92   return err;
93 }
94 
95 
96 static int
rename_tmp_file(const char * bakfname,const char * tmpfname,const char * fname,int secret)97 rename_tmp_file (const char *bakfname, const char *tmpfname,
98                  const char *fname, int secret )
99 {
100   int rc=0;
101   int block = 0;
102 
103   /* restrict the permissions for secret keyboxs */
104 #ifndef HAVE_DOSISH_SYSTEM
105 /*    if (secret && !opt.preserve_permissions) */
106 /*      { */
107 /*        if (chmod (tmpfname, S_IRUSR | S_IWUSR) )  */
108 /*          { */
109 /*            log_debug ("chmod of '%s' failed: %s\n", */
110 /*                       tmpfname, strerror(errno) ); */
111 /*            return KEYBOX_Write_File; */
112 /*  	} */
113 /*      } */
114 #endif
115 
116   /* fixme: invalidate close caches (not used with stdio)*/
117 /*    iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)tmpfname ); */
118 /*    iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)bakfname ); */
119 /*    iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname ); */
120 
121   /* First make a backup file except for secret keyboxes. */
122   if (!secret)
123     {
124       block = 1;
125       rc = gnupg_rename_file (fname, bakfname, &block);
126       if (rc)
127         goto leave;
128     }
129 
130   /* Then rename the file. */
131   rc = gnupg_rename_file (tmpfname, fname, NULL);
132   if (block)
133     {
134       gnupg_unblock_all_signals ();
135       block = 0;
136     }
137   /* if (rc) */
138   /*   { */
139   /*     if (secret) */
140   /*       { */
141   /*         log_info ("WARNING: 2 files with confidential" */
142   /*                   " information exists.\n"); */
143   /*         log_info ("%s is the unchanged one\n", fname ); */
144   /*         log_info ("%s is the new one\n", tmpfname ); */
145   /*         log_info ("Please fix this possible security flaw\n"); */
146   /*       } */
147   /*   } */
148 
149  leave:
150   if (block)
151     gnupg_unblock_all_signals ();
152   return rc;
153 }
154 
155 
156 
157 /* Perform insert/delete/update operation.  MODE is one of
158    FILECOPY_INSERT, FILECOPY_DELETE, FILECOPY_UPDATE.  FOR_OPENPGP
159    indicates that this is called due to an OpenPGP keyblock change.  */
160 static int
blob_filecopy(int mode,const char * fname,KEYBOXBLOB blob,int secret,int for_openpgp,off_t start_offset)161 blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
162                int secret, int for_openpgp, off_t start_offset)
163 {
164   gpg_err_code_t ec;
165   estream_t fp, newfp;
166   int rc = 0;
167   char *bakfname = NULL;
168   char *tmpfname = NULL;
169   char buffer[4096];  /* (Must be at least 32 bytes) */
170   int nread, nbytes;
171 
172   /* Open the source file. Because we do a rename, we have to check the
173      permissions of the file */
174   if ((ec = gnupg_access (fname, W_OK)))
175     return gpg_error (ec);
176 
177   fp = es_fopen (fname, "rb");
178   if (mode == FILECOPY_INSERT && !fp && errno == ENOENT)
179     {
180       /* Insert mode but file does not exist:
181          Create a new keybox file. */
182       newfp = es_fopen (fname, "wb");
183       if (!newfp )
184         return gpg_error_from_syserror ();
185 
186       rc = _keybox_write_header_blob (newfp, for_openpgp);
187       if (rc)
188         {
189           es_fclose (newfp);
190           return rc;
191         }
192 
193       rc = _keybox_write_blob (blob, newfp, NULL);
194       if (rc)
195         {
196           es_fclose (newfp);
197           return rc;
198         }
199 
200       if ( es_fclose (newfp) )
201         return gpg_error_from_syserror ();
202 
203 /*        if (chmod( fname, S_IRUSR | S_IWUSR )) */
204 /*          { */
205 /*            log_debug ("%s: chmod failed: %s\n", fname, strerror(errno) ); */
206 /*            return KEYBOX_File_Error; */
207 /*          } */
208       return 0; /* Ready. */
209     }
210 
211   if (!fp)
212     {
213       rc = gpg_error_from_syserror ();
214       goto leave;
215     }
216 
217   /* Create the new file.  On success NEWFP is initialized.  */
218   rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
219   if (rc)
220     {
221       es_fclose (fp);
222       goto leave;
223     }
224 
225   /* prepare for insert */
226   if (mode == FILECOPY_INSERT)
227     {
228       int first_record = 1;
229 
230       /* Copy everything to the new file.  If this is for OpenPGP, we
231          make sure that the openpgp flag is set in the header.  (We
232          failsafe the blob type.) */
233       while ( (nread = es_fread (buffer, 1, DIM(buffer), fp)) > 0 )
234         {
235           if (first_record && for_openpgp
236               && buffer[4] == KEYBOX_BLOBTYPE_HEADER)
237             {
238               first_record = 0;
239               buffer[7] |= 0x02; /* OpenPGP data may be available.  */
240             }
241 
242           if (es_fwrite (buffer, nread, 1, newfp) != 1)
243             {
244               rc = gpg_error_from_syserror ();
245               es_fclose (fp);
246               es_fclose (newfp);
247               goto leave;
248             }
249         }
250       if (es_ferror (fp))
251         {
252           rc = gpg_error_from_syserror ();
253           es_fclose (fp);
254           es_fclose (newfp);
255           goto leave;
256         }
257     }
258 
259   /* Prepare for delete or update. */
260   if ( mode == FILECOPY_DELETE || mode == FILECOPY_UPDATE )
261     {
262       off_t current = 0;
263 
264       /* Copy first part to the new file. */
265       while ( current < start_offset )
266         {
267           nbytes = DIM(buffer);
268           if (current + nbytes > start_offset)
269               nbytes = start_offset - current;
270           nread = es_fread (buffer, 1, nbytes, fp);
271           if (!nread)
272             break;
273           current += nread;
274 
275           if (es_fwrite (buffer, nread, 1, newfp) != 1)
276             {
277               rc = gpg_error_from_syserror ();
278               es_fclose (fp);
279               es_fclose (newfp);
280               goto leave;
281             }
282         }
283       if (es_ferror (fp))
284         {
285           rc = gpg_error_from_syserror ();
286           es_fclose (fp);
287           es_fclose (newfp);
288           goto leave;
289         }
290 
291       /* Skip this blob. */
292       rc = _keybox_read_blob (NULL, fp, NULL);
293       if (rc)
294         {
295           es_fclose (fp);
296           es_fclose (newfp);
297           goto leave;
298         }
299     }
300 
301   /* Do an insert or update. */
302   if ( mode == FILECOPY_INSERT || mode == FILECOPY_UPDATE )
303     {
304       rc = _keybox_write_blob (blob, newfp, NULL);
305       if (rc)
306         {
307           es_fclose (fp);
308           es_fclose (newfp);
309           goto leave;
310         }
311     }
312 
313   /* Copy the rest of the packet for an delete or update. */
314   if (mode == FILECOPY_DELETE || mode == FILECOPY_UPDATE)
315     {
316       while ( (nread = es_fread (buffer, 1, DIM(buffer), fp)) > 0 )
317         {
318           if (es_fwrite (buffer, nread, 1, newfp) != 1)
319             {
320               rc = gpg_error_from_syserror ();
321               es_fclose (fp);
322               es_fclose (newfp);
323               goto leave;
324             }
325         }
326       if (es_ferror (fp))
327         {
328           rc = gpg_error_from_syserror ();
329           es_fclose (fp);
330           es_fclose (newfp);
331           goto leave;
332         }
333     }
334 
335   /* Close both files. */
336   if (es_fclose(fp))
337     {
338       rc = gpg_error_from_syserror ();
339       es_fclose (newfp);
340       goto leave;
341     }
342   if (es_fclose(newfp))
343     {
344       rc = gpg_error_from_syserror ();
345       goto leave;
346     }
347 
348   rc = rename_tmp_file (bakfname, tmpfname, fname, secret);
349 
350  leave:
351   xfree(bakfname);
352   xfree(tmpfname);
353   return rc;
354 }
355 
356 
357 /* Insert the OpenPGP keyblock {IMAGE,IMAGELEN} into HD. */
358 gpg_error_t
keybox_insert_keyblock(KEYBOX_HANDLE hd,const void * image,size_t imagelen)359 keybox_insert_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen)
360 {
361   gpg_error_t err;
362   const char *fname;
363   KEYBOXBLOB blob;
364   size_t nparsed;
365   struct _keybox_openpgp_info info;
366 
367   if (!hd)
368     return gpg_error (GPG_ERR_INV_HANDLE);
369   if (!hd->kb)
370     return gpg_error (GPG_ERR_INV_HANDLE);
371   fname = hd->kb->fname;
372   if (!fname)
373     return gpg_error (GPG_ERR_INV_HANDLE);
374 
375 
376   /* Close this one otherwise we will mess up the position for a next
377      search.  Fixme: it would be better to adjust the position after
378      the write operation.  */
379   _keybox_close_file (hd);
380 
381   err = _keybox_parse_openpgp (image, imagelen, &nparsed, &info);
382   if (err)
383     return err;
384   assert (nparsed <= imagelen);
385   err = _keybox_create_openpgp_blob (&blob, &info, image, imagelen,
386                                       hd->ephemeral);
387   _keybox_destroy_openpgp_info (&info);
388   if (!err)
389     {
390       err = blob_filecopy (FILECOPY_INSERT, fname, blob, hd->secret, 1, 0);
391       _keybox_release_blob (blob);
392       /*    if (!rc && !hd->secret && kb_offtbl) */
393       /*      { */
394       /*        update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */
395       /*      } */
396     }
397   return err;
398 }
399 
400 
401 /* Update the current key at HD with the given OpenPGP keyblock in
402    {IMAGE,IMAGELEN}.  */
403 gpg_error_t
keybox_update_keyblock(KEYBOX_HANDLE hd,const void * image,size_t imagelen)404 keybox_update_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen)
405 {
406   gpg_error_t err;
407   const char *fname;
408   off_t off;
409   KEYBOXBLOB blob;
410   size_t nparsed;
411   struct _keybox_openpgp_info info;
412 
413   if (!hd || !image || !imagelen)
414     return gpg_error (GPG_ERR_INV_VALUE);
415   if (!hd->found.blob)
416     return gpg_error (GPG_ERR_NOTHING_FOUND);
417   if (blob_get_type (hd->found.blob) != KEYBOX_BLOBTYPE_PGP)
418     return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
419   fname = hd->kb->fname;
420   if (!fname)
421     return gpg_error (GPG_ERR_INV_HANDLE);
422 
423   off = _keybox_get_blob_fileoffset (hd->found.blob);
424   if (off == (off_t)-1)
425     return gpg_error (GPG_ERR_GENERAL);
426 
427   /* Close the file so that we do no mess up the position for a
428      next search.  */
429   _keybox_close_file (hd);
430 
431   /* Build a new blob.  */
432   err = _keybox_parse_openpgp (image, imagelen, &nparsed, &info);
433   if (err)
434     return err;
435   assert (nparsed <= imagelen);
436   err = _keybox_create_openpgp_blob (&blob, &info, image, imagelen,
437                                      hd->ephemeral);
438   _keybox_destroy_openpgp_info (&info);
439 
440   /* Update the keyblock.  */
441   if (!err)
442     {
443       err = blob_filecopy (FILECOPY_UPDATE, fname, blob, hd->secret, 1, off);
444       _keybox_release_blob (blob);
445     }
446   return err;
447 }
448 
449 
450 
451 #ifdef KEYBOX_WITH_X509
452 int
keybox_insert_cert(KEYBOX_HANDLE hd,ksba_cert_t cert,unsigned char * sha1_digest)453 keybox_insert_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
454                     unsigned char *sha1_digest)
455 {
456   int rc;
457   const char *fname;
458   KEYBOXBLOB blob;
459 
460   if (!hd)
461     return gpg_error (GPG_ERR_INV_HANDLE);
462   if (!hd->kb)
463     return gpg_error (GPG_ERR_INV_HANDLE);
464   fname = hd->kb->fname;
465   if (!fname)
466     return gpg_error (GPG_ERR_INV_HANDLE);
467 
468   /* Close this one otherwise we will mess up the position for a next
469      search.  Fixme: it would be better to adjust the position after
470      the write operation.  */
471   _keybox_close_file (hd);
472 
473   rc = _keybox_create_x509_blob (&blob, cert, sha1_digest, hd->ephemeral);
474   if (!rc)
475     {
476       rc = blob_filecopy (FILECOPY_INSERT, fname, blob, hd->secret, 0, 0);
477       _keybox_release_blob (blob);
478       /*    if (!rc && !hd->secret && kb_offtbl) */
479       /*      { */
480       /*        update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */
481       /*      } */
482     }
483   return rc;
484 }
485 
486 int
keybox_update_cert(KEYBOX_HANDLE hd,ksba_cert_t cert,unsigned char * sha1_digest)487 keybox_update_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
488                     unsigned char *sha1_digest)
489 {
490   (void)hd;
491   (void)cert;
492   (void)sha1_digest;
493   return -1;
494 }
495 
496 
497 #endif /*KEYBOX_WITH_X509*/
498 
499 /* Note: We assume that the keybox has been locked before the current
500    search was executed.  This is needed so that we can depend on the
501    offset information of the flags. */
502 int
keybox_set_flags(KEYBOX_HANDLE hd,int what,int idx,unsigned int value)503 keybox_set_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int value)
504 {
505   off_t off;
506   const char *fname;
507   estream_t fp;
508   gpg_err_code_t ec;
509   size_t flag_pos, flag_size;
510   const unsigned char *buffer;
511   size_t length;
512 
513   (void)idx;  /* Not yet used.  */
514 
515   if (!hd)
516     return gpg_error (GPG_ERR_INV_VALUE);
517   if (!hd->found.blob)
518     return gpg_error (GPG_ERR_NOTHING_FOUND);
519   if (!hd->kb)
520     return gpg_error (GPG_ERR_INV_HANDLE);
521   if (!hd->found.blob)
522     return gpg_error (GPG_ERR_NOTHING_FOUND);
523   fname = hd->kb->fname;
524   if (!fname)
525     return gpg_error (GPG_ERR_INV_HANDLE);
526 
527   off = _keybox_get_blob_fileoffset (hd->found.blob);
528   if (off == (off_t)-1)
529     return gpg_error (GPG_ERR_GENERAL);
530 
531   buffer = _keybox_get_blob_image (hd->found.blob, &length);
532   ec = _keybox_get_flag_location (buffer, length, what, &flag_pos, &flag_size);
533   if (ec)
534     return gpg_error (ec);
535 
536   off += flag_pos;
537 
538   _keybox_close_file (hd);
539   fp = es_fopen (hd->kb->fname, "r+b");
540   if (!fp)
541     return gpg_error_from_syserror ();
542 
543   ec = 0;
544   if (es_fseeko (fp, off, SEEK_SET))
545     ec = gpg_err_code_from_syserror ();
546   else
547     {
548       unsigned char tmp[4];
549 
550       tmp[0] = value >> 24;
551       tmp[1] = value >> 16;
552       tmp[2] = value >>  8;
553       tmp[3] = value;
554 
555       switch (flag_size)
556         {
557         case 1:
558         case 2:
559         case 4:
560           if (es_fwrite (tmp+4-flag_size, flag_size, 1, fp) != 1)
561             ec = gpg_err_code_from_syserror ();
562           break;
563         default:
564           ec = GPG_ERR_BUG;
565           break;
566         }
567     }
568 
569   if (es_fclose (fp))
570     {
571       if (!ec)
572         ec = gpg_err_code_from_syserror ();
573     }
574 
575   return gpg_error (ec);
576 }
577 
578 
579 
580 int
keybox_delete(KEYBOX_HANDLE hd)581 keybox_delete (KEYBOX_HANDLE hd)
582 {
583   off_t off;
584   const char *fname;
585   estream_t fp;
586   int rc;
587 
588   if (!hd)
589     return gpg_error (GPG_ERR_INV_VALUE);
590   if (!hd->found.blob)
591     return gpg_error (GPG_ERR_NOTHING_FOUND);
592   if (!hd->kb)
593     return gpg_error (GPG_ERR_INV_HANDLE);
594   fname = hd->kb->fname;
595   if (!fname)
596     return gpg_error (GPG_ERR_INV_HANDLE);
597 
598   off = _keybox_get_blob_fileoffset (hd->found.blob);
599   if (off == (off_t)-1)
600     return gpg_error (GPG_ERR_GENERAL);
601   off += 4;
602 
603   _keybox_close_file (hd);
604   fp = es_fopen (hd->kb->fname, "r+b");
605   if (!fp)
606     return gpg_error_from_syserror ();
607 
608   if (es_fseeko (fp, off, SEEK_SET))
609     rc = gpg_error_from_syserror ();
610   else if (es_fputc (0, fp) == EOF)
611     rc = gpg_error_from_syserror ();
612   else
613     rc = 0;
614 
615   if (es_fclose (fp))
616     {
617       if (!rc)
618         rc = gpg_error_from_syserror ();
619     }
620 
621   return rc;
622 }
623 
624 
625 /* Compress the keybox file.  This should be run with the file
626    locked. */
627 int
keybox_compress(KEYBOX_HANDLE hd)628 keybox_compress (KEYBOX_HANDLE hd)
629 {
630   gpg_err_code_t ec;
631   int read_rc, rc;
632   const char *fname;
633   estream_t fp, newfp;
634   char *bakfname = NULL;
635   char *tmpfname = NULL;
636   int first_blob;
637   KEYBOXBLOB blob = NULL;
638   u32 cut_time;
639   int any_changes = 0;
640   int skipped_deleted;
641 
642   if (!hd)
643     return gpg_error (GPG_ERR_INV_HANDLE);
644   if (!hd->kb)
645     return gpg_error (GPG_ERR_INV_HANDLE);
646   if (hd->secret)
647     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
648   fname = hd->kb->fname;
649   if (!fname)
650     return gpg_error (GPG_ERR_INV_HANDLE);
651 
652   _keybox_close_file (hd);
653 
654   /* Open the source file. Because we do a rename, we have to check the
655      permissions of the file */
656   if ((ec = gnupg_access (fname, W_OK)))
657     return gpg_error (ec);
658 
659   fp = es_fopen (fname, "rb");
660   if (!fp && errno == ENOENT)
661     return 0; /* Ready. File has been deleted right after the access above. */
662   if (!fp)
663     {
664       rc = gpg_error_from_syserror ();
665       return rc;
666     }
667 
668   /* A quick test to see if we need to compress the file at all.  We
669      schedule a compress run after 3 hours. */
670   if ( !_keybox_read_blob (&blob, fp, NULL) )
671     {
672       const unsigned char *buffer;
673       size_t length;
674 
675       buffer = _keybox_get_blob_image (blob, &length);
676       if (length > 4 && buffer[4] == KEYBOX_BLOBTYPE_HEADER)
677         {
678           u32 last_maint = buf32_to_u32 (buffer+20);
679 
680           if ( (last_maint + 3*3600) > make_timestamp () )
681             {
682               es_fclose (fp);
683               _keybox_release_blob (blob);
684               return 0; /* Compress run not yet needed. */
685             }
686         }
687       _keybox_release_blob (blob);
688       es_fseek (fp, 0, SEEK_SET);
689       es_clearerr (fp);
690     }
691 
692   /* Create the new file. */
693   rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
694   if (rc)
695     {
696       es_fclose (fp);
697       return rc;;
698     }
699 
700 
701   /* Processing loop.  By reading using _keybox_read_blob we
702      automagically skip any blobs flagged as deleted.  Thus what we
703      only have to do is to check all ephemeral flagged blocks whether
704      their time has come and write out all other blobs. */
705   cut_time = make_timestamp () - 86400;
706   first_blob = 1;
707   skipped_deleted = 0;
708   for (rc=0; !(read_rc = _keybox_read_blob (&blob, fp, &skipped_deleted));
709        _keybox_release_blob (blob), blob = NULL )
710     {
711       unsigned int blobflags;
712       const unsigned char *buffer;
713       size_t length, pos, size;
714       u32 created_at;
715 
716       if (skipped_deleted)
717         any_changes = 1;
718       buffer = _keybox_get_blob_image (blob, &length);
719       if (first_blob)
720         {
721           first_blob = 0;
722           if (length > 4 && buffer[4] == KEYBOX_BLOBTYPE_HEADER)
723             {
724               /* Write out the blob with an updated maintenance time
725                  stamp and if needed (ie. used by gpg) set the openpgp
726                  flag.  */
727               _keybox_update_header_blob (blob, hd->for_openpgp);
728               rc = _keybox_write_blob (blob, newfp, NULL);
729               if (rc)
730                 break;
731               continue;
732             }
733 
734           /* The header blob is missing.  Insert it.  */
735           rc = _keybox_write_header_blob (newfp, hd->for_openpgp);
736           if (rc)
737             break;
738           any_changes = 1;
739         }
740       else if (length > 4 && buffer[4] == KEYBOX_BLOBTYPE_HEADER)
741         {
742           /* Oops: There is another header record - remove it. */
743           any_changes = 1;
744           continue;
745         }
746 
747       if (_keybox_get_flag_location (buffer, length,
748                                      KEYBOX_FLAG_BLOB, &pos, &size)
749           || size != 2)
750         {
751           rc = gpg_error (GPG_ERR_BUG);
752           break;
753         }
754       blobflags = buf16_to_uint (buffer+pos);
755       if ((blobflags & KEYBOX_FLAG_BLOB_EPHEMERAL))
756         {
757           /* This is an ephemeral blob. */
758           if (_keybox_get_flag_location (buffer, length,
759                                          KEYBOX_FLAG_CREATED_AT, &pos, &size)
760               || size != 4)
761             created_at = 0; /* oops. */
762           else
763             created_at = buf32_to_u32 (buffer+pos);
764 
765           if (created_at && created_at < cut_time)
766             {
767               any_changes = 1;
768               continue; /* Skip this blob. */
769             }
770         }
771 
772       rc = _keybox_write_blob (blob, newfp, NULL);
773       if (rc)
774         break;
775     }
776   if (skipped_deleted)
777     any_changes = 1;
778   _keybox_release_blob (blob); blob = NULL;
779   if (!rc && read_rc == -1)
780     rc = 0;
781   else if (!rc)
782     rc = read_rc;
783 
784   /* Close both files. */
785   if (es_fclose(fp) && !rc)
786     rc = gpg_error_from_syserror ();
787   if (es_fclose(newfp) && !rc)
788     rc = gpg_error_from_syserror ();
789 
790   /* Rename or remove the temporary file. */
791   if (rc || !any_changes)
792     gnupg_remove (tmpfname);
793   else
794     rc = rename_tmp_file (bakfname, tmpfname, fname, hd->secret);
795 
796   xfree(bakfname);
797   xfree(tmpfname);
798   return rc;
799 }
800