1 /* keybox-update.c - keybox update operations
2 * Copyright (C) 2001, 2003, 2004, 2012 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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/>.
29 #include "keybox-defs.h"
30 #include "../common/sysutils.h"
31 #include "../common/host2net.h"
32 #include "../common/utilproto.h"
36 #define FILECOPY_INSERT 1
37 #define FILECOPY_DELETE 2
38 #define FILECOPY_UPDATE 3
41 #if !defined(HAVE_FSEEKO) && !defined(fseeko)
47 # define LONG_MAX ((long) ((unsigned long) -1 >> 1))
50 # define LONG_MIN (-1 - LONG_MAX)
54 * A substitute for fseeko, for hosts that don't have it.
57 fseeko (FILE * stream, off_t newpos, int whence)
59 while (newpos != (long) newpos)
61 long pos = newpos < 0 ? LONG_MIN : LONG_MAX;
62 if (fseek (stream, pos, whence) != 0)
67 return fseek (stream, (long) newpos, whence);
69 #endif /* !defined(HAVE_FSEEKO) && !defined(fseeko) */
73 create_tmp_file (const char *template,
74 char **r_bakfname, char **r_tmpfname, FILE **r_fp)
78 err = keybox_tmp_names (template, 0, r_bakfname, r_tmpfname);
81 *r_fp = fopen (*r_tmpfname, "wb");
84 err = gpg_error_from_syserror ();
97 rename_tmp_file (const char *bakfname, const char *tmpfname,
98 const char *fname, int secret )
103 /* restrict the permissions for secret keyboxs */
104 #ifndef HAVE_DOSISH_SYSTEM
105 /* if (secret && !opt.preserve_permissions) */
107 /* if (chmod (tmpfname, S_IRUSR | S_IWUSR) ) */
109 /* log_debug ("chmod of '%s' failed: %s\n", */
110 /* tmpfname, strerror(errno) ); */
111 /* return KEYBOX_Write_File; */
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 ); */
121 /* First make a backup file except for secret keyboxes. */
125 rc = gnupg_rename_file (fname, bakfname, &block);
130 /* Then rename the file. */
131 rc = gnupg_rename_file (tmpfname, fname, NULL);
134 gnupg_unblock_all_signals ();
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"); */
151 gnupg_unblock_all_signals ();
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. */
161 blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
162 int secret, int for_openpgp, off_t start_offset)
166 char *bakfname = NULL;
167 char *tmpfname = NULL;
168 char buffer[4096]; /* (Must be at least 32 bytes) */
171 /* Open the source file. Because we do a rename, we have to check the
172 permissions of the file */
173 if (access (fname, W_OK))
174 return gpg_error_from_syserror ();
176 fp = fopen (fname, "rb");
177 if (mode == FILECOPY_INSERT && !fp && errno == ENOENT)
179 /* Insert mode but file does not exist:
180 Create a new keybox file. */
181 newfp = fopen (fname, "wb");
183 return gpg_error_from_syserror ();
185 rc = _keybox_write_header_blob (newfp, for_openpgp);
192 rc = _keybox_write_blob (blob, newfp);
199 if ( fclose (newfp) )
200 return gpg_error_from_syserror ();
202 /* if (chmod( fname, S_IRUSR | S_IWUSR )) */
204 /* log_debug ("%s: chmod failed: %s\n", fname, strerror(errno) ); */
205 /* return KEYBOX_File_Error; */
207 return 0; /* Ready. */
212 rc = gpg_error_from_syserror ();
216 /* Create the new file. On success NEWFP is initialized. */
217 rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
224 /* prepare for insert */
225 if (mode == FILECOPY_INSERT)
227 int first_record = 1;
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 while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
234 if (first_record && for_openpgp
235 && buffer[4] == KEYBOX_BLOBTYPE_HEADER)
238 buffer[7] |= 0x02; /* OpenPGP data may be available. */
241 if (fwrite (buffer, nread, 1, newfp) != 1)
243 rc = gpg_error_from_syserror ();
251 rc = gpg_error_from_syserror ();
258 /* Prepare for delete or update. */
259 if ( mode == FILECOPY_DELETE || mode == FILECOPY_UPDATE )
263 /* Copy first part to the new file. */
264 while ( current < start_offset )
266 nbytes = DIM(buffer);
267 if (current + nbytes > start_offset)
268 nbytes = start_offset - current;
269 nread = fread (buffer, 1, nbytes, fp);
274 if (fwrite (buffer, nread, 1, newfp) != 1)
276 rc = gpg_error_from_syserror ();
284 rc = gpg_error_from_syserror ();
290 /* Skip this blob. */
291 rc = _keybox_read_blob (NULL, fp);
300 /* Do an insert or update. */
301 if ( mode == FILECOPY_INSERT || mode == FILECOPY_UPDATE )
303 rc = _keybox_write_blob (blob, newfp);
312 /* Copy the rest of the packet for an delete or update. */
313 if (mode == FILECOPY_DELETE || mode == FILECOPY_UPDATE)
315 while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
317 if (fwrite (buffer, nread, 1, newfp) != 1)
319 rc = gpg_error_from_syserror ();
327 rc = gpg_error_from_syserror ();
334 /* Close both files. */
337 rc = gpg_error_from_syserror ();
343 rc = gpg_error_from_syserror ();
347 rc = rename_tmp_file (bakfname, tmpfname, fname, secret);
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. */
360 keybox_insert_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen,
367 struct _keybox_openpgp_info info;
370 return gpg_error (GPG_ERR_INV_HANDLE);
372 return gpg_error (GPG_ERR_INV_HANDLE);
373 fname = hd->kb->fname;
375 return gpg_error (GPG_ERR_INV_HANDLE);
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 _keybox_close_file (hd);
383 err = _keybox_parse_openpgp (image, imagelen, &nparsed, &info);
386 assert (nparsed <= imagelen);
387 err = _keybox_create_openpgp_blob (&blob, &info, image, imagelen,
388 sigstatus, hd->ephemeral);
389 _keybox_destroy_openpgp_info (&info);
392 err = blob_filecopy (FILECOPY_INSERT, fname, blob, hd->secret, 1, 0);
393 _keybox_release_blob (blob);
394 /* if (!rc && !hd->secret && kb_offtbl) */
396 /* update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */
403 /* Update the current key at HD with the given OpenPGP keyblock in
406 keybox_update_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen)
413 struct _keybox_openpgp_info info;
415 if (!hd || !image || !imagelen)
416 return gpg_error (GPG_ERR_INV_VALUE);
418 return gpg_error (GPG_ERR_NOTHING_FOUND);
419 if (blob_get_type (hd->found.blob) != KEYBOX_BLOBTYPE_PGP)
420 return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
421 fname = hd->kb->fname;
423 return gpg_error (GPG_ERR_INV_HANDLE);
425 off = _keybox_get_blob_fileoffset (hd->found.blob);
426 if (off == (off_t)-1)
427 return gpg_error (GPG_ERR_GENERAL);
429 /* Close this the file so that we do no mess up the position for a
431 _keybox_close_file (hd);
433 /* Build a new blob. */
434 err = _keybox_parse_openpgp (image, imagelen, &nparsed, &info);
437 assert (nparsed <= imagelen);
438 err = _keybox_create_openpgp_blob (&blob, &info, image, imagelen,
439 NULL, hd->ephemeral);
440 _keybox_destroy_openpgp_info (&info);
442 /* Update the keyblock. */
445 err = blob_filecopy (FILECOPY_UPDATE, fname, blob, hd->secret, 1, off);
446 _keybox_release_blob (blob);
453 #ifdef KEYBOX_WITH_X509
455 keybox_insert_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
456 unsigned char *sha1_digest)
463 return gpg_error (GPG_ERR_INV_HANDLE);
465 return gpg_error (GPG_ERR_INV_HANDLE);
466 fname = hd->kb->fname;
468 return gpg_error (GPG_ERR_INV_HANDLE);
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 _keybox_close_file (hd);
475 rc = _keybox_create_x509_blob (&blob, cert, sha1_digest, hd->ephemeral);
478 rc = blob_filecopy (FILECOPY_INSERT, fname, blob, hd->secret, 0, 0);
479 _keybox_release_blob (blob);
480 /* if (!rc && !hd->secret && kb_offtbl) */
482 /* update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */
489 keybox_update_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
490 unsigned char *sha1_digest)
499 #endif /*KEYBOX_WITH_X509*/
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. */
505 keybox_set_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int value)
511 size_t flag_pos, flag_size;
512 const unsigned char *buffer;
515 (void)idx; /* Not yet used. */
518 return gpg_error (GPG_ERR_INV_VALUE);
520 return gpg_error (GPG_ERR_NOTHING_FOUND);
522 return gpg_error (GPG_ERR_INV_HANDLE);
524 return gpg_error (GPG_ERR_NOTHING_FOUND);
525 fname = hd->kb->fname;
527 return gpg_error (GPG_ERR_INV_HANDLE);
529 off = _keybox_get_blob_fileoffset (hd->found.blob);
530 if (off == (off_t)-1)
531 return gpg_error (GPG_ERR_GENERAL);
533 buffer = _keybox_get_blob_image (hd->found.blob, &length);
534 ec = _keybox_get_flag_location (buffer, length, what, &flag_pos, &flag_size);
536 return gpg_error (ec);
540 _keybox_close_file (hd);
541 fp = fopen (hd->kb->fname, "r+b");
543 return gpg_error_from_syserror ();
546 if (fseeko (fp, off, SEEK_SET))
547 ec = gpg_err_code_from_syserror ();
550 unsigned char tmp[4];
552 tmp[0] = value >> 24;
553 tmp[1] = value >> 16;
562 if (fwrite (tmp+4-flag_size, flag_size, 1, fp) != 1)
563 ec = gpg_err_code_from_syserror ();
574 ec = gpg_err_code_from_syserror ();
577 return gpg_error (ec);
583 keybox_delete (KEYBOX_HANDLE hd)
591 return gpg_error (GPG_ERR_INV_VALUE);
593 return gpg_error (GPG_ERR_NOTHING_FOUND);
595 return gpg_error (GPG_ERR_INV_HANDLE);
596 fname = hd->kb->fname;
598 return gpg_error (GPG_ERR_INV_HANDLE);
600 off = _keybox_get_blob_fileoffset (hd->found.blob);
601 if (off == (off_t)-1)
602 return gpg_error (GPG_ERR_GENERAL);
605 _keybox_close_file (hd);
606 fp = fopen (hd->kb->fname, "r+b");
608 return gpg_error_from_syserror ();
610 if (fseeko (fp, off, SEEK_SET))
611 rc = gpg_error_from_syserror ();
612 else if (putc (0, fp) == EOF)
613 rc = gpg_error_from_syserror ();
620 rc = gpg_error_from_syserror ();
627 /* Compress the keybox file. This should be run with the file
630 keybox_compress (KEYBOX_HANDLE hd)
635 char *bakfname = NULL;
636 char *tmpfname = NULL;
638 KEYBOXBLOB blob = NULL;
644 return gpg_error (GPG_ERR_INV_HANDLE);
646 return gpg_error (GPG_ERR_INV_HANDLE);
648 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
649 fname = hd->kb->fname;
651 return gpg_error (GPG_ERR_INV_HANDLE);
653 _keybox_close_file (hd);
655 /* Open the source file. Because we do a rename, we have to check the
656 permissions of the file */
657 if (access (fname, W_OK))
658 return gpg_error_from_syserror ();
660 fp = fopen (fname, "rb");
661 if (!fp && errno == ENOENT)
662 return 0; /* Ready. File has been deleted right after the access above. */
665 rc = gpg_error_from_syserror ();
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 if ( !_keybox_read_blob (&blob, fp) )
673 const unsigned char *buffer;
676 buffer = _keybox_get_blob_image (blob, &length);
677 if (length > 4 && buffer[4] == KEYBOX_BLOBTYPE_HEADER)
679 u32 last_maint = buf32_to_u32 (buffer+20);
681 if ( (last_maint + 3*3600) > time (NULL) )
684 _keybox_release_blob (blob);
685 return 0; /* Compress run not yet needed. */
688 _keybox_release_blob (blob);
689 fseek (fp, 0, SEEK_SET);
693 /* Create the new file. */
694 rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
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 cut_time = time(NULL) - 86400;
709 for (rc=0; !(read_rc = _keybox_read_blob2 (&blob, fp, &skipped_deleted));
710 _keybox_release_blob (blob), blob = NULL )
712 unsigned int blobflags;
713 const unsigned char *buffer;
714 size_t length, pos, size;
719 buffer = _keybox_get_blob_image (blob, &length);
723 if (length > 4 && buffer[4] == KEYBOX_BLOBTYPE_HEADER)
725 /* Write out the blob with an updated maintenance time
726 stamp and if needed (ie. used by gpg) set the openpgp
728 _keybox_update_header_blob (blob, hd->for_openpgp);
729 rc = _keybox_write_blob (blob, newfp);
735 /* The header blob is missing. Insert it. */
736 rc = _keybox_write_header_blob (newfp, hd->for_openpgp);
741 else if (length > 4 && buffer[4] == KEYBOX_BLOBTYPE_HEADER)
743 /* Oops: There is another header record - remove it. */
748 if (_keybox_get_flag_location (buffer, length,
749 KEYBOX_FLAG_BLOB, &pos, &size)
752 rc = gpg_error (GPG_ERR_BUG);
755 blobflags = buf16_to_uint (buffer+pos);
756 if ((blobflags & KEYBOX_FLAG_BLOB_EPHEMERAL))
758 /* This is an ephemeral blob. */
759 if (_keybox_get_flag_location (buffer, length,
760 KEYBOX_FLAG_CREATED_AT, &pos, &size)
762 created_at = 0; /* oops. */
764 created_at = buf32_to_u32 (buffer+pos);
766 if (created_at && created_at < cut_time)
769 continue; /* Skip this blob. */
773 rc = _keybox_write_blob (blob, newfp);
779 _keybox_release_blob (blob); blob = NULL;
780 if (!rc && read_rc == -1)
785 /* Close both files. */
786 if (fclose(fp) && !rc)
787 rc = gpg_error_from_syserror ();
788 if (fclose(newfp) && !rc)
789 rc = gpg_error_from_syserror ();
791 /* Rename or remove the temporary file. */
792 if (rc || !any_changes)
793 gnupg_remove (tmpfname);
795 rc = rename_tmp_file (bakfname, tmpfname, fname, hd->secret);