1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-15 00:29:49 +02:00
gnupg/g10/trustdb.c

1568 lines
39 KiB
C
Raw Normal View History

1998-01-02 21:40:10 +01:00
/* trustdb.c
* Copyright (c) 1997 by Werner Koch (dd9jn)
*
* This file is part of G10.
*
* G10 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* G10 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
1998-01-12 11:18:17 +01:00
#include <unistd.h>
1998-01-02 21:40:10 +01:00
#include <errno.h>
#include <assert.h>
1998-01-13 20:04:23 +01:00
#include <fcntl.h>
1998-01-02 21:40:10 +01:00
#include "errors.h"
#include "iobuf.h"
#include "keydb.h"
#include "memory.h"
#include "util.h"
1998-01-12 11:18:17 +01:00
#include "trustdb.h"
#include "options.h"
1998-01-16 22:15:24 +01:00
#include "packet.h"
#include "main.h"
1998-01-02 21:40:10 +01:00
1998-01-12 11:18:17 +01:00
#define TRUST_RECORD_LEN 40
1998-01-14 13:34:05 +01:00
#define SIGS_PER_RECORD ((TRUST_RECORD_LEN-10)/5)
1998-01-16 22:15:24 +01:00
#define MAX_LIST_SIGS_DEPTH 20
1998-01-12 11:18:17 +01:00
struct trust_record {
byte rectype;
byte reserved;
union {
struct { /* version record: */
byte magic[2];
byte version; /* should be 1 */
byte reserved[3];
1998-01-16 22:15:24 +01:00
ulong locked; /* pid of process which holds a lock */
ulong created; /* timestamp of trustdb creation */
ulong modified; /* timestamp of last modification */
ulong validated; /* timestamp of last validation */
ulong local_id_counter;
1998-01-12 11:18:17 +01:00
byte marginals_needed;
byte completes_needed;
byte max_cert_depth;
} version;
struct { /* public key record */
1998-01-16 22:15:24 +01:00
ulong local_id;
u32 keyid[2];
byte pubkey_algo;
1998-01-12 11:18:17 +01:00
byte reserved;
byte fingerprint[20];
byte ownertrust;
1998-01-14 13:34:05 +01:00
/* fixme: indicate a flag to */
1998-01-12 11:18:17 +01:00
} pubkey;
struct { /* cache record */
1998-01-16 22:15:24 +01:00
ulong owner;
u32 keyid[2]; /* needed?? */
1998-01-12 11:18:17 +01:00
byte valid;
byte reserved;
byte blockhash[20];
byte n_untrusted;
byte n_marginal;
byte n_fully;
byte trustlevel;
} cache;
1998-01-14 13:34:05 +01:00
struct {
1998-01-16 22:15:24 +01:00
ulong owner; /* local_id of record owner (pubkey record) */
ulong chain; /* offset of next record or NULL for last one */
1998-01-14 13:34:05 +01:00
struct {
1998-01-16 22:15:24 +01:00
ulong local_id; /* of pubkey record of signator (0=unused) */
1998-01-14 13:34:05 +01:00
byte flag; /* reserved */
} sig[SIGS_PER_RECORD];
} sigrec;
1998-01-12 11:18:17 +01:00
} r;
};
1998-01-13 20:04:23 +01:00
typedef struct trust_record TRUSTREC;
1998-01-12 11:18:17 +01:00
1998-01-16 22:15:24 +01:00
typedef struct {
ulong pubkey_id; /* localid of the pubkey */
ulong sig_id; /* returned signature id */
unsigned sig_flag; /* returned signaure record flag */
struct { /* internal data */
int eof;
TRUSTREC rec;
int index;
} ctl;
} SIGREC_CONTEXT;
typedef struct local_id_info *LOCAL_ID_INFO;
struct local_id_info {
LOCAL_ID_INFO next;
ulong lid;
unsigned flag;
};
1998-01-19 19:54:44 +01:00
typedef struct trust_seg_list *TRUST_SEG_LIST;
struct trust_seg_list {
TRUST_SEG_LIST next;
int nseg; /* number of segmens */
int dup;
ulong seg[1]; /* segment list */
};
1998-01-12 11:18:17 +01:00
1998-01-13 20:04:23 +01:00
static void create_db( const char *fname );
static void open_db(void);
1998-01-16 22:15:24 +01:00
static int read_record( ulong recnum, TRUSTREC *rec );
static int write_record( ulong recnum, TRUSTREC *rec );
static ulong new_recnum(void);
static void dump_record( ulong rnum, TRUSTREC *rec, FILE *fp );
static int walk_sigrecs( SIGREC_CONTEXT *c );
static LOCAL_ID_INFO *new_lid_table(void);
static void release_lid_table( LOCAL_ID_INFO *tbl );
1998-01-19 19:54:44 +01:00
static int ins_lid_table_item( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag );
static int qry_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned *flag );
static void upd_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag );
1998-01-16 22:15:24 +01:00
static void print_user_id( const char *text, u32 *keyid );
1998-01-19 19:54:44 +01:00
static int do_list_path( ulong *stack, int depth, int max_depth,
LOCAL_ID_INFO *lids, TRUST_SEG_LIST *tslist );
1998-01-16 22:15:24 +01:00
static int list_sigs( ulong pubkey_id );
1998-01-19 19:54:44 +01:00
static int do_check( ulong pubkeyid, int *trustlevel );
1998-01-16 22:15:24 +01:00
1998-01-12 11:18:17 +01:00
static char *db_name;
1998-01-13 20:04:23 +01:00
static int db_fd = -1;
1998-01-16 22:15:24 +01:00
/* a table used to keep track of ultimately trusted keys
* which are the ones from our secrings */
static LOCAL_ID_INFO *ultikey_table;
1998-01-13 20:04:23 +01:00
1998-01-16 22:15:24 +01:00
#define buftoulong( p ) ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \
1998-01-13 20:04:23 +01:00
(*((byte*)(p)+2) << 8) | (*((byte*)(p)+3)))
1998-01-16 22:15:24 +01:00
#define buftoushort( p ) ((*((byte*)(p)) << 8) | (*((byte*)(p)+1)))
#define ulongtobuf( p, a ) do { \
1998-01-13 20:04:23 +01:00
((byte*)p)[0] = a >> 24; \
((byte*)p)[1] = a >> 16; \
((byte*)p)[2] = a >> 8; \
((byte*)p)[3] = a ; \
} while(0)
1998-01-16 22:15:24 +01:00
#define ushorttobuf( p, a ) do { \
1998-01-13 20:04:23 +01:00
((byte*)p)[0] = a >> 8; \
((byte*)p)[1] = a ; \
} while(0)
1998-01-16 22:15:24 +01:00
#define buftou32( p) buftoulong( (p) )
#define u32tobuf( p, a) ulongtobuf( (p), (a) )
1998-01-13 20:04:23 +01:00
1998-01-12 11:18:17 +01:00
/**************************************************
************** read and write helpers ************
**************************************************/
static void
fwrite_8(FILE *fp, byte a)
{
if( putc( a & 0xff, fp ) == EOF )
log_fatal("error writing byte to trustdb: %s\n", strerror(errno) );
}
1998-01-16 22:15:24 +01:00
static void
fwrite_32( FILE*fp, ulong a)
1998-01-12 11:18:17 +01:00
{
putc( (a>>24) & 0xff, fp );
putc( (a>>16) & 0xff, fp );
putc( (a>> 8) & 0xff, fp );
if( putc( a & 0xff, fp ) == EOF )
1998-01-16 22:15:24 +01:00
log_fatal("error writing ulong to trustdb: %s\n", strerror(errno) );
1998-01-12 11:18:17 +01:00
}
1998-01-16 22:15:24 +01:00
static void
1998-01-12 11:18:17 +01:00
fwrite_zeros( FILE *fp, size_t n)
{
while( n-- )
if( putc( 0, fp ) == EOF )
log_fatal("error writing zeros to trustdb: %s\n", strerror(errno) );
}
/**************************************************
************** read and write stuff **************
**************************************************/
/****************
* Create a new trustdb
*/
static void
create_db( const char *fname )
{
FILE *fp;
fp =fopen( fname, "w" );
if( !fp )
log_fatal("can't create %s: %s\n", fname, strerror(errno) );
fwrite_8( fp, 1 );
fwrite_8( fp, 'g' );
fwrite_8( fp, '1' );
fwrite_8( fp, '0' );
fwrite_8( fp, 1 ); /* version */
fwrite_zeros( fp, 3 ); /* reserved */
fwrite_32( fp, 0 ); /* not locked */
fwrite_32( fp, make_timestamp() ); /* created */
fwrite_32( fp, 0 ); /* not yet modified */
fwrite_32( fp, 0 ); /* not yet validated*/
1998-01-13 20:04:23 +01:00
fwrite_32( fp, 0 ); /* local-id-counter (not used) */
1998-01-12 11:18:17 +01:00
fwrite_8( fp, 3 ); /* marginals needed */
fwrite_8( fp, 1 ); /* completes needed */
fwrite_8( fp, 4 ); /* max_cet_depth */
fwrite_zeros( fp, 9 ); /* filler */
fclose(fp);
}
1998-01-13 20:04:23 +01:00
static void
open_db()
{
TRUSTREC rec;
assert( db_fd == -1 );
db_fd = open( db_name, O_RDWR );
if( db_fd == -1 )
log_fatal("can't open %s: %s\n", db_name, strerror(errno) );
if( read_record( 0, &rec ) )
log_fatal("TrustDB %s is invalid\n", db_name );
/* fixme: check ->locked and other stuff */
}
1998-01-12 11:18:17 +01:00
1998-01-13 20:04:23 +01:00
/****************
* read the record with number recnum
* returns: -1 on error, 0 on success
*/
static int
1998-01-16 22:15:24 +01:00
read_record( ulong recnum, TRUSTREC *rec )
1998-01-13 20:04:23 +01:00
{
byte buf[TRUST_RECORD_LEN], *p;
int rc = 0;
1998-01-14 13:34:05 +01:00
int n, i;
1998-01-13 20:04:23 +01:00
if( db_fd == -1 )
open_db();
if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
log_error("trustdb: lseek failed: %s\n", strerror(errno) );
return G10ERR_READ_FILE;
}
n = read( db_fd, buf, TRUST_RECORD_LEN);
if( !n ) {
return -1; /* eof */
}
else if( n != TRUST_RECORD_LEN ) {
log_error("trustdb: read failed (n=%d): %s\n", n, strerror(errno) );
return G10ERR_READ_FILE;
}
p = buf;
rec->rectype = *p++;
rec->reserved = *p++;
switch( rec->rectype ) {
case 0: /* unused record */
break;
case 1: /* version record */
rec->r.version.magic[0] = *p++;
rec->r.version.magic[1] = *p++;
rec->r.version.version = *p++;
memcpy( rec->r.version.reserved, p, 3); p += 3;
1998-01-16 22:15:24 +01:00
rec->r.version.locked = buftoulong(p); p += 4;
rec->r.version.created = buftoulong(p); p += 4;
rec->r.version.modified = buftoulong(p); p += 4;
rec->r.version.validated= buftoulong(p); p += 4;
rec->r.version.local_id_counter = buftoulong(p); p += 4;
1998-01-13 20:04:23 +01:00
rec->r.version.marginals_needed = *p++;
rec->r.version.completes_needed = *p++;
rec->r.version.max_cert_depth = *p++;
if( recnum ) {
log_error("%s: version record with recnum %lu\n",
db_name, (ulong)recnum );
rc = G10ERR_TRUSTDB;
}
if( rec->reserved != 'g' || rec->r.version.magic[0] != '1'
|| rec->r.version.magic[1] != '0' ) {
log_error("%s: not a trustdb file\n", db_name );
rc = G10ERR_TRUSTDB;
}
if( rec->r.version.version != 1 ) {
log_error("%s: invalid file version %d\n",
db_name, rec->r.version.version );
rc = G10ERR_TRUSTDB;
}
break;
case 2:
1998-01-16 22:15:24 +01:00
rec->r.pubkey.local_id = buftoulong(p); p += 4;
1998-01-13 20:04:23 +01:00
rec->r.pubkey.keyid[0] = buftou32(p); p += 4;
rec->r.pubkey.keyid[1] = buftou32(p); p += 4;
1998-01-16 22:15:24 +01:00
rec->r.pubkey.pubkey_algo = *p++;
1998-01-13 20:04:23 +01:00
rec->r.pubkey.reserved = *p++;
memcpy( rec->r.pubkey.fingerprint, p, 20); p += 20;
rec->r.pubkey.ownertrust = *p++;
if( rec->r.pubkey.local_id != recnum ) {
log_error("%s: pubkey local_id != recnum (%lu,%lu)\n",
db_name,
(ulong)rec->r.pubkey.local_id,
(ulong)recnum );
rc = G10ERR_TRUSTDB;
}
break;
case 3:
1998-01-16 22:15:24 +01:00
rec->r.cache.owner = buftoulong(p); p += 4;
1998-01-13 20:04:23 +01:00
rec->r.cache.keyid[0] = buftou32(p); p += 4;
rec->r.cache.keyid[1] = buftou32(p); p += 4;
rec->r.cache.valid = *p++;
rec->r.cache.reserved = *p++;
memcpy(rec->r.cache.blockhash, p, 20); p += 20;
rec->r.cache.n_untrusted = *p++;
rec->r.cache.n_marginal = *p++;
rec->r.cache.n_fully = *p++;
rec->r.cache.trustlevel = *p++;
break;
1998-01-14 13:34:05 +01:00
case 4:
case 5:
1998-01-16 22:15:24 +01:00
rec->r.sigrec.owner = buftoulong(p); p += 4;
rec->r.sigrec.chain = buftoulong(p); p += 4;
1998-01-14 13:34:05 +01:00
for(i=0; i < SIGS_PER_RECORD; i++ ) {
1998-01-16 22:15:24 +01:00
rec->r.sigrec.sig[i].local_id = buftoulong(p); p += 4;
1998-01-14 13:34:05 +01:00
rec->r.sigrec.sig[i].flag = *p++;
}
break;
1998-01-13 20:04:23 +01:00
default:
log_error("%s: invalid record type %d at recnum %lu\n",
db_name, rec->rectype, (ulong)recnum );
rc = G10ERR_TRUSTDB;
break;
}
1998-01-12 11:18:17 +01:00
1998-01-13 20:04:23 +01:00
return rc;
}
1998-01-12 11:18:17 +01:00
1998-01-13 20:04:23 +01:00
/****************
* Write the record at RECNUM
*/
static int
1998-01-16 22:15:24 +01:00
write_record( ulong recnum, TRUSTREC *rec )
1998-01-13 20:04:23 +01:00
{
byte buf[TRUST_RECORD_LEN], *p;
int rc = 0;
1998-01-14 13:34:05 +01:00
int i, n;
1998-01-13 20:04:23 +01:00
if( db_fd == -1 )
open_db();
memset(buf, 0, TRUST_RECORD_LEN);
p = buf;
*p++ = rec->rectype;
*p++ = rec->reserved;
switch( rec->rectype ) {
case 0: /* unused record */
break;
case 1: /* version record */
1998-01-16 22:15:24 +01:00
BUG();
1998-01-13 20:04:23 +01:00
break;
case 2:
1998-01-16 22:15:24 +01:00
ulongtobuf(p, rec->r.pubkey.local_id); p += 4;
1998-01-13 20:04:23 +01:00
u32tobuf(p, rec->r.pubkey.keyid[0]); p += 4;
u32tobuf(p, rec->r.pubkey.keyid[1]); p += 4;
1998-01-16 22:15:24 +01:00
*p++ = rec->r.pubkey.pubkey_algo;
1998-01-13 20:04:23 +01:00
*p++ = rec->r.pubkey.reserved;
memcpy( p, rec->r.pubkey.fingerprint, 20); p += 20;
*p++ = rec->r.pubkey.ownertrust;
assert( rec->r.pubkey.local_id == recnum );
break;
case 3:
1998-01-16 22:15:24 +01:00
ulongtobuf(p, rec->r.cache.owner); p += 4;
1998-01-13 20:04:23 +01:00
u32tobuf(p, rec->r.cache.keyid[0]); p += 4;
u32tobuf(p, rec->r.cache.keyid[1]); p += 4;
*p++ = rec->r.cache.valid;
*p++ = rec->r.cache.reserved;
memcpy(p, rec->r.cache.blockhash, 20); p += 20;
*p++ = rec->r.cache.n_untrusted;
*p++ = rec->r.cache.n_marginal;
*p++ = rec->r.cache.n_fully;
*p++ = rec->r.cache.trustlevel;
break;
1998-01-14 13:34:05 +01:00
case 4:
case 5:
1998-01-16 22:15:24 +01:00
ulongtobuf(p, rec->r.sigrec.owner); p += 4;
ulongtobuf(p, rec->r.sigrec.chain); p += 4;
1998-01-14 13:34:05 +01:00
for(i=0; i < SIGS_PER_RECORD; i++ ) {
1998-01-16 22:15:24 +01:00
ulongtobuf(p, rec->r.sigrec.sig[i].local_id); p += 4;
1998-01-14 13:34:05 +01:00
*p++ = rec->r.sigrec.sig[i].flag;
}
break;
1998-01-13 20:04:23 +01:00
default:
1998-01-16 22:15:24 +01:00
BUG();
1998-01-13 20:04:23 +01:00
}
1998-01-12 11:18:17 +01:00
1998-01-13 20:04:23 +01:00
if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
log_error("trustdb: lseek failed: %s\n", strerror(errno) );
return G10ERR_WRITE_FILE;
}
n = write( db_fd, buf, TRUST_RECORD_LEN);
if( n != TRUST_RECORD_LEN ) {
log_error("trustdb: write failed (n=%d): %s\n", n, strerror(errno) );
return G10ERR_WRITE_FILE;
}
1998-01-12 11:18:17 +01:00
1998-01-13 20:04:23 +01:00
return rc;
}
1998-01-12 11:18:17 +01:00
1998-01-16 22:15:24 +01:00
/****************
* create a new record and return its record number
*/
static ulong
new_recnum()
1998-01-13 20:04:23 +01:00
{
off_t offset;
1998-01-16 22:15:24 +01:00
ulong recnum;
TRUSTREC rec;
int rc;
1998-01-13 20:04:23 +01:00
/* fixme: look for unused records */
offset = lseek( db_fd, 0, SEEK_END );
if( offset == -1 )
log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
recnum = offset / TRUST_RECORD_LEN;
assert(recnum); /* this is will never be the first record */
1998-01-16 22:15:24 +01:00
/* we must write a record, so that the next call to this function
* returns another recnum */
memset( &rec, 0, sizeof rec );
rec.rectype = 0; /* free record */
rc = write_record(recnum, &rec );
if( rc )
log_fatal("%s: failed to append a record: %s\n",
db_name, g10_errstr(rc));
1998-01-13 20:04:23 +01:00
return recnum ;
}
/****************
1998-01-14 13:34:05 +01:00
* Scan the trustdb for a record of type RECTYPE which matches PKC
1998-01-13 20:04:23 +01:00
* The local_id is set to the correct value
*/
static int
1998-01-14 13:34:05 +01:00
scan_record_by_pkc( PKT_public_cert *pkc, TRUSTREC *rec, int rectype )
1998-01-13 20:04:23 +01:00
{
1998-01-16 22:15:24 +01:00
ulong recnum;
1998-01-13 20:04:23 +01:00
u32 keyid[2];
byte *fingerprint;
size_t fingerlen;
int rc;
assert( rectype == 2 || rectype == 3 );
keyid_from_pkc( pkc, keyid );
fingerprint = fingerprint_from_pkc( pkc, &fingerlen );
assert( fingerlen == 20 || fingerlen == 16 );
for(recnum=1; !(rc=read_record( recnum, rec)); recnum++ ) {
if( rec->rectype != rectype )
continue;
if( rec->rectype == 2 ) {
if( rec->r.pubkey.keyid[0] == keyid[0]
&& rec->r.pubkey.keyid[1] == keyid[1]
1998-01-16 22:15:24 +01:00
&& rec->r.pubkey.pubkey_algo == pkc->pubkey_algo
1998-01-13 20:04:23 +01:00
&& !memcmp(rec->r.pubkey.fingerprint, fingerprint, fingerlen)
) { /* found */
/* store the local_id */
if( pkc->local_id && pkc->local_id != recnum )
log_error("%s: found record, but local_id from mem does "
"not match recnum (%lu,%lu)\n", db_name,
(ulong)pkc->local_id, (ulong)recnum );
pkc->local_id = recnum;
return 0;
}
}
else
log_bug("not yet implemented\n");
}
if( rc != -1 )
1998-01-14 13:34:05 +01:00
log_error("%s: scan_record_by_pkc failed: %s\n",db_name, g10_errstr(rc) );
1998-01-13 20:04:23 +01:00
return rc;
}
1998-01-12 11:18:17 +01:00
1998-01-14 13:34:05 +01:00
/****************
* scan the DB for a record of type RECTYPE which can be localized
* with LOCAL_ID
*/
static int
1998-01-16 22:15:24 +01:00
scan_record( ulong local_id, TRUSTREC *rec, int rectype, ulong *r_recnum )
1998-01-14 13:34:05 +01:00
{
1998-01-16 22:15:24 +01:00
ulong recnum;
1998-01-14 13:34:05 +01:00
int rc;
assert( rectype == 3 || rectype == 4 );
for(recnum=1; !(rc=read_record( recnum, rec)); recnum++ ) {
if( rec->rectype != rectype )
continue;
if( rec->rectype == 34 ) {
if( rec->r.cache.owner == local_id ) { /* found */
*r_recnum = recnum;
return 0;
}
}
else if( rec->rectype == 4 ) {
if( rec->r.sigrec.owner == local_id ) { /* found */
*r_recnum = recnum;
return 0;
}
}
else
log_bug("not yet implemented\n");
}
if( rc != -1 )
log_error("%s: scan_record failed: %s\n",db_name, g10_errstr(rc) );
return rc;
}
1998-01-12 11:18:17 +01:00
1998-01-16 22:15:24 +01:00
static void
dump_record( ulong rnum, TRUSTREC *rec, FILE *fp )
{
int i, any;
fprintf(fp, "trust record %lu, type=", rnum );
switch( rec->rectype ) {
case 0: fprintf(fp, "free\n");
break;
case 1: fprintf(fp, "version\n");
break;
case 2: fprintf(fp, "pubkey, keyid=%08lX, ownertrust=%02x\n",
rec->r.pubkey.keyid[1], rec->r.pubkey.ownertrust );
break;
case 3: fprintf(fp, "cache\n");
case 4:
case 5:
fprintf(fp, "sigrec, owner=%lu, chain=%lu%s\n",
rec->r.sigrec.owner, rec->r.sigrec.chain,
rec->rectype == 4?"":" (extend)");
for(i=any=0; i < SIGS_PER_RECORD; i++ ) {
if( rec->r.sigrec.sig[i].local_id ) {
if( !any ) {
putc('\t', fp);
any++;
}
fprintf(fp, " %lu:%02x", rec->r.sigrec.sig[i].local_id,
rec->r.sigrec.sig[i].flag );
}
}
if( any )
putc('\n', fp);
break;
default:
fprintf(fp, "%d (unknown)\n", rec->rectype );
break;
}
}
/****************
* If we do not have a local_id in a signature packet, find the owner of
* the signature packet in our trustdb or insert him into the trustdb
*/
static int
set_signature_packets_local_id( PKT_signature *sig )
{
PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
TRUSTREC rec;
int rc;
rc = get_pubkey( pkc, sig->keyid );
if( rc)
goto leave;
if( !pkc->local_id ) {
rc = scan_record_by_pkc( pkc, &rec, 2 );
if( rc == -1 )
rc = insert_trust_record( pkc );
if( rc )
goto leave;
/* fixme: we should propagate the local_id to all copies of the PKC */
}
sig->local_id = pkc->local_id;
leave:
free_public_cert( pkc );
return rc;
}
void
list_trustdb( const char *username )
{
TRUSTREC rec;
if( username ) {
PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
int rc;
if( (rc = get_pubkey_byname( pkc, username )) )
log_error("user '%s' not found: %s\n", username, g10_errstr(rc) );
else if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 )
log_error("problem finding '%s' in trustdb: %s\n",
username, g10_errstr(rc));
else if( rc == -1 )
log_error("user '%s' not in trustdb\n", username);
else if( (rc = list_sigs( pkc->local_id )) )
log_error("user '%s' list problem: %s\n", username, g10_errstr(rc));
free_public_cert( pkc );
}
else {
ulong recnum;
int i;
printf("TrustDB: %s\n", db_name );
for(i=9+strlen(db_name); i > 0; i-- )
putchar('-');
putchar('\n');
for(recnum=0; !read_record( recnum, &rec); recnum++ )
dump_record( recnum, &rec, stdout );
}
}
void
list_trust_path( int max_depth, const char *username )
{
int rc;
1998-01-19 19:54:44 +01:00
int i;
1998-01-16 22:15:24 +01:00
TRUSTREC rec;
PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
1998-01-19 19:54:44 +01:00
if( max_depth < 0 )
1998-01-16 22:15:24 +01:00
max_depth = MAX_LIST_SIGS_DEPTH+1;
if( (rc = get_pubkey_byname( pkc, username )) )
log_error("user '%s' not found: %s\n", username, g10_errstr(rc) );
else if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 )
log_error("problem finding '%s' in trustdb: %s\n",
username, g10_errstr(rc));
else if( rc == -1 )
log_error("user '%s' not in trustdb\n", username);
else {
LOCAL_ID_INFO *lids;
1998-01-19 19:54:44 +01:00
LOCAL_ID_INFO *work;
1998-01-16 22:15:24 +01:00
ulong stack[MAX_LIST_SIGS_DEPTH];
1998-01-19 19:54:44 +01:00
TRUST_SEG_LIST tsl, tslist = NULL;
1998-01-16 22:15:24 +01:00
lids = new_lid_table();
stack[0] = pkc->local_id;
1998-01-19 19:54:44 +01:00
rc = do_list_path( stack, 1, max_depth, lids, &tslist );
/* wipe out duplicates */
work = new_lid_table();
for( tsl=tslist; tsl; tsl = tsl->next ) {
for(i=1; i < tsl->nseg-1; i++ ) {
if( ins_lid_table_item( work, tsl->seg[i], 0 ) ) {
tsl->dup = 1; /* mark as duplicate */
break;
}
}
}
release_lid_table(work);
1998-01-16 22:15:24 +01:00
release_lid_table(lids);
if( rc )
log_error("user '%s' list problem: %s\n", username, g10_errstr(rc));
1998-01-19 19:54:44 +01:00
for(tsl = tslist; tsl; tsl = tsl->next ) {
int i;
if( tsl->dup )
continue;
printf("tslist segs:" );
for(i=0; i < tsl->nseg; i++ )
printf(" %lu", tsl->seg[i]);
putchar('\n');
}
1998-01-16 22:15:24 +01:00
}
free_public_cert( pkc );
}
/****************
* Walk throug the signatures of a public key.
* The caller must provide a context structure, with all fields set
* to zero, but the pubkeyid filed set to the requested pubkey;
* This function does not change this field. On return the context
* is filled with the local-id of the signature and the signature flag.
* No fields should be changed (clearing all fields and setting
* pubkeyid is okay to continue with an other pubkey)
* Returns: 0 - okay, -1 for eof (no more sigs) or any other errorcode
*/
static int
walk_sigrecs( SIGREC_CONTEXT *c )
{
int rc=0;
TRUSTREC *r;
ulong rnum;
if( c->ctl.eof )
return -1;
r = &c->ctl.rec;
if( !r->rectype ) { /* this is the first call */
rc = scan_record( c->pubkey_id, r, 4, &rnum );
if( rc == -1 ) { /* no signature records */
c->ctl.eof = 1;
return -1; /* return eof */
}
if( rc ) {
log_error("scan_record(sigrec) failed: %s\n", g10_errstr(rc));
c->ctl.eof = 1;
return rc;
}
c->ctl.index = 0;
}
/* enter loop to skip deleted sigs */
do {
if( c->ctl.index >= SIGS_PER_RECORD ) {
/* read the next record */
if( !r->r.sigrec.chain ) {
c->ctl.eof = 1;
return -1; /* return eof */
}
rnum = r->r.sigrec.chain;
rc = read_record( rnum, r );
if( rc ) {
log_error("error reading next sigrec: %s\n", g10_errstr(rc));
c->ctl.eof = 1;
return rc;
}
if( r->r.sigrec.owner != c->pubkey_id ) {
log_error("chained sigrec %lu has a wrong owner\n", rnum );
c->ctl.eof = 1;
return G10ERR_TRUSTDB;
}
c->ctl.index = 0;
}
} while( !r->r.sigrec.sig[c->ctl.index++].local_id );
c->sig_id = r->r.sigrec.sig[c->ctl.index-1].local_id;
c->sig_flag = r->r.sigrec.sig[c->ctl.index-1].flag;
return 0;
}
1998-01-12 11:18:17 +01:00
/***********************************************
************* trust logic *******************
***********************************************/
1998-01-16 22:15:24 +01:00
static LOCAL_ID_INFO *
new_lid_table(void)
{
return m_alloc_clear( 16 * sizeof(LOCAL_ID_INFO));
}
static void
release_lid_table( LOCAL_ID_INFO *tbl )
{
LOCAL_ID_INFO a, a2;
int i;
for(i=0; i < 16; i++ ) {
for(a=tbl[i]; a; a = a2 ) {
a2 = a->next;
m_free(a);
}
}
m_free(tbl);
}
/****************
* Add a new item to the table or return 1 if we aread have this item
* fixme: maybe its a good idea to tage items from an unused item list.
*/
static int
1998-01-19 19:54:44 +01:00
ins_lid_table_item( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag )
1998-01-16 22:15:24 +01:00
{
LOCAL_ID_INFO a;
for( a = tbl[lid & 0x0f]; a; a = a->next )
if( a->lid == lid )
return 1;
a = m_alloc( sizeof *a );
a->lid = lid;
a->flag = flag;
a->next = tbl[lid & 0x0f];
tbl[lid & 0x0f] = a;
return 0;
}
static int
1998-01-19 19:54:44 +01:00
qry_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned *flag )
1998-01-16 22:15:24 +01:00
{
LOCAL_ID_INFO a;
for( a = tbl[lid & 0x0f]; a; a = a->next )
if( a->lid == lid ) {
if( flag )
*flag = a->flag;
return 0;
}
return -1;
}
1998-01-19 19:54:44 +01:00
static void
upd_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag )
{
LOCAL_ID_INFO a;
for( a = tbl[lid & 0x0f]; a; a = a->next )
if( a->lid == lid ) {
a->flag = flag;
return;
}
BUG();
}
1998-01-16 22:15:24 +01:00
static int
keyid_from_local_id( ulong lid, u32 *keyid )
{
TRUSTREC rec;
int rc;
rc = read_record( lid, &rec );
if( rc ) {
log_error("error reading record with local_id %lu: %s\n",
lid, g10_errstr(rc));
return G10ERR_TRUSTDB;
}
if( rec.rectype != 2 ) {
log_error("record with local_id %lu is not a pubkey record\n", lid);
return G10ERR_TRUSTDB;
}
keyid[0] = rec.r.pubkey.keyid[0];
keyid[1] = rec.r.pubkey.keyid[1];
return 0;
}
1998-01-13 20:04:23 +01:00
/****************
* Verify, that all our public keys are in the trustDB and marked as
* ultimately trusted.
*/
static int
verify_own_certs()
{
int rc;
void *enum_context = NULL;
PKT_secret_cert *skc = m_alloc_clear( sizeof *skc );
PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
u32 keyid[2];
int trust;
while( !(rc=enum_secret_keys( &enum_context, skc) ) ) {
1998-01-16 22:15:24 +01:00
/* fixed: to be sure that it is a secret key of our own,
1998-01-13 20:04:23 +01:00
* we should check it, but this needs a passphrase
* for every key and this boring for the user.
* Solution: Sign the secring and the trustring
* and verify this signature during
* startup
*/
keyid_from_skc( skc, keyid );
if( DBG_TRUST )
log_debug("checking secret key %08lX\n", (ulong)keyid[1] );
/* look wether we can access the public key of this secret key */
rc = get_pubkey( pkc, keyid );
if( rc ) {
log_error("keyid %08lX: secret key without public key\n",
(ulong)keyid[1] );
goto leave;
}
if( cmp_public_secret_cert( pkc, skc ) ) {
log_error("keyid %08lX: secret and public key don't match\n",
(ulong)keyid[1] );
rc = G10ERR_GENERAL;
goto leave;
}
/* look into the trustdb */
1998-01-19 19:54:44 +01:00
rc = check_trust( pkc, &trust );
1998-01-13 20:04:23 +01:00
if( rc ) {
log_info("keyid %08lX: problem in trustdb: %s\n", (ulong)keyid[1],
g10_errstr(rc) );
goto leave;
}
1998-01-19 19:54:44 +01:00
if( trust == TRUST_UNKNOWN ) {
1998-01-16 22:15:24 +01:00
rc = insert_trust_record( pkc );
if( rc )
log_error("keyid %08lX: insert failed: %s\n",
(ulong)keyid[1], g10_errstr(rc) );
else
log_info("keyid %08lX: inserted\n", (ulong)keyid[1] );
1998-01-13 20:04:23 +01:00
}
1998-01-19 19:54:44 +01:00
else {
/* FIXME: we should chek the other values */
1998-01-16 22:15:24 +01:00
}
1998-01-19 19:54:44 +01:00
if( DBG_TRUST )
log_debug("putting %08lX(%lu) into ultikey_table\n",
(ulong)keyid[1], pkc->local_id );
if( ins_lid_table_item( ultikey_table, pkc->local_id, 0 ) )
log_error("keyid %08lX: already in ultikey_table\n",
(ulong)keyid[1]);
1998-01-13 20:04:23 +01:00
release_secret_cert_parts( skc );
release_public_cert_parts( pkc );
}
if( rc != -1 )
log_error("enum_secret_keys failed: %s\n", g10_errstr(rc) );
else
rc = 0;
leave:
free_secret_cert( skc );
free_public_cert( pkc );
return rc;
}
1998-01-16 22:15:24 +01:00
static void
print_user_id( const char *text, u32 *keyid )
{
char *p;
size_t n;
p = get_user_id( keyid, &n );
if( *text ) {
fputs( text, stdout);
putchar(' ');
}
putchar('\"');
print_string( stdout, p, n );
putchar('\"');
putchar('\n');
m_free(p);
}
/* (a non-recursive algorithm would be easier) */
static int
do_list_sigs( ulong root, ulong pubkey, int depth,
LOCAL_ID_INFO *lids, unsigned *lineno )
{
SIGREC_CONTEXT sx;
int rc;
u32 keyid[2];
memset( &sx, 0, sizeof sx );
sx.pubkey_id = pubkey;
for(;;) {
rc = walk_sigrecs( &sx );
if( rc )
break;
rc = keyid_from_local_id( sx.sig_id, keyid );
if( rc ) {
printf("%6u: %*s????????(%lu:%02x)\n", *lineno, depth*4, "",
sx.sig_id, sx.sig_flag );
++*lineno;
}
else {
printf("%6u: %*s%08lX(%lu:%02x) ", *lineno, depth*4, "",
(ulong)keyid[1], sx.sig_id, sx.sig_flag );
/* check wether we already checked this pubkey */
1998-01-19 19:54:44 +01:00
if( !qry_lid_table_flag( ultikey_table, sx.sig_id, NULL ) ) {
1998-01-16 22:15:24 +01:00
print_user_id("[ultimately trusted]", keyid);
++*lineno;
}
else if( sx.sig_id == pubkey ) {
printf("[self-signature]\n");
++*lineno;
}
else if( sx.sig_id == root ) {
printf("[closed]\n");
++*lineno;
}
1998-01-19 19:54:44 +01:00
else if( ins_lid_table_item( lids, sx.sig_id, *lineno ) ) {
1998-01-16 22:15:24 +01:00
unsigned refline;
1998-01-19 19:54:44 +01:00
qry_lid_table_flag( lids, sx.sig_id, &refline );
1998-01-16 22:15:24 +01:00
printf("[see line %u]\n", refline);
++*lineno;
}
else if( depth+1 >= MAX_LIST_SIGS_DEPTH ) {
print_user_id( "[too deeply nested]", keyid );
++*lineno;
}
else {
print_user_id( "", keyid );
++*lineno;
rc = do_list_sigs( root, sx.sig_id, depth+1, lids, lineno );
if( rc )
break;
}
}
}
return rc==-1? 0 : rc;
}
/****************
* List all signatures of a public key
*/
static int
list_sigs( ulong pubkey_id )
{
int rc;
u32 keyid[2];
LOCAL_ID_INFO *lids;
unsigned lineno = 1;
rc = keyid_from_local_id( pubkey_id, keyid );
if( rc ) {
log_error("Hmmm, no pubkey record for local_id %lu\n", pubkey_id);
return rc;
}
printf("Signatures of %08lX(%lu) ", (ulong)keyid[1], pubkey_id );
print_user_id("", keyid);
printf("----------------------\n");
lids = new_lid_table();
rc = do_list_sigs( pubkey_id, pubkey_id, 0, lids, &lineno );
putchar('\n');
release_lid_table(lids);
return rc;
}
static int
1998-01-19 19:54:44 +01:00
do_list_path( ulong *stack, int depth, int max_depth,
LOCAL_ID_INFO *lids, TRUST_SEG_LIST *tslist )
1998-01-16 22:15:24 +01:00
{
SIGREC_CONTEXT sx;
1998-01-19 19:54:44 +01:00
unsigned last_depth;
1998-01-16 22:15:24 +01:00
int rc;
1998-01-19 19:54:44 +01:00
assert(depth);
/*printf("%2lu/%d: scrutinizig\n", stack[depth-1], depth);*/
if( depth >= max_depth || depth >= MAX_LIST_SIGS_DEPTH-1 ) {
/*printf("%2lu/%d: to deeply nested\n", stack[depth-1], depth);*/
1998-01-16 22:15:24 +01:00
return 0;
1998-01-19 19:54:44 +01:00
}
memset( &sx, 0, sizeof sx );
sx.pubkey_id = stack[depth-1];
while( !(rc = walk_sigrecs( &sx )) ) {
TRUST_SEG_LIST tsl, t2, tl;
1998-01-16 22:15:24 +01:00
int i;
1998-01-19 19:54:44 +01:00
stack[depth] = sx.sig_id;
if( qry_lid_table_flag( lids, sx.sig_id, &last_depth) ) {
/*printf("%2lu/%d: marked\n", sx.sig_id, depth );*/
ins_lid_table_item( lids, sx.sig_id, depth);
last_depth = depth;
}
else if( depth < last_depth ) {
/*printf("%2lu/%d: last_depth=%u - updated\n", sx.sig_id, depth, last_depth);*/
last_depth = depth;
upd_lid_table_flag( lids, sx.sig_id, depth);
}
if( last_depth < depth )
/*printf("%2lu/%d: already visited\n", sx.sig_id, depth)*/;
else if( !qry_lid_table_flag( ultikey_table, sx.sig_id, NULL ) ) {
/* found end of path; store it, ordered by path length */
tsl = m_alloc( sizeof *tsl + depth*sizeof(ulong) );
tsl->nseg = depth+1;
tsl->dup = 0;
for(i=0; i <= depth; i++ )
tsl->seg[i] = stack[i];
for(t2=*tslist,tl=NULL; t2; tl=t2, t2 = t2->next )
if( depth < t2->nseg )
break;
if( !tl ) {
tsl->next = t2;
*tslist = tsl;
}
1998-01-16 22:15:24 +01:00
else {
1998-01-19 19:54:44 +01:00
tsl->next = t2;
tl->next = tsl;
1998-01-16 22:15:24 +01:00
}
1998-01-19 19:54:44 +01:00
/*putchar('.'); fflush(stdout);*/
/*printf("%2lu/%d: found\n", sx.sig_id, depth);*/
1998-01-16 22:15:24 +01:00
}
1998-01-19 19:54:44 +01:00
else {
rc = do_list_path( stack, depth+1, max_depth, lids, tslist);
if( rc && rc != -1 )
break;
1998-01-16 22:15:24 +01:00
}
1998-01-19 19:54:44 +01:00
}
1998-01-16 22:15:24 +01:00
return rc==-1? 0 : rc;
}
1998-01-12 11:18:17 +01:00
1998-01-13 20:04:23 +01:00
/****************
* Check all the sigs of the given keyblock and mark them
* as checked.
*/
static int
1998-01-16 22:15:24 +01:00
check_sigs( KBNODE keyblock, int *selfsig_okay )
1998-01-13 20:04:23 +01:00
{
KBNODE kbctx;
KBNODE node;
int rc;
1998-01-16 22:15:24 +01:00
*selfsig_okay = 0;
1998-01-13 20:04:23 +01:00
for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
if( node->pkt->pkttype == PKT_SIGNATURE
&& (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
1998-01-16 22:15:24 +01:00
int selfsig;
rc = check_key_signature( keyblock, node, &selfsig );
if( !rc ) {
if( selfsig ) {
node->flag |= 2; /* mark signature valid */
*selfsig_okay = 1;
}
else
node->flag |= 1; /* mark signature valid */
}
1998-01-13 20:04:23 +01:00
if( DBG_TRUST )
log_debug("trustdb: sig from %08lX: %s\n",
1998-01-16 22:15:24 +01:00
(ulong)node->pkt->pkt.signature->keyid[1],
g10_errstr(rc) );
1998-01-13 20:04:23 +01:00
}
}
return 0;
}
1998-01-14 13:34:05 +01:00
/****************
* If we do not have sigrecs for the given key, build them and write them
* to the trustdb
*/
static int
1998-01-16 22:15:24 +01:00
build_sigrecs( ulong pubkeyid )
1998-01-14 13:34:05 +01:00
{
1998-01-16 22:15:24 +01:00
TRUSTREC rec, rec2;
PUBKEY_FIND_INFO finfo=NULL;
KBPOS kbpos;
KBNODE keyblock = NULL;
KBNODE kbctx;
KBNODE node;
int rc=0;
int i, selfsig;
ulong rnum, rnum2;
if( DBG_TRUST )
log_debug("trustdb: build_sigrecs for pubkey %lu\n", (ulong)pubkeyid );
/* get the keyblock */
if( (rc=read_record( pubkeyid, &rec )) ) {
log_error("build_sigrecs: can't read pubkey record\n");
goto leave;
}
finfo = m_alloc_clear( sizeof *finfo );
finfo->keyid[0] = rec.r.pubkey.keyid[0];
finfo->keyid[1] = rec.r.pubkey.keyid[1];
finfo->pubkey_algo = rec.r.pubkey.pubkey_algo;
memcpy( finfo->fingerprint, rec.r.pubkey.fingerprint, 20);
rc = find_keyblock( finfo, &kbpos );
if( rc ) {
log_error("build_sigrecs: find_keyblock failed\n" );
goto leave;
}
rc = read_keyblock( &kbpos, &keyblock );
if( rc ) {
log_error("build_sigrecs: read_keyblock failed\n" );
goto leave;
}
/* check all key signatures */
rc = check_sigs( keyblock, &selfsig );
if( rc ) {
log_error("build_sigrecs: check_sigs failed\n" );
goto leave;
}
if( !selfsig ) {
log_error("build_sigrecs: self-certificate missing\n" );
rc = G10ERR_BAD_CERT;
goto leave;
}
/* valid key signatures are now marked; we can now build the
* sigrecs */
memset( &rec, 0, sizeof rec );
rec.rectype = 4;
i = 0;
rnum = rnum2 = 0;
for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
if( node->flag & 1 ) {
assert( node->pkt->pkttype == PKT_SIGNATURE );
if( !node->pkt->pkt.signature->local_id ) {
/* the next function should always succeed, because
* we have already checked the signature, and for this
* it was necessary to have the pubkey. The only reason
* this can fail are I/o erros of the trustdb. */
rc = set_signature_packets_local_id( node->pkt->pkt.signature );
if( rc )
log_fatal("set_signature_packets_local_id failed: %s\n",
g10_errstr(rc));
}
if( i == SIGS_PER_RECORD ) {
/* write the record */
rnum = new_recnum();
if( rnum2 ) { /* write the stored record */
rec2.r.sigrec.owner = pubkeyid;
rec2.r.sigrec.chain = rnum; /* the next record number */
rc = write_record( rnum2, &rec2 );
if( rc ) {
log_error("build_sigrecs: write_record failed\n" );
goto leave;
}
}
rec2 = rec;
rnum2 = rnum;
memset( &rec, 0, sizeof rec );
rec.rectype = 5;
i = 0;
}
rec.r.sigrec.sig[i].local_id = node->pkt->pkt.signature->local_id;
rec.r.sigrec.sig[i].flag = 0;
i++;
}
}
if( i || rnum2 ) {
/* write the record */
rnum = new_recnum();
if( rnum2 ) { /* write the stored record */
rec2.r.sigrec.owner = pubkeyid;
rec2.r.sigrec.chain = rnum;
rc = write_record( rnum2, &rec2 );
if( rc ) {
log_error("build_sigrecs: write_record failed\n" );
goto leave;
}
}
if( i ) { /* write the pending record */
rec.r.sigrec.owner = pubkeyid;
rec.r.sigrec.chain = 0;
rc = write_record( rnum, &rec );
if( rc ) {
log_error("build_sigrecs: write_record failed\n" );
goto leave;
}
}
}
leave:
m_free( finfo );
release_kbnode( keyblock );
if( DBG_TRUST )
log_debug("trustdb: build_sigrecs: %s\n", g10_errstr(rc) );
return rc;
1998-01-14 13:34:05 +01:00
}
1998-01-13 20:04:23 +01:00
/****************
*
*/
static int
1998-01-19 19:54:44 +01:00
do_check( ulong pubkeyid, int *trustlevel )
1998-01-13 20:04:23 +01:00
{
1998-01-16 22:15:24 +01:00
int rc=0;
ulong rnum;
TRUSTREC rec;
/* verify the cache */
/* do we have sigrecs */
rc = scan_record( pubkeyid, &rec, 4, &rnum );
if( rc == -1 ) { /* no sigrecs, so build them */
rc = build_sigrecs( pubkeyid );
if( !rc ) /* and read again */
rc = scan_record( pubkeyid, &rec, 4, &rnum );
}
if( rc )
return rc; /* error while looking for sigrec or building sigrecs */
1998-01-14 13:34:05 +01:00
1998-01-16 22:15:24 +01:00
return 0;
1998-01-13 20:04:23 +01:00
}
1998-01-12 11:18:17 +01:00
/*********************************************************
**************** API Interface ************************
*********************************************************/
/****************
* Perform some checks over the trustdb
1998-01-16 22:15:24 +01:00
* level 0: only open the db
* 1: used for initial program startup
1998-01-12 11:18:17 +01:00
*/
int
1998-01-16 22:15:24 +01:00
init_trustdb( int level )
1998-01-12 11:18:17 +01:00
{
1998-01-13 20:04:23 +01:00
int rc=0;
1998-01-16 22:15:24 +01:00
if( !ultikey_table )
ultikey_table = new_lid_table();
if( !level || level==1 ) {
char *fname = make_filename("~/.g10", "trustdb.g10", NULL );
1998-01-12 11:18:17 +01:00
if( access( fname, R_OK ) ) {
if( errno != ENOENT ) {
log_error("can't access %s: %s\n", fname, strerror(errno) );
m_free(fname);
return G10ERR_TRUSTDB;
}
1998-01-16 22:15:24 +01:00
if( level )
create_db( fname );
1998-01-12 11:18:17 +01:00
}
m_free(db_name);
db_name = fname;
1998-01-16 22:15:24 +01:00
if( !level )
return 0;
1998-01-12 11:18:17 +01:00
/* we can verify a signature about our local data (secring and trustdb)
1998-01-13 20:04:23 +01:00
* in ~/.g10/ here */
rc = verify_private_data();
if( !rc ) {
/* verify, that our own certificates are in the trustDB
* or move them to the trustdb. */
rc = verify_own_certs();
/* should we check wether there is no other ultimately trusted
* key in the database? */
}
1998-01-12 11:18:17 +01:00
}
else
1998-01-16 22:15:24 +01:00
BUG();
1998-01-12 11:18:17 +01:00
1998-01-13 20:04:23 +01:00
return rc;
1998-01-12 11:18:17 +01:00
}
/****************
* Get the trustlevel for this PKC.
* Note: This does not ask any questions
* Returns: 0 okay of an errorcode
*
* It operates this way:
* locate the pkc in the trustdb
* found:
* Do we have a valid cache record for it?
* yes: return trustlevel from cache
1998-01-14 13:34:05 +01:00
* no: make a cache record and all the other stuff
1998-01-12 11:18:17 +01:00
* not found:
* Return with a trustlevel, saying that we do not have
* a trust record for it. The caller may use insert_trust_record()
* and then call this function here again.
*
* Problems: How do we get the complete keyblock to check that the
* cache record is actually valid? Think we need a clever
* cache in getkey.c to keep track of this stuff. Maybe it
* is not necessary to check this if we use a local pubring. Hmmmm.
*/
int
1998-01-19 19:54:44 +01:00
check_trust( PKT_public_cert *pkc, int *r_trustlevel )
1998-01-12 11:18:17 +01:00
{
1998-01-13 20:04:23 +01:00
TRUSTREC rec;
1998-01-19 19:54:44 +01:00
int trustlevel = TRUST_UNKNOWN;
1998-01-13 20:04:23 +01:00
int rc=0;
1998-01-12 11:18:17 +01:00
1998-01-19 19:54:44 +01:00
if( DBG_TRUST )
log_info("check_trust() called.\n");
1998-01-12 11:18:17 +01:00
1998-01-13 20:04:23 +01:00
/* get the pubkey record */
if( pkc->local_id ) {
if( read_record( pkc->local_id, &rec ) ) {
1998-01-19 19:54:44 +01:00
log_error("check_trust: read record failed\n");
1998-01-13 20:04:23 +01:00
return G10ERR_TRUSTDB;
}
}
else { /* no local_id: scan the trustdb */
1998-01-14 13:34:05 +01:00
if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 ) {
1998-01-19 19:54:44 +01:00
log_error("check_trust: scan_record_by_pkc(2) failed: %s\n",
1998-01-13 20:04:23 +01:00
g10_errstr(rc));
1998-01-16 22:15:24 +01:00
return rc;
1998-01-13 20:04:23 +01:00
}
else if( rc == -1 ) {
1998-01-19 19:54:44 +01:00
log_error("check_trust: pubkey not in TrustDB\n");
1998-01-13 20:04:23 +01:00
goto leave;
}
}
/* fixme: do some additional checks on the pubkey record */
1998-01-19 19:54:44 +01:00
rc = do_check( pkc->local_id, &trustlevel );
1998-01-16 22:15:24 +01:00
if( rc ) {
1998-01-19 19:54:44 +01:00
log_error("check_trust: do_check failed: %s\n", g10_errstr(rc));
1998-01-16 22:15:24 +01:00
return rc;
}
1998-01-19 19:54:44 +01:00
if( !rec.r.pubkey.ownertrust )
trustlevel = TRUST_UNDEFINED;
else
trustlevel = TRUST_EXPIRED;
1998-01-14 13:34:05 +01:00
1998-01-13 20:04:23 +01:00
leave:
1998-01-19 19:54:44 +01:00
if( DBG_TRUST )
log_info("check_trust() returns trustlevel %04x.\n", trustlevel);
1998-01-12 11:18:17 +01:00
*r_trustlevel = trustlevel;
return 0;
}
1998-01-02 21:40:10 +01:00
1998-01-13 20:04:23 +01:00
1998-01-16 22:15:24 +01:00
int
get_ownertrust( PKT_public_cert *pkc, int *r_otrust )
{
TRUSTREC rec;
int rc;
/* get the pubkey record */
if( pkc->local_id ) {
if( read_record( pkc->local_id, &rec ) ) {
log_error("get_ownertrust: read record failed\n");
return G10ERR_TRUSTDB;
}
}
else { /* no local_id: scan the trustdb */
if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 ) {
log_error("get_ownertrust: scan_record_by_pkc(2) failed: %s\n",
g10_errstr(rc));
return rc;
}
else if( rc == -1 )
return rc;
}
*r_otrust = rec.r.pubkey.ownertrust;
return 0;
}
1998-01-13 20:04:23 +01:00
/****************
* Insert a trust record into the TrustDB
* This function failes if this record already exists.
*/
int
insert_trust_record( PKT_public_cert *pkc )
{
TRUSTREC rec;
u32 keyid[2];
1998-01-16 22:15:24 +01:00
ulong recnum;
1998-01-13 20:04:23 +01:00
byte *fingerprint;
size_t fingerlen;
1998-01-16 22:15:24 +01:00
if( pkc->local_id )
log_bug("pkc->local_id=%lu\n", (ulong)pkc->local_id );
1998-01-13 20:04:23 +01:00
keyid_from_pkc( pkc, keyid );
fingerprint = fingerprint_from_pkc( pkc, &fingerlen );
/* FIXME: check that we do not have this record. */
1998-01-16 22:15:24 +01:00
recnum = new_recnum();
1998-01-13 20:04:23 +01:00
/* build record */
memset( &rec, 0, sizeof rec );
rec.rectype = 2; /* the pubkey record */
rec.r.pubkey.local_id = recnum;
rec.r.pubkey.keyid[0] = keyid[0];
rec.r.pubkey.keyid[1] = keyid[1];
1998-01-16 22:15:24 +01:00
rec.r.pubkey.pubkey_algo = pkc->pubkey_algo;
1998-01-13 20:04:23 +01:00
memcpy(rec.r.pubkey.fingerprint, fingerprint, fingerlen );
rec.r.pubkey.ownertrust = 0;
if( write_record( recnum, &rec ) ) {
log_error("insert_trust_record: write failed\n");
return G10ERR_TRUSTDB;
}
pkc->local_id = recnum;
return 0;
}
int
update_trust_record( PKT_public_cert *pkc, int new_trust )
{
TRUSTREC rec;
1998-01-16 22:15:24 +01:00
ulong recnum;
1998-01-13 20:04:23 +01:00
assert( pkc->local_id );
if( read_record( pkc->local_id, &rec ) ) {
log_error("update_trust_record: read failed\n");
return G10ERR_TRUSTDB;
}
/* check keyid, fingerprint etc ? */
rec.r.pubkey.ownertrust = 0;
if( write_record( recnum, &rec ) ) {
log_error("insert_trust_record: write failed\n");
return G10ERR_TRUSTDB;
}
return 0;
}
int
verify_private_data()
{
int rc = 0;
char *sigfile = make_filename("~/.g10", "sig", NULL );
if( access( sigfile, R_OK ) ) {
if( errno != ENOENT ) {
log_error("can't access %s: %s\n", sigfile, strerror(errno) );
rc = G10ERR_TRUSTDB;
goto leave;
}
log_info("private data signature missing; creating ...\n");
rc = sign_private_data();
if( rc ) {
log_error("error creating %s: %s\n", sigfile, g10_errstr(rc) );
goto leave;
}
}
/* FIXME: verify this signature */
leave:
m_free(sigfile);
return rc;
}
int
sign_private_data()
{
int rc;
char *sigfile = make_filename("~/.g10", "sig", NULL );
char *secring = make_filename("~/.g10", "secring.g10", NULL );
STRLIST list = NULL;
add_to_strlist( &list, db_name );
add_to_strlist( &list, secring );
rc = sign_file( list, 1, NULL, 0, NULL, sigfile);
m_free(sigfile);
m_free(secring);
free_strlist(list);
return rc;
}