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