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