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