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