sync
[gnupg.git] / g10 / tdbio.c
1 /* tdbio.c
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GNUPG.
5  *
6  * GNUPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GNUPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31
32 #include "errors.h"
33 #include "iobuf.h"
34 #include "memory.h"
35 #include "util.h"
36 #include "options.h"
37 #include "main.h"
38 #include "i18n.h"
39 #include "trustdb.h"
40 #include "tdbio.h"
41
42
43
44 static char *db_name;
45 static int  db_fd = -1;
46
47
48
49 static void create_db( const char *fname );
50 static void open_db(void);
51
52 /**************************************************
53  ************** read and write helpers ************
54  **************************************************/
55
56 static void
57 fwrite_8(FILE *fp, byte a)
58 {
59     if( putc( a & 0xff, fp ) == EOF )
60         log_fatal("error writing byte to trustdb: %s\n", strerror(errno) );
61 }
62
63
64 static void
65 fwrite_32( FILE*fp, ulong a)
66 {
67     putc( (a>>24) & 0xff, fp );
68     putc( (a>>16) & 0xff, fp );
69     putc( (a>> 8) & 0xff, fp );
70     if( putc( a & 0xff, fp ) == EOF )
71         log_fatal("error writing ulong to trustdb: %s\n", strerror(errno) );
72 }
73
74 static void
75 fwrite_zeros( FILE *fp, size_t n)
76 {
77     while( n-- )
78         if( putc( 0, fp ) == EOF )
79             log_fatal("error writing zeros to trustdb: %s\n", strerror(errno) );
80 }
81
82
83
84
85 /**************************************************
86  ************** read and write stuff **************
87  **************************************************/
88
89 int
90 tdbio_set_dbname( const char *new_dbname, int create )
91 {
92     char *fname;
93
94     fname = new_dbname? m_strdup( new_dbname )
95                       : make_filename(opt.homedir, "trustdb.gpg", NULL );
96
97     if( access( fname, R_OK ) ) {
98         if( errno != ENOENT ) {
99             log_error_f( fname, _("can't access: %s\n"), strerror(errno) );
100             m_free(fname);
101             return G10ERR_TRUSTDB;
102         }
103         if( create ) {
104             char *p = strrchr( fname, '/' );
105             assert(p);
106             *p = 0;
107             if( access( fname, F_OK ) ) {
108                 if( strlen(fname) >= 7
109                     && !strcmp(fname+strlen(fname)-7, "/.gnupg" ) ) {
110                   #if __MINGW32__
111                     if( mkdir( fname ) )
112                   #else
113                     if( mkdir( fname, S_IRUSR|S_IWUSR|S_IXUSR ) )
114                   #endif
115                         log_fatal_f( fname, _("can't create directory: %s\n"),
116                                                             strerror(errno) );
117                 }
118                 else
119                     log_fatal_f(fname, _("directory does not exist!\n") );
120             }
121             *p = '/';
122             create_db( fname );
123         }
124     }
125     m_free(db_name);
126     db_name = fname;
127     return 0;
128 }
129
130
131 const char *
132 tdbio_get_dbname()
133 {
134     return db_name;
135 }
136
137
138
139 /****************
140  * Create a new trustdb
141  */
142 static void
143 create_db( const char *fname )
144 {
145     FILE *fp;
146
147     fp =fopen( fname, "w" );
148     if( !fp )
149         log_fatal_f( fname, _("can't create %s: %s\n"), strerror(errno) );
150     fwrite_8( fp, 2 );
151     fwrite_8( fp, 'g' );
152     fwrite_8( fp, 'p' );
153     fwrite_8( fp, 'g' );
154     fwrite_8( fp, 1 );  /* version */
155     fwrite_zeros( fp, 3 ); /* reserved */
156     fwrite_32( fp, 0 ); /* not locked */
157     fwrite_32( fp, make_timestamp() ); /* created */
158     fwrite_32( fp, 0 ); /* not yet modified */
159     fwrite_32( fp, 0 ); /* not yet validated*/
160     fwrite_32( fp, 0 ); /* reserved */
161     fwrite_8( fp, 3 );  /* marginals needed */
162     fwrite_8( fp, 1 );  /* completes needed */
163     fwrite_8( fp, 4 );  /* max_cet_depth */
164     fwrite_zeros( fp, 9 ); /* filler */
165     fclose(fp);
166 }
167
168
169
170 static void
171 open_db()
172 {
173     TRUSTREC rec;
174     assert( db_fd == -1 );
175
176     db_fd = open( db_name, O_RDWR );
177     if( db_fd == -1 )
178         log_fatal_f( db_name, _("can't open: %s\n"), strerror(errno) );
179     if( tdbio_read_record( 0, &rec, RECTYPE_VER ) )
180         log_fatal_f( db_name, _("invalid trust-db\n") );
181     /* fixme: check ->locked and other stuff */
182 }
183
184
185 void
186 tdbio_dump_record( ulong rnum, TRUSTREC *rec, FILE *fp  )
187 {
188     int i, any;
189
190     fprintf(fp, "rec %5lu, type=", rnum );
191
192     switch( rec->rectype ) {
193       case 0: fprintf(fp, "free\n");
194         break;
195       case RECTYPE_VER: fprintf(fp, "version\n");
196         break;
197       case RECTYPE_DIR:
198         fprintf(fp, "dir %lu, keys=%lu, uids=%lu, cach=%lu, ot=%02x",
199                     rec->r.dir.lid,
200                     rec->r.dir.keylist,
201                     rec->r.dir.uidlist,
202                     rec->r.dir.cacherec,
203                     rec->r.dir.ownertrust );
204         if( rec->r.dir.sigflag == 1 )
205             fputs(", (none)", fp );
206         else if( rec->r.dir.sigflag == 2 )
207             fputs(", (invalid)", fp );
208         else if( rec->r.dir.sigflag == 3 )
209             fputs(", (revoked)", fp );
210         else if( rec->r.dir.sigflag )
211             fputs(", (??)", fp );
212         putc('\n', fp);
213         break;
214       case RECTYPE_KEY:
215         fprintf(fp, "key %lu, next=%lu, algo=%d, flen=%d\n",
216                    rec->r.key.lid,
217                    rec->r.key.next,
218                    rec->r.key.pubkey_algo,
219                    rec->r.key.fingerprint_len );
220         break;
221       case RECTYPE_UID:
222         fprintf(fp, "uid %lu, next=%lu, pref=%lu, sig=%lu, hash=%02X%02X\n",
223                     rec->r.uid.lid,
224                     rec->r.uid.next,
225                     rec->r.uid.prefrec,
226                     rec->r.uid.siglist,
227                     rec->r.uid.namehash[18], rec->r.uid.namehash[19]);
228         break;
229       case RECTYPE_PREF:
230         fprintf(fp, "pref %lu, next=%lu\n",
231                     rec->r.uid.lid,
232                     rec->r.uid.next);
233         break;
234       case RECTYPE_SIG:
235         fprintf(fp, "sig %lu, next=%lu\n",
236                          rec->r.sig.lid, rec->r.sig.next );
237         for(i=any=0; i < SIGS_PER_RECORD; i++ ) {
238             if( rec->r.sig.sig[i].lid ) {
239                 if( !any ) {
240                     putc('\t', fp);
241                     any++;
242                 }
243                 fprintf(fp, "  %lu:%02x", rec->r.sig.sig[i].lid,
244                                           rec->r.sig.sig[i].flag );
245             }
246         }
247         if( any )
248             putc('\n', fp);
249         break;
250       case RECTYPE_CACH:
251         fprintf(fp, "cach\n");
252         break;
253       case RECTYPE_HTBL:
254         fprintf(fp, "htbl\n");
255         break;
256       case RECTYPE_HTBL:
257         fprintf(fp, "hlst\n");
258         break;
259       default:
260         fprintf(fp, "%d (unknown)\n", rec->rectype );
261         break;
262     }
263 }
264
265 /****************
266  * read the record with number recnum
267  * returns: -1 on error, 0 on success
268  */
269 int
270 tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
271 {
272     byte buf[TRUST_RECORD_LEN], *p;
273     int rc = 0;
274     int n, i;
275
276     if( db_fd == -1 )
277         open_db();
278     if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
279         log_error(_("trustdb: lseek failed: %s\n"), strerror(errno) );
280         return G10ERR_READ_FILE;
281     }
282     n = read( db_fd, buf, TRUST_RECORD_LEN);
283     if( !n ) {
284         return -1; /* eof */
285     }
286     else if( n != TRUST_RECORD_LEN ) {
287         log_error(_("trustdb: read failed (n=%d): %s\n"), n, strerror(errno) );
288         return G10ERR_READ_FILE;
289     }
290     p = buf;
291     rec->rectype = *p++;
292     if( expected && rec->rectype != expected ) {
293         log_error("%lu: read expected rec type %d, got %d\n",
294                     recnum, expected, rec->rectype );
295         return G10ERR_TRUSTDB;
296     }
297     p++;
298     switch( rec->rectype ) {
299       case 0:  /* unused record */
300         break;
301       case RECTYPE_VER: /* version record */
302         if( memcmp(buf+1, "gpg", 3 ) ) {
303             log_error_f( db_name, _("not a trustdb file\n") );
304             rc = G10ERR_TRUSTDB;
305         }
306         p += 2; /* skip magic */
307         rec->r.ver.version  = *p++;
308         rec->r.ver.locked   = buftoulong(p); p += 4;
309         rec->r.ver.created  = buftoulong(p); p += 4;
310         rec->r.ver.modified = buftoulong(p); p += 4;
311         rec->r.ver.validated= buftoulong(p); p += 4;
312         rec->r.ver.marginals_needed = *p++;
313         rec->r.ver.completes_needed = *p++;
314         rec->r.ver.max_cert_depth = *p++;
315         if( recnum ) {
316             log_error_f( db_name, "version record with recnum %lu\n",
317                                                              (ulong)recnum );
318             rc = G10ERR_TRUSTDB;
319         }
320         if( rec->r.ver.version != 2 ) {
321             log_error_f( db_name, "invalid file version %d\n",
322                                                         rec->r.ver.version );
323             rc = G10ERR_TRUSTDB;
324         }
325         break;
326       case RECTYPE_DIR:   /*directory record */
327         rec->r.dir.lid      = buftoulong(p); p += 4;
328         rec->r.dir.keylist  = buftoulong(p); p += 4;
329         rec->r.dir.uidlist  = buftoulong(p); p += 4;
330         rec->r.dir.cacherec = buftoulong(p); p += 4;
331         rec->r.dir.ownertrust = *p++;
332         rec->r.dir.sigflag    = *p++;
333         if( rec->r.dir.lid != recnum ) {
334             log_error_f( db_name, "dir LID != recnum (%lu,%lu)\n",
335                                          rec->r.dir.lid, (ulong)recnum );
336             rc = G10ERR_TRUSTDB;
337         }
338         break;
339       case RECTYPE_KEY:   /* public key record */
340         rec->r.key.lid      = buftoulong(p); p += 4;
341         rec->r.key.next     = buftoulong(p); p += 4;
342         p += 8;
343         rec->r.key.pubkey_algo = *p++;
344         rec->r.key.fingerprint_len = *p++;
345         if( rec->r.key.fingerprint_len < 1 || rec->r.key.fingerprint_len > 20 )
346             rec->r.key.fingerprint_len = 20;
347         memcpy( rec->r.key.fingerprint, p, 20);
348         break;
349       case RECTYPE_UID:   /* user id record */
350         rec->r.uid.lid      = buftoulong(p); p += 4;
351         rec->r.uid.next     = buftoulong(p); p += 4;
352         rec->r.uid.prefrec  = buftoulong(p); p += 4;
353         rec->r.uid.siglist  = buftoulong(p); p += 4;
354         p += 2;
355         memcpy( rec->r.uid.namehash, p, 20);
356         break;
357       case RECTYPE_PREF:  /* preference record */
358         rec->r.pref.lid     = buftoulong(p); p += 4;
359         rec->r.pref.next    = buftoulong(p); p += 4;
360         break;
361       case RECTYPE_SIG:
362         rec->r.sig.lid     = buftoulong(p); p += 4;
363         rec->r.sig.next    = buftoulong(p); p += 4;
364         for(i=0; i < SIGS_PER_RECORD; i++ ) {
365             rec->r.sig.sig[i].lid  = buftoulong(p); p += 4;
366             rec->r.sig.sig[i].flag = *p++;
367         }
368         break;
369       case RECTYPE_CACH:   /* cache record (FIXME)*/
370         rec->r.cache.lid    = buftoulong(p); p += 4;
371         memcpy(rec->r.cache.blockhash, p, 20); p += 20;
372         rec->r.cache.trustlevel = *p++;
373         break;
374       default:
375         log_error_f( db_name, "invalid record type %d at recnum %lu\n",
376                                               rec->rectype, (ulong)recnum );
377         rc = G10ERR_TRUSTDB;
378         break;
379     }
380
381     return rc;
382 }
383
384 /****************
385  * Write the record at RECNUM
386  */
387 int
388 tdbio_write_record( ulong recnum, TRUSTREC *rec )
389 {
390     byte buf[TRUST_RECORD_LEN], *p;
391     int rc = 0;
392     int i, n;
393
394     if( db_fd == -1 )
395         open_db();
396
397     memset(buf, 0, TRUST_RECORD_LEN);
398     p = buf;
399     *p++ = rec->rectype; p++;
400     switch( rec->rectype ) {
401       case 0:  /* unused record */
402         break;
403       case 1: /* version record */
404         BUG();
405         break;
406
407       case RECTYPE_DIR:   /*directory record */
408         ulongtobuf(p, rec->r.dir.lid); p += 4;
409         ulongtobuf(p, rec->r.dir.keylist); p += 4;
410         ulongtobuf(p, rec->r.dir.uidlist); p += 4;
411         ulongtobuf(p, rec->r.dir.cacherec); p += 4;
412         *p++ = rec->r.dir.ownertrust;
413         *p++ = rec->r.dir.sigflag;
414         assert( rec->r.dir.lid == recnum );
415         break;
416
417       case RECTYPE_KEY:
418         ulongtobuf(p, rec->r.key.lid); p += 4;
419         ulongtobuf(p, rec->r.key.next); p += 4;
420         p += 8;
421         *p++ = rec->r.key.pubkey_algo;
422         *p++ = rec->r.key.fingerprint_len;
423         memcpy( p, rec->r.key.fingerprint, 20); p += 20;
424         break;
425
426       case RECTYPE_UID:   /* user id record */
427         ulongtobuf(p, rec->r.uid.lid); p += 4;
428         ulongtobuf(p, rec->r.uid.next); p += 4;
429         ulongtobuf(p, rec->r.uid.prefrec); p += 4;
430         ulongtobuf(p, rec->r.uid.siglist); p += 4;
431         p += 2;
432         memcpy( p, rec->r.uid.namehash, 20 ); p += 20;
433         break;
434
435       case RECTYPE_PREF:
436         ulongtobuf(p, rec->r.pref.lid); p += 4;
437         ulongtobuf(p, rec->r.pref.next); p += 4;
438         break;
439
440       case RECTYPE_SIG:
441         ulongtobuf(p, rec->r.sig.lid); p += 4;
442         ulongtobuf(p, rec->r.sig.next); p += 4;
443         for(i=0; i < SIGS_PER_RECORD; i++ ) {
444             ulongtobuf(p, rec->r.sig.sig[i].lid); p += 4;
445             *p++ = rec->r.sig.sig[i].flag;
446         }
447         break;
448
449       case RECTYPE_CACH:   /* FIXME*/
450         ulongtobuf(p, rec->r.cache.lid); p += 4;
451         memcpy(p, rec->r.cache.blockhash, 20); p += 20;
452         *p++ = rec->r.cache.trustlevel;
453         break;
454
455       default:
456         BUG();
457     }
458
459     if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
460         log_error(_("trustdb: lseek failed: %s\n"), strerror(errno) );
461         return G10ERR_WRITE_FILE;
462     }
463     n = write( db_fd, buf, TRUST_RECORD_LEN);
464     if( n != TRUST_RECORD_LEN ) {
465         log_error(_("trustdb: write failed (n=%d): %s\n"), n, strerror(errno) );
466         return G10ERR_WRITE_FILE;
467     }
468
469     return rc;
470 }
471
472
473 /****************
474  * create a new record and return its record number
475  */
476 ulong
477 tdbio_new_recnum()
478 {
479     off_t offset;
480     ulong recnum;
481     TRUSTREC rec;
482     int rc;
483
484     /* fixme: look for unused records */
485     offset = lseek( db_fd, 0, SEEK_END );
486     if( offset == -1 )
487         log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
488     recnum = offset / TRUST_RECORD_LEN;
489     assert(recnum); /* this is will never be the first record */
490
491     /* we must write a record, so that the next call to this function
492      * returns another recnum */
493     memset( &rec, 0, sizeof rec );
494     rec.rectype = 0; /* free record */
495     rc = tdbio_write_record(recnum, &rec );
496     if( rc )
497         log_fatal_f(db_name,_("failed to append a record: %s\n"),
498                                             g10_errstr(rc));
499     return recnum ;
500 }
501
502
503
504 /****************
505  * Search the trustdb for a key which matches PK and return the dir record
506  * The local_id of PK is set to the correct value
507  *
508  * Note: To increase performance, we could use a index search here.
509  */
510 int
511 tdbio_search_dir_record( PKT_public_key *pk, TRUSTREC *rec )
512 {
513     ulong recnum;
514     u32 keyid[2];
515     byte *fingerprint;
516     size_t fingerlen;
517     int rc;
518
519     keyid_from_pk( pk, keyid );
520     fingerprint = fingerprint_from_pk( pk, NULL, &fingerlen );
521     assert( fingerlen == 20 || fingerlen == 16 );
522
523     for(recnum=1; !(rc=tdbio_read_record( recnum, rec, 0)); recnum++ ) {
524         if( rec->rectype != RECTYPE_KEY )
525             continue;
526         if( rec->r.key.pubkey_algo == pk->pubkey_algo
527             && !memcmp(rec->r.key.fingerprint, fingerprint, fingerlen) ) {
528             /* found: read the dir record for this key */
529             rc = tdbio_read_record( rec->r.key.lid, rec, RECTYPE_DIR);
530             if( rc )
531                 break;
532
533             if( pk->local_id && pk->local_id != recnum )
534                 log_error_f(db_name,
535                            "found record, but LID from memory does "
536                            "not match recnum (%lu,%lu)\n",
537                                                 pk->local_id, recnum );
538             pk->local_id = recnum;
539             return 0;
540         }
541     }
542     if( rc != -1 )
543         log_error_f( db_name, _("search_db failed: %s\n"), g10_errstr(rc) );
544     return rc;
545 }
546
547
548 int
549 tdbio_update_sigflag( ulong lid, int sigflag )
550 {
551     TRUSTREC rec;
552
553     if( tdbio_read_record( lid, &rec, RECTYPE_DIR ) ) {
554         log_error("update_sigflag: read failed\n");
555         return G10ERR_TRUSTDB;
556     }
557
558     rec.r.dir.sigflag = sigflag;
559     if( tdbio_write_record( lid, &rec ) ) {
560         log_error("update_sigflag: write failed\n");
561         return G10ERR_TRUSTDB;
562     }
563
564     return 0;
565 }
566