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