See ChangeLog: Mon Jan 24 13:04:28 CET 2000 Werner Koch
[gnupg.git] / g10 / tdbio.c
1 /* tdbio.c
2  *      Copyright (C) 1998 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 2 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
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>
31
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"
41
42
43 #ifdef MKDIR_TAKES_ONE_ARG
44 # undef mkdir
45 # define mkdir(a,b) mkdir(a)
46 #endif
47
48 /****************
49  * Yes, this is a very simple implementation. We should really
50  * use a page aligned buffer and read complete pages.
51  * To implement a simple trannsaction system, this is sufficient.
52  */
53 typedef struct cache_ctrl_struct *CACHE_CTRL;
54 struct cache_ctrl_struct {
55     CACHE_CTRL next;
56     struct {
57         unsigned used:1;
58         unsigned dirty:1;
59     } flags;
60     ulong recno;
61     char data[TRUST_RECORD_LEN];
62 };
63
64 #define MAX_CACHE_ENTRIES_SOFT  200    /* may be increased while in a */
65 #define MAX_CACHE_ENTRIES_HARD  10000  /* transaction to this one */
66 static CACHE_CTRL cache_list;
67 static int cache_entries;
68 static int cache_is_dirty;
69
70 /* a type used to pass infomation to cmp_krec_fpr */
71 struct cmp_krec_fpr_struct {
72     int pubkey_algo;
73     const char *fpr;
74     int fprlen;
75 };
76
77 /* a type used to pass infomation to cmp_[s]dir */
78 struct cmp_xdir_struct {
79     int pubkey_algo;
80     u32 keyid[2];
81 };
82
83
84 static char *db_name;
85 static DOTLOCK lockhandle;
86 static int is_locked;
87 static int  db_fd = -1;
88 static int in_transaction;
89
90 static void open_db(void);
91
92 \f
93 /*************************************
94  ************* record cache **********
95  *************************************/
96
97 /****************
98  * Get the data from therecord cache and return a
99  * pointer into that cache.  Caller should copy
100  * the return data.  NULL is returned on a cache miss.
101  */
102 static const char *
103 get_record_from_cache( ulong recno )
104 {
105     CACHE_CTRL r;
106
107     for( r = cache_list; r; r = r->next ) {
108         if( r->flags.used && r->recno == recno )
109             return r->data;
110     }
111     return NULL;
112 }
113
114
115 static int
116 write_cache_item( CACHE_CTRL r )
117 {
118     int n;
119
120     if( lseek( db_fd, r->recno * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
121         log_error(_("trustdb rec %lu: lseek failed: %s\n"),
122                                             r->recno, strerror(errno) );
123         return G10ERR_WRITE_FILE;
124     }
125     n = write( db_fd, r->data, TRUST_RECORD_LEN);
126     if( n != TRUST_RECORD_LEN ) {
127         log_error(_("trustdb rec %lu: write failed (n=%d): %s\n"),
128                                             r->recno, n, strerror(errno) );
129         return G10ERR_WRITE_FILE;
130     }
131     r->flags.dirty = 0;
132     return 0;
133 }
134
135 /****************
136  * Put data into the cache.  This function may flush the
137  * some cache entries if there is not enough space available.
138  */
139 int
140 put_record_into_cache( ulong recno, const char *data )
141 {
142     CACHE_CTRL r, unused;
143     int dirty_count = 0;
144     int clean_count = 0;
145
146     /* see whether we already cached this one */
147     for( unused = NULL, r = cache_list; r; r = r->next ) {
148         if( !r->flags.used ) {
149             if( !unused )
150                 unused = r;
151         }
152         else if( r->recno == recno ) {
153             if( !r->flags.dirty ) {
154                 /* Hmmm: should we use a a copy and compare? */
155                 if( memcmp(r->data, data, TRUST_RECORD_LEN ) ) {
156                     r->flags.dirty = 1;
157                     cache_is_dirty = 1;
158                 }
159             }
160             memcpy( r->data, data, TRUST_RECORD_LEN );
161             return 0;
162         }
163         if( r->flags.used ) {
164             if( r->flags.dirty )
165                 dirty_count++;
166             else
167                 clean_count++;
168         }
169     }
170     /* not in the cache: add a new entry */
171     if( unused ) { /* reuse this entry */
172         r = unused;
173         r->flags.used = 1;
174         r->recno = recno;
175         memcpy( r->data, data, TRUST_RECORD_LEN );
176         r->flags.dirty = 1;
177         cache_is_dirty = 1;
178         cache_entries++;
179         return 0;
180     }
181     /* see whether we reached the limit */
182     if( cache_entries < MAX_CACHE_ENTRIES_SOFT ) { /* no */
183         r = gcry_xmalloc( sizeof *r );
184         r->flags.used = 1;
185         r->recno = recno;
186         memcpy( r->data, data, TRUST_RECORD_LEN );
187         r->flags.dirty = 1;
188         r->next = cache_list;
189         cache_list = r;
190         cache_is_dirty = 1;
191         cache_entries++;
192         return 0;
193     }
194     /* cache is full: discard some clean entries */
195     if( clean_count ) {
196         int n = clean_count / 3; /* discard a third of the clean entries */
197         if( !n )
198             n = 1;
199         for( unused = NULL, r = cache_list; r; r = r->next ) {
200             if( r->flags.used && !r->flags.dirty ) {
201                 if( !unused )
202                     unused = r;
203                 r->flags.used = 0;
204                 cache_entries--;
205                 if( !--n )
206                     break;
207             }
208         }
209         assert( unused );
210         r = unused;
211         r->flags.used = 1;
212         r->recno = recno;
213         memcpy( r->data, data, TRUST_RECORD_LEN );
214         r->flags.dirty = 1;
215         cache_is_dirty = 1;
216         cache_entries++;
217         return 0;
218     }
219     /* no clean entries: have to flush some dirty entries */
220     if( in_transaction ) {
221         /* but we can't do this while in a transaction
222          * we increase the cache size instead */
223         if( cache_entries < MAX_CACHE_ENTRIES_HARD ) { /* no */
224             if( opt.debug && !(cache_entries % 100) )
225                 log_debug("increasing tdbio cache size\n");
226             r = gcry_xmalloc( sizeof *r );
227             r->flags.used = 1;
228             r->recno = recno;
229             memcpy( r->data, data, TRUST_RECORD_LEN );
230             r->flags.dirty = 1;
231             r->next = cache_list;
232             cache_list = r;
233             cache_is_dirty = 1;
234             cache_entries++;
235             return 0;
236         }
237         log_info(_("trustdb transaction too large\n"));
238         return G10ERR_RESOURCE_LIMIT;
239     }
240     if( dirty_count ) {
241         int n = dirty_count / 5; /* discard some dirty entries */
242         if( !n )
243             n = 1;
244         if( !is_locked ) {
245             if( make_dotlock( lockhandle, -1 ) )
246                 log_fatal("can't acquire lock - giving up\n");
247             else
248                 is_locked = 1;
249         }
250         for( unused = NULL, r = cache_list; r; r = r->next ) {
251             if( r->flags.used && r->flags.dirty ) {
252                 int rc = write_cache_item( r );
253                 if( rc )
254                     return rc;
255                 if( !unused )
256                     unused = r;
257                 r->flags.used = 0;
258                 cache_entries--;
259                 if( !--n )
260                     break;
261             }
262         }
263         if( !opt.lock_once ) {
264             if( !release_dotlock( lockhandle ) )
265                 is_locked = 0;
266         }
267         assert( unused );
268         r = unused;
269         r->flags.used = 1;
270         r->recno = recno;
271         memcpy( r->data, data, TRUST_RECORD_LEN );
272         r->flags.dirty = 1;
273         cache_is_dirty = 1;
274         cache_entries++;
275         return 0;
276     }
277     BUG();
278 }
279
280
281 int
282 tdbio_is_dirty()
283 {
284     return cache_is_dirty;
285 }
286
287
288 /****************
289  * Flush the cache.  This cannot be used while in a transaction.
290  */
291 int
292 tdbio_sync()
293 {
294     CACHE_CTRL r;
295     int did_lock = 0;
296
297     if( db_fd == -1 )
298         open_db();
299     if( in_transaction )
300         log_bug("tdbio: syncing while in transaction\n");
301
302     if( !cache_is_dirty )
303         return 0;
304
305     if( !is_locked ) {
306         if( make_dotlock( lockhandle, -1 ) )
307             log_fatal("can't acquire lock - giving up\n");
308         else
309             is_locked = 1;
310         did_lock = 1;
311     }
312     for( r = cache_list; r; r = r->next ) {
313         if( r->flags.used && r->flags.dirty ) {
314             int rc = write_cache_item( r );
315             if( rc )
316                 return rc;
317         }
318     }
319     cache_is_dirty = 0;
320     if( did_lock && !opt.lock_once ) {
321         if( !release_dotlock( lockhandle ) )
322             is_locked = 0;
323     }
324
325     return 0;
326 }
327
328
329
330 /****************
331  * Simple transactions system:
332  * Everything between begin_transaction and end/cancel_transaction
333  * is not immediatly written but at the time of end_transaction.
334  *
335  */
336 int
337 tdbio_begin_transaction()
338 {
339     int rc;
340
341     if( in_transaction )
342         log_bug("tdbio: nested transactions\n");
343     /* flush everything out */
344     rc = tdbio_sync();
345     if( rc )
346         return rc;
347     in_transaction = 1;
348     return 0;
349 }
350
351 int
352 tdbio_end_transaction()
353 {
354     int rc;
355
356     if( !in_transaction )
357         log_bug("tdbio: no active transaction\n");
358     if( !is_locked ) {
359         if( make_dotlock( lockhandle, -1 ) )
360             log_fatal("can't acquire lock - giving up\n");
361         else
362             is_locked = 1;
363     }
364     block_all_signals();
365     in_transaction = 0;
366     rc = tdbio_sync();
367     unblock_all_signals();
368     if( !opt.lock_once ) {
369         if( !release_dotlock( lockhandle ) )
370             is_locked = 0;
371     }
372     return rc;
373 }
374
375 int
376 tdbio_cancel_transaction()
377 {
378     CACHE_CTRL r;
379
380     if( !in_transaction )
381         log_bug("tdbio: no active transaction\n");
382
383     /* remove all dirty marked entries, so that the original ones
384      * are read back the next time */
385     if( cache_is_dirty ) {
386         for( r = cache_list; r; r = r->next ) {
387             if( r->flags.used && r->flags.dirty ) {
388                 r->flags.used = 0;
389                 cache_entries--;
390             }
391         }
392         cache_is_dirty = 0;
393     }
394
395     in_transaction = 0;
396     return 0;
397 }
398
399
400 \f
401 /********************************************************
402  **************** cached I/O functions ******************
403  ********************************************************/
404
405 static void
406 cleanup(void)
407 {
408     if( is_locked ) {
409         if( !release_dotlock(lockhandle) )
410             is_locked = 0;
411     }
412 }
413
414 int
415 tdbio_set_dbname( const char *new_dbname, int create )
416 {
417     char *fname;
418     static int initialized = 0;
419
420     if( !initialized ) {
421         atexit( cleanup );
422         initialized = 1;
423     }
424     fname = new_dbname? gcry_xstrdup( new_dbname )
425                       : make_filename(opt.homedir, "trustdb.gpg", NULL );
426
427     if( access( fname, R_OK ) ) {
428         if( errno != ENOENT ) {
429             log_error( _("%s: can't access: %s\n"), fname, strerror(errno) );
430             gcry_free(fname);
431             return G10ERR_TRUSTDB;
432         }
433         if( create ) {
434             FILE *fp;
435             TRUSTREC rec;
436             int rc;
437             char *p = strrchr( fname, '/' );
438
439             assert(p);
440             *p = 0;
441             if( access( fname, F_OK ) ) {
442                 if( strlen(fname) >= 7
443                     && !strcmp(fname+strlen(fname)-7, "/.gnupg" ) ) {
444                     if( mkdir( fname, S_IRUSR|S_IWUSR|S_IXUSR ) )
445                         log_fatal( _("%s: can't create directory: %s\n"),
446                                                     fname,  strerror(errno) );
447                     else if( !opt.quiet )
448                         log_info( _("%s: directory created\n"), fname );
449                     copy_options_file( fname );
450                 }
451                 else
452                     log_fatal( _("%s: directory does not exist!\n"), fname );
453             }
454             *p = '/';
455
456             fp =fopen( fname, "wb" );
457             if( !fp )
458                 log_fatal( _("%s: can't create: %s\n"), fname, strerror(errno) );
459             fclose(fp);
460             gcry_free(db_name);
461             db_name = fname;
462           #ifdef HAVE_DOSISH_SYSTEM
463             db_fd = open( db_name, O_RDWR | O_BINARY );
464           #else
465             db_fd = open( db_name, O_RDWR );
466           #endif
467             if( db_fd == -1 )
468                 log_fatal( _("%s: can't open: %s\n"), db_name, strerror(errno) );
469
470             if( !lockhandle )
471                 lockhandle = create_dotlock( db_name );
472             if( !lockhandle )
473                 log_fatal( _("%s: can't create lock\n"), db_name );
474
475             memset( &rec, 0, sizeof rec );
476             rec.r.ver.version = 2;
477             rec.r.ver.created = make_timestamp();
478             rec.r.ver.marginals =  opt.marginals_needed;
479             rec.r.ver.completes =  opt.completes_needed;
480             rec.r.ver.cert_depth = opt.max_cert_depth;
481             rec.rectype = RECTYPE_VER;
482             rec.recnum = 0;
483             rc = tdbio_write_record( &rec );
484             if( !rc )
485                 tdbio_sync();
486             if( rc )
487                 log_fatal( _("%s: failed to create version record: %s"),
488                                                    fname, g10_errstr(rc));
489             /* and read again to check that we are okay */
490             if( tdbio_read_record( 0, &rec, RECTYPE_VER ) )
491                 log_fatal( _("%s: invalid trustdb created\n"), db_name );
492
493             if( !opt.quiet )
494                 log_info(_("%s: trustdb created\n"), db_name);
495
496             return 0;
497         }
498     }
499     gcry_free(db_name);
500     db_name = fname;
501     return 0;
502 }
503
504
505 const char *
506 tdbio_get_dbname()
507 {
508     return db_name;
509 }
510
511
512
513 static void
514 open_db()
515 {
516     TRUSTREC rec;
517     assert( db_fd == -1 );
518
519     if( !lockhandle )
520         lockhandle = create_dotlock( db_name );
521     if( !lockhandle )
522         log_fatal( _("%s: can't create lock\n"), db_name );
523   #ifdef HAVE_DOSISH_SYSTEM
524     db_fd = open( db_name, O_RDWR | O_BINARY );
525   #else
526     db_fd = open( db_name, O_RDWR );
527   #endif
528     if( db_fd == -1 )
529         log_fatal( _("%s: can't open: %s\n"), db_name, strerror(errno) );
530     if( tdbio_read_record( 0, &rec, RECTYPE_VER ) )
531         log_fatal( _("%s: invalid trustdb\n"), db_name );
532 }
533
534
535 /****************
536  * Make a hashtable: type 0 = key hash, 1 = sdir hash
537  */
538 static void
539 create_hashtable( TRUSTREC *vr, int type )
540 {
541     TRUSTREC rec;
542     off_t offset;
543     ulong recnum;
544     int i, n, rc;
545
546     offset = lseek( db_fd, 0, SEEK_END );
547     if( offset == -1 )
548         log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
549     recnum = offset / TRUST_RECORD_LEN;
550     assert(recnum); /* this is will never be the first record */
551
552     if( !type )
553         vr->r.ver.keyhashtbl = recnum;
554     else
555         vr->r.ver.sdirhashtbl = recnum;
556     /* Now write the records */
557     n = (256+ITEMS_PER_HTBL_RECORD-1) / ITEMS_PER_HTBL_RECORD;
558     for(i=0; i < n; i++, recnum++ ) {
559          memset( &rec, 0, sizeof rec );
560          rec.rectype = RECTYPE_HTBL;
561          rec.recnum = recnum;
562          rc = tdbio_write_record( &rec );
563          if( rc )
564              log_fatal( _("%s: failed to create hashtable: %s\n"),
565                                         db_name, g10_errstr(rc));
566     }
567     /* update the version record */
568     rc = tdbio_write_record( vr );
569     if( !rc )
570         rc = tdbio_sync();
571     if( rc )
572         log_fatal( _("%s: error updating version record: %s\n"),
573                                                   db_name, g10_errstr(rc));
574 }
575
576
577 int
578 tdbio_db_matches_options()
579 {
580     static int yes_no = -1;
581
582     if( yes_no == -1 ) {
583         TRUSTREC vr;
584         int rc;
585
586         rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
587         if( rc )
588             log_fatal( _("%s: error reading version record: %s\n"),
589                                                     db_name, g10_errstr(rc) );
590
591         if( !vr.r.ver.marginals && !vr.r.ver.completes
592                                 && !vr.r.ver.cert_depth )
593         {   /* special hack for trustdbs created by old versions of GnuPG */
594             vr.r.ver.marginals =  opt.marginals_needed;
595             vr.r.ver.completes =  opt.completes_needed;
596             vr.r.ver.cert_depth = opt.max_cert_depth;
597             rc = tdbio_write_record( &vr );
598             if( !rc && !in_transaction )
599                 rc = tdbio_sync();
600             if( rc )
601                 log_error( _("%s: error writing version record: %s\n"),
602                                                 db_name, g10_errstr(rc) );
603         }
604
605         yes_no = vr.r.ver.marginals == opt.marginals_needed
606                  && vr.r.ver.completes == opt.completes_needed
607                  && vr.r.ver.cert_depth == opt.max_cert_depth;
608     }
609     return yes_no;
610 }
611
612
613 /****************
614  * Return the modifiy stamp.
615  * if modify_down is true, the modify_down stamp will be
616  * returned, otherwise the modify_up stamp.
617  */
618 ulong
619 tdbio_read_modify_stamp( int modify_down )
620 {
621     TRUSTREC vr;
622     int rc;
623     ulong mod;
624
625     rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
626     if( rc )
627         log_fatal( _("%s: error reading version record: %s\n"),
628                                                     db_name, g10_errstr(rc) );
629
630     mod = modify_down? vr.r.ver.mod_down : vr.r.ver.mod_up;
631
632     /* Always return at least 1 to make comparison easier;
633      * this is still far back in history (before Led Zeppelin III :-) */
634     return mod ? mod : 1;
635 }
636
637 void
638 tdbio_write_modify_stamp( int up, int down )
639 {
640     TRUSTREC vr;
641     int rc;
642     ulong stamp;
643
644     if( !(up || down) )
645         return;
646
647     rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
648     if( rc )
649         log_fatal( _("%s: error reading version record: %s\n"),
650                                        db_name, g10_errstr(rc) );
651
652     stamp = make_timestamp();
653     if( down )
654         vr.r.ver.mod_down = stamp;
655     if( up )
656         vr.r.ver.mod_up = stamp;
657
658     rc = tdbio_write_record( &vr );
659     if( rc )
660         log_fatal( _("%s: error writing version record: %s\n"),
661                                        db_name, g10_errstr(rc) );
662 }
663
664
665 /****************
666  * Return the record number of the keyhash tbl or create a new one.
667  */
668 static ulong
669 get_keyhashrec(void)
670 {
671     static ulong keyhashtbl; /* record number of the key hashtable */
672
673     if( !keyhashtbl ) {
674         TRUSTREC vr;
675         int rc;
676
677         rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
678         if( rc )
679             log_fatal( _("%s: error reading version record: %s\n"),
680                                             db_name, g10_errstr(rc) );
681         if( !vr.r.ver.keyhashtbl )
682             create_hashtable( &vr, 0 );
683
684         keyhashtbl = vr.r.ver.keyhashtbl;
685     }
686     return keyhashtbl;
687 }
688
689 /****************
690  * Return the record number of the shadow direcory hash table
691  * or create a new one.
692  */
693 static ulong
694 get_sdirhashrec(void)
695 {
696     static ulong sdirhashtbl; /* record number of the hashtable */
697
698     if( !sdirhashtbl ) {
699         TRUSTREC vr;
700         int rc;
701
702         rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
703         if( rc )
704             log_fatal( _("%s: error reading version record: %s\n"),
705                                                     db_name, g10_errstr(rc) );
706         if( !vr.r.ver.sdirhashtbl )
707             create_hashtable( &vr, 1 );
708
709         sdirhashtbl = vr.r.ver.sdirhashtbl;
710     }
711     return sdirhashtbl;
712 }
713
714
715 /****************
716  * Update a hashtable.
717  * table gives the start of the table, key and keylen is the key,
718  * newrecnum is the record number to insert.
719  */
720 static int
721 upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
722 {
723     TRUSTREC lastrec, rec;
724     ulong hashrec, item;
725     int msb;
726     int level=0;
727     int rc, i;
728
729     hashrec = table;
730   next_level:
731     msb = key[level];
732     hashrec += msb / ITEMS_PER_HTBL_RECORD;
733     rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL );
734     if( rc ) {
735         log_error( db_name, "upd_hashtable: read failed: %s\n",
736                                                         g10_errstr(rc) );
737         return rc;
738     }
739
740     item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
741     if( !item ) { /* insert a new item into the hash table */
742         rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = newrecnum;
743         rc = tdbio_write_record( &rec );
744         if( rc ) {
745             log_error( db_name, "upd_hashtable: write htbl failed: %s\n",
746                                                             g10_errstr(rc) );
747             return rc;
748         }
749     }
750     else if( item != newrecnum ) {  /* must do an update */
751         lastrec = rec;
752         rc = tdbio_read_record( item, &rec, 0 );
753         if( rc ) {
754             log_error( "upd_hashtable: read item failed: %s\n",
755                                                             g10_errstr(rc) );
756             return rc;
757         }
758
759         if( rec.rectype == RECTYPE_HTBL ) {
760             hashrec = item;
761             level++;
762             if( level >= keylen ) {
763                 log_error( "hashtable has invalid indirections.\n");
764                 return G10ERR_TRUSTDB;
765             }
766             goto next_level;
767         }
768         else if( rec.rectype == RECTYPE_HLST ) { /* extend list */
769             /* see whether the key is already in this list */
770             for(;;) {
771                 for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
772                     if( rec.r.hlst.rnum[i] == newrecnum ) {
773                         return 0; /* okay, already in the list */
774                     }
775                 }
776                 if( rec.r.hlst.next ) {
777                     rc = tdbio_read_record( rec.r.hlst.next,
778                                                        &rec, RECTYPE_HLST);
779                     if( rc ) {
780                         log_error( "scan keyhashtbl read hlst failed: %s\n",
781                                                              g10_errstr(rc) );
782                         return rc;
783                     }
784                 }
785                 else
786                     break; /* not there */
787             }
788             /* find the next free entry and put it in */
789             for(;;) {
790                 for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
791                     if( !rec.r.hlst.rnum[i] ) {
792                         rec.r.hlst.rnum[i] = newrecnum;
793                         rc = tdbio_write_record( &rec );
794                         if( rc )
795                             log_error( "upd_hashtable: write hlst failed: %s\n",
796                                                               g10_errstr(rc) );
797                         return rc; /* done */
798                     }
799                 }
800                 if( rec.r.hlst.next ) {
801                     rc = tdbio_read_record( rec.r.hlst.next,
802                                                       &rec, RECTYPE_HLST );
803                     if( rc ) {
804                         log_error( "upd_hashtable: read hlst failed: %s\n",
805                                                              g10_errstr(rc) );
806                         return rc;
807                     }
808                 }
809                 else { /* add a new list record */
810                     rec.r.hlst.next = item = tdbio_new_recnum();
811                     rc = tdbio_write_record( &rec );
812                     if( rc ) {
813                         log_error( "upd_hashtable: write hlst failed: %s\n",
814                                                           g10_errstr(rc) );
815                         return rc;
816                     }
817                     memset( &rec, 0, sizeof rec );
818                     rec.rectype = RECTYPE_HLST;
819                     rec.recnum = item;
820                     rec.r.hlst.rnum[0] = newrecnum;
821                     rc = tdbio_write_record( &rec );
822                     if( rc )
823                         log_error( "upd_hashtable: write ext hlst failed: %s\n",
824                                                           g10_errstr(rc) );
825                     return rc; /* done */
826                 }
827             } /* end loop over hlst slots */
828         }
829         else if( rec.rectype == RECTYPE_KEY
830                  || rec.rectype == RECTYPE_DIR
831                  || rec.rectype == RECTYPE_SDIR ) { /* insert a list record */
832             if( rec.recnum == newrecnum ) {
833                 return 0;
834             }
835             item = rec.recnum; /* save number of key record */
836             memset( &rec, 0, sizeof rec );
837             rec.rectype = RECTYPE_HLST;
838             rec.recnum = tdbio_new_recnum();
839             rec.r.hlst.rnum[0] = item;       /* old keyrecord */
840             rec.r.hlst.rnum[1] = newrecnum; /* and new one */
841             rc = tdbio_write_record( &rec );
842             if( rc ) {
843                 log_error( "upd_hashtable: write new hlst failed: %s\n",
844                                                   g10_errstr(rc) );
845                 return rc;
846             }
847             /* update the hashtable record */
848             lastrec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = rec.recnum;
849             rc = tdbio_write_record( &lastrec );
850             if( rc )
851                 log_error( "upd_hashtable: update htbl failed: %s\n",
852                                                              g10_errstr(rc) );
853             return rc; /* ready */
854         }
855         else {
856             log_error( "hashtbl %lu: %lu/%d points to an invalid record %lu\n",
857                        table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item);
858             list_trustdb(NULL);
859             return G10ERR_TRUSTDB;
860         }
861     }
862
863     return 0;
864 }
865
866
867 /****************
868  * Drop an entry from a hashtable
869  * table gives the start of the table, key and keylen is the key,
870  */
871 static int
872 drop_from_hashtable( ulong table, byte *key, int keylen, ulong recnum )
873 {
874     TRUSTREC rec;
875     ulong hashrec, item;
876     int msb;
877     int level=0;
878     int rc, i;
879
880     hashrec = table;
881   next_level:
882     msb = key[level];
883     hashrec += msb / ITEMS_PER_HTBL_RECORD;
884     rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL );
885     if( rc ) {
886         log_error( db_name, "drop_from_hashtable: read failed: %s\n",
887                                                         g10_errstr(rc) );
888         return rc;
889     }
890
891     item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
892     if( !item )  /* not found - forget about it  */
893         return 0;
894
895     if( item == recnum ) {  /* tables points direct to the record */
896         rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = 0;
897         rc = tdbio_write_record( &rec );
898         if( rc )
899             log_error( db_name, "drop_from_hashtable: write htbl failed: %s\n",
900                                                             g10_errstr(rc) );
901         return rc;
902     }
903
904     rc = tdbio_read_record( item, &rec, 0 );
905     if( rc ) {
906         log_error( "drop_from_hashtable: read item failed: %s\n",
907                                                         g10_errstr(rc) );
908         return rc;
909     }
910
911     if( rec.rectype == RECTYPE_HTBL ) {
912         hashrec = item;
913         level++;
914         if( level >= keylen ) {
915             log_error( "hashtable has invalid indirections.\n");
916             return G10ERR_TRUSTDB;
917         }
918         goto next_level;
919     }
920
921     if( rec.rectype == RECTYPE_HLST ) {
922         for(;;) {
923             for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
924                 if( rec.r.hlst.rnum[i] == recnum ) {
925                     rec.r.hlst.rnum[i] = 0; /* drop */
926                     rc = tdbio_write_record( &rec );
927                     if( rc )
928                         log_error( db_name, "drop_from_hashtable: write htbl failed: %s\n",
929                                                                         g10_errstr(rc) );
930                     return rc;
931                 }
932             }
933             if( rec.r.hlst.next ) {
934                 rc = tdbio_read_record( rec.r.hlst.next,
935                                                    &rec, RECTYPE_HLST);
936                 if( rc ) {
937                     log_error( "scan keyhashtbl read hlst failed: %s\n",
938                                                          g10_errstr(rc) );
939                     return rc;
940                 }
941             }
942             else
943                 return 0; /* key not in table */
944         }
945     }
946
947     log_error( "hashtbl %lu: %lu/%d points to wrong record %lu\n",
948                     table, hashrec, (msb % ITEMS_PER_HTBL_RECORD), item);
949     return G10ERR_TRUSTDB;
950 }
951
952
953
954 /****************
955  * Lookup a record via the hashtable tablewith key/keylen and return the
956  * result in rec.  cmp() should return if the record is the desired one.
957  * Returns -1 if not found, 0 if found or another errocode
958  */
959 static int
960 lookup_hashtable( ulong table, const byte *key, size_t keylen,
961                   int (*cmpfnc)(void*, const TRUSTREC *), void *cmpdata,
962                                                 TRUSTREC *rec )
963 {
964     int rc;
965     ulong hashrec, item;
966     int msb;
967     int level=0;
968
969     hashrec = table;
970   next_level:
971     msb = key[level];
972     hashrec += msb / ITEMS_PER_HTBL_RECORD;
973     rc = tdbio_read_record( hashrec, rec, RECTYPE_HTBL );
974     if( rc ) {
975         log_error( db_name, "lookup_hashtable failed: %s\n", g10_errstr(rc) );
976         return rc;
977     }
978
979     item = rec->r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
980     if( !item )
981         return -1; /* not found */
982
983     rc = tdbio_read_record( item, rec, 0 );
984     if( rc ) {
985         log_error( db_name, "hashtable read failed: %s\n", g10_errstr(rc) );
986         return rc;
987     }
988     if( rec->rectype == RECTYPE_HTBL ) {
989         hashrec = item;
990         level++;
991         if( level >= keylen ) {
992             log_error( db_name, "hashtable has invalid indirections\n");
993             return G10ERR_TRUSTDB;
994         }
995         goto next_level;
996     }
997     else if( rec->rectype == RECTYPE_HLST ) {
998         for(;;) {
999             int i;
1000
1001             for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
1002                 if( rec->r.hlst.rnum[i] ) {
1003                     TRUSTREC tmp;
1004
1005                     rc = tdbio_read_record( rec->r.hlst.rnum[i], &tmp, 0 );
1006                     if( rc ) {
1007                         log_error( "lookup_hashtable: read item failed: %s\n",
1008                                                               g10_errstr(rc) );
1009                         return rc;
1010                     }
1011                     if( (*cmpfnc)( cmpdata, &tmp ) ) {
1012                         *rec = tmp;
1013                         return 0;
1014                     }
1015                 }
1016             }
1017             if( rec->r.hlst.next ) {
1018                 rc = tdbio_read_record( rec->r.hlst.next, rec, RECTYPE_HLST );
1019                 if( rc ) {
1020                     log_error( "lookup_hashtable: read hlst failed: %s\n",
1021                                                          g10_errstr(rc) );
1022                     return rc;
1023                 }
1024             }
1025             else
1026                 return -1; /* not found */
1027         }
1028     }
1029
1030
1031     if( (*cmpfnc)( cmpdata, rec ) )
1032         return 0; /* really found */
1033
1034     return -1; /* no: not found */
1035 }
1036
1037
1038
1039
1040 /****************
1041  * Update the key hashtbl or create the table if it does not exist
1042  */
1043 static int
1044 update_keyhashtbl( TRUSTREC *kr )
1045 {
1046     return upd_hashtable( get_keyhashrec(),
1047                           kr->r.key.fingerprint,
1048                           kr->r.key.fingerprint_len, kr->recnum );
1049 }
1050
1051 /****************
1052  * Update the shadow dir hashtbl or create the table if it does not exist
1053  */
1054 static int
1055 update_sdirhashtbl( TRUSTREC *sr )
1056 {
1057     byte key[8];
1058
1059     u32tobuf( key   , sr->r.sdir.keyid[0] );
1060     u32tobuf( key+4 , sr->r.sdir.keyid[1] );
1061     return upd_hashtable( get_sdirhashrec(), key, 8, sr->recnum );
1062 }
1063
1064 /****************
1065  * Drop the records from the key-hashtbl
1066  */
1067 static int
1068 drop_from_keyhashtbl( TRUSTREC *kr )
1069 {
1070     return drop_from_hashtable( get_keyhashrec(),
1071                                 kr->r.key.fingerprint,
1072                                 kr->r.key.fingerprint_len, kr->recnum );
1073 }
1074
1075 /****************
1076  * Drop record drom the shadow dir hashtbl
1077  */
1078 static int
1079 drop_from_sdirhashtbl( TRUSTREC *sr )
1080 {
1081     byte key[8];
1082
1083     u32tobuf( key   , sr->r.sdir.keyid[0] );
1084     u32tobuf( key+4 , sr->r.sdir.keyid[1] );
1085     return drop_from_hashtable( get_sdirhashrec(), key, 8, sr->recnum );
1086 }
1087
1088
1089
1090
1091 void
1092 tdbio_dump_record( TRUSTREC *rec, FILE *fp  )
1093 {
1094     int i;
1095     ulong rnum = rec->recnum;
1096     byte *p;
1097
1098     fprintf(fp, "rec %5lu, ", rnum );
1099
1100     switch( rec->rectype ) {
1101       case 0: fprintf(fp, "blank\n");
1102         break;
1103       case RECTYPE_VER: fprintf(fp,
1104             "version, kd=%lu, sd=%lu, free=%lu, m/c/d=%d/%d/%d down=%s",
1105             rec->r.ver.keyhashtbl, rec->r.ver.sdirhashtbl,
1106                                    rec->r.ver.firstfree,
1107                                    rec->r.ver.marginals,
1108                                    rec->r.ver.completes,
1109                                    rec->r.ver.cert_depth,
1110                                    strtimestamp(rec->r.ver.mod_down) );
1111             fprintf(fp, ", up=%s\n", strtimestamp(rec->r.ver.mod_up) );
1112         break;
1113       case RECTYPE_FREE: fprintf(fp, "free, next=%lu\n", rec->r.free.next );
1114         break;
1115       case RECTYPE_DIR:
1116         fprintf(fp, "dir %lu, keys=%lu, uids=%lu, t=%02x",
1117                     rec->r.dir.lid,
1118                     rec->r.dir.keylist,
1119                     rec->r.dir.uidlist,
1120                     rec->r.dir.ownertrust );
1121         if( rec->r.dir.valcheck )
1122             fprintf( fp, ", v=%02x/%s", rec->r.dir.validity,
1123                                         strtimestamp(rec->r.dir.valcheck) );
1124         if( rec->r.dir.checkat )
1125             fprintf( fp, ", a=%s", strtimestamp(rec->r.dir.checkat) );
1126         if( rec->r.dir.dirflags & DIRF_CHECKED ) {
1127             if( rec->r.dir.dirflags & DIRF_VALID )
1128                 fputs(", valid", fp );
1129             if( rec->r.dir.dirflags & DIRF_EXPIRED )
1130                 fputs(", expired", fp );
1131             if( rec->r.dir.dirflags & DIRF_REVOKED )
1132                 fputs(", revoked", fp );
1133         }
1134         putc('\n', fp);
1135         break;
1136       case RECTYPE_KEY:
1137         fprintf(fp, "key %lu, n=%lu a=%d ",
1138                    rec->r.key.lid,
1139                    rec->r.key.next,
1140                    rec->r.key.pubkey_algo );
1141         for(i=0; i < rec->r.key.fingerprint_len; i++ )
1142             fprintf(fp, "%02X", rec->r.key.fingerprint[i] );
1143         if( rec->r.key.keyflags & KEYF_CHECKED ) {
1144             if( rec->r.key.keyflags & KEYF_VALID )
1145                 fputs(", valid", fp );
1146             if( rec->r.key.keyflags & KEYF_EXPIRED )
1147                 fputs(", expired", fp );
1148             if( rec->r.key.keyflags & KEYF_REVOKED )
1149                 fputs(", revoked", fp );
1150         }
1151         putc('\n', fp);
1152         break;
1153       case RECTYPE_UID:
1154         fprintf(fp, "uid %lu, next=%lu, pref=%lu, sig=%lu, hash=%02X%02X",
1155                     rec->r.uid.lid,
1156                     rec->r.uid.next,
1157                     rec->r.uid.prefrec,
1158                     rec->r.uid.siglist,
1159                     rec->r.uid.namehash[18], rec->r.uid.namehash[19]);
1160         fprintf( fp, ", v=%02x", rec->r.uid.validity );
1161         if( rec->r.uid.uidflags & UIDF_CHECKED ) {
1162             if( rec->r.uid.uidflags & UIDF_VALID )
1163                 fputs(", valid", fp );
1164             if( rec->r.uid.uidflags & UIDF_REVOKED )
1165                 fputs(", revoked", fp );
1166         }
1167         putc('\n', fp);
1168         break;
1169       case RECTYPE_PREF:
1170         fprintf(fp, "pref %lu, next=%lu,",
1171                     rec->r.pref.lid, rec->r.pref.next);
1172         for(i=0,p=rec->r.pref.data; i < ITEMS_PER_PREF_RECORD; i+=2,p+=2 ) {
1173             if( *p )
1174                 fprintf(fp, " %c%d", *p == PREFTYPE_SYM    ? 'S' :
1175                                      *p == PREFTYPE_HASH   ? 'H' :
1176                                      *p == PREFTYPE_COMPR  ? 'Z' : '?', p[1]);
1177         }
1178         putc('\n', fp);
1179         break;
1180       case RECTYPE_SIG:
1181         fprintf(fp, "sig %lu, next=%lu,",
1182                          rec->r.sig.lid, rec->r.sig.next );
1183         for(i=0; i < SIGS_PER_RECORD; i++ ) {
1184             if( rec->r.sig.sig[i].lid ) {
1185                 fprintf(fp, " %lu:", rec->r.sig.sig[i].lid );
1186                 if( rec->r.sig.sig[i].flag & SIGF_CHECKED ) {
1187                     fprintf(fp,"%c%c%c",
1188                        (rec->r.sig.sig[i].flag & SIGF_VALID)   ? 'V':
1189                        (rec->r.sig.sig[i].flag & SIGF_IGNORED) ? 'I':'-',
1190                        (rec->r.sig.sig[i].flag & SIGF_EXPIRED) ? 'E':'-',
1191                        (rec->r.sig.sig[i].flag & SIGF_REVOKED) ? 'R':'-');
1192                 }
1193                 else if( rec->r.sig.sig[i].flag & SIGF_NOPUBKEY)
1194                     fputs("?--", fp);
1195                 else
1196                     fputs("---", fp);
1197             }
1198         }
1199         putc('\n', fp);
1200         break;
1201       case RECTYPE_SDIR:
1202         fprintf(fp, "sdir %lu, keyid=%08lX%08lX, algo=%d, hint=%lu\n",
1203                     rec->r.sdir.lid,
1204                     (ulong)rec->r.sdir.keyid[0],
1205                     (ulong)rec->r.sdir.keyid[1],
1206                     rec->r.sdir.pubkey_algo,
1207                     (ulong)rec->r.sdir.hintlist );
1208         break;
1209       case RECTYPE_CACH:
1210         fprintf(fp, "cach\n");
1211         break;
1212       case RECTYPE_HTBL:
1213         fprintf(fp, "htbl,");
1214         for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ )
1215             fprintf(fp, " %lu", rec->r.htbl.item[i] );
1216         putc('\n', fp);
1217         break;
1218       case RECTYPE_HLST:
1219         fprintf(fp, "hlst, next=%lu,", rec->r.hlst.next );
1220         for(i=0; i < ITEMS_PER_HLST_RECORD; i++ )
1221             fprintf(fp, " %lu", rec->r.hlst.rnum[i] );
1222         putc('\n', fp);
1223         break;
1224       default:
1225         fprintf(fp, "unknown type %d\n", rec->rectype );
1226         break;
1227     }
1228 }
1229
1230 /****************
1231  * read the record with number recnum
1232  * returns: -1 on error, 0 on success
1233  */
1234 int
1235 tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
1236 {
1237     byte readbuf[TRUST_RECORD_LEN];
1238     const byte *buf, *p;
1239     int rc = 0;
1240     int n, i;
1241
1242     if( db_fd == -1 )
1243         open_db();
1244     buf = get_record_from_cache( recnum );
1245     if( !buf ) {
1246         if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
1247             log_error(_("trustdb: lseek failed: %s\n"), strerror(errno) );
1248             return G10ERR_READ_FILE;
1249         }
1250         n = read( db_fd, readbuf, TRUST_RECORD_LEN);
1251         if( !n ) {
1252             return -1; /* eof */
1253         }
1254         else if( n != TRUST_RECORD_LEN ) {
1255             log_error(_("trustdb: read failed (n=%d): %s\n"), n,
1256                                                         strerror(errno) );
1257             return G10ERR_READ_FILE;
1258         }
1259         buf = readbuf;
1260     }
1261     rec->recnum = recnum;
1262     rec->dirty = 0;
1263     p = buf;
1264     rec->rectype = *p++;
1265     if( expected && rec->rectype != expected ) {
1266         log_error("%lu: read expected rec type %d, got %d\n",
1267                     recnum, expected, rec->rectype );
1268         return G10ERR_TRUSTDB;
1269     }
1270     p++;    /* skip reserved byte */
1271     switch( rec->rectype ) {
1272       case 0:  /* unused (free) record */
1273         break;
1274       case RECTYPE_VER: /* version record */
1275         if( memcmp(buf+1, "gpg", 3 ) ) {
1276             log_error( _("%s: not a trustdb file\n"), db_name );
1277             rc = G10ERR_TRUSTDB;
1278         }
1279         p += 2; /* skip "pgp" */
1280         rec->r.ver.version  = *p++;
1281         rec->r.ver.marginals = *p++;
1282         rec->r.ver.completes = *p++;
1283         rec->r.ver.cert_depth = *p++;
1284         p += 4; /* lock flags */
1285         rec->r.ver.created  = buftoulong(p); p += 4;
1286         rec->r.ver.mod_down = buftoulong(p); p += 4;
1287         rec->r.ver.mod_up   = buftoulong(p); p += 4;
1288         rec->r.ver.keyhashtbl=buftoulong(p); p += 4;
1289         rec->r.ver.firstfree =buftoulong(p); p += 4;
1290         rec->r.ver.sdirhashtbl =buftoulong(p); p += 4;
1291         if( recnum ) {
1292             log_error( _("%s: version record with recnum %lu\n"), db_name,
1293                                                              (ulong)recnum );
1294             rc = G10ERR_TRUSTDB;
1295         }
1296         else if( rec->r.ver.version != 2 ) {
1297             log_error( _("%s: invalid file version %d\n"), db_name,
1298                                                         rec->r.ver.version );
1299             rc = G10ERR_TRUSTDB;
1300         }
1301         break;
1302       case RECTYPE_FREE:
1303         rec->r.free.next  = buftoulong(p); p += 4;
1304         break;
1305       case RECTYPE_DIR:   /*directory record */
1306         rec->r.dir.lid      = buftoulong(p); p += 4;
1307         rec->r.dir.keylist  = buftoulong(p); p += 4;
1308         rec->r.dir.uidlist  = buftoulong(p); p += 4;
1309         rec->r.dir.cacherec = buftoulong(p); p += 4;
1310         rec->r.dir.ownertrust = *p++;
1311         rec->r.dir.dirflags   = *p++;
1312         rec->r.dir.validity   = *p++;
1313         rec->r.dir.valcheck   = buftoulong(p); p += 4;
1314         rec->r.dir.checkat    = buftoulong(p); p += 4;
1315         switch( rec->r.dir.validity ) {
1316           case 0:
1317           case TRUST_UNDEFINED:
1318           case TRUST_NEVER:
1319           case TRUST_MARGINAL:
1320           case TRUST_FULLY:
1321           case TRUST_ULTIMATE:
1322             break;
1323           default:
1324             log_info("lid %lu: invalid validity value - cleared\n", recnum);
1325         }
1326         if( rec->r.dir.lid != recnum ) {
1327             log_error( "%s: dir LID != recnum (%lu,%lu)\n",
1328                               db_name, rec->r.dir.lid, (ulong)recnum );
1329             rc = G10ERR_TRUSTDB;
1330         }
1331         break;
1332       case RECTYPE_KEY:   /* public key record */
1333         rec->r.key.lid      = buftoulong(p); p += 4;
1334         rec->r.key.next     = buftoulong(p); p += 4;
1335         p += 7;
1336         rec->r.key.keyflags = *p++;
1337         rec->r.key.pubkey_algo = *p++;
1338         rec->r.key.fingerprint_len = *p++;
1339         if( rec->r.key.fingerprint_len < 1 || rec->r.key.fingerprint_len > 20 )
1340             rec->r.key.fingerprint_len = 20;
1341         memcpy( rec->r.key.fingerprint, p, 20);
1342         break;
1343       case RECTYPE_UID:   /* user id record */
1344         rec->r.uid.lid      = buftoulong(p); p += 4;
1345         rec->r.uid.next     = buftoulong(p); p += 4;
1346         rec->r.uid.prefrec  = buftoulong(p); p += 4;
1347         rec->r.uid.siglist  = buftoulong(p); p += 4;
1348         rec->r.uid.uidflags = *p++;
1349         rec->r.uid.validity   = *p++;
1350         switch( rec->r.uid.validity ) {
1351           case 0:
1352           case TRUST_UNDEFINED:
1353           case TRUST_NEVER:
1354           case TRUST_MARGINAL:
1355           case TRUST_FULLY:
1356           case TRUST_ULTIMATE:
1357             break;
1358           default:
1359             log_info("lid %lu: invalid validity value - cleared\n", recnum);
1360         }
1361         memcpy( rec->r.uid.namehash, p, 20);
1362         break;
1363       case RECTYPE_PREF:  /* preference record */
1364         rec->r.pref.lid     = buftoulong(p); p += 4;
1365         rec->r.pref.next    = buftoulong(p); p += 4;
1366         memcpy( rec->r.pref.data, p, 30 );
1367         break;
1368       case RECTYPE_SIG:
1369         rec->r.sig.lid     = buftoulong(p); p += 4;
1370         rec->r.sig.next    = buftoulong(p); p += 4;
1371         for(i=0; i < SIGS_PER_RECORD; i++ ) {
1372             rec->r.sig.sig[i].lid  = buftoulong(p); p += 4;
1373             rec->r.sig.sig[i].flag = *p++;
1374         }
1375         break;
1376       case RECTYPE_SDIR:   /* shadow directory record */
1377         rec->r.sdir.lid     = buftoulong(p); p += 4;
1378         rec->r.sdir.keyid[0]= buftou32(p); p += 4;
1379         rec->r.sdir.keyid[1]= buftou32(p); p += 4;
1380         rec->r.sdir.pubkey_algo = *p++;
1381         p += 3;
1382         rec->r.sdir.hintlist = buftoulong(p);
1383         if( rec->r.sdir.lid != recnum ) {
1384             log_error( "%s: sdir LID != recnum (%lu,%lu)\n",
1385                                db_name, rec->r.sdir.lid, (ulong)recnum );
1386             rc = G10ERR_TRUSTDB;
1387         }
1388         break;
1389       case RECTYPE_CACH:   /* cache record */
1390         rec->r.cache.lid    = buftoulong(p); p += 4;
1391         memcpy(rec->r.cache.blockhash, p, 20); p += 20;
1392         rec->r.cache.trustlevel = *p++;
1393         break;
1394       case RECTYPE_HTBL:
1395         for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) {
1396             rec->r.htbl.item[i] = buftoulong(p); p += 4;
1397         }
1398         break;
1399       case RECTYPE_HLST:
1400         rec->r.hlst.next = buftoulong(p); p += 4;
1401         for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
1402             rec->r.hlst.rnum[i] = buftoulong(p); p += 4;
1403         }
1404         break;
1405       default:
1406         log_error( "%s: invalid record type %d at recnum %lu\n",
1407                                    db_name, rec->rectype, (ulong)recnum );
1408         rc = G10ERR_TRUSTDB;
1409         break;
1410     }
1411
1412     return rc;
1413 }
1414
1415 /****************
1416  * Write the record at RECNUM
1417  */
1418 int
1419 tdbio_write_record( TRUSTREC *rec )
1420 {
1421     byte buf[TRUST_RECORD_LEN], *p;
1422     int rc = 0;
1423     int i;
1424     ulong recnum = rec->recnum;
1425
1426     if( db_fd == -1 )
1427         open_db();
1428
1429     memset(buf, 0, TRUST_RECORD_LEN);
1430     p = buf;
1431     *p++ = rec->rectype; p++;
1432     switch( rec->rectype ) {
1433       case 0:  /* unused record */
1434         break;
1435       case RECTYPE_VER: /* version record */
1436         if( recnum )
1437             BUG();
1438         memcpy(p-1, "gpg", 3 ); p += 2;
1439         *p++ = rec->r.ver.version;
1440         *p++ = rec->r.ver.marginals;
1441         *p++ = rec->r.ver.completes;
1442         *p++ = rec->r.ver.cert_depth;
1443         p += 4; /* skip lock flags */
1444         ulongtobuf(p, rec->r.ver.created); p += 4;
1445         ulongtobuf(p, rec->r.ver.mod_down); p += 4;
1446         ulongtobuf(p, rec->r.ver.mod_up); p += 4;
1447         ulongtobuf(p, rec->r.ver.keyhashtbl); p += 4;
1448         ulongtobuf(p, rec->r.ver.firstfree ); p += 4;
1449         ulongtobuf(p, rec->r.ver.sdirhashtbl ); p += 4;
1450         break;
1451
1452       case RECTYPE_FREE:
1453         ulongtobuf(p, rec->r.free.next); p += 4;
1454         break;
1455
1456       case RECTYPE_DIR:   /*directory record */
1457         ulongtobuf(p, rec->r.dir.lid); p += 4;
1458         ulongtobuf(p, rec->r.dir.keylist); p += 4;
1459         ulongtobuf(p, rec->r.dir.uidlist); p += 4;
1460         ulongtobuf(p, rec->r.dir.cacherec); p += 4;
1461         *p++ = rec->r.dir.ownertrust;
1462         *p++ = rec->r.dir.dirflags;
1463         *p++ = rec->r.dir.validity;
1464         ulongtobuf(p, rec->r.dir.valcheck); p += 4;
1465         ulongtobuf(p, rec->r.dir.checkat); p += 4;
1466         assert( rec->r.dir.lid == recnum );
1467         break;
1468
1469       case RECTYPE_KEY:
1470         ulongtobuf(p, rec->r.key.lid); p += 4;
1471         ulongtobuf(p, rec->r.key.next); p += 4;
1472         p += 7;
1473         *p++ = rec->r.key.keyflags;
1474         *p++ = rec->r.key.pubkey_algo;
1475         *p++ = rec->r.key.fingerprint_len;
1476         memcpy( p, rec->r.key.fingerprint, 20); p += 20;
1477         break;
1478
1479       case RECTYPE_UID:   /* user id record */
1480         ulongtobuf(p, rec->r.uid.lid); p += 4;
1481         ulongtobuf(p, rec->r.uid.next); p += 4;
1482         ulongtobuf(p, rec->r.uid.prefrec); p += 4;
1483         ulongtobuf(p, rec->r.uid.siglist); p += 4;
1484         *p++ = rec->r.uid.uidflags;
1485         *p++ = rec->r.uid.validity;
1486         memcpy( p, rec->r.uid.namehash, 20 ); p += 20;
1487         break;
1488
1489       case RECTYPE_PREF:
1490         ulongtobuf(p, rec->r.pref.lid); p += 4;
1491         ulongtobuf(p, rec->r.pref.next); p += 4;
1492         memcpy( p, rec->r.pref.data, 30 );
1493         break;
1494
1495       case RECTYPE_SIG:
1496         ulongtobuf(p, rec->r.sig.lid); p += 4;
1497         ulongtobuf(p, rec->r.sig.next); p += 4;
1498         for(i=0; i < SIGS_PER_RECORD; i++ ) {
1499             ulongtobuf(p, rec->r.sig.sig[i].lid); p += 4;
1500             *p++ = rec->r.sig.sig[i].flag;
1501         }
1502         break;
1503
1504       case RECTYPE_SDIR:
1505         ulongtobuf( p, rec->r.sdir.lid); p += 4;
1506         u32tobuf( p, rec->r.sdir.keyid[0] ); p += 4;
1507         u32tobuf( p, rec->r.sdir.keyid[1] ); p += 4;
1508         *p++ = rec->r.sdir.pubkey_algo;
1509         p += 3;
1510         ulongtobuf( p, rec->r.sdir.hintlist );
1511         break;
1512
1513       case RECTYPE_CACH:
1514         ulongtobuf(p, rec->r.cache.lid); p += 4;
1515         memcpy(p, rec->r.cache.blockhash, 20); p += 20;
1516         *p++ = rec->r.cache.trustlevel;
1517         break;
1518
1519       case RECTYPE_HTBL:
1520         for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) {
1521             ulongtobuf( p, rec->r.htbl.item[i]); p += 4;
1522         }
1523         break;
1524
1525       case RECTYPE_HLST:
1526         ulongtobuf( p, rec->r.hlst.next); p += 4;
1527         for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
1528             ulongtobuf( p, rec->r.hlst.rnum[i]); p += 4;
1529         }
1530         break;
1531
1532       default:
1533         BUG();
1534     }
1535
1536     rc = put_record_into_cache( recnum, buf );
1537     if( rc )
1538         ;
1539     else if( rec->rectype == RECTYPE_KEY )
1540         rc = update_keyhashtbl( rec );
1541     else if( rec->rectype == RECTYPE_SDIR )
1542         rc = update_sdirhashtbl( rec );
1543
1544     return rc;
1545 }
1546
1547 int
1548 tdbio_delete_record( ulong recnum )
1549 {
1550     TRUSTREC vr, rec;
1551     int rc;
1552
1553     /* Must read the record fist, so we can drop it from the hash tables */
1554     rc = tdbio_read_record( recnum, &rec, 0 );
1555     if( rc )
1556         ;
1557     else if( rec.rectype == RECTYPE_KEY )
1558         rc = drop_from_keyhashtbl( &rec );
1559     else if( rec.rectype == RECTYPE_SDIR )
1560         rc = drop_from_sdirhashtbl( &rec );
1561
1562     if( rc )
1563         return rc;
1564
1565     /* now we can chnage it to a free record */
1566     rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
1567     if( rc )
1568         log_fatal( _("%s: error reading version record: %s\n"),
1569                                        db_name, g10_errstr(rc) );
1570
1571     rec.recnum = recnum;
1572     rec.rectype = RECTYPE_FREE;
1573     rec.r.free.next = vr.r.ver.firstfree;
1574     vr.r.ver.firstfree = recnum;
1575     rc = tdbio_write_record( &rec );
1576     if( !rc )
1577         rc = tdbio_write_record( &vr );
1578     return rc;
1579 }
1580
1581 /****************
1582  * create a new record and return its record number
1583  */
1584 ulong
1585 tdbio_new_recnum()
1586 {
1587     off_t offset;
1588     ulong recnum;
1589     TRUSTREC vr, rec;
1590     int rc;
1591
1592     /* look for unused records */
1593     rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
1594     if( rc )
1595         log_fatal( _("%s: error reading version record: %s\n"),
1596                                              db_name, g10_errstr(rc) );
1597     if( vr.r.ver.firstfree ) {
1598         recnum = vr.r.ver.firstfree;
1599         rc = tdbio_read_record( recnum, &rec, RECTYPE_FREE );
1600         if( rc ) {
1601             log_error( _("%s: error reading free record: %s\n"),
1602                                                   db_name,  g10_errstr(rc) );
1603             return rc;
1604         }
1605         /* update dir record */
1606         vr.r.ver.firstfree = rec.r.free.next;
1607         rc = tdbio_write_record( &vr );
1608         if( rc ) {
1609             log_error( _("%s: error writing dir record: %s\n"),
1610                                                      db_name, g10_errstr(rc) );
1611             return rc;
1612         }
1613         /*zero out the new record */
1614         memset( &rec, 0, sizeof rec );
1615         rec.rectype = 0; /* unused record */
1616         rec.recnum = recnum;
1617         rc = tdbio_write_record( &rec );
1618         if( rc )
1619             log_fatal(_("%s: failed to zero a record: %s\n"),
1620                                        db_name, g10_errstr(rc));
1621     }
1622     else { /* not found, append a new record */
1623         offset = lseek( db_fd, 0, SEEK_END );
1624         if( offset == -1 )
1625             log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
1626         recnum = offset / TRUST_RECORD_LEN;
1627         assert(recnum); /* this is will never be the first record */
1628         /* we must write a record, so that the next call to this function
1629          * returns another recnum */
1630         memset( &rec, 0, sizeof rec );
1631         rec.rectype = 0; /* unused record */
1632         rec.recnum = recnum;
1633         rc = 0;
1634         if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
1635             log_error(_("trustdb rec %lu: lseek failed: %s\n"),
1636                                                 recnum, strerror(errno) );
1637             rc = G10ERR_WRITE_FILE;
1638         }
1639         else {
1640             int n = write( db_fd, &rec, TRUST_RECORD_LEN);
1641             if( n != TRUST_RECORD_LEN ) {
1642                 log_error(_("trustdb rec %lu: write failed (n=%d): %s\n"),
1643                                                  recnum, n, strerror(errno) );
1644                 rc = G10ERR_WRITE_FILE;
1645             }
1646         }
1647
1648         if( rc )
1649             log_fatal(_("%s: failed to append a record: %s\n"),
1650                                     db_name,    g10_errstr(rc));
1651     }
1652     return recnum ;
1653 }
1654
1655
1656
1657 /****************
1658  * Search the trustdb for a key which matches PK and return the dir record
1659  * The local_id of PK is set to the correct value
1660  */
1661 int
1662 tdbio_search_dir_bypk( PKT_public_key *pk, TRUSTREC *rec )
1663 {
1664     byte fingerprint[MAX_FINGERPRINT_LEN];
1665     size_t fingerlen;
1666     u32 keyid[2];
1667     int rc;
1668
1669     keyid_from_pk( pk, keyid );
1670     fingerprint_from_pk( pk, fingerprint, &fingerlen );
1671     rc = tdbio_search_dir_byfpr( fingerprint, fingerlen,
1672                                  pk->pubkey_algo, rec );
1673
1674     if( !rc ) {
1675         if( pk->local_id && pk->local_id != rec->recnum )
1676             log_error("%s: found record, but LID from memory does "
1677                        "not match recnum (%lu,%lu)\n",
1678                             db_name,  pk->local_id, rec->recnum );
1679         pk->local_id = rec->recnum;
1680     }
1681     return rc;
1682 }
1683
1684
1685 static int
1686 cmp_krec_fpr( void *dataptr, const TRUSTREC *rec )
1687 {
1688     const struct cmp_krec_fpr_struct *d = dataptr;
1689
1690     return rec->rectype == RECTYPE_KEY
1691            && ( !d->pubkey_algo || rec->r.key.pubkey_algo == d->pubkey_algo )
1692            && rec->r.key.fingerprint_len == d->fprlen
1693            && !memcmp( rec->r.key.fingerprint, d->fpr, d->fprlen );
1694 }
1695
1696 int
1697 tdbio_search_dir_byfpr( const byte *fingerprint, size_t fingerlen,
1698                         int pubkey_algo, TRUSTREC *rec )
1699 {
1700     struct cmp_krec_fpr_struct cmpdata;
1701     ulong recnum;
1702     int rc;
1703
1704     assert( fingerlen == 20 || fingerlen == 16 );
1705
1706     /* locate the key using the hash table */
1707     cmpdata.pubkey_algo = pubkey_algo;
1708     cmpdata.fpr = fingerprint;
1709     cmpdata.fprlen = fingerlen;
1710     rc = lookup_hashtable( get_keyhashrec(), fingerprint, fingerlen,
1711                            cmp_krec_fpr, &cmpdata, rec );
1712     if( !rc ) {
1713         recnum = rec->r.key.lid;
1714         /* Now read the dir record */
1715         rc = tdbio_read_record( recnum, rec, RECTYPE_DIR);
1716         if( rc )
1717             log_error("%s: can't read dirrec %lu: %s\n",
1718                                      db_name, recnum, g10_errstr(rc) );
1719     }
1720     return rc;
1721 }
1722
1723
1724
1725 static int
1726 cmp_sdir( void *dataptr, const TRUSTREC *rec )
1727 {
1728     const struct cmp_xdir_struct *d = dataptr;
1729
1730     return rec->rectype == RECTYPE_SDIR
1731            && ( !d->pubkey_algo || rec->r.sdir.pubkey_algo == d->pubkey_algo )
1732            && rec->r.sdir.keyid[0] == d->keyid[0]
1733            && rec->r.sdir.keyid[1] == d->keyid[1];
1734 }
1735
1736
1737 int
1738 tdbio_search_sdir( u32 *keyid, int pubkey_algo, TRUSTREC *rec )
1739 {
1740     struct cmp_xdir_struct cmpdata;
1741     int rc;
1742     byte key[8];
1743
1744     /* locate the shadow dir record using the hash table */
1745     u32tobuf( key   , keyid[0] );
1746     u32tobuf( key+4 , keyid[1] );
1747     cmpdata.pubkey_algo = pubkey_algo;
1748     cmpdata.keyid[0] = keyid[0];
1749     cmpdata.keyid[1] = keyid[1];
1750     rc = lookup_hashtable( get_sdirhashrec(), key, 8,
1751                            cmp_sdir, &cmpdata, rec );
1752     return rc;
1753 }
1754
1755
1756 void
1757 tdbio_invalid(void)
1758 {
1759     log_error(_(
1760         "the trustdb is corrupted; please run \"gpg --fix-trustdb\".\n") );
1761     g10_exit(2);
1762 }
1763
1764