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