Epxerimenta support for GDBM keyings.
[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 "memory.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 /****************
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.
47  */
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];
57 };
58
59 #define MAX_CACHE_ENTRIES    200
60 static CACHE_CTRL cache_list;
61 static int cache_entries;
62
63 /* a type used to pass infomation to cmp_krec_fpr */
64 struct cmp_krec_fpr_struct {
65     int pubkey_algo;
66     const char *fpr;
67     int fprlen;
68 };
69
70 /* a type used to pass infomation to cmp_sdir */
71 struct cmp_sdir_struct {
72     int pubkey_algo;
73     u32 keyid[2];
74 };
75
76
77 static char *db_name;
78 static int  db_fd = -1;
79
80
81 static void open_db(void);
82
83 \f
84 /*************************************
85  ************* record cache **********
86  *************************************/
87
88 /****************
89  * Get the data from therecord cache and return a
90  * pointer into that cache.  Caller should copy
91  * the return data.  NULL is returned on a cache miss.
92  */
93 static const char *
94 get_record_from_cache( ulong recno )
95 {
96     CACHE_CTRL r;
97
98     for( r = cache_list; r; r = r->next ) {
99         if( r->flags.used && r->recno == recno )
100             return r->data;
101     }
102     return NULL;
103 }
104
105
106 static int
107 write_cache_item( CACHE_CTRL r )
108 {
109     int n;
110
111     if( lseek( db_fd, r->recno * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
112         log_error(_("trustdb rec %lu: lseek failed: %s\n"),
113                                             r->recno, strerror(errno) );
114         return G10ERR_WRITE_FILE;
115     }
116     n = write( db_fd, r->data, TRUST_RECORD_LEN);
117     if( n != TRUST_RECORD_LEN ) {
118         log_error(_("trustdb rec %lu: write failed (n=%d): %s\n"),
119                                             r->recno, n, strerror(errno) );
120         return G10ERR_WRITE_FILE;
121     }
122     r->flags.dirty = 0;
123     return 0;
124 }
125
126 /****************
127  * Put data into the cache.  This function may flush the
128  * some cache entries if there is not enough space available.
129  */
130 int
131 put_record_into_cache( ulong recno, const char *data )
132 {
133     CACHE_CTRL r, unused;
134     int dirty_count = 0;
135     int clean_count = 0;
136
137     /* see whether we already cached this one */
138     for( unused = NULL, r = cache_list; r; r = r->next ) {
139         if( !r->flags.used ) {
140             if( !unused )
141                 unused = r;
142         }
143         else if( r->recno == recno ) {
144             if( !r->flags.dirty ) {
145                 /* Hmmm: should we use a a copy and compare? */
146                 if( memcmp(r->data, data, TRUST_RECORD_LEN ) )
147                     r->flags.dirty = 1;
148             }
149             memcpy( r->data, data, TRUST_RECORD_LEN );
150             return 0;
151         }
152         if( r->flags.used ) {
153             if( r->flags.dirty )
154                 dirty_count++;
155             else
156                 clean_count++;
157         }
158     }
159     /* not in the cache: add a new entry */
160     if( unused ) { /* reuse this entry */
161         r = unused;
162         r->flags.used = 1;
163         r->recno = recno;
164         memcpy( r->data, data, TRUST_RECORD_LEN );
165         r->flags.dirty = 1;
166         cache_entries++;
167         return 0;
168     }
169     /* see whether we reached the limit */
170     if( cache_entries < MAX_CACHE_ENTRIES ) { /* no */
171         r = m_alloc( sizeof *r );
172         r->flags.used = 1;
173         r->recno = recno;
174         memcpy( r->data, data, TRUST_RECORD_LEN );
175         r->flags.dirty = 1;
176         r->next = cache_list;
177         cache_list = r;
178         cache_entries++;
179         return 0;
180     }
181     /* cache is full: discard some clean entries */
182     if( clean_count ) {
183         int n = clean_count / 3; /* discard a third of the clean entries */
184         if( !n )
185             n = 1;
186         for( unused = NULL, r = cache_list; r; r = r->next ) {
187             if( r->flags.used && !r->flags.dirty ) {
188                 if( !unused )
189                     unused = r;
190                 r->flags.used = 0;
191                 cache_entries--;
192                 if( !--n )
193                     break;
194             }
195         }
196         assert( unused );
197         r = unused;
198         r->flags.used = 1;
199         r->recno = recno;
200         memcpy( r->data, data, TRUST_RECORD_LEN );
201         r->flags.dirty = 1;
202         cache_entries++;
203         return 0;
204     }
205     /* no clean entries: have to flush some dirty entries */
206     if( dirty_count ) {
207         int n = dirty_count / 5; /* discard some dirty entries */
208         if( !n )
209             n = 1;
210         for( unused = NULL, r = cache_list; r; r = r->next ) {
211             if( r->flags.used && r->flags.dirty ) {
212                 int rc = write_cache_item( r );
213                 if( rc )
214                     return rc;
215                 if( !unused )
216                     unused = r;
217                 r->flags.used = 0;
218                 cache_entries--;
219                 if( !--n )
220                     break;
221             }
222         }
223         assert( unused );
224         r = unused;
225         r->flags.used = 1;
226         r->recno = recno;
227         memcpy( r->data, data, TRUST_RECORD_LEN );
228         r->flags.dirty = 1;
229         cache_entries++;
230         return 0;
231     }
232     BUG();
233 }
234
235
236
237 /****************
238  * Sync the cache to disk
239  */
240
241 int
242 tdbio_sync()
243 {
244     CACHE_CTRL r;
245
246     for( r = cache_list; r; r = r->next ) {
247         if( r->flags.used && r->flags.dirty ) {
248             int rc = write_cache_item( r );
249             if( rc )
250                 return rc;
251         }
252     }
253     return 0;
254 }
255
256
257 \f
258 /********************************************************
259  **************** cached I/O functions ******************
260  ********************************************************/
261
262 int
263 tdbio_set_dbname( const char *new_dbname, int create )
264 {
265     char *fname;
266
267     fname = new_dbname? m_strdup( new_dbname )
268                       : make_filename(opt.homedir, "trustdb.gpg", NULL );
269
270     if( access( fname, R_OK ) ) {
271         if( errno != ENOENT ) {
272             log_error( _("%s: can't access: %s\n"), fname, strerror(errno) );
273             m_free(fname);
274             return G10ERR_TRUSTDB;
275         }
276         if( create ) {
277             FILE *fp;
278             TRUSTREC rec;
279             int rc;
280             char *p = strrchr( fname, '/' );
281
282             assert(p);
283             *p = 0;
284             if( access( fname, F_OK ) ) {
285                 if( strlen(fname) >= 7
286                     && !strcmp(fname+strlen(fname)-7, "/.gnupg" ) ) {
287                   #if __MINGW32__
288                     if( mkdir( fname ) )
289                   #else
290                     if( mkdir( fname, S_IRUSR|S_IWUSR|S_IXUSR ) )
291                   #endif
292                         log_fatal( _("%s: can't create directory: %s\n"),
293                                                     fname,  strerror(errno) );
294                     else
295                         log_info( _("%s: directory created\n"), fname );
296                 }
297                 else
298                     log_fatal( _("%s: directory does not exist!\n"), fname );
299             }
300             *p = '/';
301
302             fp =fopen( fname, "wb" );
303             if( !fp )
304                 log_fatal( _("%s: can't create: %s\n"), fname, strerror(errno) );
305             fclose(fp);
306             m_free(db_name);
307             db_name = fname;
308           #ifdef __MINGW32__
309             db_fd = open( db_name, O_RDWR | O_BINARY );
310           #else
311             db_fd = open( db_name, O_RDWR );
312           #endif
313             if( db_fd == -1 )
314                 log_fatal( _("%s: can't open: %s\n"), db_name, strerror(errno) );
315
316             memset( &rec, 0, sizeof rec );
317             rec.r.ver.version = 2;
318             rec.r.ver.created = make_timestamp();
319             rec.rectype = RECTYPE_VER;
320             rec.recnum = 0;
321             rc = tdbio_write_record( &rec );
322             if( !rc )
323                 tdbio_sync();
324             if( rc )
325                 log_fatal( _("%s: failed to create version record: %s"),
326                                                    fname, g10_errstr(rc));
327             /* and read again to check that we are okay */
328             if( tdbio_read_record( 0, &rec, RECTYPE_VER ) )
329                 log_fatal( _("%s: invalid trust-db created\n"), db_name );
330
331             log_info(_("%s: trust-db created\n"), db_name);
332
333             return 0;
334         }
335     }
336     m_free(db_name);
337     db_name = fname;
338     return 0;
339 }
340
341
342 const char *
343 tdbio_get_dbname()
344 {
345     return db_name;
346 }
347
348
349
350 static void
351 open_db()
352 {
353     TRUSTREC rec;
354     assert( db_fd == -1 );
355
356   #ifdef __MINGW32__
357     db_fd = open( db_name, O_RDWR | O_BINARY );
358   #else
359     db_fd = open( db_name, O_RDWR );
360   #endif
361     if( db_fd == -1 )
362         log_fatal( _("%s: can't open: %s\n"), db_name, strerror(errno) );
363     if( tdbio_read_record( 0, &rec, RECTYPE_VER ) )
364         log_fatal( _("%s: invalid trust-db\n"), db_name );
365     /* fixme: check ->locked and other stuff */
366 }
367
368
369 /****************
370  * Make a hashtable: type 0 = key hash, 1 = sdir hash
371  */
372 static void
373 create_hashtable( TRUSTREC *vr, int type )
374 {
375     TRUSTREC rec;
376     off_t offset;
377     ulong recnum;
378     int i, n, rc;
379
380     offset = lseek( db_fd, 0, SEEK_END );
381     if( offset == -1 )
382         log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
383     recnum = offset / TRUST_RECORD_LEN;
384     assert(recnum); /* this is will never be the first record */
385
386     if( !type )
387         vr->r.ver.keyhashtbl = recnum;
388     else
389         vr->r.ver.sdirhashtbl = recnum;
390     /* Now write the records */
391     n = (256+ITEMS_PER_HTBL_RECORD-1) / ITEMS_PER_HTBL_RECORD;
392     for(i=0; i < n; i++, recnum++ ) {
393          memset( &rec, 0, sizeof rec );
394          rec.rectype = RECTYPE_HTBL;
395          rec.recnum = recnum;
396          rc = tdbio_write_record( &rec );
397          if( rc )
398              log_fatal( _("%s: failed to create hashtable: %s\n"),
399                                         db_name, g10_errstr(rc));
400     }
401     /* update the version record */
402     rc = tdbio_write_record( vr );
403     if( !rc )
404         rc = tdbio_sync();
405     if( rc )
406         log_fatal( _("%s: error updating version record: %s\n"),
407                                                   db_name, g10_errstr(rc));
408 }
409
410
411
412 /****************
413  * Return the record number of the keyhash tbl or create a new one.
414  */
415 static ulong
416 get_keyhashrec()
417 {
418     static ulong keyhashtbl; /* record number of the key hashtable */
419
420     if( !keyhashtbl ) {
421         TRUSTREC vr;
422         int rc;
423
424         rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
425         if( rc )
426             log_fatal( _("%s: error reading version record: %s\n"),
427                                             db_name, g10_errstr(rc) );
428         if( !vr.r.ver.keyhashtbl )
429             create_hashtable( &vr, 0 );
430
431         keyhashtbl = vr.r.ver.keyhashtbl;
432     }
433     return keyhashtbl;
434 }
435
436 /****************
437  * Return the record number of the shadow direcory hash table
438  * or create a new one.
439  */
440 static ulong
441 get_sdirhashrec()
442 {
443     static ulong sdirhashtbl; /* record number of the hashtable */
444
445     if( !sdirhashtbl ) {
446         TRUSTREC vr;
447         int rc;
448
449         rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
450         if( rc )
451             log_fatal( _("%s: error reading version record: %s\n"),
452                                                     db_name, g10_errstr(rc) );
453         if( !vr.r.ver.sdirhashtbl )
454             create_hashtable( &vr, 1 );
455
456         sdirhashtbl = vr.r.ver.sdirhashtbl;
457     }
458     return sdirhashtbl;
459 }
460
461
462 /****************
463  * Update a hashtable.
464  * table gives the start of the table, key and keylen is the key,
465  * newrecnum is the record number to insert.
466  */
467 static int
468 upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
469 {
470     TRUSTREC lastrec, rec;
471     ulong hashrec, item;
472     int msb;
473     int level=0;
474     int rc, i;
475
476     hashrec = table;
477   next_level:
478     msb = key[level];
479     hashrec += msb / ITEMS_PER_HTBL_RECORD;
480     rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL );
481     if( rc ) {
482         log_error( db_name, "upd_hashtable: read failed: %s\n",
483                                                         g10_errstr(rc) );
484         return rc;
485     }
486
487     item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
488     if( !item ) { /* insert a new item into the hash table */
489         rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = newrecnum;
490         rc = tdbio_write_record( &rec );
491         if( rc ) {
492             log_error( db_name, "upd_hashtable: write htbl failed: %s\n",
493                                                             g10_errstr(rc) );
494             return rc;
495         }
496     }
497     else if( item != newrecnum ) {  /* must do an update */
498         lastrec = rec;
499         rc = tdbio_read_record( item, &rec, 0 );
500         if( rc ) {
501             log_error( "upd_hashtable: read item failed: %s\n",
502                                                             g10_errstr(rc) );
503             return rc;
504         }
505
506         if( rec.rectype == RECTYPE_HTBL ) {
507             hashrec = item;
508             level++;
509             if( level >= keylen ) {
510                 log_error( "hashtable has invalid indirections.\n");
511                 return G10ERR_TRUSTDB;
512             }
513             goto next_level;
514         }
515         else if( rec.rectype == RECTYPE_HLST ) { /* extend list */
516             /* see whether the key is already in this list */
517             for(;;) {
518                 for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
519                     if( rec.r.hlst.rnum[i] == newrecnum ) {
520                         return 0; /* okay, already in the list */
521                     }
522                 }
523                 if( rec.r.hlst.next ) {
524                     rc = tdbio_read_record( rec.r.hlst.next,
525                                                        &rec, RECTYPE_HLST);
526                     if( rc ) {
527                         log_error( "scan keyhashtbl read hlst failed: %s\n",
528                                                              g10_errstr(rc) );
529                         return rc;
530                     }
531                 }
532                 else
533                     break; /* not there */
534             }
535             /* find the next free entry and put it in */
536             for(;;) {
537                 for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
538                     if( !rec.r.hlst.rnum[i] ) {
539                         rec.r.hlst.rnum[i] = newrecnum;
540                         rc = tdbio_write_record( &rec );
541                         if( rc )
542                             log_error( "upd_hashtable: write hlst failed: %s\n",
543                                                               g10_errstr(rc) );
544                         return rc; /* done */
545                     }
546                 }
547                 if( rec.r.hlst.next ) {
548                     rc = tdbio_read_record( rec.r.hlst.next,
549                                                       &rec, RECTYPE_HLST );
550                     if( rc ) {
551                         log_error( "upd_hashtable: read hlst failed: %s\n",
552                                                              g10_errstr(rc) );
553                         return rc;
554                     }
555                 }
556                 else { /* add a new list record */
557                     rec.r.hlst.next = item = tdbio_new_recnum();
558                     rc = tdbio_write_record( &rec );
559                     if( rc ) {
560                         log_error( "upd_hashtable: write hlst failed: %s\n",
561                                                           g10_errstr(rc) );
562                         return rc;
563                     }
564                     memset( &rec, 0, sizeof rec );
565                     rec.rectype = RECTYPE_HLST;
566                     rec.recnum = item;
567                     rec.r.hlst.rnum[0] = newrecnum;
568                     rc = tdbio_write_record( &rec );
569                     if( rc )
570                         log_error( "upd_hashtable: write ext hlst failed: %s\n",
571                                                           g10_errstr(rc) );
572                     return rc; /* done */
573                 }
574             } /* end loop over hlst slots */
575         }
576         else if( rec.rectype == RECTYPE_KEY
577                  || rec.rectype == RECTYPE_DIR
578                  || rec.rectype == RECTYPE_SDIR ) { /* insert a list record */
579             if( rec.recnum == newrecnum ) {
580                 return 0;
581             }
582             item = rec.recnum; /* save number of key record */
583             memset( &rec, 0, sizeof rec );
584             rec.rectype = RECTYPE_HLST;
585             rec.recnum = tdbio_new_recnum();
586             rec.r.hlst.rnum[0] = item;       /* old keyrecord */
587             rec.r.hlst.rnum[1] = newrecnum; /* and new one */
588             rc = tdbio_write_record( &rec );
589             if( rc ) {
590                 log_error( "upd_hashtable: write new hlst failed: %s\n",
591                                                   g10_errstr(rc) );
592                 return rc;
593             }
594             /* update the hashtable record */
595             lastrec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = rec.recnum;
596             rc = tdbio_write_record( &lastrec );
597             if( rc )
598                 log_error( "upd_hashtable: update htbl failed: %s\n",
599                                                              g10_errstr(rc) );
600             return rc; /* ready */
601         }
602         else {
603             log_error( "hashtbl %lu points to an invalid record\n",
604                                                                     item);
605             return G10ERR_TRUSTDB;
606         }
607     }
608
609     return 0;
610 }
611
612
613
614 /****************
615  * Lookup a record via the hashtable tablewith key/keylen and return the
616  * result in rec.  cmp() should return if the record is the desired one.
617  * Returns -1 if not found, 0 if found or another errocode
618  */
619 static int
620 lookup_hashtable( ulong table, const byte *key, size_t keylen,
621                   int (*cmpfnc)(void*, const TRUSTREC *), void *cmpdata,
622                                                 TRUSTREC *rec )
623 {
624     int rc;
625     ulong hashrec, item;
626     int msb;
627     int level=0;
628
629     hashrec = table;
630   next_level:
631     msb = key[level];
632     hashrec += msb / ITEMS_PER_HTBL_RECORD;
633     rc = tdbio_read_record( hashrec, rec, RECTYPE_HTBL );
634     if( rc ) {
635         log_error( db_name, "lookup_hashtable failed: %s\n", g10_errstr(rc) );
636         return rc;
637     }
638
639     item = rec->r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
640     if( !item )
641         return -1; /* not found */
642
643     rc = tdbio_read_record( item, rec, 0 );
644     if( rc ) {
645         log_error( db_name, "hashtable read failed: %s\n", g10_errstr(rc) );
646         return rc;
647     }
648     if( rec->rectype == RECTYPE_HTBL ) {
649         hashrec = item;
650         level++;
651         if( level >= keylen ) {
652             log_error( db_name, "hashtable has invalid indirections\n");
653             return G10ERR_TRUSTDB;
654         }
655         goto next_level;
656     }
657     else if( rec->rectype == RECTYPE_HLST ) {
658         for(;;) {
659             int i;
660
661             for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
662                 if( rec->r.hlst.rnum[i] ) {
663                     TRUSTREC tmp;
664
665                     rc = tdbio_read_record( rec->r.hlst.rnum[i], &tmp, 0 );
666                     if( rc ) {
667                         log_error( "lookup_hashtable: read item failed: %s\n",
668                                                               g10_errstr(rc) );
669                         return rc;
670                     }
671                     if( (*cmpfnc)( cmpdata, &tmp ) ) {
672                         *rec = tmp;
673                         return 0;
674                     }
675                 }
676             }
677             if( rec->r.hlst.next ) {
678                 rc = tdbio_read_record( rec->r.hlst.next, rec, RECTYPE_HLST );
679                 if( rc ) {
680                     log_error( "lookup_hashtable: read hlst failed: %s\n",
681                                                          g10_errstr(rc) );
682                     return rc;
683                 }
684             }
685             else
686                 return -1; /* not found */
687         }
688     }
689
690
691     if( (*cmpfnc)( cmpdata, rec ) )
692         return 0; /* really found */
693
694     return -1; /* no: not found */
695 }
696
697
698
699
700 /****************
701  * Update the key hashtbl or create the table if it does not exist
702  */
703 static int
704 update_keyhashtbl( TRUSTREC *kr )
705 {
706     return upd_hashtable( get_keyhashrec(),
707                           kr->r.key.fingerprint,
708                           kr->r.key.fingerprint_len, kr->recnum );
709 }
710
711 /****************
712  * Update the shadow dir hashtbl or create the table if it does not exist
713  */
714 static int
715 update_sdirhashtbl( TRUSTREC *sr )
716 {
717     byte key[8];
718
719     u32tobuf( key   , sr->r.sdir.keyid[0] );
720     u32tobuf( key+4 , sr->r.sdir.keyid[1] );
721     return upd_hashtable( get_sdirhashrec(), key, 8, sr->recnum );
722 }
723
724
725
726
727 void
728 tdbio_dump_record( TRUSTREC *rec, FILE *fp  )
729 {
730     int i;
731     ulong rnum = rec->recnum;
732     byte *p;
733
734     fprintf(fp, "rec %5lu, ", rnum );
735
736     switch( rec->rectype ) {
737       case 0: fprintf(fp, "blank\n");
738         break;
739       case RECTYPE_VER: fprintf(fp, "version, kd=%lu, sd=%lu, free=%lu\n",
740             rec->r.ver.keyhashtbl, rec->r.ver.sdirhashtbl,
741                                    rec->r.ver.firstfree );
742         break;
743       case RECTYPE_FREE: fprintf(fp, "free, next=%lu\n", rec->r.free.next );
744         break;
745       case RECTYPE_DIR:
746         fprintf(fp, "dir %lu, keys=%lu, uids=%lu, cach=%lu, ot=%02x",
747                     rec->r.dir.lid,
748                     rec->r.dir.keylist,
749                     rec->r.dir.uidlist,
750                     rec->r.dir.cacherec,
751                     rec->r.dir.ownertrust );
752         if( rec->r.dir.dirflags & DIRF_CHECKED ) {
753             if( rec->r.dir.dirflags & DIRF_VALID )
754                 fputs(", valid", fp );
755             if( rec->r.dir.dirflags & DIRF_EXPIRED )
756                 fputs(", expired", fp );
757             if( rec->r.dir.dirflags & DIRF_REVOKED )
758                 fputs(", revoked", fp );
759         }
760         putc('\n', fp);
761         break;
762       case RECTYPE_KEY:
763         fprintf(fp, "key %lu, next=%lu, algo=%d, ",
764                    rec->r.key.lid,
765                    rec->r.key.next,
766                    rec->r.key.pubkey_algo );
767         for(i=0; i < rec->r.key.fingerprint_len; i++ )
768             fprintf(fp, "%02X", rec->r.key.fingerprint[i] );
769         if( rec->r.key.keyflags & KEYF_CHECKED ) {
770             if( rec->r.key.keyflags & KEYF_VALID )
771                 fputs(", valid", fp );
772             if( rec->r.key.keyflags & KEYF_EXPIRED )
773                 fputs(", expired", fp );
774             if( rec->r.key.keyflags & KEYF_REVOKED )
775                 fputs(", revoked", fp );
776         }
777         putc('\n', fp);
778         break;
779       case RECTYPE_UID:
780         fprintf(fp, "uid %lu, next=%lu, pref=%lu, sig=%lu, hash=%02X%02X",
781                     rec->r.uid.lid,
782                     rec->r.uid.next,
783                     rec->r.uid.prefrec,
784                     rec->r.uid.siglist,
785                     rec->r.uid.namehash[18], rec->r.uid.namehash[19]);
786         if( rec->r.uid.uidflags & UIDF_CHECKED ) {
787             if( rec->r.uid.uidflags & UIDF_VALID )
788                 fputs(", valid", fp );
789             if( rec->r.uid.uidflags & UIDF_REVOKED )
790                 fputs(", revoked", fp );
791         }
792         putc('\n', fp);
793         break;
794       case RECTYPE_PREF:
795         fprintf(fp, "pref %lu, next=%lu,",
796                     rec->r.pref.lid, rec->r.pref.next);
797         for(i=0,p=rec->r.pref.data; i < ITEMS_PER_PREF_RECORD; i+=2,p+=2 ) {
798             if( *p )
799                 fprintf(fp, " %c%d", *p == PREFTYPE_SYM    ? 'S' :
800                                      *p == PREFTYPE_HASH   ? 'H' :
801                                      *p == PREFTYPE_COMPR  ? 'Z' : '?', p[1]);
802         }
803         putc('\n', fp);
804         break;
805       case RECTYPE_SIG:
806         fprintf(fp, "sig %lu, next=%lu,",
807                          rec->r.sig.lid, rec->r.sig.next );
808         for(i=0; i < SIGS_PER_RECORD; i++ ) {
809             if( rec->r.sig.sig[i].lid ) {
810                 fprintf(fp, " %lu:", rec->r.sig.sig[i].lid );
811                 if( rec->r.sig.sig[i].flag & SIGF_CHECKED ) {
812                     fprintf(fp,"%c%c%c",
813                        (rec->r.sig.sig[i].flag & SIGF_VALID)   ? 'V':'-',
814                        (rec->r.sig.sig[i].flag & SIGF_EXPIRED) ? 'E':'-',
815                        (rec->r.sig.sig[i].flag & SIGF_REVOKED) ? 'R':'-');
816                 }
817                 else if( rec->r.sig.sig[i].flag & SIGF_NOPUBKEY)
818                     fputs("?--", fp);
819                 else
820                     fputs("---", fp);
821             }
822         }
823         putc('\n', fp);
824         break;
825       case RECTYPE_SDIR:
826         fprintf(fp, "sdir %lu, keyid=%08lX%08lX, algo=%d, hint=%lu\n",
827                     rec->r.sdir.lid,
828                     (ulong)rec->r.sdir.keyid[0],
829                     (ulong)rec->r.sdir.keyid[1],
830                     rec->r.sdir.pubkey_algo,
831                     (ulong)rec->r.sdir.hintlist );
832         break;
833       case RECTYPE_CACH:
834         fprintf(fp, "cach\n");
835         break;
836       case RECTYPE_HTBL:
837         fprintf(fp, "htbl,");
838         for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ )
839             fprintf(fp, " %lu", rec->r.htbl.item[i] );
840         putc('\n', fp);
841         break;
842       case RECTYPE_HLST:
843         fprintf(fp, "hlst, next=%lu,", rec->r.hlst.next );
844         for(i=0; i < ITEMS_PER_HLST_RECORD; i++ )
845             fprintf(fp, " %lu", rec->r.hlst.rnum[i] );
846         putc('\n', fp);
847         break;
848       default:
849         fprintf(fp, "unknown type %d\n", rec->rectype );
850         break;
851     }
852 }
853
854 /****************
855  * read the record with number recnum
856  * returns: -1 on error, 0 on success
857  */
858 int
859 tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
860 {
861     byte readbuf[TRUST_RECORD_LEN];
862     const byte *buf, *p;
863     int rc = 0;
864     int n, i;
865
866     if( db_fd == -1 )
867         open_db();
868     buf = get_record_from_cache( recnum );
869     if( !buf ) {
870         if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
871             log_error(_("trustdb: lseek failed: %s\n"), strerror(errno) );
872             return G10ERR_READ_FILE;
873         }
874         n = read( db_fd, readbuf, TRUST_RECORD_LEN);
875         if( !n ) {
876             return -1; /* eof */
877         }
878         else if( n != TRUST_RECORD_LEN ) {
879             log_error(_("trustdb: read failed (n=%d): %s\n"), n,
880                                                         strerror(errno) );
881             return G10ERR_READ_FILE;
882         }
883         buf = readbuf;
884     }
885     rec->recnum = recnum;
886     rec->dirty = 0;
887     p = buf;
888     rec->rectype = *p++;
889     if( expected && rec->rectype != expected ) {
890         log_error("%lu: read expected rec type %d, got %d\n",
891                     recnum, expected, rec->rectype );
892         return G10ERR_TRUSTDB;
893     }
894     p++;    /* skip reserved byte */
895     switch( rec->rectype ) {
896       case 0:  /* unused (free) record */
897         break;
898       case RECTYPE_VER: /* version record */
899         if( memcmp(buf+1, "gpg", 3 ) ) {
900             log_error( _("%s: not a trustdb file\n"), db_name );
901             rc = G10ERR_TRUSTDB;
902         }
903         p += 2; /* skip "pgp" */
904         rec->r.ver.version  = *p++;
905         p += 3; /* reserved bytes */
906         p += 4; /* lock flags */
907         rec->r.ver.created  = buftoulong(p); p += 4;
908         rec->r.ver.modified = buftoulong(p); p += 4;
909         rec->r.ver.validated= buftoulong(p); p += 4;
910         rec->r.ver.keyhashtbl=buftoulong(p); p += 4;
911         rec->r.ver.firstfree =buftoulong(p); p += 4;
912         rec->r.ver.sdirhashtbl =buftoulong(p); p += 4;
913         if( recnum ) {
914             log_error( _("%s: version record with recnum %lu\n"), db_name,
915                                                              (ulong)recnum );
916             rc = G10ERR_TRUSTDB;
917         }
918         else if( rec->r.ver.version != 2 ) {
919             log_error( _("%s: invalid file version %d\n"), db_name,
920                                                         rec->r.ver.version );
921             rc = G10ERR_TRUSTDB;
922         }
923         break;
924       case RECTYPE_FREE:
925         rec->r.free.next  = buftoulong(p); p += 4;
926         break;
927       case RECTYPE_DIR:   /*directory record */
928         rec->r.dir.lid      = buftoulong(p); p += 4;
929         rec->r.dir.keylist  = buftoulong(p); p += 4;
930         rec->r.dir.uidlist  = buftoulong(p); p += 4;
931         rec->r.dir.cacherec = buftoulong(p); p += 4;
932         rec->r.dir.ownertrust = *p++;
933         rec->r.dir.dirflags   = *p++;
934         if( rec->r.dir.lid != recnum ) {
935             log_error( "%s: dir LID != recnum (%lu,%lu)\n",
936                               db_name, rec->r.dir.lid, (ulong)recnum );
937             rc = G10ERR_TRUSTDB;
938         }
939         break;
940       case RECTYPE_KEY:   /* public key record */
941         rec->r.key.lid      = buftoulong(p); p += 4;
942         rec->r.key.next     = buftoulong(p); p += 4;
943         p += 7;
944         rec->r.key.keyflags = *p++;
945         rec->r.key.pubkey_algo = *p++;
946         rec->r.key.fingerprint_len = *p++;
947         if( rec->r.key.fingerprint_len < 1 || rec->r.key.fingerprint_len > 20 )
948             rec->r.key.fingerprint_len = 20;
949         memcpy( rec->r.key.fingerprint, p, 20);
950         break;
951       case RECTYPE_UID:   /* user id record */
952         rec->r.uid.lid      = buftoulong(p); p += 4;
953         rec->r.uid.next     = buftoulong(p); p += 4;
954         rec->r.uid.prefrec  = buftoulong(p); p += 4;
955         rec->r.uid.siglist  = buftoulong(p); p += 4;
956         rec->r.uid.uidflags = *p++;
957         p ++;
958         memcpy( rec->r.uid.namehash, p, 20);
959         break;
960       case RECTYPE_PREF:  /* preference record */
961         rec->r.pref.lid     = buftoulong(p); p += 4;
962         rec->r.pref.next    = buftoulong(p); p += 4;
963         memcpy( rec->r.pref.data, p, 30 );
964         break;
965       case RECTYPE_SIG:
966         rec->r.sig.lid     = buftoulong(p); p += 4;
967         rec->r.sig.next    = buftoulong(p); p += 4;
968         for(i=0; i < SIGS_PER_RECORD; i++ ) {
969             rec->r.sig.sig[i].lid  = buftoulong(p); p += 4;
970             rec->r.sig.sig[i].flag = *p++;
971         }
972         break;
973       case RECTYPE_SDIR:   /* shadow directory record */
974         rec->r.sdir.lid     = buftoulong(p); p += 4;
975         rec->r.sdir.keyid[0]= buftou32(p); p += 4;
976         rec->r.sdir.keyid[1]= buftou32(p); p += 4;
977         rec->r.sdir.pubkey_algo = *p++;
978         p += 3;
979         rec->r.sdir.hintlist = buftoulong(p);
980         if( rec->r.sdir.lid != recnum ) {
981             log_error( "%s: sdir LID != recnum (%lu,%lu)\n",
982                                db_name, rec->r.sdir.lid, (ulong)recnum );
983             rc = G10ERR_TRUSTDB;
984         }
985         break;
986       case RECTYPE_CACH:   /* cache record */
987         rec->r.cache.lid    = buftoulong(p); p += 4;
988         memcpy(rec->r.cache.blockhash, p, 20); p += 20;
989         rec->r.cache.trustlevel = *p++;
990         break;
991       case RECTYPE_HTBL:
992         for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) {
993             rec->r.htbl.item[i] = buftoulong(p); p += 4;
994         }
995         break;
996       case RECTYPE_HLST:
997         rec->r.hlst.next = buftoulong(p); p += 4;
998         for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
999             rec->r.hlst.rnum[i] = buftoulong(p); p += 4;
1000         }
1001         break;
1002       default:
1003         log_error( "%s: invalid record type %d at recnum %lu\n",
1004                                    db_name, rec->rectype, (ulong)recnum );
1005         rc = G10ERR_TRUSTDB;
1006         break;
1007     }
1008
1009     return rc;
1010 }
1011
1012 /****************
1013  * Write the record at RECNUM
1014  */
1015 int
1016 tdbio_write_record( TRUSTREC *rec )
1017 {
1018     byte buf[TRUST_RECORD_LEN], *p;
1019     int rc = 0;
1020     int i;
1021     ulong recnum = rec->recnum;
1022
1023     if( db_fd == -1 )
1024         open_db();
1025
1026     memset(buf, 0, TRUST_RECORD_LEN);
1027     p = buf;
1028     *p++ = rec->rectype; p++;
1029     switch( rec->rectype ) {
1030       case 0:  /* unused record */
1031         break;
1032       case RECTYPE_VER: /* version record */
1033         if( recnum )
1034             BUG();
1035         memcpy(p-1, "gpg", 3 ); p += 2;
1036         *p++ = rec->r.ver.version;
1037         p += 7; /* skip reserved bytes and lock flags */
1038         ulongtobuf(p, rec->r.ver.created); p += 4;
1039         ulongtobuf(p, rec->r.ver.modified); p += 4;
1040         ulongtobuf(p, rec->r.ver.validated); p += 4;
1041         ulongtobuf(p, rec->r.ver.keyhashtbl); p += 4;
1042         ulongtobuf(p, rec->r.ver.firstfree ); p += 4;
1043         ulongtobuf(p, rec->r.ver.sdirhashtbl ); p += 4;
1044         break;
1045
1046       case RECTYPE_FREE:
1047         ulongtobuf(p, rec->r.free.next); p += 4;
1048         break;
1049
1050       case RECTYPE_DIR:   /*directory record */
1051         ulongtobuf(p, rec->r.dir.lid); p += 4;
1052         ulongtobuf(p, rec->r.dir.keylist); p += 4;
1053         ulongtobuf(p, rec->r.dir.uidlist); p += 4;
1054         ulongtobuf(p, rec->r.dir.cacherec); p += 4;
1055         *p++ = rec->r.dir.ownertrust;
1056         *p++ = rec->r.dir.dirflags;
1057         assert( rec->r.dir.lid == recnum );
1058         break;
1059
1060       case RECTYPE_KEY:
1061         ulongtobuf(p, rec->r.key.lid); p += 4;
1062         ulongtobuf(p, rec->r.key.next); p += 4;
1063         p += 7;
1064         *p++ = rec->r.key.keyflags;
1065         *p++ = rec->r.key.pubkey_algo;
1066         *p++ = rec->r.key.fingerprint_len;
1067         memcpy( p, rec->r.key.fingerprint, 20); p += 20;
1068         break;
1069
1070       case RECTYPE_UID:   /* user id record */
1071         ulongtobuf(p, rec->r.uid.lid); p += 4;
1072         ulongtobuf(p, rec->r.uid.next); p += 4;
1073         ulongtobuf(p, rec->r.uid.prefrec); p += 4;
1074         ulongtobuf(p, rec->r.uid.siglist); p += 4;
1075         *p++ = rec->r.uid.uidflags;
1076         p++;
1077         memcpy( p, rec->r.uid.namehash, 20 ); p += 20;
1078         break;
1079
1080       case RECTYPE_PREF:
1081         ulongtobuf(p, rec->r.pref.lid); p += 4;
1082         ulongtobuf(p, rec->r.pref.next); p += 4;
1083         memcpy( p, rec->r.pref.data, 30 );
1084         break;
1085
1086       case RECTYPE_SIG:
1087         ulongtobuf(p, rec->r.sig.lid); p += 4;
1088         ulongtobuf(p, rec->r.sig.next); p += 4;
1089         for(i=0; i < SIGS_PER_RECORD; i++ ) {
1090             ulongtobuf(p, rec->r.sig.sig[i].lid); p += 4;
1091             *p++ = rec->r.sig.sig[i].flag;
1092         }
1093         break;
1094
1095       case RECTYPE_SDIR:
1096         ulongtobuf( p, rec->r.sdir.lid); p += 4;
1097         u32tobuf( p, rec->r.sdir.keyid[0] ); p += 4;
1098         u32tobuf( p, rec->r.sdir.keyid[1] ); p += 4;
1099         *p++ = rec->r.sdir.pubkey_algo;
1100         p += 3;
1101         ulongtobuf( p, rec->r.sdir.hintlist );
1102         break;
1103
1104       case RECTYPE_CACH:
1105         ulongtobuf(p, rec->r.cache.lid); p += 4;
1106         memcpy(p, rec->r.cache.blockhash, 20); p += 20;
1107         *p++ = rec->r.cache.trustlevel;
1108         break;
1109
1110       case RECTYPE_HTBL:
1111         for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) {
1112             ulongtobuf( p, rec->r.htbl.item[i]); p += 4;
1113         }
1114         break;
1115
1116       case RECTYPE_HLST:
1117         ulongtobuf( p, rec->r.hlst.next); p += 4;
1118         for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
1119             ulongtobuf( p, rec->r.hlst.rnum[i]); p += 4;
1120         }
1121         break;
1122
1123       default:
1124         BUG();
1125     }
1126
1127     rc = put_record_into_cache( recnum, buf );
1128     if( rc )
1129         ;
1130     if( rec->rectype == RECTYPE_KEY )
1131         rc = update_keyhashtbl( rec );
1132     else if( rec->rectype == RECTYPE_SDIR )
1133         rc = update_sdirhashtbl( rec );
1134
1135     return rc;
1136 }
1137
1138 int
1139 tdbio_delete_record( ulong recnum )
1140 {
1141     TRUSTREC vr, rec;
1142     int rc;
1143
1144     rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
1145     if( rc )
1146         log_fatal( _("%s: error reading version record: %s\n"),
1147                                        db_name, g10_errstr(rc) );
1148
1149     rec.recnum = recnum;
1150     rec.rectype = RECTYPE_FREE;
1151     rec.r.free.next = vr.r.ver.firstfree;
1152     vr.r.ver.firstfree = recnum;
1153     rc = tdbio_write_record( &rec );
1154     if( !rc )
1155         rc = tdbio_write_record( &vr );
1156     return rc;
1157 }
1158
1159 /****************
1160  * create a new record and return its record number
1161  */
1162 ulong
1163 tdbio_new_recnum()
1164 {
1165     off_t offset;
1166     ulong recnum;
1167     TRUSTREC vr, rec;
1168     int rc;
1169
1170     /* look for unused records */
1171     rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
1172     if( rc )
1173         log_fatal( _("%s: error reading version record: %s\n"),
1174                                              db_name, g10_errstr(rc) );
1175     if( vr.r.ver.firstfree ) {
1176         recnum = vr.r.ver.firstfree;
1177         rc = tdbio_read_record( recnum, &rec, RECTYPE_FREE );
1178         if( rc ) {
1179             log_error( _("%s: error reading free record: %s\n"),
1180                                                   db_name,  g10_errstr(rc) );
1181             return rc;
1182         }
1183         /* update dir record */
1184         vr.r.ver.firstfree = rec.r.free.next;
1185         rc = tdbio_write_record( &vr );
1186         if( rc ) {
1187             log_error( _("%s: error writing dir record: %s\n"),
1188                                                      db_name, g10_errstr(rc) );
1189             return rc;
1190         }
1191         /*zero out the new record */
1192         memset( &rec, 0, sizeof rec );
1193         rec.rectype = 0; /* unused record */
1194         rec.recnum = recnum;
1195         rc = tdbio_write_record( &rec );
1196         if( rc )
1197             log_fatal(_("%s: failed to zero a record: %s\n"),
1198                                        db_name, g10_errstr(rc));
1199     }
1200     else { /* not found, append a new record */
1201         offset = lseek( db_fd, 0, SEEK_END );
1202         if( offset == -1 )
1203             log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
1204         recnum = offset / TRUST_RECORD_LEN;
1205         assert(recnum); /* this is will never be the first record */
1206         /* we must write a record, so that the next call to this function
1207          * returns another recnum */
1208         memset( &rec, 0, sizeof rec );
1209         rec.rectype = 0; /* unused record */
1210         rec.recnum = recnum;
1211         rc = 0;
1212         if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
1213             log_error(_("trustdb rec %lu: lseek failed: %s\n"),
1214                                                 recnum, strerror(errno) );
1215             rc = G10ERR_WRITE_FILE;
1216         }
1217         else {
1218             int n = write( db_fd, &rec, TRUST_RECORD_LEN);
1219             if( n != TRUST_RECORD_LEN ) {
1220                 log_error(_("trustdb rec %lu: write failed (n=%d): %s\n"),
1221                                                  recnum, n, strerror(errno) );
1222                 rc = G10ERR_WRITE_FILE;
1223             }
1224         }
1225
1226         if( rc )
1227             log_fatal(_("%s: failed to append a record: %s\n"),
1228                                     db_name,    g10_errstr(rc));
1229     }
1230     return recnum ;
1231 }
1232
1233
1234
1235 /****************
1236  * Search the trustdb for a key which matches PK and return the dir record
1237  * The local_id of PK is set to the correct value
1238  */
1239 int
1240 tdbio_search_dir_bypk( PKT_public_key *pk, TRUSTREC *rec )
1241 {
1242     byte fingerprint[MAX_FINGERPRINT_LEN];
1243     size_t fingerlen;
1244     u32 keyid[2];
1245     int rc;
1246
1247     keyid_from_pk( pk, keyid );
1248     fingerprint_from_pk( pk, fingerprint, &fingerlen );
1249     rc = tdbio_search_dir_byfpr( fingerprint, fingerlen,
1250                                  pk->pubkey_algo, rec );
1251
1252     if( !rc ) {
1253         if( pk->local_id && pk->local_id != rec->recnum )
1254             log_error("%s: found record, but LID from memory does "
1255                        "not match recnum (%lu,%lu)\n",
1256                             db_name,  pk->local_id, rec->recnum );
1257         pk->local_id = rec->recnum;
1258     }
1259     return rc;
1260 }
1261
1262
1263 static int
1264 cmp_krec_fpr( void *dataptr, const TRUSTREC *rec )
1265 {
1266     const struct cmp_krec_fpr_struct *d = dataptr;
1267
1268     return rec->rectype == RECTYPE_KEY
1269            && ( !d->pubkey_algo || rec->r.key.pubkey_algo == d->pubkey_algo )
1270            && rec->r.key.fingerprint_len == d->fprlen
1271            && !memcmp( rec->r.key.fingerprint, d->fpr, d->fprlen );
1272 }
1273
1274 int
1275 tdbio_search_dir_byfpr( const byte *fingerprint, size_t fingerlen,
1276                         int pubkey_algo, TRUSTREC *rec )
1277 {
1278     struct cmp_krec_fpr_struct cmpdata;
1279     ulong recnum;
1280     int rc;
1281
1282     assert( fingerlen == 20 || fingerlen == 16 );
1283
1284     /* locate the key using the hash table */
1285     cmpdata.pubkey_algo = pubkey_algo;
1286     cmpdata.fpr = fingerprint;
1287     cmpdata.fprlen = fingerlen;
1288     rc = lookup_hashtable( get_keyhashrec(), fingerprint, fingerlen,
1289                            cmp_krec_fpr, &cmpdata, rec );
1290     if( !rc ) {
1291         recnum = rec->r.key.lid;
1292         /* Now read the dir record */
1293         rc = tdbio_read_record( recnum, rec, RECTYPE_DIR);
1294         if( rc )
1295             log_error("%s: can't read dirrec %lu: %s\n",
1296                                      db_name, recnum, g10_errstr(rc) );
1297     }
1298     return rc;
1299 }
1300
1301
1302
1303 static int
1304 cmp_sdir( void *dataptr, const TRUSTREC *rec )
1305 {
1306     const struct cmp_sdir_struct *d = dataptr;
1307
1308     return rec->rectype == RECTYPE_SDIR
1309            && ( !d->pubkey_algo || rec->r.sdir.pubkey_algo == d->pubkey_algo )
1310            && rec->r.sdir.keyid[0] == d->keyid[0]
1311            && rec->r.sdir.keyid[1] == d->keyid[1];
1312 }
1313
1314
1315 int
1316 tdbio_search_sdir( u32 *keyid, int pubkey_algo, TRUSTREC *rec )
1317 {
1318     struct cmp_sdir_struct cmpdata;
1319     int rc;
1320     byte key[8];
1321
1322     /* locate the shadow dir record using the hash table */
1323     u32tobuf( key   , keyid[0] );
1324     u32tobuf( key+4 , keyid[1] );
1325     cmpdata.pubkey_algo = pubkey_algo;
1326     cmpdata.keyid[0] = keyid[0];
1327     cmpdata.keyid[1] = keyid[1];
1328     rc = lookup_hashtable( get_sdirhashrec(), key, 8,
1329                            cmp_sdir, &cmpdata, rec );
1330     return rc;
1331 }
1332
1333