gpg: First working support for keyboxes.
[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.  */
375 gpg_error_t
376 keybox_insert_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen)
377 {
378   gpg_error_t err;
379   const char *fname;
380   KEYBOXBLOB blob;
381   size_t nparsed;
382   struct _keybox_openpgp_info info;
383
384   if (!hd)
385     return gpg_error (GPG_ERR_INV_HANDLE);
386   if (!hd->kb)
387     return gpg_error (GPG_ERR_INV_HANDLE);
388   fname = hd->kb->fname;
389   if (!fname)
390     return gpg_error (GPG_ERR_INV_HANDLE);
391
392
393   /* Close this one otherwise we will mess up the position for a next
394      search.  Fixme: it would be better to adjust the position after
395      the write operation.  */
396   _keybox_close_file (hd);
397
398   err = _keybox_parse_openpgp (image, imagelen, &nparsed, &info);
399   if (err)
400     return err;
401   assert (nparsed <= imagelen);
402   err = _keybox_create_openpgp_blob (&blob, &info, image, imagelen,
403                                      hd->ephemeral);
404   _keybox_destroy_openpgp_info (&info);
405   if (!err)
406     {
407       err = blob_filecopy (1, fname, blob, hd->secret, 0);
408       _keybox_release_blob (blob);
409       /*    if (!rc && !hd->secret && kb_offtbl) */
410       /*      { */
411       /*        update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */
412       /*      } */
413     }
414   return err;
415 }
416
417
418 /* Update the current key at HD with the given OpenPGP keyblock in
419    {IMAGE,IMAGELEN}.  */
420 gpg_error_t
421 keybox_update_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen)
422 {
423   (void)hd;
424   (void)image;
425   (void)imagelen;
426   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
427 }
428
429
430
431 #ifdef KEYBOX_WITH_X509
432 int
433 keybox_insert_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
434                     unsigned char *sha1_digest)
435 {
436   int rc;
437   const char *fname;
438   KEYBOXBLOB blob;
439
440   if (!hd)
441     return gpg_error (GPG_ERR_INV_HANDLE);
442   if (!hd->kb)
443     return gpg_error (GPG_ERR_INV_HANDLE);
444   fname = hd->kb->fname;
445   if (!fname)
446     return gpg_error (GPG_ERR_INV_HANDLE);
447
448   /* Close this one otherwise we will mess up the position for a next
449      search.  Fixme: it would be better to adjust the position after
450      the write operation.  */
451   _keybox_close_file (hd);
452
453   rc = _keybox_create_x509_blob (&blob, cert, sha1_digest, hd->ephemeral);
454   if (!rc)
455     {
456       rc = blob_filecopy (1, fname, blob, hd->secret, 0);
457       _keybox_release_blob (blob);
458       /*    if (!rc && !hd->secret && kb_offtbl) */
459       /*      { */
460       /*        update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */
461       /*      } */
462     }
463   return rc;
464 }
465
466 int
467 keybox_update_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
468                     unsigned char *sha1_digest)
469 {
470   (void)hd;
471   (void)cert;
472   (void)sha1_digest;
473   return -1;
474 }
475
476
477 #endif /*KEYBOX_WITH_X509*/
478
479 /* Note: We assume that the keybox has been locked before the current
480    search was executed.  This is needed so that we can depend on the
481    offset information of the flags. */
482 int
483 keybox_set_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int value)
484 {
485   off_t off;
486   const char *fname;
487   FILE *fp;
488   gpg_err_code_t ec;
489   size_t flag_pos, flag_size;
490   const unsigned char *buffer;
491   size_t length;
492
493   (void)idx;  /* Not yet used.  */
494
495   if (!hd)
496     return gpg_error (GPG_ERR_INV_VALUE);
497   if (!hd->found.blob)
498     return gpg_error (GPG_ERR_NOTHING_FOUND);
499   if (!hd->kb)
500     return gpg_error (GPG_ERR_INV_HANDLE);
501   if (!hd->found.blob)
502     return gpg_error (GPG_ERR_NOTHING_FOUND);
503   fname = hd->kb->fname;
504   if (!fname)
505     return gpg_error (GPG_ERR_INV_HANDLE);
506
507   off = _keybox_get_blob_fileoffset (hd->found.blob);
508   if (off == (off_t)-1)
509     return gpg_error (GPG_ERR_GENERAL);
510
511   buffer = _keybox_get_blob_image (hd->found.blob, &length);
512   ec = _keybox_get_flag_location (buffer, length, what, &flag_pos, &flag_size);
513   if (ec)
514     return gpg_error (ec);
515
516   off += flag_pos;
517
518   _keybox_close_file (hd);
519   fp = fopen (hd->kb->fname, "r+b");
520   if (!fp)
521     return gpg_error_from_syserror ();
522
523   ec = 0;
524   if (fseeko (fp, off, SEEK_SET))
525     ec = gpg_error_from_syserror ();
526   else
527     {
528       unsigned char tmp[4];
529
530       tmp[0] = value >> 24;
531       tmp[1] = value >> 16;
532       tmp[2] = value >>  8;
533       tmp[3] = value;
534
535       switch (flag_size)
536         {
537         case 1:
538         case 2:
539         case 4:
540           if (fwrite (tmp+4-flag_size, flag_size, 1, fp) != 1)
541             ec = gpg_err_code_from_syserror ();
542           break;
543         default:
544           ec = GPG_ERR_BUG;
545           break;
546         }
547     }
548
549   if (fclose (fp))
550     {
551       if (!ec)
552         ec = gpg_err_code_from_syserror ();
553     }
554
555   return gpg_error (ec);
556 }
557
558
559
560 int
561 keybox_delete (KEYBOX_HANDLE hd)
562 {
563   off_t off;
564   const char *fname;
565   FILE *fp;
566   int rc;
567
568   if (!hd)
569     return gpg_error (GPG_ERR_INV_VALUE);
570   if (!hd->found.blob)
571     return gpg_error (GPG_ERR_NOTHING_FOUND);
572   if (!hd->kb)
573     return gpg_error (GPG_ERR_INV_HANDLE);
574   fname = hd->kb->fname;
575   if (!fname)
576     return gpg_error (GPG_ERR_INV_HANDLE);
577
578   off = _keybox_get_blob_fileoffset (hd->found.blob);
579   if (off == (off_t)-1)
580     return gpg_error (GPG_ERR_GENERAL);
581   off += 4;
582
583   _keybox_close_file (hd);
584   fp = fopen (hd->kb->fname, "r+b");
585   if (!fp)
586     return gpg_error_from_syserror ();
587
588   if (fseeko (fp, off, SEEK_SET))
589     rc = gpg_error_from_syserror ();
590   else if (putc (0, fp) == EOF)
591     rc = gpg_error_from_syserror ();
592   else
593     rc = 0;
594
595   if (fclose (fp))
596     {
597       if (!rc)
598         rc = gpg_error_from_syserror ();
599     }
600
601   return rc;
602 }
603
604
605 /* Compress the keybox file.  This should be run with the file
606    locked. */
607 int
608 keybox_compress (KEYBOX_HANDLE hd)
609 {
610   int read_rc, rc;
611   const char *fname;
612   FILE *fp, *newfp;
613   char *bakfname = NULL;
614   char *tmpfname = NULL;
615   int first_blob;
616   KEYBOXBLOB blob = NULL;
617   u32 cut_time;
618   int any_changes = 0;
619   int skipped_deleted;
620
621   if (!hd)
622     return gpg_error (GPG_ERR_INV_HANDLE);
623   if (!hd->kb)
624     return gpg_error (GPG_ERR_INV_HANDLE);
625   if (hd->secret)
626     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
627   fname = hd->kb->fname;
628   if (!fname)
629     return gpg_error (GPG_ERR_INV_HANDLE);
630
631   _keybox_close_file (hd);
632
633   /* Open the source file. Because we do a rename, we have to check the
634      permissions of the file */
635   if (access (fname, W_OK))
636     return gpg_error_from_syserror ();
637
638   fp = fopen (fname, "rb");
639   if (!fp && errno == ENOENT)
640     return 0; /* Ready. File has been deleted right after the access above. */
641   if (!fp)
642     {
643       rc = gpg_error_from_syserror ();
644       return rc;
645     }
646
647   /* A quick test to see if we need to compress the file at all.  We
648      schedule a compress run after 3 hours. */
649   if ( !_keybox_read_blob (&blob, fp) )
650     {
651       const unsigned char *buffer;
652       size_t length;
653
654       buffer = _keybox_get_blob_image (blob, &length);
655       if (length > 4 && buffer[4] == BLOBTYPE_HEADER)
656         {
657           u32 last_maint = ((buffer[20] << 24) | (buffer[20+1] << 16)
658                             | (buffer[20+2] << 8) | (buffer[20+3]));
659
660           if ( (last_maint + 3*3600) > time (NULL) )
661             {
662               fclose (fp);
663               _keybox_release_blob (blob);
664               return 0; /* Compress run not yet needed. */
665             }
666         }
667       _keybox_release_blob (blob);
668       fseek (fp, 0, SEEK_SET);
669       clearerr (fp);
670     }
671
672   /* Create the new file. */
673   rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
674   if (rc)
675     {
676       fclose(fp);
677       return rc;;
678     }
679
680
681   /* Processing loop.  By reading using _keybox_read_blob we
682      automagically skip any blobs flagged as deleted.  Thus what we
683      only have to do is to check all ephemeral flagged blocks whether
684      their time has come and write out all other blobs. */
685   cut_time = time(NULL) - 86400;
686   first_blob = 1;
687   skipped_deleted = 0;
688   for (rc=0; !(read_rc = _keybox_read_blob2 (&blob, fp, &skipped_deleted));
689        _keybox_release_blob (blob), blob = NULL )
690     {
691       unsigned int blobflags;
692       const unsigned char *buffer;
693       size_t length, pos, size;
694       u32 created_at;
695
696       if (skipped_deleted)
697         any_changes = 1;
698       buffer = _keybox_get_blob_image (blob, &length);
699       if (first_blob)
700         {
701           first_blob = 0;
702           if (length > 4 && buffer[4] == BLOBTYPE_HEADER)
703             {
704               /* Write out the blob with an updated maintenance time stamp. */
705               _keybox_update_header_blob (blob);
706               rc = _keybox_write_blob (blob, newfp);
707               if (rc)
708                 break;
709               continue;
710             }
711
712           /* The header blob is missing.  Insert it.  */
713           rc = _keybox_write_header_blob (newfp);
714           if (rc)
715             break;
716           any_changes = 1;
717         }
718       else if (length > 4 && buffer[4] == BLOBTYPE_HEADER)
719         {
720           /* Oops: There is another header record - remove it. */
721           any_changes = 1;
722           continue;
723         }
724
725       if (_keybox_get_flag_location (buffer, length,
726                                      KEYBOX_FLAG_BLOB, &pos, &size)
727           || size != 2)
728         {
729           rc = gpg_error (GPG_ERR_BUG);
730           break;
731         }
732       blobflags = ((buffer[pos] << 8) | (buffer[pos+1]));
733       if ((blobflags & KEYBOX_FLAG_BLOB_EPHEMERAL))
734         {
735           /* This is an ephemeral blob. */
736           if (_keybox_get_flag_location (buffer, length,
737                                          KEYBOX_FLAG_CREATED_AT, &pos, &size)
738               || size != 4)
739             created_at = 0; /* oops. */
740           else
741             created_at = ((buffer[pos] << 24) | (buffer[pos+1] << 16)
742                           | (buffer[pos+2] << 8) | (buffer[pos+3]));
743
744           if (created_at && created_at < cut_time)
745             {
746               any_changes = 1;
747               continue; /* Skip this blob. */
748             }
749         }
750
751       rc = _keybox_write_blob (blob, newfp);
752       if (rc)
753         break;
754     }
755   if (skipped_deleted)
756     any_changes = 1;
757   _keybox_release_blob (blob); blob = NULL;
758   if (!rc && read_rc == -1)
759     rc = 0;
760   else if (!rc)
761     rc = read_rc;
762
763   /* Close both files. */
764   if (fclose(fp) && !rc)
765     rc = gpg_error_from_syserror ();
766   if (fclose(newfp) && !rc)
767     rc = gpg_error_from_syserror ();
768
769   /* Rename or remove the temporary file. */
770   if (rc || !any_changes)
771     gnupg_remove (tmpfname);
772   else
773     rc = rename_tmp_file (bakfname, tmpfname, fname, hd->secret);
774
775   xfree(bakfname);
776   xfree(tmpfname);
777   return rc;
778 }