agent/
[gnupg.git] / kbx / keybox-update.c
blobdfa7af34683d8f0cf55aa5469f14ced0e35efc03
1 /* keybox-update.c - keybox update operations
2 * Copyright (C) 2001, 2003, 2004 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 <http://www.gnu.org/licenses/>.
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>
28 #include "keybox-defs.h"
30 #define EXTSEP_S "."
33 #if !defined(HAVE_FSEEKO) && !defined(fseeko)
35 #ifdef HAVE_LIMITS_H
36 # include <limits.h>
37 #endif
38 #ifndef LONG_MAX
39 # define LONG_MAX ((long) ((unsigned long) -1 >> 1))
40 #endif
41 #ifndef LONG_MIN
42 # define LONG_MIN (-1 - LONG_MAX)
43 #endif
45 /****************
46 * A substitute for fseeko, for hosts that don't have it.
48 static int
49 fseeko (FILE * stream, off_t newpos, int whence)
51 while (newpos != (long) newpos)
53 long pos = newpos < 0 ? LONG_MIN : LONG_MAX;
54 if (fseek (stream, pos, whence) != 0)
55 return -1;
56 newpos -= pos;
57 whence = SEEK_CUR;
59 return fseek (stream, (long) newpos, whence);
61 #endif /* !defined(HAVE_FSEEKO) && !defined(fseeko) */
65 static int
66 create_tmp_file (const char *template,
67 char **r_bakfname, char **r_tmpfname, FILE **r_fp)
69 char *bakfname, *tmpfname;
71 *r_bakfname = NULL;
72 *r_tmpfname = NULL;
74 # ifdef USE_ONLY_8DOT3
75 /* Here is another Windoze bug?:
76 * you cant rename("pubring.kbx.tmp", "pubring.kbx");
77 * but rename("pubring.kbx.tmp", "pubring.aaa");
78 * works. So we replace ".kbx" by ".kb_" or ".k__". Note that we
79 * can't use ".bak" and ".tmp", because these suffixes are used by
80 * gpg and would lead to a sharing violation or data corruption.
82 if (strlen (template) > 4
83 && !strcmp (template+strlen(template)-4, EXTSEP_S "kbx") )
85 bakfname = xtrymalloc (strlen (template) + 1);
86 if (!bakfname)
87 return gpg_error_from_syserror ();
88 strcpy (bakfname, template);
89 strcpy (bakfname+strlen(template)-4, EXTSEP_S "kb_");
91 tmpfname = xtrymalloc (strlen (template) + 1);
92 if (!tmpfname)
94 gpg_error_t tmperr = gpg_error_from_syserror ();
95 xfree (bakfname);
96 return tmperr;
98 strcpy (tmpfname,template);
99 strcpy (tmpfname + strlen (template)-4, EXTSEP_S "k__");
101 else
102 { /* File does not end with kbx, thus we hope we are working on a
103 modern file system and appending a suffix works. */
104 bakfname = xtrymalloc ( strlen (template) + 5);
105 if (!bakfname)
106 return gpg_error_from_syserror ();
107 strcpy (stpcpy (bakfname, template), EXTSEP_S "kb_");
109 tmpfname = xtrymalloc ( strlen (template) + 5);
110 if (!tmpfname)
112 gpg_error_t tmperr = gpg_error_from_syserror ();
113 xfree (bakfname);
114 return tmperr;
116 strcpy (stpcpy (tmpfname, template), EXTSEP_S "k__");
118 # else /* Posix file names */
119 bakfname = xtrymalloc (strlen (template) + 2);
120 if (!bakfname)
121 return gpg_error_from_syserror ();
122 strcpy (stpcpy (bakfname,template),"~");
124 tmpfname = xtrymalloc ( strlen (template) + 5);
125 if (!tmpfname)
127 gpg_error_t tmperr = gpg_error_from_syserror ();
128 xfree (bakfname);
129 return tmperr;
131 strcpy (stpcpy (tmpfname,template), EXTSEP_S "tmp");
132 # endif /* Posix filename */
134 *r_fp = fopen (tmpfname, "wb");
135 if (!*r_fp)
137 gpg_error_t tmperr = gpg_error_from_syserror ();
138 xfree (tmpfname);
139 xfree (bakfname);
140 return tmperr;
143 *r_bakfname = bakfname;
144 *r_tmpfname = tmpfname;
145 return 0;
149 static int
150 rename_tmp_file (const char *bakfname, const char *tmpfname,
151 const char *fname, int secret )
153 int rc=0;
155 /* restrict the permissions for secret keyboxs */
156 #ifndef HAVE_DOSISH_SYSTEM
157 /* if (secret && !opt.preserve_permissions) */
158 /* { */
159 /* if (chmod (tmpfname, S_IRUSR | S_IWUSR) ) */
160 /* { */
161 /* log_debug ("chmod of `%s' failed: %s\n", */
162 /* tmpfname, strerror(errno) ); */
163 /* return KEYBOX_Write_File; */
164 /* } */
165 /* } */
166 #endif
168 /* fixme: invalidate close caches (not used with stdio)*/
169 /* iobuf_ioctl (NULL, 2, 0, (char*)tmpfname ); */
170 /* iobuf_ioctl (NULL, 2, 0, (char*)bakfname ); */
171 /* iobuf_ioctl (NULL, 2, 0, (char*)fname ); */
173 /* First make a backup file except for secret keyboxes. */
174 if (!secret)
176 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
177 remove (bakfname);
178 #endif
179 if (rename (fname, bakfname) )
181 return gpg_error_from_syserror ();
185 /* Then rename the file. */
186 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
187 remove (fname);
188 #endif
189 if (rename (tmpfname, fname) )
191 rc = gpg_error_from_syserror ();
192 if (secret)
194 /* log_info ("WARNING: 2 files with confidential" */
195 /* " information exists.\n"); */
196 /* log_info ("%s is the unchanged one\n", fname ); */
197 /* log_info ("%s is the new one\n", tmpfname ); */
198 /* log_info ("Please fix this possible security flaw\n"); */
200 return rc;
203 return 0;
208 /* Perform insert/delete/update operation.
209 mode 1 = insert
210 2 = delete
211 3 = update
213 static int
214 blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
215 int secret, off_t start_offset)
217 FILE *fp, *newfp;
218 int rc=0;
219 char *bakfname = NULL;
220 char *tmpfname = NULL;
221 char buffer[4096];
222 int nread, nbytes;
224 /* Open the source file. Because we do a rename, we have to check the
225 permissions of the file */
226 if (access (fname, W_OK))
227 return gpg_error_from_syserror ();
229 fp = fopen (fname, "rb");
230 if (mode == 1 && !fp && errno == ENOENT)
232 /* Insert mode but file does not exist:
233 Create a new keybox file. */
234 newfp = fopen (fname, "wb");
235 if (!newfp )
236 return gpg_error_from_syserror ();
238 rc = _keybox_write_header_blob (newfp);
239 if (rc)
240 return rc;
242 rc = _keybox_write_blob (blob, newfp);
243 if (rc)
244 return rc;
246 if ( fclose (newfp) )
247 return gpg_error_from_syserror ();
249 /* if (chmod( fname, S_IRUSR | S_IWUSR )) */
250 /* { */
251 /* log_debug ("%s: chmod failed: %s\n", fname, strerror(errno) ); */
252 /* return KEYBOX_File_Error; */
253 /* } */
254 return 0; /* Ready. */
257 if (!fp)
259 rc = gpg_error_from_syserror ();
260 goto leave;
263 /* Create the new file. */
264 rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
265 if (rc)
267 fclose(fp);
268 goto leave;
271 /* prepare for insert */
272 if (mode == 1)
274 /* Copy everything to the new file. */
275 while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
277 if (fwrite (buffer, nread, 1, newfp) != 1)
279 rc = gpg_error_from_syserror ();
280 goto leave;
283 if (ferror (fp))
285 rc = gpg_error_from_syserror ();
286 goto leave;
290 /* Prepare for delete or update. */
291 if ( mode == 2 || mode == 3 )
293 off_t current = 0;
295 /* Copy first part to the new file. */
296 while ( current < start_offset )
298 nbytes = DIM(buffer);
299 if (current + nbytes > start_offset)
300 nbytes = start_offset - current;
301 nread = fread (buffer, 1, nbytes, fp);
302 if (!nread)
303 break;
304 current += nread;
306 if (fwrite (buffer, nread, 1, newfp) != 1)
308 rc = gpg_error_from_syserror ();
309 goto leave;
312 if (ferror (fp))
314 rc = gpg_error_from_syserror ();
315 goto leave;
318 /* Skip this blob. */
319 rc = _keybox_read_blob (NULL, fp);
320 if (rc)
321 return rc;
324 /* Do an insert or update. */
325 if ( mode == 1 || mode == 3 )
327 rc = _keybox_write_blob (blob, newfp);
328 if (rc)
329 return rc;
332 /* Copy the rest of the packet for an delete or update. */
333 if (mode == 2 || mode == 3)
335 while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
337 if (fwrite (buffer, nread, 1, newfp) != 1)
339 rc = gpg_error_from_syserror ();
340 goto leave;
343 if (ferror (fp))
345 rc = gpg_error_from_syserror ();
346 goto leave;
350 /* Close both files. */
351 if (fclose(fp))
353 rc = gpg_error_from_syserror ();
354 fclose (newfp);
355 goto leave;
357 if (fclose(newfp))
359 rc = gpg_error_from_syserror ();
360 goto leave;
363 rc = rename_tmp_file (bakfname, tmpfname, fname, secret);
365 leave:
366 xfree(bakfname);
367 xfree(tmpfname);
368 return rc;
373 #ifdef KEYBOX_WITH_X509
375 keybox_insert_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
376 unsigned char *sha1_digest)
378 int rc;
379 const char *fname;
380 KEYBOXBLOB blob;
382 if (!hd)
383 return gpg_error (GPG_ERR_INV_HANDLE);
384 if (!hd->kb)
385 return gpg_error (GPG_ERR_INV_HANDLE);
386 fname = hd->kb->fname;
387 if (!fname)
388 return gpg_error (GPG_ERR_INV_HANDLE);
390 /* Close this one otherwise we will mess up the position for a next
391 search. Fixme: it would be better to adjust the position after
392 the write operation. */
393 _keybox_close_file (hd);
395 rc = _keybox_create_x509_blob (&blob, cert, sha1_digest, hd->ephemeral);
396 if (!rc)
398 rc = blob_filecopy (1, fname, blob, hd->secret, 0);
399 _keybox_release_blob (blob);
400 /* if (!rc && !hd->secret && kb_offtbl) */
401 /* { */
402 /* update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */
403 /* } */
405 return rc;
409 keybox_update_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
410 unsigned char *sha1_digest)
412 (void)hd;
413 (void)cert;
414 (void)sha1_digest;
415 return -1;
419 #endif /*KEYBOX_WITH_X509*/
421 /* Note: We assume that the keybox has been locked before the current
422 search was executed. This is needed so that we can depend on the
423 offset information of the flags. */
425 keybox_set_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int value)
427 off_t off;
428 const char *fname;
429 FILE *fp;
430 gpg_err_code_t ec;
431 size_t flag_pos, flag_size;
432 const unsigned char *buffer;
433 size_t length;
435 (void)idx; /* Not yet used. */
437 if (!hd)
438 return gpg_error (GPG_ERR_INV_VALUE);
439 if (!hd->found.blob)
440 return gpg_error (GPG_ERR_NOTHING_FOUND);
441 if (!hd->kb)
442 return gpg_error (GPG_ERR_INV_HANDLE);
443 if (!hd->found.blob)
444 return gpg_error (GPG_ERR_NOTHING_FOUND);
445 fname = hd->kb->fname;
446 if (!fname)
447 return gpg_error (GPG_ERR_INV_HANDLE);
449 off = _keybox_get_blob_fileoffset (hd->found.blob);
450 if (off == (off_t)-1)
451 return gpg_error (GPG_ERR_GENERAL);
453 buffer = _keybox_get_blob_image (hd->found.blob, &length);
454 ec = _keybox_get_flag_location (buffer, length, what, &flag_pos, &flag_size);
455 if (ec)
456 return gpg_error (ec);
458 off += flag_pos;
460 _keybox_close_file (hd);
461 fp = fopen (hd->kb->fname, "r+b");
462 if (!fp)
463 return gpg_error_from_syserror ();
465 ec = 0;
466 if (fseeko (fp, off, SEEK_SET))
467 ec = gpg_error_from_syserror ();
468 else
470 unsigned char tmp[4];
472 tmp[0] = value >> 24;
473 tmp[1] = value >> 16;
474 tmp[2] = value >> 8;
475 tmp[3] = value;
477 switch (flag_size)
479 case 1:
480 case 2:
481 case 4:
482 if (fwrite (tmp+4-flag_size, flag_size, 1, fp) != 1)
483 ec = gpg_err_code_from_syserror ();
484 break;
485 default:
486 ec = GPG_ERR_BUG;
487 break;
491 if (fclose (fp))
493 if (!ec)
494 ec = gpg_err_code_from_syserror ();
497 return gpg_error (ec);
503 keybox_delete (KEYBOX_HANDLE hd)
505 off_t off;
506 const char *fname;
507 FILE *fp;
508 int rc;
510 if (!hd)
511 return gpg_error (GPG_ERR_INV_VALUE);
512 if (!hd->found.blob)
513 return gpg_error (GPG_ERR_NOTHING_FOUND);
514 if (!hd->kb)
515 return gpg_error (GPG_ERR_INV_HANDLE);
516 fname = hd->kb->fname;
517 if (!fname)
518 return gpg_error (GPG_ERR_INV_HANDLE);
520 off = _keybox_get_blob_fileoffset (hd->found.blob);
521 if (off == (off_t)-1)
522 return gpg_error (GPG_ERR_GENERAL);
523 off += 4;
525 _keybox_close_file (hd);
526 fp = fopen (hd->kb->fname, "r+b");
527 if (!fp)
528 return gpg_error_from_syserror ();
530 if (fseeko (fp, off, SEEK_SET))
531 rc = gpg_error_from_syserror ();
532 else if (putc (0, fp) == EOF)
533 rc = gpg_error_from_syserror ();
534 else
535 rc = 0;
537 if (fclose (fp))
539 if (!rc)
540 rc = gpg_error_from_syserror ();
543 return rc;
547 /* Compress the keybox file. This should be run with the file
548 locked. */
550 keybox_compress (KEYBOX_HANDLE hd)
552 int read_rc, rc;
553 const char *fname;
554 FILE *fp, *newfp;
555 char *bakfname = NULL;
556 char *tmpfname = NULL;
557 int first_blob;
558 KEYBOXBLOB blob = NULL;
559 u32 cut_time;
560 int any_changes = 0;
561 int skipped_deleted;
563 if (!hd)
564 return gpg_error (GPG_ERR_INV_HANDLE);
565 if (!hd->kb)
566 return gpg_error (GPG_ERR_INV_HANDLE);
567 if (hd->secret)
568 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
569 fname = hd->kb->fname;
570 if (!fname)
571 return gpg_error (GPG_ERR_INV_HANDLE);
573 _keybox_close_file (hd);
575 /* Open the source file. Because we do a rename, we have to check the
576 permissions of the file */
577 if (access (fname, W_OK))
578 return gpg_error_from_syserror ();
580 fp = fopen (fname, "rb");
581 if (!fp && errno == ENOENT)
582 return 0; /* Ready. File has been deleted right after the access above. */
583 if (!fp)
585 rc = gpg_error_from_syserror ();
586 return rc;
589 /* A quick test to see if we need to compress the file at all. We
590 schedule a compress run after 3 hours. */
591 if ( !_keybox_read_blob (&blob, fp) )
593 const unsigned char *buffer;
594 size_t length;
596 buffer = _keybox_get_blob_image (blob, &length);
597 if (length > 4 && buffer[4] == BLOBTYPE_HEADER)
599 u32 last_maint = ((buffer[20] << 24) | (buffer[20+1] << 16)
600 | (buffer[20+2] << 8) | (buffer[20+3]));
602 if ( (last_maint + 3*3600) > time (NULL) )
604 fclose (fp);
605 _keybox_release_blob (blob);
606 return 0; /* Compress run not yet needed. */
609 _keybox_release_blob (blob);
610 rewind (fp);
613 /* Create the new file. */
614 rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
615 if (rc)
617 fclose(fp);
618 return rc;;
622 /* Processing loop. By reading using _keybox_read_blob we
623 automagically skip any blobs flagged as deleted. Thus what we
624 only have to do is to check all ephemeral flagged blocks whether
625 their time has come and write out all other blobs. */
626 cut_time = time(NULL) - 86400;
627 first_blob = 1;
628 skipped_deleted = 0;
629 for (rc=0; !(read_rc = _keybox_read_blob2 (&blob, fp, &skipped_deleted));
630 _keybox_release_blob (blob), blob = NULL )
632 unsigned int blobflags;
633 const unsigned char *buffer;
634 size_t length, pos, size;
635 u32 created_at;
637 if (skipped_deleted)
638 any_changes = 1;
639 buffer = _keybox_get_blob_image (blob, &length);
640 if (first_blob)
642 first_blob = 0;
643 if (length > 4 && buffer[4] == BLOBTYPE_HEADER)
645 /* Write out the blob with an updated maintenance time stamp. */
646 _keybox_update_header_blob (blob);
647 rc = _keybox_write_blob (blob, newfp);
648 if (rc)
649 break;
650 continue;
653 /* The header blob is missing. Insert it. */
654 rc = _keybox_write_header_blob (newfp);
655 if (rc)
656 break;
657 any_changes = 1;
659 else if (length > 4 && buffer[4] == BLOBTYPE_HEADER)
661 /* Oops: There is another header record - remove it. */
662 any_changes = 1;
663 continue;
666 if (_keybox_get_flag_location (buffer, length,
667 KEYBOX_FLAG_BLOB, &pos, &size)
668 || size != 2)
670 rc = gpg_error (GPG_ERR_BUG);
671 break;
673 blobflags = ((buffer[pos] << 8) | (buffer[pos+1]));
674 if ((blobflags & KEYBOX_FLAG_BLOB_EPHEMERAL))
676 /* This is an ephemeral blob. */
677 if (_keybox_get_flag_location (buffer, length,
678 KEYBOX_FLAG_CREATED_AT, &pos, &size)
679 || size != 4)
680 created_at = 0; /* oops. */
681 else
682 created_at = ((buffer[pos] << 24) | (buffer[pos+1] << 16)
683 | (buffer[pos+2] << 8) | (buffer[pos+3]));
685 if (created_at && created_at < cut_time)
687 any_changes = 1;
688 continue; /* Skip this blob. */
692 rc = _keybox_write_blob (blob, newfp);
693 if (rc)
694 break;
696 if (skipped_deleted)
697 any_changes = 1;
698 _keybox_release_blob (blob); blob = NULL;
699 if (!rc && read_rc == -1)
700 rc = 0;
701 else if (!rc)
702 rc = read_rc;
704 /* Close both files. */
705 if (fclose(fp) && !rc)
706 rc = gpg_error_from_syserror ();
707 if (fclose(newfp) && !rc)
708 rc = gpg_error_from_syserror ();
710 /* Rename or remove the temporary file. */
711 if (rc || !any_changes)
712 remove (tmpfname);
713 else
714 rc = rename_tmp_file (bakfname, tmpfname, fname, hd->secret);
716 xfree(bakfname);
717 xfree(tmpfname);
718 return rc;