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