fixed severe exploit
[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, 1 );
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 keyid=%08lX, key=%lu, ctl=%lu, sig=%lu",
199                     (ulong)rec->r.dir.keyid[1],
200                     rec->r.dir.keyrec, rec->r.dir.ctlrec, rec->r.dir.sigrec );
201         if( rec->r.dir.no_sigs == 1 )
202             fputs(", (none)", fp );
203         else if( rec->r.dir.no_sigs == 2 )
204             fputs(", (invalid)", fp );
205         else if( rec->r.dir.no_sigs == 3 )
206             fputs(", (revoked)", fp );
207         else if( rec->r.dir.no_sigs )
208             fputs(", (??)", fp );
209         putc('\n', fp);
210         break;
211       case RECTYPE_KEY: fprintf(fp,
212                     "key %08lX, own=%lu, ownertrust=%02x, fl=%d\n",
213                    (ulong)rec->r.key.keyid[1],
214                    rec->r.key.owner, rec->r.key.ownertrust,
215                    rec->r.key.fingerprint_len );
216         break;
217       case RECTYPE_UID:
218         if( !rec->r.uid.subtype )
219             fprintf(fp,
220                     "uid %02x%02x, owner=%lu, chain=%lu, pref=%lu, otr=%02x\n",
221                    rec->r.uid.namehash[18], rec->r.uid.namehash[19],
222                    rec->r.uid.owner, rec->r.uid.chain, (ulong)rec->r.uid.prefrec,
223                    rec->r.uid.ownertrust );
224         else
225             fprintf(fp,
226                     "uid subtype%d, owner=%lu, chain=%lu\n",
227                    rec->r.uid.subtype, rec->r.uid.owner, rec->r.uid.chain);
228         break;
229       case RECTYPE_CTL: fprintf(fp, "ctl\n");
230         break;
231       case RECTYPE_SIG:
232         fprintf(fp, "sigrec, owner=%lu, chain=%lu\n",
233                          rec->r.sig.owner, rec->r.sig.chain );
234         for(i=any=0; i < SIGS_PER_RECORD; i++ ) {
235             if( rec->r.sig.sig[i].local_id ) {
236                 if( !any ) {
237                     putc('\t', fp);
238                     any++;
239                 }
240                 fprintf(fp, "  %lu:%02x", rec->r.sig.sig[i].local_id,
241                                               rec->r.sig.sig[i].flag );
242             }
243         }
244         if( any )
245             putc('\n', fp);
246         break;
247       default:
248         fprintf(fp, "%d (unknown)\n", rec->rectype );
249         break;
250     }
251 }
252
253 /****************
254  * read the record with number recnum
255  * returns: -1 on error, 0 on success
256  */
257 int
258 tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
259 {
260     byte buf[TRUST_RECORD_LEN], *p;
261     int rc = 0;
262     int n, i;
263
264     if( db_fd == -1 )
265         open_db();
266     if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
267         log_error(_("trustdb: lseek failed: %s\n"), strerror(errno) );
268         return G10ERR_READ_FILE;
269     }
270     n = read( db_fd, buf, TRUST_RECORD_LEN);
271     if( !n ) {
272         return -1; /* eof */
273     }
274     else if( n != TRUST_RECORD_LEN ) {
275         log_error(_("trustdb: read failed (n=%d): %s\n"), n, strerror(errno) );
276         return G10ERR_READ_FILE;
277     }
278     p = buf;
279     rec->rectype = *p++;
280     if( expected && rec->rectype != expected ) {
281         log_error("%lu: read expected rec type %d, got %d\n",
282                     recnum, expected, rec->rectype );
283         return G10ERR_TRUSTDB;
284     }
285     p++;
286     switch( rec->rectype ) {
287       case 0:  /* unused record */
288         break;
289       case RECTYPE_VER: /* version record */
290         /* g10 was the original name */
291         if( memcmp(buf+1, "gpg", 3 ) && memcmp(buf+1, "g10", 3 ) ) {
292             log_error_f( db_name, _("not a trustdb file\n") );
293             rc = G10ERR_TRUSTDB;
294         }
295         p += 2; /* skip magic */
296         rec->r.ver.version  = *p++;
297         rec->r.ver.locked   = buftoulong(p); p += 4;
298         rec->r.ver.created  = buftoulong(p); p += 4;
299         rec->r.ver.modified = buftoulong(p); p += 4;
300         rec->r.ver.validated= buftoulong(p); p += 4;
301         rec->r.ver.marginals_needed = *p++;
302         rec->r.ver.completes_needed = *p++;
303         rec->r.ver.max_cert_depth = *p++;
304         if( recnum ) {
305             log_error_f( db_name, "version record with recnum %lu\n",
306                                                              (ulong)recnum );
307             rc = G10ERR_TRUSTDB;
308         }
309         if( rec->r.ver.version != 1 ) {
310             log_error_f( db_name, "invalid file version %d\n",
311                                                         rec->r.ver.version );
312             rc = G10ERR_TRUSTDB;
313         }
314         break;
315       case RECTYPE_DIR:   /*directory record */
316         rec->r.dir.local_id = buftoulong(p); p += 4;
317         rec->r.dir.keyid[0] = buftou32(p); p += 4;
318         rec->r.dir.keyid[1] = buftou32(p); p += 4;
319         rec->r.dir.keyrec   = buftoulong(p); p += 4;
320         rec->r.dir.ctlrec   = buftoulong(p); p += 4;
321         rec->r.dir.sigrec   = buftoulong(p); p += 4;
322         rec->r.dir.no_sigs = *p++;
323         if( rec->r.dir.local_id != recnum ) {
324             log_error_f( db_name, "dir local_id != recnum (%lu,%lu)\n",
325                                         (ulong)rec->r.dir.local_id,
326                                         (ulong)recnum );
327             rc = G10ERR_TRUSTDB;
328         }
329         break;
330       case RECTYPE_KEY:   /* public key record */
331         rec->r.key.owner    = buftoulong(p); p += 4;
332         rec->r.dir.keyid[0] = buftou32(p); p += 4;
333         rec->r.dir.keyid[1] = buftou32(p); p += 4;
334         rec->r.key.pubkey_algo = *p++;
335         rec->r.key.fingerprint_len = *p++;
336         if( rec->r.key.fingerprint_len < 1 || rec->r.key.fingerprint_len > 20 )
337             rec->r.key.fingerprint_len = 20;
338         memcpy( rec->r.key.fingerprint, p, 20); p += 20;
339         rec->r.key.ownertrust = *p++;
340         break;
341       case RECTYPE_CTL:   /* control record */
342         rec->r.ctl.owner    = buftoulong(p); p += 4;
343         memcpy(rec->r.ctl.blockhash, p, 20); p += 20;
344         rec->r.ctl.trustlevel = *p++;
345         break;
346       case RECTYPE_SIG:
347         rec->r.sig.owner   = buftoulong(p); p += 4;
348         rec->r.sig.chain   = buftoulong(p); p += 4;
349         for(i=0; i < SIGS_PER_RECORD; i++ ) {
350             rec->r.sig.sig[i].local_id = buftoulong(p); p += 4;
351             rec->r.sig.sig[i].flag = *p++;
352         }
353         break;
354       default:
355         log_error_f( db_name, "invalid record type %d at recnum %lu\n",
356                                               rec->rectype, (ulong)recnum );
357         rc = G10ERR_TRUSTDB;
358         break;
359     }
360
361     return rc;
362 }
363
364 /****************
365  * Write the record at RECNUM
366  */
367 int
368 tdbio_write_record( ulong recnum, TRUSTREC *rec )
369 {
370     byte buf[TRUST_RECORD_LEN], *p;
371     int rc = 0;
372     int i, n;
373
374     if( db_fd == -1 )
375         open_db();
376
377     memset(buf, 0, TRUST_RECORD_LEN);
378     p = buf;
379     *p++ = rec->rectype; p++;
380     switch( rec->rectype ) {
381       case 0:  /* unused record */
382         break;
383       case 1: /* version record */
384         BUG();
385         break;
386
387       case RECTYPE_DIR:   /*directory record */
388         ulongtobuf(p, rec->r.dir.local_id); p += 4;
389         u32tobuf(p, rec->r.key.keyid[0]); p += 4;
390         u32tobuf(p, rec->r.key.keyid[1]); p += 4;
391         ulongtobuf(p, rec->r.dir.keyrec); p += 4;
392         ulongtobuf(p, rec->r.dir.ctlrec); p += 4;
393         ulongtobuf(p, rec->r.dir.sigrec); p += 4;
394         *p++ = rec->r.dir.no_sigs;
395         assert( rec->r.dir.local_id == recnum );
396         break;
397
398       case RECTYPE_KEY:
399         ulongtobuf(p, rec->r.key.owner); p += 4;
400         u32tobuf(p, rec->r.key.keyid[0]); p += 4;
401         u32tobuf(p, rec->r.key.keyid[1]); p += 4;
402         *p++ = rec->r.key.pubkey_algo;
403         *p++ = rec->r.key.fingerprint_len;
404         memcpy( p, rec->r.key.fingerprint, 20); p += 20;
405         *p++ = rec->r.key.ownertrust;
406         break;
407
408       case RECTYPE_CTL:   /* control record */
409         ulongtobuf(p, rec->r.ctl.owner); p += 4;
410         memcpy(p, rec->r.ctl.blockhash, 20); p += 20;
411         *p++ = rec->r.ctl.trustlevel;
412         break;
413
414       case RECTYPE_SIG:
415         ulongtobuf(p, rec->r.sig.owner); p += 4;
416         ulongtobuf(p, rec->r.sig.chain); p += 4;
417         for(i=0; i < SIGS_PER_RECORD; i++ ) {
418             ulongtobuf(p, rec->r.sig.sig[i].local_id); p += 4;
419             *p++ = rec->r.sig.sig[i].flag;
420         }
421         break;
422       default:
423         BUG();
424     }
425
426     if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
427         log_error(_("trustdb: lseek failed: %s\n"), strerror(errno) );
428         return G10ERR_WRITE_FILE;
429     }
430     n = write( db_fd, buf, TRUST_RECORD_LEN);
431     if( n != TRUST_RECORD_LEN ) {
432         log_error(_("trustdb: write failed (n=%d): %s\n"), n, strerror(errno) );
433         return G10ERR_WRITE_FILE;
434     }
435
436     return rc;
437 }
438
439
440 /****************
441  * create a new record and return its record number
442  */
443 ulong
444 tdbio_new_recnum()
445 {
446     off_t offset;
447     ulong recnum;
448     TRUSTREC rec;
449     int rc;
450
451     /* fixme: look for unused records */
452     offset = lseek( db_fd, 0, SEEK_END );
453     if( offset == -1 )
454         log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
455     recnum = offset / TRUST_RECORD_LEN;
456     assert(recnum); /* this is will never be the first record */
457
458     /* we must write a record, so that the next call to this function
459      * returns another recnum */
460     memset( &rec, 0, sizeof rec );
461     rec.rectype = 0; /* free record */
462     rc = tdbio_write_record(recnum, &rec );
463     if( rc )
464         log_fatal_f(db_name,_("failed to append a record: %s\n"),
465                                             g10_errstr(rc));
466     return recnum ;
467 }
468
469
470
471 /****************
472  * Search the trustdb for a key which matches PK and return the dir record
473  * The local_id of PK is set to the correct value
474  *
475  * Note: To increase performance, we could use a index search here.
476  */
477 int
478 tdbio_search_record( PKT_public_key *pk, TRUSTREC *rec )
479 {
480     ulong recnum;
481     u32 keyid[2];
482     byte *fingerprint;
483     size_t fingerlen;
484     int rc;
485
486     keyid_from_pk( pk, keyid );
487     fingerprint = fingerprint_from_pk( pk, &fingerlen );
488     assert( fingerlen == 20 || fingerlen == 16 );
489
490     for(recnum=1; !(rc=tdbio_read_record( recnum, rec, 0)); recnum++ ) {
491         if( rec->rectype != RECTYPE_DIR )
492             continue;
493         if( rec->r.dir.keyid[0] == keyid[0]
494             && rec->r.dir.keyid[1] == keyid[1]){
495             TRUSTREC keyrec;
496
497             if( tdbio_read_record( rec->r.dir.keyrec, &keyrec, RECTYPE_KEY ) ) {
498                 log_error("%lu: ooops: invalid key record\n", recnum );
499                 break;
500             }
501             if( keyrec.r.key.pubkey_algo == pk->pubkey_algo
502                 && !memcmp(keyrec.r.key.fingerprint, fingerprint, fingerlen) ){
503                 if( pk->local_id && pk->local_id != recnum )
504                     log_error_f(db_name,
505                                "found record, but local_id from memory does "
506                                "not match recnum (%lu,%lu)\n",
507                                      (ulong)pk->local_id, (ulong)recnum );
508                 pk->local_id = recnum;
509                 return 0;
510             }
511         }
512     }
513     if( rc != -1 )
514         log_error_f( db_name, _("search_db failed: %s\n"), g10_errstr(rc) );
515     return rc;
516 }
517
518