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