2002-04-24 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / g10 / tdbio.c
blob669f66ffc648dd6dfd6896aeeef5578c688cb27f
1 /* tdbio.c
2 * Copyright (C) 1998, 1999, 2000 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 2 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, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <unistd.h>
32 #include "errors.h"
33 #include "iobuf.h"
34 #include <gcrypt.h>
35 #include "util.h"
36 #include "options.h"
37 #include "main.h"
38 #include "i18n.h"
39 #include "trustdb.h"
40 #include "tdbio.h"
43 /****************
44 * Yes, this is a very simple implementation. We should really
45 * use a page aligned buffer and read complete pages.
46 * To implement a simple trannsaction system, this is sufficient.
48 typedef struct cache_ctrl_struct *CACHE_CTRL;
49 struct cache_ctrl_struct {
50 CACHE_CTRL next;
51 struct {
52 unsigned used:1;
53 unsigned dirty:1;
54 } flags;
55 ulong recno;
56 char data[TRUST_RECORD_LEN];
59 #define MAX_CACHE_ENTRIES_SOFT 200 /* may be increased while in a */
60 #define MAX_CACHE_ENTRIES_HARD 10000 /* transaction to this one */
61 static CACHE_CTRL cache_list;
62 static int cache_entries;
63 static int cache_is_dirty;
65 /* a type used to pass infomation to cmp_krec_fpr */
66 struct cmp_krec_fpr_struct {
67 int pubkey_algo;
68 const char *fpr;
69 int fprlen;
72 /* a type used to pass infomation to cmp_[s]dir */
73 struct cmp_xdir_struct {
74 int pubkey_algo;
75 u32 keyid[2];
79 static char *db_name;
80 static DOTLOCK lockhandle;
81 static int is_locked;
82 static int db_fd = -1;
83 static int in_transaction;
85 static void open_db(void);
88 /*************************************
89 ************* record cache **********
90 *************************************/
92 /****************
93 * Get the data from therecord cache and return a
94 * pointer into that cache. Caller should copy
95 * the return data. NULL is returned on a cache miss.
97 static const char *
98 get_record_from_cache( ulong recno )
100 CACHE_CTRL r;
102 for( r = cache_list; r; r = r->next ) {
103 if( r->flags.used && r->recno == recno )
104 return r->data;
106 return NULL;
110 static int
111 write_cache_item( CACHE_CTRL r )
113 int n;
115 if( lseek( db_fd, r->recno * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
116 log_error(_("trustdb rec %lu: lseek failed: %s\n"),
117 r->recno, strerror(errno) );
118 return GPGERR_WRITE_FILE;
120 n = write( db_fd, r->data, TRUST_RECORD_LEN);
121 if( n != TRUST_RECORD_LEN ) {
122 log_error(_("trustdb rec %lu: write failed (n=%d): %s\n"),
123 r->recno, n, strerror(errno) );
124 return GPGERR_WRITE_FILE;
126 r->flags.dirty = 0;
127 return 0;
130 /****************
131 * Put data into the cache. This function may flush the
132 * some cache entries if there is not enough space available.
135 put_record_into_cache( ulong recno, const char *data )
137 CACHE_CTRL r, unused;
138 int dirty_count = 0;
139 int clean_count = 0;
141 /* see whether we already cached this one */
142 for( unused = NULL, r = cache_list; r; r = r->next ) {
143 if( !r->flags.used ) {
144 if( !unused )
145 unused = r;
147 else if( r->recno == recno ) {
148 if( !r->flags.dirty ) {
149 /* Hmmm: should we use a a copy and compare? */
150 if( memcmp(r->data, data, TRUST_RECORD_LEN ) ) {
151 r->flags.dirty = 1;
152 cache_is_dirty = 1;
155 memcpy( r->data, data, TRUST_RECORD_LEN );
156 return 0;
158 if( r->flags.used ) {
159 if( r->flags.dirty )
160 dirty_count++;
161 else
162 clean_count++;
165 /* not in the cache: add a new entry */
166 if( unused ) { /* reuse this entry */
167 r = unused;
168 r->flags.used = 1;
169 r->recno = recno;
170 memcpy( r->data, data, TRUST_RECORD_LEN );
171 r->flags.dirty = 1;
172 cache_is_dirty = 1;
173 cache_entries++;
174 return 0;
176 /* see whether we reached the limit */
177 if( cache_entries < MAX_CACHE_ENTRIES_SOFT ) { /* no */
178 r = gcry_xmalloc( sizeof *r );
179 r->flags.used = 1;
180 r->recno = recno;
181 memcpy( r->data, data, TRUST_RECORD_LEN );
182 r->flags.dirty = 1;
183 r->next = cache_list;
184 cache_list = r;
185 cache_is_dirty = 1;
186 cache_entries++;
187 return 0;
189 /* cache is full: discard some clean entries */
190 if( clean_count ) {
191 int n = clean_count / 3; /* discard a third of the clean entries */
192 if( !n )
193 n = 1;
194 for( unused = NULL, r = cache_list; r; r = r->next ) {
195 if( r->flags.used && !r->flags.dirty ) {
196 if( !unused )
197 unused = r;
198 r->flags.used = 0;
199 cache_entries--;
200 if( !--n )
201 break;
204 assert( unused );
205 r = unused;
206 r->flags.used = 1;
207 r->recno = recno;
208 memcpy( r->data, data, TRUST_RECORD_LEN );
209 r->flags.dirty = 1;
210 cache_is_dirty = 1;
211 cache_entries++;
212 return 0;
214 /* no clean entries: have to flush some dirty entries */
215 if( in_transaction ) {
216 /* but we can't do this while in a transaction
217 * we increase the cache size instead */
218 if( cache_entries < MAX_CACHE_ENTRIES_HARD ) { /* no */
219 if( opt.debug && !(cache_entries % 100) )
220 log_debug("increasing tdbio cache size\n");
221 r = gcry_xmalloc( sizeof *r );
222 r->flags.used = 1;
223 r->recno = recno;
224 memcpy( r->data, data, TRUST_RECORD_LEN );
225 r->flags.dirty = 1;
226 r->next = cache_list;
227 cache_list = r;
228 cache_is_dirty = 1;
229 cache_entries++;
230 return 0;
232 log_info(_("trustdb transaction too large\n"));
233 return GPGERR_RESOURCE_LIMIT;
235 if( dirty_count ) {
236 int n = dirty_count / 5; /* discard some dirty entries */
237 if( !n )
238 n = 1;
239 if( !is_locked ) {
240 if( make_dotlock( lockhandle, -1 ) )
241 log_fatal("can't acquire lock - giving up\n");
242 else
243 is_locked = 1;
245 for( unused = NULL, r = cache_list; r; r = r->next ) {
246 if( r->flags.used && r->flags.dirty ) {
247 int rc = write_cache_item( r );
248 if( rc )
249 return rc;
250 if( !unused )
251 unused = r;
252 r->flags.used = 0;
253 cache_entries--;
254 if( !--n )
255 break;
258 if( !opt.lock_once ) {
259 if( !release_dotlock( lockhandle ) )
260 is_locked = 0;
262 assert( unused );
263 r = unused;
264 r->flags.used = 1;
265 r->recno = recno;
266 memcpy( r->data, data, TRUST_RECORD_LEN );
267 r->flags.dirty = 1;
268 cache_is_dirty = 1;
269 cache_entries++;
270 return 0;
272 BUG();
277 tdbio_is_dirty()
279 return cache_is_dirty;
283 /****************
284 * Flush the cache. This cannot be used while in a transaction.
287 tdbio_sync()
289 CACHE_CTRL r;
290 int did_lock = 0;
292 if( db_fd == -1 )
293 open_db();
294 if( in_transaction )
295 log_bug("tdbio: syncing while in transaction\n");
297 if( !cache_is_dirty )
298 return 0;
300 if( !is_locked ) {
301 if( make_dotlock( lockhandle, -1 ) )
302 log_fatal("can't acquire lock - giving up\n");
303 else
304 is_locked = 1;
305 did_lock = 1;
307 for( r = cache_list; r; r = r->next ) {
308 if( r->flags.used && r->flags.dirty ) {
309 int rc = write_cache_item( r );
310 if( rc )
311 return rc;
314 cache_is_dirty = 0;
315 if( did_lock && !opt.lock_once ) {
316 if( !release_dotlock( lockhandle ) )
317 is_locked = 0;
320 return 0;
325 /****************
326 * Simple transactions system:
327 * Everything between begin_transaction and end/cancel_transaction
328 * is not immediatly written but at the time of end_transaction.
332 tdbio_begin_transaction()
334 int rc;
336 if( in_transaction )
337 log_bug("tdbio: nested transactions\n");
338 /* flush everything out */
339 rc = tdbio_sync();
340 if( rc )
341 return rc;
342 in_transaction = 1;
343 return 0;
347 tdbio_end_transaction()
349 int rc;
351 if( !in_transaction )
352 log_bug("tdbio: no active transaction\n");
353 if( !is_locked ) {
354 if( make_dotlock( lockhandle, -1 ) )
355 log_fatal("can't acquire lock - giving up\n");
356 else
357 is_locked = 1;
359 block_all_signals();
360 in_transaction = 0;
361 rc = tdbio_sync();
362 unblock_all_signals();
363 if( !opt.lock_once ) {
364 if( !release_dotlock( lockhandle ) )
365 is_locked = 0;
367 return rc;
371 tdbio_cancel_transaction()
373 CACHE_CTRL r;
375 if( !in_transaction )
376 log_bug("tdbio: no active transaction\n");
378 /* remove all dirty marked entries, so that the original ones
379 * are read back the next time */
380 if( cache_is_dirty ) {
381 for( r = cache_list; r; r = r->next ) {
382 if( r->flags.used && r->flags.dirty ) {
383 r->flags.used = 0;
384 cache_entries--;
387 cache_is_dirty = 0;
390 in_transaction = 0;
391 return 0;
396 /********************************************************
397 **************** cached I/O functions ******************
398 ********************************************************/
400 static void
401 cleanup(void)
403 if( is_locked ) {
404 if( !release_dotlock(lockhandle) )
405 is_locked = 0;
410 tdbio_set_dbname( const char *new_dbname, int create )
412 char *fname;
413 static int initialized = 0;
415 if( !initialized ) {
416 atexit( cleanup );
417 initialized = 1;
419 fname = new_dbname? gcry_xstrdup( new_dbname )
420 : make_filename(opt.homedir, "trustdb.gpg", NULL );
422 if( access( fname, R_OK ) ) {
423 if( errno != ENOENT ) {
424 log_error( _("%s: can't access: %s\n"), fname, strerror(errno) );
425 gcry_free(fname);
426 return GPGERR_TRUSTDB;
428 if( create ) {
429 FILE *fp;
430 TRUSTREC rec;
431 int rc;
432 char *p = strrchr( fname, '/' );
434 assert(p);
435 *p = 0;
436 if( access( fname, F_OK ) ) {
437 try_make_homedir( fname );
438 log_fatal( _("%s: directory does not exist!\n"), fname );
440 *p = '/';
442 fp =fopen( fname, "wb" );
443 if( !fp )
444 log_fatal( _("%s: can't create: %s\n"), fname, strerror(errno) );
445 fclose(fp);
446 gcry_free(db_name);
447 db_name = fname;
448 #ifdef HAVE_DOSISH_SYSTEM
449 db_fd = open( db_name, O_RDWR | O_BINARY );
450 #else
451 db_fd = open( db_name, O_RDWR );
452 #endif
453 if( db_fd == -1 )
454 log_fatal( _("%s: can't open: %s\n"), db_name, strerror(errno) );
456 if( !lockhandle )
457 lockhandle = create_dotlock( db_name );
458 if( !lockhandle )
459 log_fatal( _("%s: can't create lock\n"), db_name );
461 memset( &rec, 0, sizeof rec );
462 rec.r.ver.version = 2;
463 rec.r.ver.created = make_timestamp();
464 rec.r.ver.marginals = opt.marginals_needed;
465 rec.r.ver.completes = opt.completes_needed;
466 rec.r.ver.cert_depth = opt.max_cert_depth;
467 rec.rectype = RECTYPE_VER;
468 rec.recnum = 0;
469 rc = tdbio_write_record( &rec );
470 if( !rc )
471 tdbio_sync();
472 if( rc )
473 log_fatal( _("%s: failed to create version record: %s"),
474 fname, gpg_errstr(rc));
475 /* and read again to check that we are okay */
476 if( tdbio_read_record( 0, &rec, RECTYPE_VER ) )
477 log_fatal( _("%s: invalid trustdb created\n"), db_name );
479 if( !opt.quiet )
480 log_info(_("%s: trustdb created\n"), db_name);
482 return 0;
485 gcry_free(db_name);
486 db_name = fname;
487 return 0;
491 const char *
492 tdbio_get_dbname()
494 return db_name;
499 static void
500 open_db()
502 TRUSTREC rec;
503 assert( db_fd == -1 );
505 if( !lockhandle )
506 lockhandle = create_dotlock( db_name );
507 if( !lockhandle )
508 log_fatal( _("%s: can't create lock\n"), db_name );
509 #ifdef HAVE_DOSISH_SYSTEM
510 db_fd = open( db_name, O_RDWR | O_BINARY );
511 #else
512 db_fd = open( db_name, O_RDWR );
513 #endif
514 if( db_fd == -1 )
515 log_fatal( _("%s: can't open: %s\n"), db_name, strerror(errno) );
516 if( tdbio_read_record( 0, &rec, RECTYPE_VER ) )
517 log_fatal( _("%s: invalid trustdb\n"), db_name );
521 /****************
522 * Make a hashtable: type 0 = key hash, 1 = sdir hash
524 static void
525 create_hashtable( TRUSTREC *vr, int type )
527 TRUSTREC rec;
528 off_t offset;
529 ulong recnum;
530 int i, n, rc;
532 offset = lseek( db_fd, 0, SEEK_END );
533 if( offset == -1 )
534 log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
535 recnum = offset / TRUST_RECORD_LEN;
536 assert(recnum); /* this is will never be the first record */
538 if( !type )
539 vr->r.ver.keyhashtbl = recnum;
540 else
541 vr->r.ver.sdirhashtbl = recnum;
542 /* Now write the records */
543 n = (256+ITEMS_PER_HTBL_RECORD-1) / ITEMS_PER_HTBL_RECORD;
544 for(i=0; i < n; i++, recnum++ ) {
545 memset( &rec, 0, sizeof rec );
546 rec.rectype = RECTYPE_HTBL;
547 rec.recnum = recnum;
548 rc = tdbio_write_record( &rec );
549 if( rc )
550 log_fatal( _("%s: failed to create hashtable: %s\n"),
551 db_name, gpg_errstr(rc));
553 /* update the version record */
554 rc = tdbio_write_record( vr );
555 if( !rc )
556 rc = tdbio_sync();
557 if( rc )
558 log_fatal( _("%s: error updating version record: %s\n"),
559 db_name, gpg_errstr(rc));
564 tdbio_db_matches_options()
566 static int yes_no = -1;
568 if( yes_no == -1 ) {
569 TRUSTREC vr;
570 int rc;
572 rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
573 if( rc )
574 log_fatal( _("%s: error reading version record: %s\n"),
575 db_name, gpg_errstr(rc) );
577 if( !vr.r.ver.marginals && !vr.r.ver.completes
578 && !vr.r.ver.cert_depth )
579 { /* special hack for trustdbs created by old versions of GnuPG */
580 vr.r.ver.marginals = opt.marginals_needed;
581 vr.r.ver.completes = opt.completes_needed;
582 vr.r.ver.cert_depth = opt.max_cert_depth;
583 rc = tdbio_write_record( &vr );
584 if( !rc && !in_transaction )
585 rc = tdbio_sync();
586 if( rc )
587 log_error( _("%s: error writing version record: %s\n"),
588 db_name, gpg_errstr(rc) );
591 yes_no = vr.r.ver.marginals == opt.marginals_needed
592 && vr.r.ver.completes == opt.completes_needed
593 && vr.r.ver.cert_depth == opt.max_cert_depth;
595 return yes_no;
599 /****************
600 * Return the modifiy stamp.
601 * if modify_down is true, the modify_down stamp will be
602 * returned, otherwise the modify_up stamp.
604 ulong
605 tdbio_read_modify_stamp( int modify_down )
607 TRUSTREC vr;
608 int rc;
609 ulong mod;
611 rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
612 if( rc )
613 log_fatal( _("%s: error reading version record: %s\n"),
614 db_name, gpg_errstr(rc) );
616 mod = modify_down? vr.r.ver.mod_down : vr.r.ver.mod_up;
618 /* Always return at least 1 to make comparison easier;
619 * this is still far back in history (before Led Zeppelin III :-) */
620 return mod ? mod : 1;
623 void
624 tdbio_write_modify_stamp( int up, int down )
626 TRUSTREC vr;
627 int rc;
628 ulong stamp;
630 if( !(up || down) )
631 return;
633 rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
634 if( rc )
635 log_fatal( _("%s: error reading version record: %s\n"),
636 db_name, gpg_errstr(rc) );
638 stamp = make_timestamp();
639 if( down )
640 vr.r.ver.mod_down = stamp;
641 if( up )
642 vr.r.ver.mod_up = stamp;
644 rc = tdbio_write_record( &vr );
645 if( rc )
646 log_fatal( _("%s: error writing version record: %s\n"),
647 db_name, gpg_errstr(rc) );
651 /****************
652 * Return the record number of the keyhash tbl or create a new one.
654 static ulong
655 get_keyhashrec(void)
657 static ulong keyhashtbl; /* record number of the key hashtable */
659 if( !keyhashtbl ) {
660 TRUSTREC vr;
661 int rc;
663 rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
664 if( rc )
665 log_fatal( _("%s: error reading version record: %s\n"),
666 db_name, gpg_errstr(rc) );
667 if( !vr.r.ver.keyhashtbl )
668 create_hashtable( &vr, 0 );
670 keyhashtbl = vr.r.ver.keyhashtbl;
672 return keyhashtbl;
675 /****************
676 * Return the record number of the shadow direcory hash table
677 * or create a new one.
679 static ulong
680 get_sdirhashrec(void)
682 static ulong sdirhashtbl; /* record number of the hashtable */
684 if( !sdirhashtbl ) {
685 TRUSTREC vr;
686 int rc;
688 rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
689 if( rc )
690 log_fatal( _("%s: error reading version record: %s\n"),
691 db_name, gpg_errstr(rc) );
692 if( !vr.r.ver.sdirhashtbl )
693 create_hashtable( &vr, 1 );
695 sdirhashtbl = vr.r.ver.sdirhashtbl;
697 return sdirhashtbl;
701 /****************
702 * Update a hashtable.
703 * table gives the start of the table, key and keylen is the key,
704 * newrecnum is the record number to insert.
706 static int
707 upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
709 TRUSTREC lastrec, rec;
710 ulong hashrec, item;
711 int msb;
712 int level=0;
713 int rc, i;
715 hashrec = table;
716 next_level:
717 msb = key[level];
718 hashrec += msb / ITEMS_PER_HTBL_RECORD;
719 rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL );
720 if( rc ) {
721 log_error( db_name, "upd_hashtable: read failed: %s\n",
722 gpg_errstr(rc) );
723 return rc;
726 item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
727 if( !item ) { /* insert a new item into the hash table */
728 rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = newrecnum;
729 rc = tdbio_write_record( &rec );
730 if( rc ) {
731 log_error( db_name, "upd_hashtable: write htbl failed: %s\n",
732 gpg_errstr(rc) );
733 return rc;
736 else if( item != newrecnum ) { /* must do an update */
737 lastrec = rec;
738 rc = tdbio_read_record( item, &rec, 0 );
739 if( rc ) {
740 log_error( "upd_hashtable: read item failed: %s\n",
741 gpg_errstr(rc) );
742 return rc;
745 if( rec.rectype == RECTYPE_HTBL ) {
746 hashrec = item;
747 level++;
748 if( level >= keylen ) {
749 log_error( "hashtable has invalid indirections.\n");
750 return GPGERR_TRUSTDB;
752 goto next_level;
754 else if( rec.rectype == RECTYPE_HLST ) { /* extend list */
755 /* see whether the key is already in this list */
756 for(;;) {
757 for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
758 if( rec.r.hlst.rnum[i] == newrecnum ) {
759 return 0; /* okay, already in the list */
762 if( rec.r.hlst.next ) {
763 rc = tdbio_read_record( rec.r.hlst.next,
764 &rec, RECTYPE_HLST);
765 if( rc ) {
766 log_error( "scan keyhashtbl read hlst failed: %s\n",
767 gpg_errstr(rc) );
768 return rc;
771 else
772 break; /* not there */
774 /* find the next free entry and put it in */
775 for(;;) {
776 for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
777 if( !rec.r.hlst.rnum[i] ) {
778 rec.r.hlst.rnum[i] = newrecnum;
779 rc = tdbio_write_record( &rec );
780 if( rc )
781 log_error( "upd_hashtable: write hlst failed: %s\n",
782 gpg_errstr(rc) );
783 return rc; /* done */
786 if( rec.r.hlst.next ) {
787 rc = tdbio_read_record( rec.r.hlst.next,
788 &rec, RECTYPE_HLST );
789 if( rc ) {
790 log_error( "upd_hashtable: read hlst failed: %s\n",
791 gpg_errstr(rc) );
792 return rc;
795 else { /* add a new list record */
796 rec.r.hlst.next = item = tdbio_new_recnum();
797 rc = tdbio_write_record( &rec );
798 if( rc ) {
799 log_error( "upd_hashtable: write hlst failed: %s\n",
800 gpg_errstr(rc) );
801 return rc;
803 memset( &rec, 0, sizeof rec );
804 rec.rectype = RECTYPE_HLST;
805 rec.recnum = item;
806 rec.r.hlst.rnum[0] = newrecnum;
807 rc = tdbio_write_record( &rec );
808 if( rc )
809 log_error( "upd_hashtable: write ext hlst failed: %s\n",
810 gpg_errstr(rc) );
811 return rc; /* done */
813 } /* end loop over hlst slots */
815 else if( rec.rectype == RECTYPE_KEY
816 || rec.rectype == RECTYPE_DIR
817 || rec.rectype == RECTYPE_SDIR ) { /* insert a list record */
818 if( rec.recnum == newrecnum ) {
819 return 0;
821 item = rec.recnum; /* save number of key record */
822 memset( &rec, 0, sizeof rec );
823 rec.rectype = RECTYPE_HLST;
824 rec.recnum = tdbio_new_recnum();
825 rec.r.hlst.rnum[0] = item; /* old keyrecord */
826 rec.r.hlst.rnum[1] = newrecnum; /* and new one */
827 rc = tdbio_write_record( &rec );
828 if( rc ) {
829 log_error( "upd_hashtable: write new hlst failed: %s\n",
830 gpg_errstr(rc) );
831 return rc;
833 /* update the hashtable record */
834 lastrec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = rec.recnum;
835 rc = tdbio_write_record( &lastrec );
836 if( rc )
837 log_error( "upd_hashtable: update htbl failed: %s\n",
838 gpg_errstr(rc) );
839 return rc; /* ready */
841 else {
842 log_error( "hashtbl %lu: %lu/%d points to an invalid record %lu\n",
843 table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item);
844 list_trustdb(NULL);
845 return GPGERR_TRUSTDB;
849 return 0;
853 /****************
854 * Drop an entry from a hashtable
855 * table gives the start of the table, key and keylen is the key,
857 static int
858 drop_from_hashtable( ulong table, byte *key, int keylen, ulong recnum )
860 TRUSTREC rec;
861 ulong hashrec, item;
862 int msb;
863 int level=0;
864 int rc, i;
866 hashrec = table;
867 next_level:
868 msb = key[level];
869 hashrec += msb / ITEMS_PER_HTBL_RECORD;
870 rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL );
871 if( rc ) {
872 log_error( db_name, "drop_from_hashtable: read failed: %s\n",
873 gpg_errstr(rc) );
874 return rc;
877 item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
878 if( !item ) /* not found - forget about it */
879 return 0;
881 if( item == recnum ) { /* tables points direct to the record */
882 rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = 0;
883 rc = tdbio_write_record( &rec );
884 if( rc )
885 log_error( db_name, "drop_from_hashtable: write htbl failed: %s\n",
886 gpg_errstr(rc) );
887 return rc;
890 rc = tdbio_read_record( item, &rec, 0 );
891 if( rc ) {
892 log_error( "drop_from_hashtable: read item failed: %s\n",
893 gpg_errstr(rc) );
894 return rc;
897 if( rec.rectype == RECTYPE_HTBL ) {
898 hashrec = item;
899 level++;
900 if( level >= keylen ) {
901 log_error( "hashtable has invalid indirections.\n");
902 return GPGERR_TRUSTDB;
904 goto next_level;
907 if( rec.rectype == RECTYPE_HLST ) {
908 for(;;) {
909 for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
910 if( rec.r.hlst.rnum[i] == recnum ) {
911 rec.r.hlst.rnum[i] = 0; /* drop */
912 rc = tdbio_write_record( &rec );
913 if( rc )
914 log_error( db_name, "drop_from_hashtable: write htbl failed: %s\n",
915 gpg_errstr(rc) );
916 return rc;
919 if( rec.r.hlst.next ) {
920 rc = tdbio_read_record( rec.r.hlst.next,
921 &rec, RECTYPE_HLST);
922 if( rc ) {
923 log_error( "scan keyhashtbl read hlst failed: %s\n",
924 gpg_errstr(rc) );
925 return rc;
928 else
929 return 0; /* key not in table */
933 log_error( "hashtbl %lu: %lu/%d points to wrong record %lu\n",
934 table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item);
935 return GPGERR_TRUSTDB;
940 /****************
941 * Lookup a record via the hashtable tablewith key/keylen and return the
942 * result in rec. cmp() should return if the record is the desired one.
943 * Returns -1 if not found, 0 if found or another errocode
945 static int
946 lookup_hashtable( ulong table, const byte *key, size_t keylen,
947 int (*cmpfnc)(void*, const TRUSTREC *), void *cmpdata,
948 TRUSTREC *rec )
950 int rc;
951 ulong hashrec, item;
952 int msb;
953 int level=0;
955 hashrec = table;
956 next_level:
957 msb = key[level];
958 hashrec += msb / ITEMS_PER_HTBL_RECORD;
959 rc = tdbio_read_record( hashrec, rec, RECTYPE_HTBL );
960 if( rc ) {
961 log_error( db_name, "lookup_hashtable failed: %s\n", gpg_errstr(rc) );
962 return rc;
965 item = rec->r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
966 if( !item )
967 return -1; /* not found */
969 rc = tdbio_read_record( item, rec, 0 );
970 if( rc ) {
971 log_error( db_name, "hashtable read failed: %s\n", gpg_errstr(rc) );
972 return rc;
974 if( rec->rectype == RECTYPE_HTBL ) {
975 hashrec = item;
976 level++;
977 if( level >= keylen ) {
978 log_error( db_name, "hashtable has invalid indirections\n");
979 return GPGERR_TRUSTDB;
981 goto next_level;
983 else if( rec->rectype == RECTYPE_HLST ) {
984 for(;;) {
985 int i;
987 for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
988 if( rec->r.hlst.rnum[i] ) {
989 TRUSTREC tmp;
991 rc = tdbio_read_record( rec->r.hlst.rnum[i], &tmp, 0 );
992 if( rc ) {
993 log_error( "lookup_hashtable: read item failed: %s\n",
994 gpg_errstr(rc) );
995 return rc;
997 if( (*cmpfnc)( cmpdata, &tmp ) ) {
998 *rec = tmp;
999 return 0;
1003 if( rec->r.hlst.next ) {
1004 rc = tdbio_read_record( rec->r.hlst.next, rec, RECTYPE_HLST );
1005 if( rc ) {
1006 log_error( "lookup_hashtable: read hlst failed: %s\n",
1007 gpg_errstr(rc) );
1008 return rc;
1011 else
1012 return -1; /* not found */
1017 if( (*cmpfnc)( cmpdata, rec ) )
1018 return 0; /* really found */
1020 return -1; /* no: not found */
1026 /****************
1027 * Update the key hashtbl or create the table if it does not exist
1029 static int
1030 update_keyhashtbl( TRUSTREC *kr )
1032 return upd_hashtable( get_keyhashrec(),
1033 kr->r.key.fingerprint,
1034 kr->r.key.fingerprint_len, kr->recnum );
1037 /****************
1038 * Update the shadow dir hashtbl or create the table if it does not exist
1040 static int
1041 update_sdirhashtbl( TRUSTREC *sr )
1043 byte key[8];
1045 u32tobuf( key , sr->r.sdir.keyid[0] );
1046 u32tobuf( key+4 , sr->r.sdir.keyid[1] );
1047 return upd_hashtable( get_sdirhashrec(), key, 8, sr->recnum );
1050 /****************
1051 * Drop the records from the key-hashtbl
1053 static int
1054 drop_from_keyhashtbl( TRUSTREC *kr )
1056 return drop_from_hashtable( get_keyhashrec(),
1057 kr->r.key.fingerprint,
1058 kr->r.key.fingerprint_len, kr->recnum );
1061 /****************
1062 * Drop record drom the shadow dir hashtbl
1064 static int
1065 drop_from_sdirhashtbl( TRUSTREC *sr )
1067 byte key[8];
1069 u32tobuf( key , sr->r.sdir.keyid[0] );
1070 u32tobuf( key+4 , sr->r.sdir.keyid[1] );
1071 return drop_from_hashtable( get_sdirhashrec(), key, 8, sr->recnum );
1077 void
1078 tdbio_dump_record( TRUSTREC *rec, FILE *fp )
1080 int i;
1081 ulong rnum = rec->recnum;
1082 byte *p;
1084 fprintf(fp, "rec %5lu, ", rnum );
1086 switch( rec->rectype ) {
1087 case 0: fprintf(fp, "blank\n");
1088 break;
1089 case RECTYPE_VER: fprintf(fp,
1090 "version, kd=%lu, sd=%lu, free=%lu, m/c/d=%d/%d/%d down=%s",
1091 rec->r.ver.keyhashtbl, rec->r.ver.sdirhashtbl,
1092 rec->r.ver.firstfree,
1093 rec->r.ver.marginals,
1094 rec->r.ver.completes,
1095 rec->r.ver.cert_depth,
1096 strtimestamp(rec->r.ver.mod_down) );
1097 fprintf(fp, ", up=%s\n", strtimestamp(rec->r.ver.mod_up) );
1098 break;
1099 case RECTYPE_FREE: fprintf(fp, "free, next=%lu\n", rec->r.free.next );
1100 break;
1101 case RECTYPE_DIR:
1102 fprintf(fp, "dir %lu, keys=%lu, uids=%lu, t=%02x",
1103 rec->r.dir.lid,
1104 rec->r.dir.keylist,
1105 rec->r.dir.uidlist,
1106 rec->r.dir.ownertrust );
1107 if( rec->r.dir.valcheck )
1108 fprintf( fp, ", v=%02x/%s", rec->r.dir.validity,
1109 strtimestamp(rec->r.dir.valcheck) );
1110 if( rec->r.dir.checkat )
1111 fprintf( fp, ", a=%s", strtimestamp(rec->r.dir.checkat) );
1112 if( rec->r.dir.dirflags & DIRF_CHECKED ) {
1113 if( rec->r.dir.dirflags & DIRF_VALID )
1114 fputs(", valid", fp );
1115 if( rec->r.dir.dirflags & DIRF_EXPIRED )
1116 fputs(", expired", fp );
1117 if( rec->r.dir.dirflags & DIRF_REVOKED )
1118 fputs(", revoked", fp );
1119 if( rec->r.dir.dirflags & DIRF_NEWKEYS )
1120 fputs(", newkeys", fp );
1122 putc('\n', fp);
1123 break;
1124 case RECTYPE_KEY:
1125 fprintf(fp, "key %lu, n=%lu a=%d ",
1126 rec->r.key.lid,
1127 rec->r.key.next,
1128 rec->r.key.pubkey_algo );
1129 for(i=0; i < rec->r.key.fingerprint_len; i++ )
1130 fprintf(fp, "%02X", rec->r.key.fingerprint[i] );
1131 if( rec->r.key.keyflags & KEYF_CHECKED ) {
1132 if( rec->r.key.keyflags & KEYF_VALID )
1133 fputs(", valid", fp );
1134 if( rec->r.key.keyflags & KEYF_EXPIRED )
1135 fputs(", expired", fp );
1136 if( rec->r.key.keyflags & KEYF_REVOKED )
1137 fputs(", revoked", fp );
1139 putc('\n', fp);
1140 break;
1141 case RECTYPE_UID:
1142 fprintf(fp, "uid %lu, next=%lu, pref=%lu, sig=%lu, hash=%02X%02X",
1143 rec->r.uid.lid,
1144 rec->r.uid.next,
1145 rec->r.uid.prefrec,
1146 rec->r.uid.siglist,
1147 rec->r.uid.namehash[18], rec->r.uid.namehash[19]);
1148 fprintf( fp, ", v=%02x", rec->r.uid.validity );
1149 if( rec->r.uid.uidflags & UIDF_CHECKED ) {
1150 if( rec->r.uid.uidflags & UIDF_VALID )
1151 fputs(", valid", fp );
1152 if( rec->r.uid.uidflags & UIDF_REVOKED )
1153 fputs(", revoked", fp );
1155 putc('\n', fp);
1156 break;
1157 case RECTYPE_PREF:
1158 fprintf(fp, "pref %lu, next=%lu,",
1159 rec->r.pref.lid, rec->r.pref.next);
1160 for(i=0,p=rec->r.pref.data; i < ITEMS_PER_PREF_RECORD; i+=2,p+=2 ) {
1161 if( *p )
1162 fprintf(fp, " %c%d", *p == PREFTYPE_SYM ? 'S' :
1163 *p == PREFTYPE_HASH ? 'H' :
1164 *p == PREFTYPE_COMPR ? 'Z' : '?', p[1]);
1166 putc('\n', fp);
1167 break;
1168 case RECTYPE_SIG:
1169 fprintf(fp, "sig %lu, next=%lu,",
1170 rec->r.sig.lid, rec->r.sig.next );
1171 for(i=0; i < SIGS_PER_RECORD; i++ ) {
1172 if( rec->r.sig.sig[i].lid ) {
1173 fprintf(fp, " %lu:", rec->r.sig.sig[i].lid );
1174 if( rec->r.sig.sig[i].flag & SIGF_CHECKED ) {
1175 fprintf(fp,"%c%c%c",
1176 (rec->r.sig.sig[i].flag & SIGF_VALID) ? 'V':
1177 (rec->r.sig.sig[i].flag & SIGF_IGNORED) ? 'I':'-',
1178 (rec->r.sig.sig[i].flag & SIGF_EXPIRED) ? 'E':'-',
1179 (rec->r.sig.sig[i].flag & SIGF_REVOKED) ? 'R':'-');
1181 else if( rec->r.sig.sig[i].flag & SIGF_NOPUBKEY)
1182 fputs("?--", fp);
1183 else
1184 fputs("---", fp);
1187 putc('\n', fp);
1188 break;
1189 case RECTYPE_SDIR:
1190 fprintf(fp, "sdir %lu, keyid=%08lX%08lX, algo=%d, hint=%lu\n",
1191 rec->r.sdir.lid,
1192 (ulong)rec->r.sdir.keyid[0],
1193 (ulong)rec->r.sdir.keyid[1],
1194 rec->r.sdir.pubkey_algo,
1195 (ulong)rec->r.sdir.hintlist );
1196 break;
1197 case RECTYPE_CACH:
1198 fprintf(fp, "cach\n");
1199 break;
1200 case RECTYPE_HTBL:
1201 fprintf(fp, "htbl,");
1202 for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ )
1203 fprintf(fp, " %lu", rec->r.htbl.item[i] );
1204 putc('\n', fp);
1205 break;
1206 case RECTYPE_HLST:
1207 fprintf(fp, "hlst, next=%lu,", rec->r.hlst.next );
1208 for(i=0; i < ITEMS_PER_HLST_RECORD; i++ )
1209 fprintf(fp, " %lu", rec->r.hlst.rnum[i] );
1210 putc('\n', fp);
1211 break;
1212 default:
1213 fprintf(fp, "unknown type %d\n", rec->rectype );
1214 break;
1218 /****************
1219 * read the record with number recnum
1220 * returns: -1 on error, 0 on success
1223 tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
1225 byte readbuf[TRUST_RECORD_LEN];
1226 const byte *buf, *p;
1227 int rc = 0;
1228 int n, i;
1230 if( db_fd == -1 )
1231 open_db();
1232 buf = get_record_from_cache( recnum );
1233 if( !buf ) {
1234 if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
1235 log_error(_("trustdb: lseek failed: %s\n"), strerror(errno) );
1236 return GPGERR_READ_FILE;
1238 n = read( db_fd, readbuf, TRUST_RECORD_LEN);
1239 if( !n ) {
1240 return -1; /* eof */
1242 else if( n != TRUST_RECORD_LEN ) {
1243 log_error(_("trustdb: read failed (n=%d): %s\n"), n,
1244 strerror(errno) );
1245 return GPGERR_READ_FILE;
1247 buf = readbuf;
1249 rec->recnum = recnum;
1250 rec->dirty = 0;
1251 p = buf;
1252 rec->rectype = *p++;
1253 if( expected && rec->rectype != expected ) {
1254 log_error("%lu: read expected rec type %d, got %d\n",
1255 recnum, expected, rec->rectype );
1256 return GPGERR_TRUSTDB;
1258 p++; /* skip reserved byte */
1259 switch( rec->rectype ) {
1260 case 0: /* unused (free) record */
1261 break;
1262 case RECTYPE_VER: /* version record */
1263 if( memcmp(buf+1, "gpg", 3 ) ) {
1264 log_error( _("%s: not a trustdb file\n"), db_name );
1265 rc = GPGERR_TRUSTDB;
1267 p += 2; /* skip "pgp" */
1268 rec->r.ver.version = *p++;
1269 rec->r.ver.marginals = *p++;
1270 rec->r.ver.completes = *p++;
1271 rec->r.ver.cert_depth = *p++;
1272 p += 4; /* lock flags */
1273 rec->r.ver.created = buftoulong(p); p += 4;
1274 rec->r.ver.mod_down = buftoulong(p); p += 4;
1275 rec->r.ver.mod_up = buftoulong(p); p += 4;
1276 rec->r.ver.keyhashtbl=buftoulong(p); p += 4;
1277 rec->r.ver.firstfree =buftoulong(p); p += 4;
1278 rec->r.ver.sdirhashtbl =buftoulong(p); p += 4;
1279 if( recnum ) {
1280 log_error( _("%s: version record with recnum %lu\n"), db_name,
1281 (ulong)recnum );
1282 rc = GPGERR_TRUSTDB;
1284 else if( rec->r.ver.version != 2 ) {
1285 log_error( _("%s: invalid file version %d\n"), db_name,
1286 rec->r.ver.version );
1287 rc = GPGERR_TRUSTDB;
1289 break;
1290 case RECTYPE_FREE:
1291 rec->r.free.next = buftoulong(p); p += 4;
1292 break;
1293 case RECTYPE_DIR: /*directory record */
1294 rec->r.dir.lid = buftoulong(p); p += 4;
1295 rec->r.dir.keylist = buftoulong(p); p += 4;
1296 rec->r.dir.uidlist = buftoulong(p); p += 4;
1297 rec->r.dir.cacherec = buftoulong(p); p += 4;
1298 rec->r.dir.ownertrust = *p++;
1299 rec->r.dir.dirflags = *p++;
1300 rec->r.dir.validity = *p++;
1301 rec->r.dir.valcheck = buftoulong(p); p += 4;
1302 rec->r.dir.checkat = buftoulong(p); p += 4;
1303 switch( rec->r.dir.validity ) {
1304 case 0:
1305 case TRUST_UNDEFINED:
1306 case TRUST_NEVER:
1307 case TRUST_MARGINAL:
1308 case TRUST_FULLY:
1309 case TRUST_ULTIMATE:
1310 break;
1311 default:
1312 log_info("lid %lu: invalid validity value - cleared\n", recnum);
1314 if( rec->r.dir.lid != recnum ) {
1315 log_error( "%s: dir LID != recnum (%lu,%lu)\n",
1316 db_name, rec->r.dir.lid, (ulong)recnum );
1317 rc = GPGERR_TRUSTDB;
1319 break;
1320 case RECTYPE_KEY: /* public key record */
1321 rec->r.key.lid = buftoulong(p); p += 4;
1322 rec->r.key.next = buftoulong(p); p += 4;
1323 p += 7;
1324 rec->r.key.keyflags = *p++;
1325 rec->r.key.pubkey_algo = *p++;
1326 rec->r.key.fingerprint_len = *p++;
1327 if( rec->r.key.fingerprint_len < 1 || rec->r.key.fingerprint_len > 20 )
1328 rec->r.key.fingerprint_len = 20;
1329 memcpy( rec->r.key.fingerprint, p, 20);
1330 break;
1331 case RECTYPE_UID: /* user id record */
1332 rec->r.uid.lid = buftoulong(p); p += 4;
1333 rec->r.uid.next = buftoulong(p); p += 4;
1334 rec->r.uid.prefrec = buftoulong(p); p += 4;
1335 rec->r.uid.siglist = buftoulong(p); p += 4;
1336 rec->r.uid.uidflags = *p++;
1337 rec->r.uid.validity = *p++;
1338 switch( rec->r.uid.validity ) {
1339 case 0:
1340 case TRUST_UNDEFINED:
1341 case TRUST_NEVER:
1342 case TRUST_MARGINAL:
1343 case TRUST_FULLY:
1344 case TRUST_ULTIMATE:
1345 break;
1346 default:
1347 log_info("lid %lu: invalid validity value - cleared\n", recnum);
1349 memcpy( rec->r.uid.namehash, p, 20);
1350 break;
1351 case RECTYPE_PREF: /* preference record */
1352 rec->r.pref.lid = buftoulong(p); p += 4;
1353 rec->r.pref.next = buftoulong(p); p += 4;
1354 memcpy( rec->r.pref.data, p, 30 );
1355 break;
1356 case RECTYPE_SIG:
1357 rec->r.sig.lid = buftoulong(p); p += 4;
1358 rec->r.sig.next = buftoulong(p); p += 4;
1359 for(i=0; i < SIGS_PER_RECORD; i++ ) {
1360 rec->r.sig.sig[i].lid = buftoulong(p); p += 4;
1361 rec->r.sig.sig[i].flag = *p++;
1363 break;
1364 case RECTYPE_SDIR: /* shadow directory record */
1365 rec->r.sdir.lid = buftoulong(p); p += 4;
1366 rec->r.sdir.keyid[0]= buftou32(p); p += 4;
1367 rec->r.sdir.keyid[1]= buftou32(p); p += 4;
1368 rec->r.sdir.pubkey_algo = *p++;
1369 p += 3;
1370 rec->r.sdir.hintlist = buftoulong(p);
1371 if( rec->r.sdir.lid != recnum ) {
1372 log_error( "%s: sdir LID != recnum (%lu,%lu)\n",
1373 db_name, rec->r.sdir.lid, (ulong)recnum );
1374 rc = GPGERR_TRUSTDB;
1376 break;
1377 case RECTYPE_CACH: /* cache record */
1378 rec->r.cache.lid = buftoulong(p); p += 4;
1379 memcpy(rec->r.cache.blockhash, p, 20); p += 20;
1380 rec->r.cache.trustlevel = *p++;
1381 break;
1382 case RECTYPE_HTBL:
1383 for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) {
1384 rec->r.htbl.item[i] = buftoulong(p); p += 4;
1386 break;
1387 case RECTYPE_HLST:
1388 rec->r.hlst.next = buftoulong(p); p += 4;
1389 for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
1390 rec->r.hlst.rnum[i] = buftoulong(p); p += 4;
1392 break;
1393 default:
1394 log_error( "%s: invalid record type %d at recnum %lu\n",
1395 db_name, rec->rectype, (ulong)recnum );
1396 rc = GPGERR_TRUSTDB;
1397 break;
1400 return rc;
1403 /****************
1404 * Write the record at RECNUM
1407 tdbio_write_record( TRUSTREC *rec )
1409 byte buf[TRUST_RECORD_LEN], *p;
1410 int rc = 0;
1411 int i;
1412 ulong recnum = rec->recnum;
1414 if( db_fd == -1 )
1415 open_db();
1417 memset(buf, 0, TRUST_RECORD_LEN);
1418 p = buf;
1419 *p++ = rec->rectype; p++;
1420 switch( rec->rectype ) {
1421 case 0: /* unused record */
1422 break;
1423 case RECTYPE_VER: /* version record */
1424 if( recnum )
1425 BUG();
1426 memcpy(p-1, "gpg", 3 ); p += 2;
1427 *p++ = rec->r.ver.version;
1428 *p++ = rec->r.ver.marginals;
1429 *p++ = rec->r.ver.completes;
1430 *p++ = rec->r.ver.cert_depth;
1431 p += 4; /* skip lock flags */
1432 ulongtobuf(p, rec->r.ver.created); p += 4;
1433 ulongtobuf(p, rec->r.ver.mod_down); p += 4;
1434 ulongtobuf(p, rec->r.ver.mod_up); p += 4;
1435 ulongtobuf(p, rec->r.ver.keyhashtbl); p += 4;
1436 ulongtobuf(p, rec->r.ver.firstfree ); p += 4;
1437 ulongtobuf(p, rec->r.ver.sdirhashtbl ); p += 4;
1438 break;
1440 case RECTYPE_FREE:
1441 ulongtobuf(p, rec->r.free.next); p += 4;
1442 break;
1444 case RECTYPE_DIR: /*directory record */
1445 ulongtobuf(p, rec->r.dir.lid); p += 4;
1446 ulongtobuf(p, rec->r.dir.keylist); p += 4;
1447 ulongtobuf(p, rec->r.dir.uidlist); p += 4;
1448 ulongtobuf(p, rec->r.dir.cacherec); p += 4;
1449 *p++ = rec->r.dir.ownertrust;
1450 *p++ = rec->r.dir.dirflags;
1451 *p++ = rec->r.dir.validity;
1452 ulongtobuf(p, rec->r.dir.valcheck); p += 4;
1453 ulongtobuf(p, rec->r.dir.checkat); p += 4;
1454 assert( rec->r.dir.lid == recnum );
1455 break;
1457 case RECTYPE_KEY:
1458 ulongtobuf(p, rec->r.key.lid); p += 4;
1459 ulongtobuf(p, rec->r.key.next); p += 4;
1460 p += 7;
1461 *p++ = rec->r.key.keyflags;
1462 *p++ = rec->r.key.pubkey_algo;
1463 *p++ = rec->r.key.fingerprint_len;
1464 memcpy( p, rec->r.key.fingerprint, 20); p += 20;
1465 break;
1467 case RECTYPE_UID: /* user id record */
1468 ulongtobuf(p, rec->r.uid.lid); p += 4;
1469 ulongtobuf(p, rec->r.uid.next); p += 4;
1470 ulongtobuf(p, rec->r.uid.prefrec); p += 4;
1471 ulongtobuf(p, rec->r.uid.siglist); p += 4;
1472 *p++ = rec->r.uid.uidflags;
1473 *p++ = rec->r.uid.validity;
1474 memcpy( p, rec->r.uid.namehash, 20 ); p += 20;
1475 break;
1477 case RECTYPE_PREF:
1478 ulongtobuf(p, rec->r.pref.lid); p += 4;
1479 ulongtobuf(p, rec->r.pref.next); p += 4;
1480 memcpy( p, rec->r.pref.data, 30 );
1481 break;
1483 case RECTYPE_SIG:
1484 ulongtobuf(p, rec->r.sig.lid); p += 4;
1485 ulongtobuf(p, rec->r.sig.next); p += 4;
1486 for(i=0; i < SIGS_PER_RECORD; i++ ) {
1487 ulongtobuf(p, rec->r.sig.sig[i].lid); p += 4;
1488 *p++ = rec->r.sig.sig[i].flag;
1490 break;
1492 case RECTYPE_SDIR:
1493 ulongtobuf( p, rec->r.sdir.lid); p += 4;
1494 u32tobuf( p, rec->r.sdir.keyid[0] ); p += 4;
1495 u32tobuf( p, rec->r.sdir.keyid[1] ); p += 4;
1496 *p++ = rec->r.sdir.pubkey_algo;
1497 p += 3;
1498 ulongtobuf( p, rec->r.sdir.hintlist );
1499 break;
1501 case RECTYPE_CACH:
1502 ulongtobuf(p, rec->r.cache.lid); p += 4;
1503 memcpy(p, rec->r.cache.blockhash, 20); p += 20;
1504 *p++ = rec->r.cache.trustlevel;
1505 break;
1507 case RECTYPE_HTBL:
1508 for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) {
1509 ulongtobuf( p, rec->r.htbl.item[i]); p += 4;
1511 break;
1513 case RECTYPE_HLST:
1514 ulongtobuf( p, rec->r.hlst.next); p += 4;
1515 for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
1516 ulongtobuf( p, rec->r.hlst.rnum[i]); p += 4;
1518 break;
1520 default:
1521 BUG();
1524 rc = put_record_into_cache( recnum, buf );
1525 if( rc )
1527 else if( rec->rectype == RECTYPE_KEY )
1528 rc = update_keyhashtbl( rec );
1529 else if( rec->rectype == RECTYPE_SDIR )
1530 rc = update_sdirhashtbl( rec );
1532 return rc;
1536 tdbio_delete_record( ulong recnum )
1538 TRUSTREC vr, rec;
1539 int rc;
1541 /* Must read the record fist, so we can drop it from the hash tables */
1542 rc = tdbio_read_record( recnum, &rec, 0 );
1543 if( rc )
1545 else if( rec.rectype == RECTYPE_KEY )
1546 rc = drop_from_keyhashtbl( &rec );
1547 else if( rec.rectype == RECTYPE_SDIR )
1548 rc = drop_from_sdirhashtbl( &rec );
1550 if( rc )
1551 return rc;
1553 /* now we can chnage it to a free record */
1554 rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
1555 if( rc )
1556 log_fatal( _("%s: error reading version record: %s\n"),
1557 db_name, gpg_errstr(rc) );
1559 rec.recnum = recnum;
1560 rec.rectype = RECTYPE_FREE;
1561 rec.r.free.next = vr.r.ver.firstfree;
1562 vr.r.ver.firstfree = recnum;
1563 rc = tdbio_write_record( &rec );
1564 if( !rc )
1565 rc = tdbio_write_record( &vr );
1566 return rc;
1569 /****************
1570 * create a new record and return its record number
1572 ulong
1573 tdbio_new_recnum()
1575 off_t offset;
1576 ulong recnum;
1577 TRUSTREC vr, rec;
1578 int rc;
1580 /* look for unused records */
1581 rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
1582 if( rc )
1583 log_fatal( _("%s: error reading version record: %s\n"),
1584 db_name, gpg_errstr(rc) );
1585 if( vr.r.ver.firstfree ) {
1586 recnum = vr.r.ver.firstfree;
1587 rc = tdbio_read_record( recnum, &rec, RECTYPE_FREE );
1588 if( rc ) {
1589 log_error( _("%s: error reading free record: %s\n"),
1590 db_name, gpg_errstr(rc) );
1591 return rc;
1593 /* update dir record */
1594 vr.r.ver.firstfree = rec.r.free.next;
1595 rc = tdbio_write_record( &vr );
1596 if( rc ) {
1597 log_error( _("%s: error writing dir record: %s\n"),
1598 db_name, gpg_errstr(rc) );
1599 return rc;
1601 /*zero out the new record */
1602 memset( &rec, 0, sizeof rec );
1603 rec.rectype = 0; /* unused record */
1604 rec.recnum = recnum;
1605 rc = tdbio_write_record( &rec );
1606 if( rc )
1607 log_fatal(_("%s: failed to zero a record: %s\n"),
1608 db_name, gpg_errstr(rc));
1610 else { /* not found, append a new record */
1611 offset = lseek( db_fd, 0, SEEK_END );
1612 if( offset == -1 )
1613 log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
1614 recnum = offset / TRUST_RECORD_LEN;
1615 assert(recnum); /* this is will never be the first record */
1616 /* we must write a record, so that the next call to this function
1617 * returns another recnum */
1618 memset( &rec, 0, sizeof rec );
1619 rec.rectype = 0; /* unused record */
1620 rec.recnum = recnum;
1621 rc = 0;
1622 if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
1623 log_error(_("trustdb rec %lu: lseek failed: %s\n"),
1624 recnum, strerror(errno) );
1625 rc = GPGERR_WRITE_FILE;
1627 else {
1628 int n = write( db_fd, &rec, TRUST_RECORD_LEN);
1629 if( n != TRUST_RECORD_LEN ) {
1630 log_error(_("trustdb rec %lu: write failed (n=%d): %s\n"),
1631 recnum, n, strerror(errno) );
1632 rc = GPGERR_WRITE_FILE;
1636 if( rc )
1637 log_fatal(_("%s: failed to append a record: %s\n"),
1638 db_name, gpg_errstr(rc));
1640 return recnum ;
1645 /****************
1646 * Search the trustdb for a key which matches PK and return the dir record
1647 * The local_id of PK is set to the correct value
1650 tdbio_search_dir_bypk( PKT_public_key *pk, TRUSTREC *rec )
1652 byte fingerprint[MAX_FINGERPRINT_LEN];
1653 size_t fingerlen;
1654 u32 keyid[2];
1655 int rc;
1657 keyid_from_pk( pk, keyid );
1658 fingerprint_from_pk( pk, fingerprint, &fingerlen );
1659 rc = tdbio_search_dir_byfpr( fingerprint, fingerlen,
1660 pk->pubkey_algo, rec );
1662 if( !rc ) {
1663 if( pk->local_id && pk->local_id != rec->recnum )
1664 log_error("%s: found record, but LID from memory does "
1665 "not match recnum (%lu,%lu)\n",
1666 db_name, pk->local_id, rec->recnum );
1667 pk->local_id = rec->recnum;
1669 return rc;
1673 static int
1674 cmp_krec_fpr( void *dataptr, const TRUSTREC *rec )
1676 const struct cmp_krec_fpr_struct *d = dataptr;
1678 return rec->rectype == RECTYPE_KEY
1679 && ( !d->pubkey_algo || rec->r.key.pubkey_algo == d->pubkey_algo )
1680 && rec->r.key.fingerprint_len == d->fprlen
1681 && !memcmp( rec->r.key.fingerprint, d->fpr, d->fprlen );
1685 tdbio_search_dir_byfpr( const byte *fingerprint, size_t fingerlen,
1686 int pubkey_algo, TRUSTREC *rec )
1688 struct cmp_krec_fpr_struct cmpdata;
1689 ulong recnum;
1690 int rc;
1692 assert( fingerlen == 20 || fingerlen == 16 );
1694 /* locate the key using the hash table */
1695 cmpdata.pubkey_algo = pubkey_algo;
1696 cmpdata.fpr = fingerprint;
1697 cmpdata.fprlen = fingerlen;
1698 rc = lookup_hashtable( get_keyhashrec(), fingerprint, fingerlen,
1699 cmp_krec_fpr, &cmpdata, rec );
1700 if( !rc ) {
1701 recnum = rec->r.key.lid;
1702 /* Now read the dir record */
1703 rc = tdbio_read_record( recnum, rec, RECTYPE_DIR);
1704 if( rc )
1705 log_error("%s: can't read dirrec %lu: %s\n",
1706 db_name, recnum, gpg_errstr(rc) );
1708 return rc;
1713 static int
1714 cmp_sdir( void *dataptr, const TRUSTREC *rec )
1716 const struct cmp_xdir_struct *d = dataptr;
1718 return rec->rectype == RECTYPE_SDIR
1719 && ( !d->pubkey_algo || rec->r.sdir.pubkey_algo == d->pubkey_algo )
1720 && rec->r.sdir.keyid[0] == d->keyid[0]
1721 && rec->r.sdir.keyid[1] == d->keyid[1];
1726 tdbio_search_sdir( u32 *keyid, int pubkey_algo, TRUSTREC *rec )
1728 struct cmp_xdir_struct cmpdata;
1729 int rc;
1730 byte key[8];
1732 /* locate the shadow dir record using the hash table */
1733 u32tobuf( key , keyid[0] );
1734 u32tobuf( key+4 , keyid[1] );
1735 cmpdata.pubkey_algo = pubkey_algo;
1736 cmpdata.keyid[0] = keyid[0];
1737 cmpdata.keyid[1] = keyid[1];
1738 rc = lookup_hashtable( get_sdirhashrec(), key, 8,
1739 cmp_sdir, &cmpdata, rec );
1740 return rc;
1744 void
1745 tdbio_invalid(void)
1747 log_error(_(
1748 "the trustdb is corrupted; please run \"gpg --fix-trustdb\".\n") );
1749 gpg_exit(2);