gpg,gpgsm: Block signals during keyring/keybox update.
[gnupg.git] / kbx / keybox-update.c
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 <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 #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
33 #define EXTSEP_S "."
34
35 #define FILECOPY_INSERT 1
36 #define FILECOPY_DELETE 2
37 #define FILECOPY_UPDATE 3
38
39
40 #if !defined(HAVE_FSEEKO) && !defined(fseeko)
41
42 #ifdef HAVE_LIMITS_H
43 # include <limits.h>
44 #endif
45 #ifndef LONG_MAX
46 # define LONG_MAX ((long) ((unsigned long) -1 >> 1))
47 #endif
48 #ifndef LONG_MIN
49 # define LONG_MIN (-1 - LONG_MAX)
50 #endif
51
52 /****************
53  * A substitute for fseeko, for hosts that don't have it.
54  */
55 static int
56 fseeko (FILE * stream, off_t newpos, int whence)
57 {
58   while (newpos != (long) newpos)
59     {
60       long pos = newpos < 0 ? LONG_MIN : LONG_MAX;
61       if (fseek (stream, pos, whence) != 0)
62         return -1;
63       newpos -= pos;
64       whence = SEEK_CUR;
65     }
66   return fseek (stream, (long) newpos, whence);
67 }
68 #endif /* !defined(HAVE_FSEEKO) && !defined(fseeko) */
69
70
71 static int
72 create_tmp_file (const char *template,
73                  char **r_bakfname, char **r_tmpfname, FILE **r_fp)
74 {
75   gpg_error_t err;
76
77   err = keybox_tmp_names (template, 0, r_bakfname, r_tmpfname);
78   if (!err)
79     {
80       *r_fp = fopen (*r_tmpfname, "wb");
81       if (!*r_fp)
82         {
83           err = gpg_error_from_syserror ();
84           xfree (*r_tmpfname);
85           *r_tmpfname = NULL;
86           xfree (*r_bakfname);
87           *r_bakfname = NULL;
88         }
89     }
90
91   return err;
92 }
93
94
95 static int
96 rename_tmp_file (const char *bakfname, const char *tmpfname,
97                  const char *fname, int secret )
98 {
99   int rc=0;
100   int block = 0;
101
102   /* restrict the permissions for secret keyboxs */
103 #ifndef HAVE_DOSISH_SYSTEM
104 /*    if (secret && !opt.preserve_permissions) */
105 /*      { */
106 /*        if (chmod (tmpfname, S_IRUSR | S_IWUSR) )  */
107 /*          { */
108 /*            log_debug ("chmod of '%s' failed: %s\n", */
109 /*                       tmpfname, strerror(errno) ); */
110 /*            return KEYBOX_Write_File; */
111 /*      } */
112 /*      } */
113 #endif
114
115   /* fixme: invalidate close caches (not used with stdio)*/
116 /*    iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)tmpfname ); */
117 /*    iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)bakfname ); */
118 /*    iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname ); */
119
120   /* First make a backup file except for secret keyboxes. */
121   if (!secret)
122     {
123       block = 1;
124       rc = keybox_file_rename (fname, bakfname, &block);
125       if (rc)
126         goto leave;
127     }
128
129   /* Then rename the file. */
130   rc = keybox_file_rename (tmpfname, fname, NULL);
131   if (block)
132     {
133       gnupg_unblock_all_signals ();
134       block = 0;
135     }
136   /* if (rc) */
137   /*   { */
138   /*     if (secret) */
139   /*       { */
140   /*         log_info ("WARNING: 2 files with confidential" */
141   /*                   " information exists.\n"); */
142   /*         log_info ("%s is the unchanged one\n", fname ); */
143   /*         log_info ("%s is the new one\n", tmpfname ); */
144   /*         log_info ("Please fix this possible security flaw\n"); */
145   /*       } */
146   /*   } */
147
148  leave:
149   if (block)
150     gnupg_unblock_all_signals ();
151   return rc;
152 }
153
154
155
156 /* Perform insert/delete/update operation.  MODE is one of
157    FILECOPY_INSERT, FILECOPY_DELETE, FILECOPY_UPDATE.  FOR_OPENPGP
158    indicates that this is called due to an OpenPGP keyblock change.  */
159 static int
160 blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
161                int secret, int for_openpgp, off_t start_offset)
162 {
163   FILE *fp, *newfp;
164   int rc=0;
165   char *bakfname = NULL;
166   char *tmpfname = NULL;
167   char buffer[4096];  /* (Must be at least 32 bytes) */
168   int nread, nbytes;
169
170   /* Open the source file. Because we do a rename, we have to check the
171      permissions of the file */
172   if (access (fname, W_OK))
173     return gpg_error_from_syserror ();
174
175   fp = fopen (fname, "rb");
176   if (mode == FILECOPY_INSERT && !fp && errno == ENOENT)
177     {
178       /* Insert mode but file does not exist:
179          Create a new keybox file. */
180       newfp = fopen (fname, "wb");
181       if (!newfp )
182         return gpg_error_from_syserror ();
183
184       rc = _keybox_write_header_blob (newfp, for_openpgp);
185       if (rc)
186         {
187           fclose (newfp);
188           return rc;
189         }
190
191       rc = _keybox_write_blob (blob, newfp);
192       if (rc)
193         {
194           fclose (newfp);
195           return rc;
196         }
197
198       if ( fclose (newfp) )
199         return gpg_error_from_syserror ();
200
201 /*        if (chmod( fname, S_IRUSR | S_IWUSR )) */
202 /*          { */
203 /*            log_debug ("%s: chmod failed: %s\n", fname, strerror(errno) ); */
204 /*            return KEYBOX_File_Error; */
205 /*          } */
206       return 0; /* Ready. */
207     }
208
209   if (!fp)
210     {
211       rc = gpg_error_from_syserror ();
212       goto leave;
213     }
214
215   /* Create the new file.  On success NEWFP is initialized.  */
216   rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
217   if (rc)
218     {
219       fclose (fp);
220       goto leave;
221     }
222
223   /* prepare for insert */
224   if (mode == FILECOPY_INSERT)
225     {
226       int first_record = 1;
227
228       /* Copy everything to the new file.  If this is for OpenPGP, we
229          make sure that the openpgp flag is set in the header.  (We
230          failsafe the blob type.) */
231       while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
232         {
233           if (first_record && for_openpgp
234               && buffer[4] == KEYBOX_BLOBTYPE_HEADER)
235             {
236               first_record = 0;
237               buffer[7] |= 0x02; /* OpenPGP data may be available.  */
238             }
239
240           if (fwrite (buffer, nread, 1, newfp) != 1)
241             {
242               rc = gpg_error_from_syserror ();
243               fclose (fp);
244               fclose (newfp);
245               goto leave;
246             }
247         }
248       if (ferror (fp))
249         {
250           rc = gpg_error_from_syserror ();
251           fclose (fp);
252           fclose (newfp);
253           goto leave;
254         }
255     }
256
257   /* Prepare for delete or update. */
258   if ( mode == FILECOPY_DELETE || mode == FILECOPY_UPDATE )
259     {
260       off_t current = 0;
261
262       /* Copy first part to the new file. */
263       while ( current < start_offset )
264         {
265           nbytes = DIM(buffer);
266           if (current + nbytes > start_offset)
267               nbytes = start_offset - current;
268           nread = fread (buffer, 1, nbytes, fp);
269           if (!nread)
270             break;
271           current += nread;
272
273           if (fwrite (buffer, nread, 1, newfp) != 1)
274             {
275               rc = gpg_error_from_syserror ();
276               fclose (fp);
277               fclose (newfp);
278               goto leave;
279             }
280         }
281       if (ferror (fp))
282         {
283           rc = gpg_error_from_syserror ();
284           fclose (fp);
285           fclose (newfp);
286           goto leave;
287         }
288
289       /* Skip this blob. */
290       rc = _keybox_read_blob (NULL, fp);
291       if (rc)
292         {
293           fclose (fp);
294           fclose (newfp);
295           return rc;
296         }
297     }
298
299   /* Do an insert or update. */
300   if ( mode == FILECOPY_INSERT || mode == FILECOPY_UPDATE )
301     {
302       rc = _keybox_write_blob (blob, newfp);
303       if (rc)
304         {
305           fclose (fp);
306           fclose (newfp);
307           return rc;
308         }
309     }
310
311   /* Copy the rest of the packet for an delete or update. */
312   if (mode == FILECOPY_DELETE || mode == FILECOPY_UPDATE)
313     {
314       while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
315         {
316           if (fwrite (buffer, nread, 1, newfp) != 1)
317             {
318               rc = gpg_error_from_syserror ();
319               fclose (fp);
320               fclose (newfp);
321               goto leave;
322             }
323         }
324       if (ferror (fp))
325         {
326           rc = gpg_error_from_syserror ();
327           fclose (fp);
328           fclose (newfp);
329           goto leave;
330         }
331     }
332
333   /* Close both files. */
334   if (fclose(fp))
335     {
336       rc = gpg_error_from_syserror ();
337       fclose (newfp);
338       goto leave;
339     }
340   if (fclose(newfp))
341     {
342       rc = gpg_error_from_syserror ();
343       goto leave;
344     }
345
346   rc = rename_tmp_file (bakfname, tmpfname, fname, secret);
347
348  leave:
349   xfree(bakfname);
350   xfree(tmpfname);
351   return rc;
352 }
353
354
355 /* Insert the OpenPGP keyblock {IMAGE,IMAGELEN} into HD.  SIGSTATUS is
356    a vector describing the status of the signatures; its first element
357    gives the number of following elements.  */
358 gpg_error_t
359 keybox_insert_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen,
360                         u32 *sigstatus)
361 {
362   gpg_error_t err;
363   const char *fname;
364   KEYBOXBLOB blob;
365   size_t nparsed;
366   struct _keybox_openpgp_info info;
367
368   if (!hd)
369     return gpg_error (GPG_ERR_INV_HANDLE);
370   if (!hd->kb)
371     return gpg_error (GPG_ERR_INV_HANDLE);
372   fname = hd->kb->fname;
373   if (!fname)
374     return gpg_error (GPG_ERR_INV_HANDLE);
375
376
377   /* Close this one otherwise we will mess up the position for a next
378      search.  Fixme: it would be better to adjust the position after
379      the write operation.  */
380   _keybox_close_file (hd);
381
382   err = _keybox_parse_openpgp (image, imagelen, &nparsed, &info);
383   if (err)
384     return err;
385   assert (nparsed <= imagelen);
386   err = _keybox_create_openpgp_blob (&blob, &info, image, imagelen,
387                                      sigstatus, hd->ephemeral);
388   _keybox_destroy_openpgp_info (&info);
389   if (!err)
390     {
391       err = blob_filecopy (FILECOPY_INSERT, fname, blob, hd->secret, 1, 0);
392       _keybox_release_blob (blob);
393       /*    if (!rc && !hd->secret && kb_offtbl) */
394       /*      { */
395       /*        update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */
396       /*      } */
397     }
398   return err;
399 }
400
401
402 /* Update the current key at HD with the given OpenPGP keyblock in
403    {IMAGE,IMAGELEN}.  */
404 gpg_error_t
405 keybox_update_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen)
406 {
407   gpg_error_t err;
408   const char *fname;
409   off_t off;
410   KEYBOXBLOB blob;
411   size_t nparsed;
412   struct _keybox_openpgp_info info;
413
414   if (!hd || !image || !imagelen)
415     return gpg_error (GPG_ERR_INV_VALUE);
416   if (!hd->found.blob)
417     return gpg_error (GPG_ERR_NOTHING_FOUND);
418   if (blob_get_type (hd->found.blob) != KEYBOX_BLOBTYPE_PGP)
419     return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
420   fname = hd->kb->fname;
421   if (!fname)
422     return gpg_error (GPG_ERR_INV_HANDLE);
423
424   off = _keybox_get_blob_fileoffset (hd->found.blob);
425   if (off == (off_t)-1)
426     return gpg_error (GPG_ERR_GENERAL);
427
428   /* Close this the file so that we do no mess up the position for a
429      next search.  */
430   _keybox_close_file (hd);
431
432   /* Build a new blob.  */
433   err = _keybox_parse_openpgp (image, imagelen, &nparsed, &info);
434   if (err)
435     return err;
436   assert (nparsed <= imagelen);
437   err = _keybox_create_openpgp_blob (&blob, &info, image, imagelen,
438                                      NULL, hd->ephemeral);
439   _keybox_destroy_openpgp_info (&info);
440
441   /* Update the keyblock.  */
442   if (!err)
443     {
444       err = blob_filecopy (FILECOPY_UPDATE, fname, blob, hd->secret, 1, off);
445       _keybox_release_blob (blob);
446     }
447   return err;
448 }
449
450
451
452 #ifdef KEYBOX_WITH_X509
453 int
454 keybox_insert_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
455                     unsigned char *sha1_digest)
456 {
457   int rc;
458   const char *fname;
459   KEYBOXBLOB blob;
460
461   if (!hd)
462     return gpg_error (GPG_ERR_INV_HANDLE);
463   if (!hd->kb)
464     return gpg_error (GPG_ERR_INV_HANDLE);
465   fname = hd->kb->fname;
466   if (!fname)
467     return gpg_error (GPG_ERR_INV_HANDLE);
468
469   /* Close this one otherwise we will mess up the position for a next
470      search.  Fixme: it would be better to adjust the position after
471      the write operation.  */
472   _keybox_close_file (hd);
473
474   rc = _keybox_create_x509_blob (&blob, cert, sha1_digest, hd->ephemeral);
475   if (!rc)
476     {
477       rc = blob_filecopy (FILECOPY_INSERT, fname, blob, hd->secret, 0, 0);
478       _keybox_release_blob (blob);
479       /*    if (!rc && !hd->secret && kb_offtbl) */
480       /*      { */
481       /*        update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */
482       /*      } */
483     }
484   return rc;
485 }
486
487 int
488 keybox_update_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
489                     unsigned char *sha1_digest)
490 {
491   (void)hd;
492   (void)cert;
493   (void)sha1_digest;
494   return -1;
495 }
496
497
498 #endif /*KEYBOX_WITH_X509*/
499
500 /* Note: We assume that the keybox has been locked before the current
501    search was executed.  This is needed so that we can depend on the
502    offset information of the flags. */
503 int
504 keybox_set_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int value)
505 {
506   off_t off;
507   const char *fname;
508   FILE *fp;
509   gpg_err_code_t ec;
510   size_t flag_pos, flag_size;
511   const unsigned char *buffer;
512   size_t length;
513
514   (void)idx;  /* Not yet used.  */
515
516   if (!hd)
517     return gpg_error (GPG_ERR_INV_VALUE);
518   if (!hd->found.blob)
519     return gpg_error (GPG_ERR_NOTHING_FOUND);
520   if (!hd->kb)
521     return gpg_error (GPG_ERR_INV_HANDLE);
522   if (!hd->found.blob)
523     return gpg_error (GPG_ERR_NOTHING_FOUND);
524   fname = hd->kb->fname;
525   if (!fname)
526     return gpg_error (GPG_ERR_INV_HANDLE);
527
528   off = _keybox_get_blob_fileoffset (hd->found.blob);
529   if (off == (off_t)-1)
530     return gpg_error (GPG_ERR_GENERAL);
531
532   buffer = _keybox_get_blob_image (hd->found.blob, &length);
533   ec = _keybox_get_flag_location (buffer, length, what, &flag_pos, &flag_size);
534   if (ec)
535     return gpg_error (ec);
536
537   off += flag_pos;
538
539   _keybox_close_file (hd);
540   fp = fopen (hd->kb->fname, "r+b");
541   if (!fp)
542     return gpg_error_from_syserror ();
543
544   ec = 0;
545   if (fseeko (fp, off, SEEK_SET))
546     ec = gpg_err_code_from_syserror ();
547   else
548     {
549       unsigned char tmp[4];
550
551       tmp[0] = value >> 24;
552       tmp[1] = value >> 16;
553       tmp[2] = value >>  8;
554       tmp[3] = value;
555
556       switch (flag_size)
557         {
558         case 1:
559         case 2:
560         case 4:
561           if (fwrite (tmp+4-flag_size, flag_size, 1, fp) != 1)
562             ec = gpg_err_code_from_syserror ();
563           break;
564         default:
565           ec = GPG_ERR_BUG;
566           break;
567         }
568     }
569
570   if (fclose (fp))
571     {
572       if (!ec)
573         ec = gpg_err_code_from_syserror ();
574     }
575
576   return gpg_error (ec);
577 }
578
579
580
581 int
582 keybox_delete (KEYBOX_HANDLE hd)
583 {
584   off_t off;
585   const char *fname;
586   FILE *fp;
587   int rc;
588
589   if (!hd)
590     return gpg_error (GPG_ERR_INV_VALUE);
591   if (!hd->found.blob)
592     return gpg_error (GPG_ERR_NOTHING_FOUND);
593   if (!hd->kb)
594     return gpg_error (GPG_ERR_INV_HANDLE);
595   fname = hd->kb->fname;
596   if (!fname)
597     return gpg_error (GPG_ERR_INV_HANDLE);
598
599   off = _keybox_get_blob_fileoffset (hd->found.blob);
600   if (off == (off_t)-1)
601     return gpg_error (GPG_ERR_GENERAL);
602   off += 4;
603
604   _keybox_close_file (hd);
605   fp = fopen (hd->kb->fname, "r+b");
606   if (!fp)
607     return gpg_error_from_syserror ();
608
609   if (fseeko (fp, off, SEEK_SET))
610     rc = gpg_error_from_syserror ();
611   else if (putc (0, fp) == EOF)
612     rc = gpg_error_from_syserror ();
613   else
614     rc = 0;
615
616   if (fclose (fp))
617     {
618       if (!rc)
619         rc = gpg_error_from_syserror ();
620     }
621
622   return rc;
623 }
624
625
626 /* Compress the keybox file.  This should be run with the file
627    locked. */
628 int
629 keybox_compress (KEYBOX_HANDLE hd)
630 {
631   int read_rc, rc;
632   const char *fname;
633   FILE *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 (access (fname, W_OK))
657     return gpg_error_from_syserror ();
658
659   fp = 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) )
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) > time (NULL) )
681             {
682               fclose (fp);
683               _keybox_release_blob (blob);
684               return 0; /* Compress run not yet needed. */
685             }
686         }
687       _keybox_release_blob (blob);
688       fseek (fp, 0, SEEK_SET);
689       clearerr (fp);
690     }
691
692   /* Create the new file. */
693   rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
694   if (rc)
695     {
696       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 = time(NULL) - 86400;
706   first_blob = 1;
707   skipped_deleted = 0;
708   for (rc=0; !(read_rc = _keybox_read_blob2 (&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);
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);
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 (fclose(fp) && !rc)
786     rc = gpg_error_from_syserror ();
787   if (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 }