See ChangeLog: Wed Apr 28 13:03:03 CEST 1999 Werner Koch
[gnupg.git] / g10 / tdbdump.c
1 /* tdbdump.c
2  *      Copyright (C) 1999 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 <ctype.h>
27 #include <assert.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32
33 #include "errors.h"
34 #include "iobuf.h"
35 #include "keydb.h"
36 #include "memory.h"
37 #include "util.h"
38 #include "trustdb.h"
39 #include "options.h"
40 #include "packet.h"
41 #include "main.h"
42 #include "i18n.h"
43 #include "tdbio.h"
44
45
46 #define HEXTOBIN(a) ( (a) >= '0' && (a) <= '9' ? ((a)-'0') : \
47                       (a) >= 'A' && (a) <= 'F' ? ((a)-'A'+10) : ((a)-'a'+10))
48
49 /****************
50  * Read a record but die if it does not exist
51  * fixme: duplicate: remove it
52  */
53 static void
54 read_record( ulong recno, TRUSTREC *rec, int rectype )
55 {
56     int rc = tdbio_read_record( recno, rec, rectype );
57     if( !rc )
58         return;
59     log_error(_("trust record %lu, req type %d: read failed: %s\n"),
60                                     recno, rectype,  g10_errstr(rc) );
61     tdbio_invalid();
62 }
63
64 /****************
65  * Wirte a record but die on error
66  */
67 static void
68 write_record( TRUSTREC *rec )
69 {
70     int rc = tdbio_write_record( rec );
71     if( !rc )
72         return;
73     log_error(_("trust record %lu, type %d: write failed: %s\n"),
74                             rec->recnum, rec->rectype, g10_errstr(rc) );
75     tdbio_invalid();
76 }
77
78
79 /****************
80  * sync the db
81  */
82 static void
83 do_sync(void)
84 {
85     int rc = tdbio_sync();
86     if( !rc )
87         return;
88     log_error(_("trustdb: sync failed: %s\n"), g10_errstr(rc) );
89     g10_exit(2);
90 }
91
92
93 static int
94 print_sigflags( FILE *fp, unsigned flags )
95 {
96     if( flags & SIGF_CHECKED ) {
97         fprintf(fp,"%c%c%c",
98            (flags & SIGF_VALID)   ? 'V':'-',
99            (flags & SIGF_EXPIRED) ? 'E':'-',
100            (flags & SIGF_REVOKED) ? 'R':'-');
101     }
102     else if( flags & SIGF_NOPUBKEY)
103         fputs("?--", fp);
104     else
105         fputs("---", fp);
106     return 3;
107 }
108
109
110
111 /****************
112  * Walk through the signatures of a public key.
113  * The caller must provide a context structure, with all fields set
114  * to zero, but the local_id field set to the requested key;
115  * This function does not change this field.  On return the context
116  * is filled with the local-id of the signature and the signature flag.
117  * No fields should be changed (clearing all fields and setting
118  * pubkeyid is okay to continue with an other pubkey)
119  * Returns: 0 - okay, -1 for eof (no more sigs) or any other errorcode
120  * FIXME: Do we really need this large and complicated function?
121  */
122 static int
123 walk_sigrecs( SIGREC_CONTEXT *c )
124 {
125     TRUSTREC *r;
126     ulong rnum;
127
128     if( c->ctl.eof )
129         return -1;
130     r = &c->ctl.rec;
131     if( !c->ctl.init_done ) {
132         c->ctl.init_done = 1;
133         read_record( c->lid, r, 0 );
134         if( r->rectype != RECTYPE_DIR ) {
135             c->ctl.eof = 1;
136             return -1;  /* return eof */
137         }
138         c->ctl.nextuid = r->r.dir.uidlist;
139         /* force a read */
140         c->ctl.index = SIGS_PER_RECORD;
141         r->r.sig.next = 0;
142     }
143
144     /* need a loop to skip over deleted sigs */
145     do {
146         if( c->ctl.index >= SIGS_PER_RECORD ) { /* read the record */
147             rnum = r->r.sig.next;
148             if( !rnum && c->ctl.nextuid ) { /* read next uid record */
149                 read_record( c->ctl.nextuid, r, RECTYPE_UID );
150                 c->ctl.nextuid = r->r.uid.next;
151                 rnum = r->r.uid.siglist;
152             }
153             if( !rnum ) {
154                 c->ctl.eof = 1;
155                 return -1;  /* return eof */
156             }
157             read_record( rnum, r, RECTYPE_SIG );
158             if( r->r.sig.lid != c->lid ) {
159                 log_error(_("chained sigrec %lu has a wrong owner\n"), rnum );
160                 c->ctl.eof = 1;
161                 tdbio_invalid();
162             }
163             c->ctl.index = 0;
164         }
165     } while( !r->r.sig.sig[c->ctl.index++].lid );
166
167     c->sig_lid = r->r.sig.sig[c->ctl.index-1].lid;
168     c->sig_flag = r->r.sig.sig[c->ctl.index-1].flag;
169     return 0;
170 }
171
172
173 #if 0
174 static int
175 do_list_sigs( ulong root, ulong pk_lid, int depth,
176               LOCAL_ID_TABLE lids, unsigned *lineno )
177 {
178     SIGREC_CONTEXT sx;
179     int rc;
180     u32 keyid[2];
181
182     memset( &sx, 0, sizeof sx );
183     sx.lid = pk_lid;
184     for(;;) {
185         rc = walk_sigrecs( &sx ); /* should we replace it and use */
186         if( rc )
187             break;
188         rc = keyid_from_lid( sx.sig_lid, keyid );
189         if( rc ) {
190             printf("%6u: %*s????????.%lu:", *lineno, depth*4, "", sx.sig_lid );
191             print_sigflags( stdout, sx.sig_flag );
192             putchar('\n');
193             ++*lineno;
194         }
195         else {
196             printf("%6u: %*s%08lX.%lu:", *lineno, depth*4, "",
197                               (ulong)keyid[1], sx.sig_lid );
198             print_sigflags( stdout, sx.sig_flag );
199             putchar(' ');
200             /* check whether we already checked this pk_lid */
201             if( !qry_lid_table_flag( ultikey_table, sx.sig_lid, NULL ) ) {
202                 print_user_id("[ultimately trusted]", keyid);
203                 ++*lineno;
204             }
205             else if( sx.sig_lid == pk_lid ) {
206                 printf("[self-signature]\n");
207                 ++*lineno;
208             }
209             else if( sx.sig_lid == root ) {
210                 printf("[closed]\n");
211                 ++*lineno;
212             }
213             else if( ins_lid_table_item( lids, sx.sig_lid, *lineno ) ) {
214                 unsigned refline;
215                 qry_lid_table_flag( lids, sx.sig_lid, &refline );
216                 printf("[see line %u]\n", refline);
217                 ++*lineno;
218             }
219             else if( depth+1 >= MAX_LIST_SIGS_DEPTH  ) {
220                 print_user_id( "[too deeply nested]", keyid );
221                 ++*lineno;
222             }
223             else {
224                 print_user_id( "", keyid );
225                 ++*lineno;
226                 rc = do_list_sigs( root, sx.sig_lid, depth+1, lids, lineno );
227                 if( rc )
228                     break;
229             }
230         }
231     }
232     return rc==-1? 0 : rc;
233 }
234 #endif
235 /****************
236  * List all signatures of a public key
237  */
238 static int
239 list_sigs( ulong pubkey_id )
240 {
241     int rc=0;
242   #if 0
243     u32 keyid[2];
244     LOCAL_ID_TABLE lids;
245     unsigned lineno = 1;
246
247     rc = keyid_from_lid( pubkey_id, keyid );
248     if( rc )
249         return rc;
250     printf("Signatures of %08lX.%lu ", (ulong)keyid[1], pubkey_id );
251     print_user_id("", keyid);
252     printf("----------------------\n");
253
254     lids = new_lid_table();
255     rc = do_list_sigs( pubkey_id, pubkey_id, 0, lids, &lineno );
256     putchar('\n');
257     release_lid_table(lids);
258   #endif
259     return rc;
260 }
261
262 /****************
263  * List all records of a public key
264  */
265 static int
266 list_records( ulong lid )
267 {
268     int rc;
269     TRUSTREC dr, ur, rec;
270     ulong recno;
271
272     rc = tdbio_read_record( lid, &dr, RECTYPE_DIR );
273     if( rc ) {
274         log_error(_("lid %lu: read dir record failed: %s\n"),
275                                                 lid, g10_errstr(rc));
276         return rc;
277     }
278     tdbio_dump_record( &dr, stdout );
279
280     for( recno=dr.r.dir.keylist; recno; recno = rec.r.key.next ) {
281         rc = tdbio_read_record( recno, &rec, 0 );
282         if( rc ) {
283             log_error(_("lid %lu: read key record failed: %s\n"),
284                                                 lid, g10_errstr(rc));
285             return rc;
286         }
287         tdbio_dump_record( &rec, stdout );
288     }
289
290     for( recno=dr.r.dir.uidlist; recno; recno = ur.r.uid.next ) {
291         rc = tdbio_read_record( recno, &ur, RECTYPE_UID );
292         if( rc ) {
293             log_error(_("lid %lu: read uid record failed: %s\n"),
294                                                 lid, g10_errstr(rc));
295             return rc;
296         }
297         tdbio_dump_record( &ur, stdout );
298         /* preference records */
299         for(recno=ur.r.uid.prefrec; recno; recno = rec.r.pref.next ) {
300             rc = tdbio_read_record( recno, &rec, RECTYPE_PREF );
301             if( rc ) {
302                 log_error(_("lid %lu: read pref record failed: %s\n"),
303                                                     lid, g10_errstr(rc));
304                 return rc;
305             }
306             tdbio_dump_record( &rec, stdout );
307         }
308         /* sig records */
309         for(recno=ur.r.uid.siglist; recno; recno = rec.r.sig.next ) {
310             rc = tdbio_read_record( recno, &rec, RECTYPE_SIG );
311             if( rc ) {
312                 log_error(_("lid %lu: read sig record failed: %s\n"),
313                                                     lid, g10_errstr(rc));
314                 return rc;
315             }
316             tdbio_dump_record( &rec, stdout );
317         }
318     }
319
320     /* add cache record dump here */
321
322
323
324     return rc;
325 }
326
327
328 /****************
329  * Dump the complte trustdb or only the entries of one key.
330  */
331 void
332 list_trustdb( const char *username )
333 {
334     TRUSTREC rec;
335
336     init_trustdb();
337
338     if( username && *username == '#' ) {
339         int rc;
340         ulong lid = atoi(username+1);
341
342         if( (rc = list_records( lid)) )
343             log_error(_("user '%s' read problem: %s\n"),
344                                             username, g10_errstr(rc));
345         else if( (rc = list_sigs( lid )) )
346             log_error(_("user '%s' list problem: %s\n"),
347                                             username, g10_errstr(rc));
348     }
349     else if( username ) {
350         PKT_public_key *pk = m_alloc_clear( sizeof *pk );
351         int rc;
352
353         if( (rc = get_pubkey_byname( NULL, pk, username, NULL )) )
354             log_error(_("user '%s' not found: %s\n"), username, g10_errstr(rc) );
355         else if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 )
356             log_error(_("problem finding '%s' in trustdb: %s\n"),
357                                                 username, g10_errstr(rc));
358         else if( rc == -1 )
359             log_error(_("user '%s' not in trustdb\n"), username);
360         else if( (rc = list_records( pk->local_id)) )
361             log_error(_("user '%s' read problem: %s\n"),
362                                                 username, g10_errstr(rc));
363         else if( (rc = list_sigs( pk->local_id )) )
364             log_error(_("user '%s' list problem: %s\n"),
365                                                 username, g10_errstr(rc));
366         free_public_key( pk );
367     }
368     else {
369         ulong recnum;
370         int i;
371
372         printf("TrustDB: %s\n", tdbio_get_dbname() );
373         for(i=9+strlen(tdbio_get_dbname()); i > 0; i-- )
374             putchar('-');
375         putchar('\n');
376         for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ )
377             tdbio_dump_record( &rec, stdout );
378     }
379 }
380
381
382
383
384
385 /****************
386  * Print a list of all defined owner trust value.
387  */
388 void
389 export_ownertrust()
390 {
391     TRUSTREC rec;
392     TRUSTREC rec2;
393     ulong recnum;
394     int i;
395     byte *p;
396     int rc;
397
398     init_trustdb();
399     printf(_("# List of assigned trustvalues, created %s\n"
400              "# (Use \"gpgm --import-ownertrust\" to restore them)\n"),
401            asctimestamp( make_timestamp() ) );
402     for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
403         if( rec.rectype == RECTYPE_DIR ) {
404             if( !rec.r.dir.keylist ) {
405                 log_error(_("directory record w/o primary key\n"));
406                 continue;
407             }
408             if( !rec.r.dir.ownertrust )
409                 continue;
410             rc = tdbio_read_record( rec.r.dir.keylist, &rec2, RECTYPE_KEY);
411             if( rc ) {
412                 log_error(_("error reading key record: %s\n"), g10_errstr(rc));
413                 continue;
414             }
415             p = rec2.r.key.fingerprint;
416             for(i=0; i < rec2.r.key.fingerprint_len; i++, p++ )
417                 printf("%02X", *p );
418             printf(":%u:\n", (unsigned)rec.r.dir.ownertrust );
419         }
420     }
421 }
422
423
424 void
425 import_ownertrust( const char *fname )
426 {
427     FILE *fp;
428     int is_stdin=0;
429     char line[256];
430     char *p;
431     size_t n, fprlen;
432     unsigned otrust;
433
434     init_trustdb();
435     if( !fname || (*fname == '-' && !fname[1]) ) {
436         fp = stdin;
437         fname = "[stdin]";
438         is_stdin = 1;
439     }
440     else if( !(fp = fopen( fname, "r" )) ) {
441         log_error_f(fname, _("can't open file: %s\n"), strerror(errno) );
442         return;
443     }
444
445     while( fgets( line, DIM(line)-1, fp ) ) {
446         TRUSTREC rec;
447         int rc;
448
449         if( !*line || *line == '#' )
450             continue;
451         n = strlen(line);
452         if( line[n-1] != '\n' ) {
453             log_error_f(fname, _("line too long\n") );
454             /* ... or last line does not have a LF */
455             break; /* can't continue */
456         }
457         for(p = line; *p && *p != ':' ; p++ )
458             if( !isxdigit(*p) )
459                 break;
460         if( *p != ':' ) {
461             log_error_f(fname, _("error: missing colon\n") );
462             continue;
463         }
464         fprlen = p - line;
465         if( fprlen != 32 && fprlen != 40 ) {
466             log_error_f(fname, _("error: invalid fingerprint\n") );
467             continue;
468         }
469         if( sscanf(p, ":%u:", &otrust ) != 1 ) {
470             log_error_f(fname, _("error: no ownertrust value\n") );
471             continue;
472         }
473         if( !otrust )
474             continue; /* no otrust defined - no need to update or insert */
475         /* convert the ascii fingerprint to binary */
476         for(p=line, fprlen=0; *p != ':'; p += 2 )
477             line[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]);
478         line[fprlen] = 0;
479
480       repeat:
481         rc = tdbio_search_dir_byfpr( line, fprlen, 0, &rec );
482         if( !rc ) { /* found: update */
483             if( rec.r.dir.ownertrust )
484                 log_info("LID %lu: changing trust from %u to %u\n",
485                           rec.r.dir.lid, rec.r.dir.ownertrust, otrust );
486             else
487                 log_info("LID %lu: setting trust to %u\n",
488                                    rec.r.dir.lid, otrust );
489             rec.r.dir.ownertrust = otrust;
490             write_record( &rec );
491         }
492         else if( rc == -1 ) { /* not found; get the key from the ring */
493             PKT_public_key *pk = m_alloc_clear( sizeof *pk );
494
495             log_info_f(fname, _("key not in trustdb, searching ring.\n"));
496             rc = get_pubkey_byfprint( pk, line, fprlen );
497             if( rc )
498                 log_info_f(fname, _("key not in ring: %s\n"), g10_errstr(rc));
499             else {
500                 rc = query_trust_record( pk );  /* only as assertion */
501                 if( rc != -1 )
502                     log_error_f(fname, _("Oops: key is now in trustdb???\n"));
503                 else {
504                     rc = insert_trust_record( pk );
505                     if( !rc )
506                         goto repeat; /* update the ownertrust */
507                     log_error_f(fname, _("insert trust record failed: %s\n"),
508                                                            g10_errstr(rc) );
509                 }
510             }
511         }
512         else /* error */
513             log_error_f(fname, _("error finding dir record: %s\n"),
514                                                     g10_errstr(rc));
515     }
516     if( ferror(fp) )
517         log_error_f(fname, _("read error: %s\n"), strerror(errno) );
518     if( !is_stdin )
519         fclose(fp);
520     do_sync();
521 }
522