Trust stuff works partly.
[gnupg.git] / g10 / trustdb.c
1 /* trustdb.c
2  *      Copyright (c) 1997 by Werner Koch (dd9jn)
3  *
4  * This file is part of G10.
5  *
6  * G10 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  * G10 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 <unistd.h>
26 #include <errno.h>
27 #include <assert.h>
28 #include <fcntl.h>
29
30 #include "errors.h"
31 #include "iobuf.h"
32 #include "keydb.h"
33 #include "memory.h"
34 #include "util.h"
35 #include "trustdb.h"
36 #include "options.h"
37 #include "packet.h"
38 #include "main.h"
39
40
41 #define TRUST_RECORD_LEN 40
42 #define SIGS_PER_RECORD ((TRUST_RECORD_LEN-10)/5)
43 #define MAX_LIST_SIGS_DEPTH  20
44
45 struct trust_record {
46     byte rectype;
47     byte reserved;
48     union {
49         struct {            /* version record: */
50             byte magic[2];
51             byte version;   /* should be 1 */
52             byte reserved[3];
53             ulong locked;    /* pid of process which holds a lock */
54             ulong created;   /* timestamp of trustdb creation  */
55             ulong modified;  /* timestamp of last modification */
56             ulong validated; /* timestamp of last validation   */
57             ulong local_id_counter;
58             byte marginals_needed;
59             byte completes_needed;
60             byte max_cert_depth;
61         } version;
62         struct {            /* public key record */
63             ulong local_id;
64             u32   keyid[2];
65             byte pubkey_algo;
66             byte reserved;
67             byte fingerprint[20];
68             byte ownertrust;
69             /* fixme: indicate a flag to */
70         } pubkey;
71         struct {            /* cache record */
72             ulong owner;
73             u32   keyid[2];       /* needed?? */
74             byte valid;
75             byte reserved;
76             byte blockhash[20];
77             byte n_untrusted;
78             byte n_marginal;
79             byte n_fully;
80             byte trustlevel;
81         } cache;
82         struct {
83             ulong owner;  /* local_id of record owner (pubkey record) */
84             ulong chain;  /* offset of next record or NULL for last one */
85             struct {
86                 ulong  local_id; /* of pubkey record of signator (0=unused) */
87                 byte flag;     /* reserved */
88             } sig[SIGS_PER_RECORD];
89         } sigrec;
90     } r;
91 };
92 typedef struct trust_record TRUSTREC;
93
94 typedef struct {
95     ulong     pubkey_id;   /* localid of the pubkey */
96     ulong     sig_id;      /* returned signature id */
97     unsigned  sig_flag;    /* returned signaure record flag */
98     struct {               /* internal data */
99         int eof;
100         TRUSTREC rec;
101         int index;
102     } ctl;
103 } SIGREC_CONTEXT;
104
105 typedef struct local_id_info *LOCAL_ID_INFO;
106 struct local_id_info {
107     LOCAL_ID_INFO next;
108     ulong lid;
109     unsigned flag;
110 };
111
112
113 typedef struct trust_info TRUST_INFO;
114 struct trust_info {
115     ulong    lid;
116     unsigned trust;
117 };
118
119
120 typedef struct trust_seg_list *TRUST_SEG_LIST;
121 struct trust_seg_list {
122     TRUST_SEG_LIST next;
123     int   nseg;     /* number of segmens */
124     int   dup;
125     TRUST_INFO seg[1];   /* segment list */
126 };
127
128
129 typedef struct {
130     TRUST_SEG_LIST tsl;
131     int index;
132 } ENUM_TRUST_WEB_CONTEXT;
133
134
135 static void create_db( const char *fname );
136 static void open_db(void);
137 static int  read_record( ulong recnum, TRUSTREC *rec );
138 static int  write_record( ulong recnum, TRUSTREC *rec );
139 static ulong new_recnum(void);
140 static void dump_record( ulong rnum, TRUSTREC *rec, FILE *fp );
141 static int walk_sigrecs( SIGREC_CONTEXT *c );
142
143 static LOCAL_ID_INFO *new_lid_table(void);
144 static void release_lid_table( LOCAL_ID_INFO *tbl );
145 static int ins_lid_table_item( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag );
146 static int qry_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned *flag );
147 static void upd_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag );
148
149 static void print_user_id( const char *text, u32 *keyid );
150 static int do_list_path( TRUST_INFO *stack, int depth, int max_depth,
151                          LOCAL_ID_INFO *lids, TRUST_SEG_LIST *tslist );
152
153 static int list_sigs( ulong pubkey_id );
154 static int propagate_trust( TRUST_SEG_LIST tslist );
155 static int do_check( ulong pubkeyid, unsigned *trustlevel );
156
157
158 static char *db_name;
159 static int  db_fd = -1;
160 /* a table used to keep track of ultimately trusted keys
161  * which are the ones from our secrings */
162 static LOCAL_ID_INFO *ultikey_table;
163
164 static ulong last_trust_web_key;
165 static TRUST_SEG_LIST last_trust_web_tslist;
166
167 #define buftoulong( p )  ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \
168                        (*((byte*)(p)+2) << 8) | (*((byte*)(p)+3)))
169 #define buftoushort( p )  ((*((byte*)(p)) << 8) | (*((byte*)(p)+1)))
170 #define ulongtobuf( p, a ) do {                           \
171                             ((byte*)p)[0] = a >> 24;    \
172                             ((byte*)p)[1] = a >> 16;    \
173                             ((byte*)p)[2] = a >>  8;    \
174                             ((byte*)p)[3] = a      ;    \
175                         } while(0)
176 #define ushorttobuf( p, a ) do {                           \
177                             ((byte*)p)[0] = a >>  8;    \
178                             ((byte*)p)[1] = a      ;    \
179                         } while(0)
180 #define buftou32( p)    buftoulong( (p) )
181 #define u32tobuf( p, a) ulongtobuf( (p), (a) )
182
183
184 /**************************************************
185  ************** read and write helpers ************
186  **************************************************/
187
188 static void
189 fwrite_8(FILE *fp, byte a)
190 {
191     if( putc( a & 0xff, fp ) == EOF )
192         log_fatal("error writing byte to trustdb: %s\n", strerror(errno) );
193 }
194
195
196 static void
197 fwrite_32( FILE*fp, ulong a)
198 {
199     putc( (a>>24) & 0xff, fp );
200     putc( (a>>16) & 0xff, fp );
201     putc( (a>> 8) & 0xff, fp );
202     if( putc( a & 0xff, fp ) == EOF )
203         log_fatal("error writing ulong to trustdb: %s\n", strerror(errno) );
204 }
205
206 static void
207 fwrite_zeros( FILE *fp, size_t n)
208 {
209     while( n-- )
210         if( putc( 0, fp ) == EOF )
211             log_fatal("error writing zeros to trustdb: %s\n", strerror(errno) );
212 }
213
214
215 /**************************************************
216  ************** read and write stuff **************
217  **************************************************/
218
219
220 /****************
221  * Create a new trustdb
222  */
223 static void
224 create_db( const char *fname )
225 {
226     FILE *fp;
227
228     fp =fopen( fname, "w" );
229     if( !fp )
230         log_fatal("can't create %s: %s\n", fname, strerror(errno) );
231     fwrite_8( fp, 1 );
232     fwrite_8( fp, 'g' );
233     fwrite_8( fp, '1' );
234     fwrite_8( fp, '0' );
235     fwrite_8( fp, 1 );  /* version */
236     fwrite_zeros( fp, 3 ); /* reserved */
237     fwrite_32( fp, 0 ); /* not locked */
238     fwrite_32( fp, make_timestamp() ); /* created */
239     fwrite_32( fp, 0 ); /* not yet modified */
240     fwrite_32( fp, 0 ); /* not yet validated*/
241     fwrite_32( fp, 0 ); /* local-id-counter (not used) */
242     fwrite_8( fp, 3 );  /* marginals needed */
243     fwrite_8( fp, 1 );  /* completes needed */
244     fwrite_8( fp, 4 );  /* max_cet_depth */
245     fwrite_zeros( fp, 9 ); /* filler */
246     fclose(fp);
247 }
248
249 static void
250 open_db()
251 {
252     TRUSTREC rec;
253     assert( db_fd == -1 );
254
255     db_fd = open( db_name, O_RDWR );
256     if( db_fd == -1 )
257         log_fatal("can't open %s: %s\n", db_name, strerror(errno) );
258     if( read_record( 0, &rec ) )
259         log_fatal("TrustDB %s is invalid\n", db_name );
260     /* fixme: check ->locked and other stuff */
261 }
262
263
264 /****************
265  * read the record with number recnum
266  * returns: -1 on error, 0 on success
267  */
268 static int
269 read_record( ulong recnum, TRUSTREC *rec )
270 {
271     byte buf[TRUST_RECORD_LEN], *p;
272     int rc = 0;
273     int n, i;
274
275     if( db_fd == -1 )
276         open_db();
277     if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
278         log_error("trustdb: lseek failed: %s\n", strerror(errno) );
279         return G10ERR_READ_FILE;
280     }
281     n = read( db_fd, buf, TRUST_RECORD_LEN);
282     if( !n ) {
283         return -1; /* eof */
284     }
285     else if( n != TRUST_RECORD_LEN ) {
286         log_error("trustdb: read failed (n=%d): %s\n", n, strerror(errno) );
287         return G10ERR_READ_FILE;
288     }
289     p = buf;
290     rec->rectype = *p++;
291     rec->reserved = *p++;
292     switch( rec->rectype ) {
293       case 0:  /* unused record */
294         break;
295       case 1: /* version record */
296         rec->r.version.magic[0] = *p++;
297         rec->r.version.magic[1] = *p++;
298         rec->r.version.version  = *p++;
299         memcpy( rec->r.version.reserved, p, 3); p += 3;
300         rec->r.version.locked   = buftoulong(p); p += 4;
301         rec->r.version.created  = buftoulong(p); p += 4;
302         rec->r.version.modified = buftoulong(p); p += 4;
303         rec->r.version.validated= buftoulong(p); p += 4;
304         rec->r.version.local_id_counter = buftoulong(p); p += 4;
305         rec->r.version.marginals_needed = *p++;
306         rec->r.version.completes_needed = *p++;
307         rec->r.version.max_cert_depth = *p++;
308         if( recnum ) {
309             log_error("%s: version record with recnum %lu\n",
310                                                     db_name, (ulong)recnum );
311             rc = G10ERR_TRUSTDB;
312         }
313         if( rec->reserved != 'g' || rec->r.version.magic[0] != '1'
314                                   || rec->r.version.magic[1] != '0' ) {
315             log_error("%s: not a trustdb file\n", db_name );
316             rc = G10ERR_TRUSTDB;
317         }
318         if( rec->r.version.version != 1 ) {
319             log_error("%s: invalid file version %d\n",
320                                        db_name, rec->r.version.version );
321             rc = G10ERR_TRUSTDB;
322         }
323         break;
324       case 2:
325         rec->r.pubkey.local_id = buftoulong(p); p += 4;
326         rec->r.pubkey.keyid[0] = buftou32(p); p += 4;
327         rec->r.pubkey.keyid[1] = buftou32(p); p += 4;
328         rec->r.pubkey.pubkey_algo = *p++;
329         rec->r.pubkey.reserved = *p++;
330         memcpy( rec->r.pubkey.fingerprint, p, 20); p += 20;
331         rec->r.pubkey.ownertrust = *p++;
332         if( rec->r.pubkey.local_id != recnum ) {
333             log_error("%s: pubkey local_id != recnum (%lu,%lu)\n",
334                                         db_name,
335                                         (ulong)rec->r.pubkey.local_id,
336                                         (ulong)recnum );
337             rc = G10ERR_TRUSTDB;
338         }
339         break;
340       case 3:
341         rec->r.cache.owner    = buftoulong(p); p += 4;
342         rec->r.cache.keyid[0] = buftou32(p); p += 4;
343         rec->r.cache.keyid[1] = buftou32(p); p += 4;
344         rec->r.cache.valid = *p++;
345         rec->r.cache.reserved = *p++;
346         memcpy(rec->r.cache.blockhash, p, 20); p += 20;
347         rec->r.cache.n_untrusted = *p++;
348         rec->r.cache.n_marginal = *p++;
349         rec->r.cache.n_fully = *p++;
350         rec->r.cache.trustlevel = *p++;
351         break;
352       case 4:
353       case 5:
354         rec->r.sigrec.owner   = buftoulong(p); p += 4;
355         rec->r.sigrec.chain   = buftoulong(p); p += 4;
356         for(i=0; i < SIGS_PER_RECORD; i++ ) {
357             rec->r.sigrec.sig[i].local_id = buftoulong(p); p += 4;
358             rec->r.sigrec.sig[i].flag = *p++;
359         }
360         break;
361       default:
362         log_error("%s: invalid record type %d at recnum %lu\n",
363                                         db_name, rec->rectype, (ulong)recnum );
364         rc = G10ERR_TRUSTDB;
365         break;
366     }
367
368     return rc;
369 }
370
371 /****************
372  * Write the record at RECNUM
373  */
374 static int
375 write_record( ulong recnum, TRUSTREC *rec )
376 {
377     byte buf[TRUST_RECORD_LEN], *p;
378     int rc = 0;
379     int i, n;
380
381     if( db_fd == -1 )
382         open_db();
383
384     memset(buf, 0, TRUST_RECORD_LEN);
385     p = buf;
386     *p++ = rec->rectype;
387     *p++ = rec->reserved;
388     switch( rec->rectype ) {
389       case 0:  /* unused record */
390         break;
391       case 1: /* version record */
392         BUG();
393         break;
394       case 2:
395         ulongtobuf(p, rec->r.pubkey.local_id); p += 4;
396         u32tobuf(p, rec->r.pubkey.keyid[0]); p += 4;
397         u32tobuf(p, rec->r.pubkey.keyid[1]); p += 4;
398         *p++ = rec->r.pubkey.pubkey_algo;
399         *p++ = rec->r.pubkey.reserved;
400         memcpy( p, rec->r.pubkey.fingerprint, 20); p += 20;
401         *p++ = rec->r.pubkey.ownertrust;
402         assert( rec->r.pubkey.local_id == recnum );
403         break;
404       case 3:
405         ulongtobuf(p, rec->r.cache.owner); p += 4;
406         u32tobuf(p, rec->r.cache.keyid[0]); p += 4;
407         u32tobuf(p, rec->r.cache.keyid[1]); p += 4;
408         *p++ = rec->r.cache.valid;
409         *p++ = rec->r.cache.reserved;
410         memcpy(p, rec->r.cache.blockhash, 20); p += 20;
411         *p++ = rec->r.cache.n_untrusted;
412         *p++ = rec->r.cache.n_marginal;
413         *p++ = rec->r.cache.n_fully;
414         *p++ = rec->r.cache.trustlevel;
415         break;
416       case 4:
417       case 5:
418         ulongtobuf(p, rec->r.sigrec.owner); p += 4;
419         ulongtobuf(p, rec->r.sigrec.chain); p += 4;
420         for(i=0; i < SIGS_PER_RECORD; i++ ) {
421             ulongtobuf(p, rec->r.sigrec.sig[i].local_id); p += 4;
422             *p++ = rec->r.sigrec.sig[i].flag;
423         }
424         break;
425       default:
426         BUG();
427     }
428
429     if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
430         log_error("trustdb: lseek failed: %s\n", strerror(errno) );
431         return G10ERR_WRITE_FILE;
432     }
433     n = write( db_fd, buf, TRUST_RECORD_LEN);
434     if( n != TRUST_RECORD_LEN ) {
435         log_error("trustdb: write failed (n=%d): %s\n", n, strerror(errno) );
436         return G10ERR_WRITE_FILE;
437     }
438
439     return rc;
440 }
441
442
443
444 /****************
445  * create a new record and return its record number
446  */
447 static ulong
448 new_recnum()
449 {
450     off_t offset;
451     ulong recnum;
452     TRUSTREC rec;
453     int rc;
454
455     /* fixme: look for unused records */
456     offset = lseek( db_fd, 0, SEEK_END );
457     if( offset == -1 )
458         log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
459     recnum = offset / TRUST_RECORD_LEN;
460     assert(recnum); /* this is will never be the first record */
461
462     /* we must write a record, so that the next call to this function
463      * returns another recnum */
464     memset( &rec, 0, sizeof rec );
465     rec.rectype = 0; /* free record */
466     rc = write_record(recnum, &rec );
467     if( rc )
468         log_fatal("%s: failed to append a record: %s\n",
469                                             db_name, g10_errstr(rc));
470     return recnum ;
471 }
472
473 /****************
474  * Scan the trustdb for a record of type RECTYPE which matches PKC
475  * The local_id is set to the correct value
476  */
477 static int
478 scan_record_by_pkc( PKT_public_cert *pkc, TRUSTREC *rec, int rectype )
479 {
480     ulong recnum;
481     u32 keyid[2];
482     byte *fingerprint;
483     size_t fingerlen;
484     int rc;
485
486     assert( rectype == 2 || rectype == 3 );
487
488     keyid_from_pkc( pkc, keyid );
489     fingerprint = fingerprint_from_pkc( pkc, &fingerlen );
490     assert( fingerlen == 20 || fingerlen == 16 );
491
492     for(recnum=1; !(rc=read_record( recnum, rec)); recnum++ ) {
493         if( rec->rectype != rectype )
494             continue;
495         if( rec->rectype == 2 ) {
496             if( rec->r.pubkey.keyid[0] == keyid[0]
497                 && rec->r.pubkey.keyid[1] == keyid[1]
498                 && rec->r.pubkey.pubkey_algo == pkc->pubkey_algo
499                 && !memcmp(rec->r.pubkey.fingerprint, fingerprint, fingerlen)
500               ) { /* found */
501                 /* store the local_id */
502                 if( pkc->local_id && pkc->local_id != recnum )
503                     log_error("%s: found record, but local_id from mem does "
504                               "not match recnum (%lu,%lu)\n", db_name,
505                                          (ulong)pkc->local_id, (ulong)recnum );
506                 pkc->local_id = recnum;
507                 return 0;
508             }
509         }
510         else
511             log_bug("not yet implemented\n");
512     }
513     if( rc != -1 )
514         log_error("%s: scan_record_by_pkc failed: %s\n",db_name, g10_errstr(rc) );
515     return rc;
516 }
517
518 /****************
519  * scan the DB for a record of type RECTYPE which can be localized
520  * with LOCAL_ID
521  */
522 static int
523 scan_record( ulong local_id, TRUSTREC *rec, int rectype, ulong *r_recnum )
524 {
525     ulong recnum;
526     int rc;
527
528     assert( rectype == 3 || rectype == 4 );
529
530     for(recnum=1; !(rc=read_record( recnum, rec)); recnum++ ) {
531         if( rec->rectype != rectype )
532             continue;
533         if( rec->rectype == 34 ) {
534             if( rec->r.cache.owner == local_id ) { /* found */
535                 *r_recnum = recnum;
536                 return 0;
537             }
538         }
539         else if( rec->rectype == 4 ) {
540             if( rec->r.sigrec.owner == local_id ) { /* found */
541                 *r_recnum = recnum;
542                 return 0;
543             }
544         }
545         else
546             log_bug("not yet implemented\n");
547     }
548     if( rc != -1 )
549         log_error("%s: scan_record failed: %s\n",db_name, g10_errstr(rc) );
550     return rc;
551 }
552
553
554 static void
555 dump_record( ulong rnum, TRUSTREC *rec, FILE *fp  )
556 {
557     int i, any;
558
559     fprintf(fp, "trust record %lu, type=", rnum );
560
561     switch( rec->rectype ) {
562       case 0: fprintf(fp, "free\n");
563         break;
564       case 1: fprintf(fp, "version\n");
565         break;
566       case 2: fprintf(fp, "pubkey, keyid=%08lX, ownertrust=%02x\n",
567                    rec->r.pubkey.keyid[1], rec->r.pubkey.ownertrust );
568         break;
569       case 3: fprintf(fp, "cache\n");
570       case 4:
571       case 5:
572         fprintf(fp, "sigrec, owner=%lu, chain=%lu%s\n",
573                          rec->r.sigrec.owner, rec->r.sigrec.chain,
574                          rec->rectype == 4?"":" (extend)");
575         for(i=any=0; i < SIGS_PER_RECORD; i++ ) {
576             if( rec->r.sigrec.sig[i].local_id ) {
577                 if( !any ) {
578                     putc('\t', fp);
579                     any++;
580                 }
581                 fprintf(fp, "  %lu:%02x", rec->r.sigrec.sig[i].local_id,
582                                               rec->r.sigrec.sig[i].flag );
583             }
584         }
585         if( any )
586             putc('\n', fp);
587         break;
588       default:
589         fprintf(fp, "%d (unknown)\n", rec->rectype );
590         break;
591     }
592 }
593
594
595 /****************
596  * If we do not have a local_id in a signature packet, find the owner of
597  * the signature packet in our trustdb or insert him into the trustdb
598  */
599 static int
600 set_signature_packets_local_id( PKT_signature *sig )
601 {
602     PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
603     TRUSTREC rec;
604     int rc;
605
606     rc = get_pubkey( pkc, sig->keyid );
607     if( rc)
608         goto leave;
609     if( !pkc->local_id ) {
610         rc = scan_record_by_pkc( pkc, &rec, 2 );
611         if( rc == -1 )
612             rc = insert_trust_record( pkc );
613         if( rc )
614             goto leave;
615         /* fixme: we should propagate the local_id to all copies of the PKC */
616     }
617     sig->local_id = pkc->local_id;
618
619   leave:
620     free_public_cert( pkc );
621     return rc;
622 }
623
624
625 void
626 list_trustdb( const char *username )
627 {
628     TRUSTREC rec;
629
630     if( username ) {
631         PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
632         int rc;
633
634         if( (rc = get_pubkey_byname( pkc, username )) )
635             log_error("user '%s' not found: %s\n", username, g10_errstr(rc) );
636         else if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 )
637             log_error("problem finding '%s' in trustdb: %s\n",
638                                                 username, g10_errstr(rc));
639         else if( rc == -1 )
640             log_error("user '%s' not in trustdb\n", username);
641         else if( (rc = list_sigs( pkc->local_id )) )
642             log_error("user '%s' list problem: %s\n", username, g10_errstr(rc));
643         free_public_cert( pkc );
644     }
645     else {
646         ulong recnum;
647         int i;
648
649         printf("TrustDB: %s\n", db_name );
650         for(i=9+strlen(db_name); i > 0; i-- )
651             putchar('-');
652         putchar('\n');
653         for(recnum=0; !read_record( recnum, &rec); recnum++ )
654             dump_record( recnum, &rec, stdout );
655     }
656 }
657
658 void
659 list_trust_path( int max_depth, const char *username )
660 {
661     int rc;
662     int wipe=0;
663     int i;
664     TRUSTREC rec;
665     PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
666
667     if( max_depth < 0 ) {
668         wipe = 1;
669         max_depth = -max_depth;
670     }
671
672     if( (rc = get_pubkey_byname( pkc, username )) )
673         log_error("user '%s' not found: %s\n", username, g10_errstr(rc) );
674     else if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 )
675         log_error("problem finding '%s' in trustdb: %s\n",
676                                             username, g10_errstr(rc));
677     else if( rc == -1 )
678         log_error("user '%s' not in trustdb\n", username);
679     else {
680         TRUST_SEG_LIST tsl, tslist = NULL;
681
682         if( !qry_lid_table_flag( ultikey_table, pkc->local_id, NULL ) ) {
683             tslist = m_alloc( sizeof *tslist );
684             tslist->nseg = 1;
685             tslist->dup = 0;
686             tslist->seg[0].lid = pkc->local_id;
687             tslist->seg[0].trust = 0;
688             tslist->next = NULL;
689             rc = 0;
690         }
691         else {
692             LOCAL_ID_INFO *lids = new_lid_table();
693             TRUST_INFO stack[MAX_LIST_SIGS_DEPTH];
694
695             stack[0].lid = pkc->local_id;
696             stack[0].trust = 0;
697             rc = do_list_path( stack, 1, max_depth, lids, &tslist );
698             if( wipe ) { /* wipe out duplicates */
699                 LOCAL_ID_INFO *work;
700
701                 work = new_lid_table();
702                 for( tsl=tslist; tsl; tsl = tsl->next ) {
703                     for(i=1; i < tsl->nseg-1; i++ ) {
704                         if( ins_lid_table_item( work, tsl->seg[i].lid, 0 ) ) {
705                             tsl->dup = 1; /* mark as duplicate */
706                             break;
707                         }
708                     }
709                 }
710                 release_lid_table(work);
711             }
712             release_lid_table(lids);
713         }
714         if( rc )
715             log_error("user '%s' list problem: %s\n", username, g10_errstr(rc));
716         rc = propagate_trust( tslist );
717         if( rc )
718             log_error("user '%s' trust problem: %s\n", username, g10_errstr(rc));
719         for(tsl = tslist; tsl; tsl = tsl->next ) {
720             int i;
721
722             if( tsl->dup )
723                 continue;
724             printf("trust path:" );
725             for(i=0; i < tsl->nseg; i++ )
726                 printf("  %lu/%02x", tsl->seg[i].lid, tsl->seg[i].trust );
727             putchar('\n');
728         }
729     }
730
731     free_public_cert( pkc );
732 }
733
734 /****************
735  * Walk throug the signatures of a public key.
736  * The caller must provide a context structure, with all fields set
737  * to zero, but the pubkeyid filed set to the requested pubkey;
738  * This function does not change this field.  On return the context
739  * is filled with the local-id of the signature and the signature flag.
740  * No fields should be changed (clearing all fields and setting
741  * pubkeyid is okay to continue with an other pubkey)
742  * Returns: 0 - okay, -1 for eof (no more sigs) or any other errorcode
743  */
744 static int
745 walk_sigrecs( SIGREC_CONTEXT *c )
746 {
747     int rc=0;
748     TRUSTREC *r;
749     ulong rnum;
750
751     if( c->ctl.eof )
752         return -1;
753     r = &c->ctl.rec;
754     if( !r->rectype ) { /* this is the first call */
755         rc = scan_record( c->pubkey_id, r, 4, &rnum );
756         if( rc == -1 ) { /* no signature records */
757             c->ctl.eof = 1;
758             return -1;  /* return eof */
759         }
760         if( rc ) {
761             log_error("scan_record(sigrec) failed: %s\n", g10_errstr(rc));
762             c->ctl.eof = 1;
763             return rc;
764         }
765         c->ctl.index = 0;
766     }
767     /* enter loop to skip deleted sigs */
768     do {
769         if( c->ctl.index >= SIGS_PER_RECORD ) {
770             /* read the next record */
771             if( !r->r.sigrec.chain ) {
772                 c->ctl.eof = 1;
773                 return -1;  /* return eof */
774             }
775             rnum = r->r.sigrec.chain;
776             rc = read_record( rnum, r );
777             if( rc ) {
778                 log_error("error reading next sigrec: %s\n", g10_errstr(rc));
779                 c->ctl.eof = 1;
780                 return rc;
781             }
782             if( r->r.sigrec.owner != c->pubkey_id ) {
783                 log_error("chained sigrec %lu has a wrong owner\n", rnum );
784                 c->ctl.eof = 1;
785                 return G10ERR_TRUSTDB;
786             }
787             c->ctl.index = 0;
788         }
789     } while( !r->r.sigrec.sig[c->ctl.index++].local_id );
790     c->sig_id = r->r.sigrec.sig[c->ctl.index-1].local_id;
791     c->sig_flag = r->r.sigrec.sig[c->ctl.index-1].flag;
792     return 0;
793 }
794
795 /***********************************************
796  *************  trust logic  *******************
797  ***********************************************/
798
799 static LOCAL_ID_INFO *
800 new_lid_table(void)
801 {
802     return m_alloc_clear( 16 * sizeof(LOCAL_ID_INFO));
803 }
804
805 static void
806 release_lid_table( LOCAL_ID_INFO *tbl )
807 {
808     LOCAL_ID_INFO a, a2;
809     int i;
810
811     for(i=0; i < 16; i++ ) {
812         for(a=tbl[i]; a; a = a2 ) {
813             a2 = a->next;
814             m_free(a);
815         }
816     }
817     m_free(tbl);
818 }
819
820 /****************
821  * Add a new item to the table or return 1 if we aread have this item
822  * fixme: maybe its a good idea to tage items from an unused item list.
823  */
824 static int
825 ins_lid_table_item( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag )
826 {
827     LOCAL_ID_INFO a;
828
829     for( a = tbl[lid & 0x0f]; a; a = a->next )
830         if( a->lid == lid )
831             return 1;
832     a = m_alloc( sizeof *a );
833     a->lid = lid;
834     a->flag = flag;
835     a->next = tbl[lid & 0x0f];
836     tbl[lid & 0x0f] = a;
837     return 0;
838 }
839
840 static int
841 qry_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned *flag )
842 {
843     LOCAL_ID_INFO a;
844
845     for( a = tbl[lid & 0x0f]; a; a = a->next )
846         if( a->lid == lid ) {
847             if( flag )
848                 *flag = a->flag;
849             return 0;
850         }
851     return -1;
852 }
853
854 static void
855 upd_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag )
856 {
857     LOCAL_ID_INFO a;
858
859     for( a = tbl[lid & 0x0f]; a; a = a->next )
860         if( a->lid == lid ) {
861             a->flag = flag;
862             return;
863         }
864     BUG();
865 }
866
867
868
869
870 static int
871 keyid_from_local_id( ulong lid, u32 *keyid )
872 {
873     TRUSTREC rec;
874     int rc;
875
876     rc = read_record( lid, &rec );
877     if( rc ) {
878         log_error("error reading record with local_id %lu: %s\n",
879                                                     lid, g10_errstr(rc));
880         return G10ERR_TRUSTDB;
881     }
882     if( rec.rectype != 2 ) {
883         log_error("record with local_id %lu is not a pubkey record\n", lid);
884         return G10ERR_TRUSTDB;
885     }
886     keyid[0] = rec.r.pubkey.keyid[0];
887     keyid[1] = rec.r.pubkey.keyid[1];
888     return 0;
889 }
890
891
892 /****************
893  * Verify, that all our public keys are in the trustDB.
894  */
895 static int
896 verify_own_certs()
897 {
898     int rc;
899     void *enum_context = NULL;
900     PKT_secret_cert *skc = m_alloc_clear( sizeof *skc );
901     PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
902     u32 keyid[2];
903
904     while( !(rc=enum_secret_keys( &enum_context, skc) ) ) {
905         /* fixed: to be sure that it is a secret key of our own,
906          *        we should check it, but this needs a passphrase
907          *        for every key and this boring for the user.
908          *        Solution:  Sign the secring and the trustring
909          *                   and verify this signature during
910          *                   startup
911          */
912
913         keyid_from_skc( skc, keyid );
914
915         if( DBG_TRUST )
916             log_debug("checking secret key %08lX\n", (ulong)keyid[1] );
917
918         /* look wether we can access the public key of this secret key */
919         rc = get_pubkey( pkc, keyid );
920         if( rc ) {
921             log_error("keyid %08lX: secret key without public key\n",
922                                                             (ulong)keyid[1] );
923             goto leave;
924         }
925         if( cmp_public_secret_cert( pkc, skc ) ) {
926             log_error("keyid %08lX: secret and public key don't match\n",
927                                                             (ulong)keyid[1] );
928             rc = G10ERR_GENERAL;
929             goto leave;
930         }
931
932         /* make sure that the pubkey is in the trustdb */
933         rc = query_trust_record( pkc );
934         if( rc == -1 ) { /* put it into the trustdb */
935             rc = insert_trust_record( pkc );
936             if( rc ) {
937                 log_error("keyid %08lX: can't put it into the trustdb\n",
938                                                             (ulong)keyid[1] );
939                 goto leave;
940             }
941         }
942         else if( rc ) {
943             log_error("keyid %08lX: query record failed\n", (ulong)keyid[1] );
944             goto leave;
945
946         }
947
948         if( DBG_TRUST )
949             log_debug("putting %08lX(%lu) into ultikey_table\n",
950                                     (ulong)keyid[1], pkc->local_id );
951         if( ins_lid_table_item( ultikey_table, pkc->local_id, 0 ) )
952             log_error("keyid %08lX: already in ultikey_table\n",
953                                                         (ulong)keyid[1]);
954
955
956         release_secret_cert_parts( skc );
957         release_public_cert_parts( pkc );
958     }
959     if( rc != -1 )
960         log_error("enum_secret_keys failed: %s\n", g10_errstr(rc) );
961     else
962         rc = 0;
963
964   leave:
965     free_secret_cert( skc );
966     free_public_cert( pkc );
967     return rc;
968 }
969
970 static void
971 print_user_id( const char *text, u32 *keyid )
972 {
973     char *p;
974     size_t n;
975
976     p = get_user_id( keyid, &n );
977     if( *text ) {
978         fputs( text, stdout);
979         putchar(' ');
980     }
981     putchar('\"');
982     print_string( stdout, p, n );
983     putchar('\"');
984     putchar('\n');
985     m_free(p);
986 }
987
988 /* (a non-recursive algorithm would be easier) */
989 static int
990 do_list_sigs( ulong root, ulong pubkey, int depth,
991               LOCAL_ID_INFO *lids, unsigned *lineno )
992 {
993     SIGREC_CONTEXT sx;
994     int rc;
995     u32 keyid[2];
996
997     memset( &sx, 0, sizeof sx );
998     sx.pubkey_id = pubkey;
999     for(;;) {
1000         rc = walk_sigrecs( &sx );
1001         if( rc )
1002             break;
1003         rc = keyid_from_local_id( sx.sig_id, keyid );
1004         if( rc ) {
1005             printf("%6u: %*s????????(%lu:%02x)\n", *lineno, depth*4, "",
1006                                                    sx.sig_id, sx.sig_flag );
1007             ++*lineno;
1008         }
1009         else {
1010             printf("%6u: %*s%08lX(%lu:%02x) ", *lineno, depth*4, "",
1011                               (ulong)keyid[1], sx.sig_id, sx.sig_flag );
1012             /* check wether we already checked this pubkey */
1013             if( !qry_lid_table_flag( ultikey_table, sx.sig_id, NULL ) ) {
1014                 print_user_id("[ultimately trusted]", keyid);
1015                 ++*lineno;
1016             }
1017             else if( sx.sig_id == pubkey ) {
1018                 printf("[self-signature]\n");
1019                 ++*lineno;
1020             }
1021             else if( sx.sig_id == root ) {
1022                 printf("[closed]\n");
1023                 ++*lineno;
1024             }
1025             else if( ins_lid_table_item( lids, sx.sig_id, *lineno ) ) {
1026                 unsigned refline;
1027                 qry_lid_table_flag( lids, sx.sig_id, &refline );
1028                 printf("[see line %u]\n", refline);
1029                 ++*lineno;
1030             }
1031             else if( depth+1 >= MAX_LIST_SIGS_DEPTH  ) {
1032                 print_user_id( "[too deeply nested]", keyid );
1033                 ++*lineno;
1034             }
1035             else {
1036                 print_user_id( "", keyid );
1037                 ++*lineno;
1038                 rc = do_list_sigs( root, sx.sig_id, depth+1, lids, lineno );
1039                 if( rc )
1040                     break;
1041             }
1042         }
1043     }
1044     return rc==-1? 0 : rc;
1045 }
1046
1047 /****************
1048  * List all signatures of a public key
1049  */
1050 static int
1051 list_sigs( ulong pubkey_id )
1052 {
1053     int rc;
1054     u32 keyid[2];
1055     LOCAL_ID_INFO *lids;
1056     unsigned lineno = 1;
1057
1058     rc = keyid_from_local_id( pubkey_id, keyid );
1059     if( rc ) {
1060         log_error("Hmmm, no pubkey record for local_id %lu\n", pubkey_id);
1061         return rc;
1062     }
1063     printf("Signatures of %08lX(%lu) ", (ulong)keyid[1], pubkey_id );
1064     print_user_id("", keyid);
1065     printf("----------------------\n");
1066
1067     lids = new_lid_table();
1068     rc = do_list_sigs( pubkey_id, pubkey_id, 0, lids, &lineno );
1069     putchar('\n');
1070     release_lid_table(lids);
1071     return rc;
1072 }
1073
1074
1075
1076 static int
1077 do_list_path( TRUST_INFO *stack, int depth, int max_depth,
1078               LOCAL_ID_INFO *lids, TRUST_SEG_LIST *tslist )
1079 {
1080     SIGREC_CONTEXT sx;
1081     unsigned last_depth;
1082     int rc;
1083
1084     assert(depth);
1085
1086     /*printf("%2lu/%d: scrutinizig\n", stack[depth-1], depth);*/
1087     if( depth >= max_depth || depth >= MAX_LIST_SIGS_DEPTH-1 ) {
1088         /*printf("%2lu/%d: to deeply nested\n", stack[depth-1], depth);*/
1089         return 0;
1090     }
1091     memset( &sx, 0, sizeof sx );
1092     sx.pubkey_id = stack[depth-1].lid;
1093     while( !(rc = walk_sigrecs( &sx )) ) {
1094         TRUST_SEG_LIST tsl, t2, tl;
1095         int i;
1096
1097         stack[depth].lid = sx.sig_id;
1098         stack[depth].trust = 0;
1099         if( qry_lid_table_flag( lids, sx.sig_id, &last_depth) ) {
1100             /*printf("%2lu/%d: marked\n", sx.sig_id, depth );*/
1101             ins_lid_table_item( lids, sx.sig_id, depth);
1102             last_depth = depth;
1103         }
1104         else if( depth  < last_depth ) {
1105             /*printf("%2lu/%d: last_depth=%u - updated\n", sx.sig_id, depth, last_depth);*/
1106             last_depth = depth;
1107             upd_lid_table_flag( lids, sx.sig_id, depth);
1108         }
1109
1110         if( last_depth < depth )
1111             /*printf("%2lu/%d: already visited\n", sx.sig_id, depth)*/;
1112         else if( !qry_lid_table_flag( ultikey_table, sx.sig_id, NULL ) ) {
1113             /* found end of path; store it, ordered by path length */
1114             tsl = m_alloc( sizeof *tsl + depth*sizeof(TRUST_INFO) );
1115             tsl->nseg = depth+1;
1116             tsl->dup = 0;
1117             for(i=0; i <= depth; i++ )
1118                 tsl->seg[i] = stack[i];
1119             for(t2=*tslist,tl=NULL; t2; tl=t2, t2 = t2->next )
1120                 if( depth < t2->nseg )
1121                     break;
1122             if( !tl ) {
1123                 tsl->next = t2;
1124                 *tslist = tsl;
1125             }
1126             else {
1127                 tsl->next = t2;
1128                 tl->next = tsl;
1129             }
1130             /*putchar('.'); fflush(stdout);*/
1131             /*printf("%2lu/%d: found\n", sx.sig_id, depth);*/
1132         }
1133         else {
1134             rc = do_list_path( stack, depth+1, max_depth, lids, tslist);
1135             if( rc && rc != -1 )
1136                 break;
1137         }
1138     }
1139     return rc==-1? 0 : rc;
1140 }
1141
1142
1143
1144 /****************
1145  * Check all the sigs of the given keyblock and mark them
1146  * as checked.
1147  */
1148 static int
1149 check_sigs( KBNODE keyblock, int *selfsig_okay )
1150 {
1151     KBNODE kbctx;
1152     KBNODE node;
1153     int rc;
1154
1155     *selfsig_okay = 0;
1156     for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
1157         if( node->pkt->pkttype == PKT_SIGNATURE
1158             && (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
1159             int selfsig;
1160             rc = check_key_signature( keyblock, node, &selfsig );
1161             if( !rc ) {
1162                 if( selfsig ) {
1163                     node->flag |= 2; /* mark signature valid */
1164                     *selfsig_okay = 1;
1165                 }
1166                 else
1167                     node->flag |= 1; /* mark signature valid */
1168             }
1169             if( DBG_TRUST )
1170                 log_debug("trustdb: sig from %08lX: %s\n",
1171                                 (ulong)node->pkt->pkt.signature->keyid[1],
1172                                                     g10_errstr(rc) );
1173         }
1174     }
1175     return 0;
1176 }
1177
1178
1179 /****************
1180  * If we do not have sigrecs for the given key, build them and write them
1181  * to the trustdb
1182  */
1183 static int
1184 build_sigrecs( ulong pubkeyid )
1185 {
1186     TRUSTREC rec, rec2;
1187     PUBKEY_FIND_INFO finfo=NULL;
1188     KBPOS kbpos;
1189     KBNODE keyblock = NULL;
1190     KBNODE kbctx;
1191     KBNODE node;
1192     int rc=0;
1193     int i, selfsig;
1194     ulong rnum, rnum2;
1195
1196     if( DBG_TRUST )
1197         log_debug("trustdb: build_sigrecs for pubkey %lu\n", (ulong)pubkeyid );
1198
1199     /* get the keyblock */
1200     if( (rc=read_record( pubkeyid, &rec )) ) {
1201         log_error("build_sigrecs: can't read pubkey record\n");
1202         goto leave;
1203     }
1204     finfo = m_alloc_clear( sizeof *finfo );
1205     finfo->keyid[0] = rec.r.pubkey.keyid[0];
1206     finfo->keyid[1] = rec.r.pubkey.keyid[1];
1207     finfo->pubkey_algo = rec.r.pubkey.pubkey_algo;
1208     memcpy( finfo->fingerprint, rec.r.pubkey.fingerprint, 20);
1209     rc = find_keyblock( finfo, &kbpos );
1210     if( rc ) {
1211         log_error("build_sigrecs: find_keyblock failed\n" );
1212         goto leave;
1213     }
1214     rc = read_keyblock( &kbpos, &keyblock );
1215     if( rc ) {
1216         log_error("build_sigrecs: read_keyblock failed\n" );
1217         goto leave;
1218     }
1219     /* check all key signatures */
1220     rc = check_sigs( keyblock, &selfsig );
1221     if( rc ) {
1222         log_error("build_sigrecs: check_sigs failed\n" );
1223         goto leave;
1224     }
1225     if( !selfsig ) {
1226         log_error("build_sigrecs: self-certificate missing\n" );
1227         rc = G10ERR_BAD_CERT;
1228         goto leave;
1229     }
1230
1231     /* valid key signatures are now marked; we can now build the
1232      * sigrecs */
1233     memset( &rec, 0, sizeof rec );
1234     rec.rectype = 4;
1235     i = 0;
1236     rnum = rnum2 = 0;
1237     for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
1238         if( node->flag & 1 ) {
1239             assert( node->pkt->pkttype == PKT_SIGNATURE );
1240             if( !node->pkt->pkt.signature->local_id )  {
1241                 /* the next function should always succeed, because
1242                  * we have already checked the signature, and for this
1243                  * it was necessary to have the pubkey. The only reason
1244                  * this can fail are I/o erros of the trustdb. */
1245                 rc = set_signature_packets_local_id( node->pkt->pkt.signature );
1246                 if( rc )
1247                     log_fatal("set_signature_packets_local_id failed: %s\n",
1248                                                               g10_errstr(rc));
1249             }
1250             if( i == SIGS_PER_RECORD ) {
1251                 /* write the record */
1252                 rnum = new_recnum();
1253                 if( rnum2 ) { /* write the stored record */
1254                     rec2.r.sigrec.owner = pubkeyid;
1255                     rec2.r.sigrec.chain = rnum; /* the next record number */
1256                     rc = write_record( rnum2, &rec2 );
1257                     if( rc ) {
1258                         log_error("build_sigrecs: write_record failed\n" );
1259                         goto leave;
1260                     }
1261                 }
1262                 rec2 = rec;
1263                 rnum2 = rnum;
1264                 memset( &rec, 0, sizeof rec );
1265                 rec.rectype = 5;
1266                 i = 0;
1267             }
1268             rec.r.sigrec.sig[i].local_id = node->pkt->pkt.signature->local_id;
1269             rec.r.sigrec.sig[i].flag = 0;
1270             i++;
1271         }
1272     }
1273     if( i || rnum2 ) {
1274         /* write the record */
1275         rnum = new_recnum();
1276         if( rnum2 ) { /* write the stored record */
1277             rec2.r.sigrec.owner = pubkeyid;
1278             rec2.r.sigrec.chain = rnum;
1279             rc = write_record( rnum2, &rec2 );
1280             if( rc ) {
1281                 log_error("build_sigrecs: write_record failed\n" );
1282                 goto leave;
1283             }
1284         }
1285         if( i ) { /* write the pending record */
1286             rec.r.sigrec.owner = pubkeyid;
1287             rec.r.sigrec.chain = 0;
1288             rc = write_record( rnum, &rec );
1289             if( rc ) {
1290                 log_error("build_sigrecs: write_record failed\n" );
1291                 goto leave;
1292             }
1293         }
1294     }
1295
1296   leave:
1297     m_free( finfo );
1298     release_kbnode( keyblock );
1299     if( DBG_TRUST )
1300         log_debug("trustdb: build_sigrecs: %s\n", g10_errstr(rc) );
1301     return rc;
1302 }
1303
1304 /****************
1305  * Make a list of trust paths
1306  */
1307 static int
1308 make_tsl( ulong pubkey_id, TRUST_SEG_LIST *ret_tslist )
1309 {
1310     int i, rc;
1311     LOCAL_ID_INFO *lids = new_lid_table();
1312     TRUST_INFO stack[MAX_LIST_SIGS_DEPTH];
1313     TRUST_SEG_LIST tsl, tslist;
1314     int max_depth = 4;
1315
1316     tslist = *ret_tslist = NULL;
1317
1318     if( !qry_lid_table_flag( ultikey_table, pubkey_id, NULL ) ) {
1319         tslist = m_alloc( sizeof *tslist );
1320         tslist->nseg = 1;
1321         tslist->dup = 0;
1322         tslist->seg[0].lid = pubkey_id;
1323         tslist->seg[0].trust = 0;
1324         tslist->next = NULL;
1325         rc = 0;
1326     }
1327     else {
1328         stack[0].lid = pubkey_id;
1329         stack[0].trust = 0;
1330         rc = do_list_path( stack, 1, max_depth, lids, &tslist );
1331     }
1332     if( !rc ) { /* wipe out duplicates */
1333         LOCAL_ID_INFO *work = new_lid_table();
1334         for( tsl=tslist; tsl; tsl = tsl->next ) {
1335             for(i=1; i < tsl->nseg-1; i++ ) {
1336                 if( ins_lid_table_item( work, tsl->seg[i].lid, 0 ) ) {
1337                     tsl->dup = 1; /* mark as duplicate */
1338                     break;
1339                 }
1340             }
1341         }
1342         release_lid_table(work);
1343         *ret_tslist = tslist;
1344     }
1345     else
1346         ; /* FIXME: release tslist */
1347     release_lid_table(lids);
1348     return rc;
1349 }
1350
1351
1352 /****************
1353  * Given a trust segment list tslist, walk over all paths and fill in
1354  * the trust information for each segment.  What this function does is
1355  * to assign a trustvalue to the first segment (which is the requested key)
1356  * of each path.
1357  *
1358  * FIXME: We have to do more thinks here. e.g. we should never increase
1359  *        the trust value.
1360  *
1361  * Do not do it for duplicates.
1362  */
1363 static int
1364 propagate_trust( TRUST_SEG_LIST tslist )
1365 {
1366     int i, rc;
1367     unsigned trust;
1368     TRUST_SEG_LIST tsl;
1369
1370     for(tsl = tslist; tsl; tsl = tsl->next ) {
1371         if( tsl->dup )
1372             continue;
1373         assert( tsl->nseg );
1374         /* the last segment is always a ultimately trusted one, so we can
1375          * assign a fully trust to the next one */
1376         i = tsl->nseg-1;
1377         tsl->seg[i].trust = TRUST_ULTIMATE;
1378         trust = TRUST_FULLY;
1379         for(i-- ; i >= 0; i-- ) {
1380             tsl->seg[i].trust = trust;
1381             if( i > 0 ) {
1382                 /* get the trust of this pubkey */
1383                 rc = get_ownertrust( tsl->seg[i].lid, &trust );
1384                 if( rc )
1385                     return rc;
1386             }
1387         }
1388     }
1389     return 0;
1390 }
1391
1392
1393 /****************
1394  * we have the pubkey record but nothing more is known
1395  */
1396 static int
1397 do_check( ulong pubkeyid, unsigned *trustlevel )
1398 {
1399     int i, rc=0;
1400     ulong rnum;
1401     TRUSTREC rec;
1402     TRUST_SEG_LIST tsl, tsl2, tslist;
1403     int marginal, fully;
1404     int fully_needed = 4;
1405     int marginal_needed = 6;
1406
1407     *trustlevel = TRUST_UNDEFINED;
1408
1409     /* verify the cache */
1410
1411     /* do we have sigrecs */
1412     rc = scan_record( pubkeyid, &rec, 4, &rnum );
1413     if( rc == -1 ) { /* no sigrecs, so build them */
1414         rc = build_sigrecs( pubkeyid );
1415         if( !rc ) /* and read again */
1416             rc = scan_record( pubkeyid, &rec, 4, &rnum );
1417     }
1418     if( rc )
1419         return rc;  /* error while looking for sigrec or building sigrecs */
1420
1421     /* fixme: take it from the cache if it is valid */
1422
1423     /* Make a list of all possible trust-paths */
1424     rc = make_tsl( pubkeyid, &tslist );
1425     if( rc )
1426         return rc;
1427     rc = propagate_trust( tslist );
1428     if( rc )
1429         return rc;
1430     for(tsl = tslist; tsl; tsl = tsl->next ) {
1431         if( tsl->dup )
1432             continue;
1433
1434         log_debug("tslist segs:" );
1435         for(i=0; i < tsl->nseg; i++ )
1436             fprintf(stderr, "  %lu/%02x", tsl->seg[i].lid, tsl->seg[i].trust );
1437         putc('\n',stderr);
1438     }
1439
1440     /* and look wether there is a trusted path.
1441      * We only have to look at the first segment, because
1442      * propagate_trust has investigated all other segments */
1443     marginal = fully = 0;
1444     for(tsl = tslist; tsl; tsl = tsl->next ) {
1445         if( tsl->dup )
1446             continue;
1447         if( tsl->seg[0].trust == TRUST_ULTIMATE ) {
1448             *trustlevel = TRUST_ULTIMATE; /* our own key */
1449             break;
1450         }
1451         if( tsl->seg[0].trust == TRUST_FULLY ) {
1452             marginal++;
1453             fully++;
1454         }
1455         else if( tsl->seg[0].trust == TRUST_MARGINAL )
1456             marginal++;
1457
1458         if( fully >= fully_needed ) {
1459             *trustlevel = TRUST_FULLY;
1460             break;
1461         }
1462     }
1463     if( !tsl && marginal >= marginal_needed )
1464         *trustlevel = TRUST_MARGINAL;
1465
1466     /* cache the tslist */
1467     if( last_trust_web_key ) {
1468         for( tsl = last_trust_web_tslist; tsl; tsl = tsl2 ) {
1469             tsl2 = tsl->next;
1470             m_free(tsl);
1471         }
1472     }
1473     last_trust_web_key = pubkeyid;
1474     last_trust_web_tslist = tslist;
1475     return 0;
1476 }
1477
1478
1479 /*********************************************************
1480  ****************  API Interface  ************************
1481  *********************************************************/
1482
1483 /****************
1484  * Perform some checks over the trustdb
1485  *  level 0: only open the db
1486  *        1: used for initial program startup
1487  */
1488 int
1489 init_trustdb( int level )
1490 {
1491     int rc=0;
1492
1493     if( !ultikey_table )
1494         ultikey_table = new_lid_table();
1495
1496     if( !level || level==1 ) {
1497         char *fname = make_filename("~/.g10", "trustdb.g10", NULL );
1498         if( access( fname, R_OK ) ) {
1499             if( errno != ENOENT ) {
1500                 log_error("can't access %s: %s\n", fname, strerror(errno) );
1501                 m_free(fname);
1502                 return G10ERR_TRUSTDB;
1503             }
1504             if( level )
1505                 create_db( fname );
1506         }
1507         m_free(db_name);
1508         db_name = fname;
1509
1510         if( !level )
1511             return 0;
1512
1513         /* we can verify a signature about our local data (secring and trustdb)
1514          * in ~/.g10/ here */
1515         rc = verify_private_data();
1516         if( !rc ) {
1517             /* verify, that our own certificates are in the trustDB
1518              * or move them to the trustdb. */
1519             rc = verify_own_certs();
1520
1521             /* should we check wether there is no other ultimately trusted
1522              * key in the database? */
1523
1524         }
1525     }
1526     else
1527         BUG();
1528
1529     return rc;
1530 }
1531
1532
1533 /****************
1534  * Get the trustlevel for this PKC.
1535  * Note: This does not ask any questions
1536  * Returns: 0 okay of an errorcode
1537  *
1538  * It operates this way:
1539  *  locate the pkc in the trustdb
1540  *      found:
1541  *          Do we have a valid cache record for it?
1542  *              yes: return trustlevel from cache
1543  *              no:  make a cache record and all the other stuff
1544  *      not found:
1545  *          Return with a trustlevel, saying that we do not have
1546  *          a trust record for it. The caller may use insert_trust_record()
1547  *          and then call this function here again.
1548  *
1549  * Problems: How do we get the complete keyblock to check that the
1550  *           cache record is actually valid?  Think we need a clever
1551  *           cache in getkey.c  to keep track of this stuff. Maybe it
1552  *           is not necessary to check this if we use a local pubring. Hmmmm.
1553  */
1554 int
1555 check_trust( PKT_public_cert *pkc, unsigned *r_trustlevel )
1556 {
1557     TRUSTREC rec;
1558     unsigned trustlevel = TRUST_UNKNOWN;
1559     int rc=0;
1560
1561     if( DBG_TRUST )
1562         log_info("check_trust() called.\n");
1563
1564     /* get the pubkey record */
1565     if( pkc->local_id ) {
1566         if( read_record( pkc->local_id, &rec ) ) {
1567             log_error("check_trust: read record failed\n");
1568             return G10ERR_TRUSTDB;
1569         }
1570     }
1571     else { /* no local_id: scan the trustdb */
1572         if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 ) {
1573             log_error("check_trust: scan_record_by_pkc(2) failed: %s\n",
1574                                                             g10_errstr(rc));
1575             return rc;
1576         }
1577         else if( rc == -1 ) {
1578             log_error("check_trust: pubkey not in TrustDB\n");
1579             goto leave;
1580         }
1581     }
1582     /* fixme: do some additional checks on the pubkey record */
1583
1584     rc = do_check( pkc->local_id, &trustlevel );
1585     if( rc ) {
1586         log_error("check_trust: do_check failed: %s\n", g10_errstr(rc));
1587         return rc;
1588     }
1589
1590
1591   leave:
1592     if( DBG_TRUST )
1593         log_info("check_trust() returns trustlevel %04x.\n", trustlevel);
1594     *r_trustlevel = trustlevel;
1595     return 0;
1596 }
1597
1598
1599
1600
1601 /****************
1602  * Enumerate all keys, which are needed to build all trust paths for
1603  * the given key.  This function dies not return the key itself or
1604  * the ultimate key.
1605  *
1606  *  1) create a void pointer and initialize it to NULL
1607  *  2) pass this void pointer by reference to this function.
1608  *     Set lid to the key you want to enumerate and pass it by reference.
1609  *  3) call this function as long as it does not return -1
1610  *     to indicate EOF. LID does contain the next key used to build the web
1611  *  4) Always call this function a last time with LID set to NULL,
1612  *     so that it can free it's context.
1613  */
1614 int
1615 enum_trust_web( void **context, ulong *lid )
1616 {
1617     ENUM_TRUST_WEB_CONTEXT *c = *context;
1618
1619     if( !c ) { /* make a new context */
1620         c = m_alloc_clear( sizeof *c );
1621         *context = c;
1622         if( *lid != last_trust_web_key )
1623             log_bug("enum_trust_web: nyi\n");
1624         c->tsl = last_trust_web_tslist;
1625         c->index = 1;
1626     }
1627
1628     if( !lid ) { /* free the context */
1629         m_free( c );
1630         *context = NULL;
1631         return 0;
1632     }
1633
1634     while( c->tsl ) {
1635         if( !c->tsl->dup && c->index < c->tsl->nseg-1 ) {
1636             *lid = c->tsl->seg[c->index].lid;
1637             c->index++;
1638             return 0;
1639         }
1640         c->index = 1;
1641         c->tsl = c->tsl->next;
1642     }
1643     return -1; /* eof */
1644 }
1645
1646
1647 /****************
1648  * Return the assigned ownertrust value for the given LID
1649  */
1650 int
1651 get_ownertrust( ulong lid, unsigned *r_otrust )
1652 {
1653     TRUSTREC rec;
1654
1655     if( read_record( lid, &rec ) ) {
1656         log_error("get_ownertrust: read record failed\n");
1657         return G10ERR_TRUSTDB;
1658     }
1659     if( r_otrust )
1660         *r_otrust = rec.r.pubkey.ownertrust;
1661     return 0;
1662 }
1663
1664 int
1665 keyid_from_trustdb( ulong lid, u32 *keyid )
1666 {
1667     TRUSTREC rec;
1668
1669     if( read_record( lid, &rec ) ) {
1670         log_error("keyid_from_trustdb: read record failed\n");
1671         return G10ERR_TRUSTDB;
1672     }
1673     if( keyid ) {
1674         keyid[0] = rec.r.pubkey.keyid[0];
1675         keyid[1] = rec.r.pubkey.keyid[1];
1676     }
1677     return 0;
1678 }
1679
1680
1681 int
1682 query_trust_record( PKT_public_cert *pkc )
1683 {
1684     TRUSTREC rec;
1685     int rc=0;
1686
1687     if( pkc->local_id ) {
1688         if( read_record( pkc->local_id, &rec ) ) {
1689             log_error("query_trust_record: read record failed\n");
1690             return G10ERR_TRUSTDB;
1691         }
1692     }
1693     else { /* no local_id: scan the trustdb */
1694         if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 ) {
1695             log_error("query_trust_record: scan_record_by_pkc(2) failed: %s\n",
1696                                                             g10_errstr(rc));
1697             return rc;
1698         }
1699         else if( rc == -1 )
1700             return rc;
1701     }
1702     return 0;
1703 }
1704
1705
1706 /****************
1707  * Insert a trust record into the TrustDB
1708  * This function failes if this record already exists.
1709  */
1710 int
1711 insert_trust_record( PKT_public_cert *pkc )
1712 {
1713     TRUSTREC rec;
1714     u32 keyid[2];
1715     ulong recnum;
1716     byte *fingerprint;
1717     size_t fingerlen;
1718
1719
1720     if( pkc->local_id )
1721         log_bug("pkc->local_id=%lu\n", (ulong)pkc->local_id );
1722
1723     keyid_from_pkc( pkc, keyid );
1724     fingerprint = fingerprint_from_pkc( pkc, &fingerlen );
1725
1726     /* FIXME: check that we do not have this record. */
1727
1728     recnum = new_recnum();
1729     /* build record */
1730     memset( &rec, 0, sizeof rec );
1731     rec.rectype = 2; /* the pubkey record */
1732     rec.r.pubkey.local_id = recnum;
1733     rec.r.pubkey.keyid[0] = keyid[0];
1734     rec.r.pubkey.keyid[1] = keyid[1];
1735     rec.r.pubkey.pubkey_algo = pkc->pubkey_algo;
1736     memcpy(rec.r.pubkey.fingerprint, fingerprint, fingerlen );
1737     rec.r.pubkey.ownertrust = 0;
1738     if( write_record( recnum, &rec ) ) {
1739         log_error("insert_trust_record: write failed\n");
1740         return G10ERR_TRUSTDB;
1741     }
1742
1743     pkc->local_id = recnum;
1744
1745     return 0;
1746 }
1747
1748
1749 int
1750 update_ownertrust( ulong lid, unsigned new_trust )
1751 {
1752     TRUSTREC rec;
1753
1754     if( read_record( lid, &rec ) ) {
1755         log_error("update_ownertrust: read failed\n");
1756         return G10ERR_TRUSTDB;
1757     }
1758     /* check keyid, fingerprint etc ? */
1759     if( rec.rectype != 2 ) {
1760         log_error("update_ownertrust: invalid record type\n");
1761         return G10ERR_TRUSTDB;
1762     }
1763
1764     rec.r.pubkey.ownertrust = new_trust;
1765     if( write_record( lid, &rec ) ) {
1766         log_error("update_ownertrust: write failed\n");
1767         return G10ERR_TRUSTDB;
1768     }
1769
1770     return 0;
1771 }
1772
1773
1774 int
1775 verify_private_data()
1776 {
1777     int rc = 0;
1778     char *sigfile = make_filename("~/.g10", "sig", NULL );
1779
1780     if( access( sigfile, R_OK ) ) {
1781         if( errno != ENOENT ) {
1782             log_error("can't access %s: %s\n", sigfile, strerror(errno) );
1783             rc = G10ERR_TRUSTDB;
1784             goto leave;
1785         }
1786         log_info("private data signature missing; creating ...\n");
1787         rc = sign_private_data();
1788         if( rc ) {
1789             log_error("error creating %s: %s\n", sigfile, g10_errstr(rc) );
1790             goto leave;
1791         }
1792     }
1793
1794     /* FIXME: verify this signature */
1795
1796   leave:
1797     m_free(sigfile);
1798     return rc;
1799 }
1800
1801
1802 int
1803 sign_private_data()
1804 {
1805     int rc;
1806     char *sigfile = make_filename("~/.g10", "sig", NULL );
1807     char *secring = make_filename("~/.g10", "secring.g10", NULL );
1808     STRLIST list = NULL;
1809
1810     add_to_strlist( &list, db_name );
1811     add_to_strlist( &list, secring );
1812
1813     rc = sign_file( list, 1, NULL, 0, NULL, sigfile);
1814
1815     m_free(sigfile);
1816     m_free(secring);
1817     free_strlist(list);
1818     return rc;
1819 }
1820