Line data Source code
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 165 : create_tmp_file (const char *template,
74 : char **r_bakfname, char **r_tmpfname, FILE **r_fp)
75 : {
76 : gpg_error_t err;
77 :
78 165 : err = keybox_tmp_names (template, 0, r_bakfname, r_tmpfname);
79 165 : if (!err)
80 : {
81 165 : *r_fp = fopen (*r_tmpfname, "wb");
82 165 : if (!*r_fp)
83 : {
84 0 : err = gpg_error_from_syserror ();
85 0 : xfree (*r_tmpfname);
86 0 : *r_tmpfname = NULL;
87 0 : xfree (*r_bakfname);
88 0 : *r_bakfname = NULL;
89 : }
90 : }
91 :
92 165 : return err;
93 : }
94 :
95 :
96 : static int
97 165 : rename_tmp_file (const char *bakfname, const char *tmpfname,
98 : const char *fname, int secret )
99 : {
100 165 : int rc=0;
101 165 : 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 165 : if (!secret)
123 : {
124 165 : block = 1;
125 165 : rc = gnupg_rename_file (fname, bakfname, &block);
126 165 : if (rc)
127 0 : goto leave;
128 : }
129 :
130 : /* Then rename the file. */
131 165 : rc = gnupg_rename_file (tmpfname, fname, NULL);
132 165 : if (block)
133 : {
134 165 : gnupg_unblock_all_signals ();
135 165 : 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 165 : if (block)
151 0 : gnupg_unblock_all_signals ();
152 165 : 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 165 : 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 165 : int rc=0;
166 165 : char *bakfname = NULL;
167 165 : 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 165 : if (access (fname, W_OK))
174 0 : return gpg_error_from_syserror ();
175 :
176 165 : fp = fopen (fname, "rb");
177 165 : if (mode == FILECOPY_INSERT && !fp && errno == ENOENT)
178 : {
179 : /* Insert mode but file does not exist:
180 : Create a new keybox file. */
181 0 : newfp = fopen (fname, "wb");
182 0 : if (!newfp )
183 0 : return gpg_error_from_syserror ();
184 :
185 0 : rc = _keybox_write_header_blob (newfp, for_openpgp);
186 0 : if (rc)
187 : {
188 0 : fclose (newfp);
189 0 : return rc;
190 : }
191 :
192 0 : rc = _keybox_write_blob (blob, newfp);
193 0 : if (rc)
194 : {
195 0 : fclose (newfp);
196 0 : return rc;
197 : }
198 :
199 0 : if ( fclose (newfp) )
200 0 : 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 0 : return 0; /* Ready. */
208 : }
209 :
210 165 : if (!fp)
211 : {
212 0 : rc = gpg_error_from_syserror ();
213 0 : goto leave;
214 : }
215 :
216 : /* Create the new file. On success NEWFP is initialized. */
217 165 : rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
218 165 : if (rc)
219 : {
220 0 : fclose (fp);
221 0 : goto leave;
222 : }
223 :
224 : /* prepare for insert */
225 165 : if (mode == FILECOPY_INSERT)
226 : {
227 153 : 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 2588 : while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
233 : {
234 2282 : if (first_record && for_openpgp
235 150 : && buffer[4] == KEYBOX_BLOBTYPE_HEADER)
236 : {
237 150 : first_record = 0;
238 150 : buffer[7] |= 0x02; /* OpenPGP data may be available. */
239 : }
240 :
241 2282 : if (fwrite (buffer, nread, 1, newfp) != 1)
242 : {
243 0 : rc = gpg_error_from_syserror ();
244 0 : fclose (fp);
245 0 : fclose (newfp);
246 0 : goto leave;
247 : }
248 : }
249 153 : if (ferror (fp))
250 : {
251 0 : rc = gpg_error_from_syserror ();
252 0 : fclose (fp);
253 0 : fclose (newfp);
254 0 : goto leave;
255 : }
256 : }
257 :
258 : /* Prepare for delete or update. */
259 165 : if ( mode == FILECOPY_DELETE || mode == FILECOPY_UPDATE )
260 : {
261 12 : off_t current = 0;
262 :
263 : /* Copy first part to the new file. */
264 45 : while ( current < start_offset )
265 : {
266 21 : nbytes = DIM(buffer);
267 21 : if (current + nbytes > start_offset)
268 12 : nbytes = start_offset - current;
269 21 : nread = fread (buffer, 1, nbytes, fp);
270 21 : if (!nread)
271 0 : break;
272 21 : current += nread;
273 :
274 21 : if (fwrite (buffer, nread, 1, newfp) != 1)
275 : {
276 0 : rc = gpg_error_from_syserror ();
277 0 : fclose (fp);
278 0 : fclose (newfp);
279 0 : goto leave;
280 : }
281 : }
282 12 : if (ferror (fp))
283 : {
284 0 : rc = gpg_error_from_syserror ();
285 0 : fclose (fp);
286 0 : fclose (newfp);
287 0 : goto leave;
288 : }
289 :
290 : /* Skip this blob. */
291 12 : rc = _keybox_read_blob (NULL, fp);
292 12 : if (rc)
293 : {
294 0 : fclose (fp);
295 0 : fclose (newfp);
296 0 : return rc;
297 : }
298 : }
299 :
300 : /* Do an insert or update. */
301 165 : if ( mode == FILECOPY_INSERT || mode == FILECOPY_UPDATE )
302 : {
303 165 : rc = _keybox_write_blob (blob, newfp);
304 165 : if (rc)
305 : {
306 0 : fclose (fp);
307 0 : fclose (newfp);
308 0 : return rc;
309 : }
310 : }
311 :
312 : /* Copy the rest of the packet for an delete or update. */
313 165 : if (mode == FILECOPY_DELETE || mode == FILECOPY_UPDATE)
314 : {
315 38 : while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
316 : {
317 14 : if (fwrite (buffer, nread, 1, newfp) != 1)
318 : {
319 0 : rc = gpg_error_from_syserror ();
320 0 : fclose (fp);
321 0 : fclose (newfp);
322 0 : goto leave;
323 : }
324 : }
325 12 : if (ferror (fp))
326 : {
327 0 : rc = gpg_error_from_syserror ();
328 0 : fclose (fp);
329 0 : fclose (newfp);
330 0 : goto leave;
331 : }
332 : }
333 :
334 : /* Close both files. */
335 165 : if (fclose(fp))
336 : {
337 0 : rc = gpg_error_from_syserror ();
338 0 : fclose (newfp);
339 0 : goto leave;
340 : }
341 165 : if (fclose(newfp))
342 : {
343 0 : rc = gpg_error_from_syserror ();
344 0 : goto leave;
345 : }
346 :
347 165 : rc = rename_tmp_file (bakfname, tmpfname, fname, secret);
348 :
349 : leave:
350 165 : xfree(bakfname);
351 165 : xfree(tmpfname);
352 165 : 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 150 : 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 150 : if (!hd)
370 0 : return gpg_error (GPG_ERR_INV_HANDLE);
371 150 : if (!hd->kb)
372 0 : return gpg_error (GPG_ERR_INV_HANDLE);
373 150 : fname = hd->kb->fname;
374 150 : if (!fname)
375 0 : 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 150 : _keybox_close_file (hd);
382 :
383 150 : err = _keybox_parse_openpgp (image, imagelen, &nparsed, &info);
384 150 : if (err)
385 0 : return err;
386 150 : assert (nparsed <= imagelen);
387 150 : err = _keybox_create_openpgp_blob (&blob, &info, image, imagelen,
388 : sigstatus, hd->ephemeral);
389 150 : _keybox_destroy_openpgp_info (&info);
390 150 : if (!err)
391 : {
392 150 : err = blob_filecopy (FILECOPY_INSERT, fname, blob, hd->secret, 1, 0);
393 150 : _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 150 : 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 12 : 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 12 : if (!hd || !image || !imagelen)
416 0 : return gpg_error (GPG_ERR_INV_VALUE);
417 12 : if (!hd->found.blob)
418 0 : return gpg_error (GPG_ERR_NOTHING_FOUND);
419 12 : if (blob_get_type (hd->found.blob) != KEYBOX_BLOBTYPE_PGP)
420 0 : return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
421 12 : fname = hd->kb->fname;
422 12 : if (!fname)
423 0 : return gpg_error (GPG_ERR_INV_HANDLE);
424 :
425 12 : off = _keybox_get_blob_fileoffset (hd->found.blob);
426 12 : if (off == (off_t)-1)
427 0 : 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 12 : _keybox_close_file (hd);
432 :
433 : /* Build a new blob. */
434 12 : err = _keybox_parse_openpgp (image, imagelen, &nparsed, &info);
435 12 : if (err)
436 0 : return err;
437 12 : assert (nparsed <= imagelen);
438 12 : err = _keybox_create_openpgp_blob (&blob, &info, image, imagelen,
439 : NULL, hd->ephemeral);
440 12 : _keybox_destroy_openpgp_info (&info);
441 :
442 : /* Update the keyblock. */
443 12 : if (!err)
444 : {
445 12 : err = blob_filecopy (FILECOPY_UPDATE, fname, blob, hd->secret, 1, off);
446 12 : _keybox_release_blob (blob);
447 : }
448 12 : return err;
449 : }
450 :
451 :
452 :
453 : #ifdef KEYBOX_WITH_X509
454 : int
455 3 : 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 3 : if (!hd)
463 0 : return gpg_error (GPG_ERR_INV_HANDLE);
464 3 : if (!hd->kb)
465 0 : return gpg_error (GPG_ERR_INV_HANDLE);
466 3 : fname = hd->kb->fname;
467 3 : if (!fname)
468 0 : 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 3 : _keybox_close_file (hd);
474 :
475 3 : rc = _keybox_create_x509_blob (&blob, cert, sha1_digest, hd->ephemeral);
476 3 : if (!rc)
477 : {
478 3 : rc = blob_filecopy (FILECOPY_INSERT, fname, blob, hd->secret, 0, 0);
479 3 : _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 3 : return rc;
486 : }
487 :
488 : int
489 0 : 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 0 : 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 0 : 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 0 : if (!hd)
518 0 : return gpg_error (GPG_ERR_INV_VALUE);
519 0 : if (!hd->found.blob)
520 0 : return gpg_error (GPG_ERR_NOTHING_FOUND);
521 0 : if (!hd->kb)
522 0 : return gpg_error (GPG_ERR_INV_HANDLE);
523 0 : if (!hd->found.blob)
524 0 : return gpg_error (GPG_ERR_NOTHING_FOUND);
525 0 : fname = hd->kb->fname;
526 0 : if (!fname)
527 0 : return gpg_error (GPG_ERR_INV_HANDLE);
528 :
529 0 : off = _keybox_get_blob_fileoffset (hd->found.blob);
530 0 : if (off == (off_t)-1)
531 0 : return gpg_error (GPG_ERR_GENERAL);
532 :
533 0 : buffer = _keybox_get_blob_image (hd->found.blob, &length);
534 0 : ec = _keybox_get_flag_location (buffer, length, what, &flag_pos, &flag_size);
535 0 : if (ec)
536 0 : return gpg_error (ec);
537 :
538 0 : off += flag_pos;
539 :
540 0 : _keybox_close_file (hd);
541 0 : fp = fopen (hd->kb->fname, "r+b");
542 0 : if (!fp)
543 0 : return gpg_error_from_syserror ();
544 :
545 0 : ec = 0;
546 0 : if (fseeko (fp, off, SEEK_SET))
547 0 : ec = gpg_err_code_from_syserror ();
548 : else
549 : {
550 : unsigned char tmp[4];
551 :
552 0 : tmp[0] = value >> 24;
553 0 : tmp[1] = value >> 16;
554 0 : tmp[2] = value >> 8;
555 0 : tmp[3] = value;
556 :
557 0 : switch (flag_size)
558 : {
559 : case 1:
560 : case 2:
561 : case 4:
562 0 : if (fwrite (tmp+4-flag_size, flag_size, 1, fp) != 1)
563 0 : ec = gpg_err_code_from_syserror ();
564 0 : break;
565 : default:
566 0 : ec = GPG_ERR_BUG;
567 0 : break;
568 : }
569 : }
570 :
571 0 : if (fclose (fp))
572 : {
573 0 : if (!ec)
574 0 : ec = gpg_err_code_from_syserror ();
575 : }
576 :
577 0 : return gpg_error (ec);
578 : }
579 :
580 :
581 :
582 : int
583 87 : keybox_delete (KEYBOX_HANDLE hd)
584 : {
585 : off_t off;
586 : const char *fname;
587 : FILE *fp;
588 : int rc;
589 :
590 87 : if (!hd)
591 0 : return gpg_error (GPG_ERR_INV_VALUE);
592 87 : if (!hd->found.blob)
593 0 : return gpg_error (GPG_ERR_NOTHING_FOUND);
594 87 : if (!hd->kb)
595 0 : return gpg_error (GPG_ERR_INV_HANDLE);
596 87 : fname = hd->kb->fname;
597 87 : if (!fname)
598 0 : return gpg_error (GPG_ERR_INV_HANDLE);
599 :
600 87 : off = _keybox_get_blob_fileoffset (hd->found.blob);
601 87 : if (off == (off_t)-1)
602 0 : return gpg_error (GPG_ERR_GENERAL);
603 87 : off += 4;
604 :
605 87 : _keybox_close_file (hd);
606 87 : fp = fopen (hd->kb->fname, "r+b");
607 87 : if (!fp)
608 0 : return gpg_error_from_syserror ();
609 :
610 87 : if (fseeko (fp, off, SEEK_SET))
611 0 : rc = gpg_error_from_syserror ();
612 87 : else if (putc (0, fp) == EOF)
613 0 : rc = gpg_error_from_syserror ();
614 : else
615 87 : rc = 0;
616 :
617 87 : if (fclose (fp))
618 : {
619 0 : if (!rc)
620 0 : rc = gpg_error_from_syserror ();
621 : }
622 :
623 87 : return rc;
624 : }
625 :
626 :
627 : /* Compress the keybox file. This should be run with the file
628 : locked. */
629 : int
630 3 : keybox_compress (KEYBOX_HANDLE hd)
631 : {
632 : int read_rc, rc;
633 : const char *fname;
634 : FILE *fp, *newfp;
635 3 : char *bakfname = NULL;
636 3 : char *tmpfname = NULL;
637 : int first_blob;
638 3 : KEYBOXBLOB blob = NULL;
639 : u32 cut_time;
640 3 : int any_changes = 0;
641 : int skipped_deleted;
642 :
643 3 : if (!hd)
644 0 : return gpg_error (GPG_ERR_INV_HANDLE);
645 3 : if (!hd->kb)
646 0 : return gpg_error (GPG_ERR_INV_HANDLE);
647 3 : if (hd->secret)
648 0 : return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
649 3 : fname = hd->kb->fname;
650 3 : if (!fname)
651 0 : return gpg_error (GPG_ERR_INV_HANDLE);
652 :
653 3 : _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 3 : if (access (fname, W_OK))
658 0 : return gpg_error_from_syserror ();
659 :
660 3 : fp = fopen (fname, "rb");
661 3 : if (!fp && errno == ENOENT)
662 0 : return 0; /* Ready. File has been deleted right after the access above. */
663 3 : if (!fp)
664 : {
665 0 : rc = gpg_error_from_syserror ();
666 0 : 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 3 : if ( !_keybox_read_blob (&blob, fp) )
672 : {
673 : const unsigned char *buffer;
674 : size_t length;
675 :
676 3 : buffer = _keybox_get_blob_image (blob, &length);
677 3 : if (length > 4 && buffer[4] == KEYBOX_BLOBTYPE_HEADER)
678 : {
679 3 : u32 last_maint = buf32_to_u32 (buffer+20);
680 :
681 3 : if ( (last_maint + 3*3600) > time (NULL) )
682 : {
683 3 : fclose (fp);
684 3 : _keybox_release_blob (blob);
685 3 : return 0; /* Compress run not yet needed. */
686 : }
687 : }
688 0 : _keybox_release_blob (blob);
689 0 : fseek (fp, 0, SEEK_SET);
690 0 : clearerr (fp);
691 : }
692 :
693 : /* Create the new file. */
694 0 : rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
695 0 : if (rc)
696 : {
697 0 : fclose (fp);
698 0 : 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 0 : cut_time = time(NULL) - 86400;
707 0 : first_blob = 1;
708 0 : skipped_deleted = 0;
709 0 : for (rc=0; !(read_rc = _keybox_read_blob2 (&blob, fp, &skipped_deleted));
710 0 : _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 0 : if (skipped_deleted)
718 0 : any_changes = 1;
719 0 : buffer = _keybox_get_blob_image (blob, &length);
720 0 : if (first_blob)
721 : {
722 0 : first_blob = 0;
723 0 : 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 0 : _keybox_update_header_blob (blob, hd->for_openpgp);
729 0 : rc = _keybox_write_blob (blob, newfp);
730 0 : if (rc)
731 0 : break;
732 0 : continue;
733 : }
734 :
735 : /* The header blob is missing. Insert it. */
736 0 : rc = _keybox_write_header_blob (newfp, hd->for_openpgp);
737 0 : if (rc)
738 0 : break;
739 0 : any_changes = 1;
740 : }
741 0 : else if (length > 4 && buffer[4] == KEYBOX_BLOBTYPE_HEADER)
742 : {
743 : /* Oops: There is another header record - remove it. */
744 0 : any_changes = 1;
745 0 : continue;
746 : }
747 :
748 0 : if (_keybox_get_flag_location (buffer, length,
749 : KEYBOX_FLAG_BLOB, &pos, &size)
750 0 : || size != 2)
751 : {
752 0 : rc = gpg_error (GPG_ERR_BUG);
753 0 : break;
754 : }
755 0 : blobflags = buf16_to_uint (buffer+pos);
756 0 : if ((blobflags & KEYBOX_FLAG_BLOB_EPHEMERAL))
757 : {
758 : /* This is an ephemeral blob. */
759 0 : if (_keybox_get_flag_location (buffer, length,
760 : KEYBOX_FLAG_CREATED_AT, &pos, &size)
761 0 : || size != 4)
762 0 : created_at = 0; /* oops. */
763 : else
764 0 : created_at = buf32_to_u32 (buffer+pos);
765 :
766 0 : if (created_at && created_at < cut_time)
767 : {
768 0 : any_changes = 1;
769 0 : continue; /* Skip this blob. */
770 : }
771 : }
772 :
773 0 : rc = _keybox_write_blob (blob, newfp);
774 0 : if (rc)
775 0 : break;
776 : }
777 0 : if (skipped_deleted)
778 0 : any_changes = 1;
779 0 : _keybox_release_blob (blob); blob = NULL;
780 0 : if (!rc && read_rc == -1)
781 0 : rc = 0;
782 0 : else if (!rc)
783 0 : rc = read_rc;
784 :
785 : /* Close both files. */
786 0 : if (fclose(fp) && !rc)
787 0 : rc = gpg_error_from_syserror ();
788 0 : if (fclose(newfp) && !rc)
789 0 : rc = gpg_error_from_syserror ();
790 :
791 : /* Rename or remove the temporary file. */
792 0 : if (rc || !any_changes)
793 0 : gnupg_remove (tmpfname);
794 : else
795 0 : rc = rename_tmp_file (bakfname, tmpfname, fname, hd->secret);
796 :
797 0 : xfree(bakfname);
798 0 : xfree(tmpfname);
799 0 : return rc;
800 : }
|