1998-01-02 21:40:10 +01:00
|
|
|
/* trustdb.c
|
1998-02-24 19:50:46 +01:00
|
|
|
* Copyright (C) 1998 Free Software Foundation, Inc.
|
1998-01-02 21:40:10 +01:00
|
|
|
*
|
1998-02-24 19:50:46 +01:00
|
|
|
* This file is part of GNUPG.
|
1998-01-02 21:40:10 +01:00
|
|
|
*
|
1998-02-24 19:50:46 +01:00
|
|
|
* GNUPG is free software; you can redistribute it and/or modify
|
1998-01-02 21:40:10 +01:00
|
|
|
* 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.
|
|
|
|
*
|
1998-02-24 19:50:46 +01:00
|
|
|
* GNUPG is distributed in the hope that it will be useful,
|
1998-01-02 21:40:10 +01:00
|
|
|
* 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>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <assert.h>
|
1998-02-17 21:48:52 +01:00
|
|
|
#include <sys/types.h>
|
1998-05-13 19:53:36 +02:00
|
|
|
#include <sys/stat.h>
|
1998-01-13 20:04:23 +01:00
|
|
|
#include <fcntl.h>
|
1998-02-17 21:48:52 +01:00
|
|
|
#include <unistd.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-04-02 12:30:03 +02:00
|
|
|
#include "i18n.h"
|
1998-07-09 15:37:17 +02:00
|
|
|
#include "tdbio.h"
|
1998-01-02 21:40:10 +01:00
|
|
|
|
|
|
|
|
1998-01-16 22:15:24 +01:00
|
|
|
typedef struct local_id_info *LOCAL_ID_INFO;
|
|
|
|
struct local_id_info {
|
|
|
|
LOCAL_ID_INFO next;
|
|
|
|
ulong lid;
|
|
|
|
unsigned flag;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
1998-01-24 17:32:27 +01:00
|
|
|
typedef struct trust_info TRUST_INFO;
|
|
|
|
struct trust_info {
|
|
|
|
ulong lid;
|
|
|
|
unsigned trust;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
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;
|
1998-01-24 17:32:27 +01:00
|
|
|
TRUST_INFO seg[1]; /* segment list */
|
1998-01-19 19:54:44 +01:00
|
|
|
};
|
|
|
|
|
1998-01-12 11:18:17 +01:00
|
|
|
|
1998-01-24 17:32:27 +01:00
|
|
|
typedef struct {
|
|
|
|
TRUST_SEG_LIST tsl;
|
|
|
|
int index;
|
|
|
|
} ENUM_TRUST_WEB_CONTEXT;
|
|
|
|
|
|
|
|
|
1998-01-25 19:56:33 +01:00
|
|
|
static int walk_sigrecs( SIGREC_CONTEXT *c, int create );
|
1998-01-16 22:15:24 +01:00
|
|
|
|
|
|
|
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-24 17:32:27 +01:00
|
|
|
static int do_list_path( TRUST_INFO *stack, int depth, int max_depth,
|
1998-01-19 19:54:44 +01:00
|
|
|
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-31 22:24:36 +01:00
|
|
|
static int build_sigrecs( ulong pubkeyid );
|
1998-01-24 17:32:27 +01:00
|
|
|
static int propagate_trust( TRUST_SEG_LIST tslist );
|
1998-01-31 22:24:36 +01:00
|
|
|
static int do_check( ulong pubkeyid, TRUSTREC *drec, unsigned *trustlevel );
|
1998-01-16 22:15:24 +01:00
|
|
|
|
1998-01-25 19:56:33 +01:00
|
|
|
static int update_no_sigs( ulong lid, int no_sigs );
|
1998-01-12 11:18:17 +01:00
|
|
|
|
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-24 17:32:27 +01:00
|
|
|
static ulong last_trust_web_key;
|
|
|
|
static TRUST_SEG_LIST last_trust_web_tslist;
|
|
|
|
|
1998-01-12 11:18:17 +01:00
|
|
|
|
1998-01-30 21:25:31 +01:00
|
|
|
/**********************************************
|
|
|
|
************* list helpers *******************
|
|
|
|
**********************************************/
|
|
|
|
|
|
|
|
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 already have this item
|
1998-04-14 19:51:16 +02:00
|
|
|
* fixme: maybe it's a good idea to take items from an unused item list.
|
1998-01-30 21:25:31 +01:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
ins_lid_table_item( 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 )
|
|
|
|
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
|
|
|
|
qry_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 ) {
|
|
|
|
if( flag )
|
|
|
|
*flag = a->flag;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
/****************
|
1998-01-30 21:25:31 +01:00
|
|
|
* If we do not have a local_id in a signature packet, find the owner of
|
1998-04-14 19:51:16 +02:00
|
|
|
* the signature packet in our trustdb or insert them into the trustdb
|
1998-01-30 21:25:31 +01:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
set_signature_packets_local_id( PKT_signature *sig )
|
|
|
|
{
|
1998-06-29 14:30:57 +02:00
|
|
|
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
|
1998-01-30 21:25:31 +01:00
|
|
|
TRUSTREC rec;
|
|
|
|
int rc;
|
1998-01-19 19:54:44 +01:00
|
|
|
|
1998-06-29 14:30:57 +02:00
|
|
|
rc = get_pubkey( pk, sig->keyid );
|
1998-01-30 21:25:31 +01:00
|
|
|
if( rc)
|
|
|
|
goto leave;
|
1998-06-29 14:30:57 +02:00
|
|
|
if( !pk->local_id ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
rc = tdbio_search_record( pk, &rec );
|
1998-01-30 21:25:31 +01:00
|
|
|
if( rc == -1 )
|
1998-06-29 14:30:57 +02:00
|
|
|
rc = insert_trust_record( pk );
|
1998-01-30 21:25:31 +01:00
|
|
|
if( rc )
|
|
|
|
goto leave;
|
1998-06-29 14:30:57 +02:00
|
|
|
/* fixme: we should propagate the local_id to all copies of the PK */
|
1998-01-16 22:15:24 +01:00
|
|
|
}
|
1998-06-29 14:30:57 +02:00
|
|
|
sig->local_id = pk->local_id;
|
1998-01-16 22:15:24 +01:00
|
|
|
|
1998-01-30 21:25:31 +01:00
|
|
|
leave:
|
1998-06-29 14:30:57 +02:00
|
|
|
free_public_key( pk );
|
1998-01-30 21:25:31 +01:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
keyid_from_local_id( ulong lid, u32 *keyid )
|
|
|
|
{
|
|
|
|
TRUSTREC rec;
|
|
|
|
int rc;
|
|
|
|
|
1998-07-09 15:37:17 +02:00
|
|
|
rc = tdbio_read_record( lid, &rec, RECTYPE_DIR );
|
1998-01-30 21:25:31 +01:00
|
|
|
if( rc ) {
|
1998-04-20 16:47:21 +02:00
|
|
|
log_error(_("error reading record with local_id %lu: %s\n"),
|
1998-01-30 21:25:31 +01:00
|
|
|
lid, g10_errstr(rc));
|
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
}
|
|
|
|
if( rec.rectype != RECTYPE_DIR ) {
|
1998-04-20 16:47:21 +02:00
|
|
|
log_error(_("record with local_id %lu is not a dir record\n"), lid);
|
1998-01-30 21:25:31 +01:00
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
}
|
|
|
|
keyid[0] = rec.r.dir.keyid[0];
|
|
|
|
keyid[1] = rec.r.dir.keyid[1];
|
|
|
|
return 0;
|
1998-01-16 22:15:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************
|
1998-04-14 19:51:16 +02:00
|
|
|
* Walk through the signatures of a public key.
|
1998-01-16 22:15:24 +01:00
|
|
|
* The caller must provide a context structure, with all fields set
|
1998-01-30 21:25:31 +01:00
|
|
|
* to zero, but the local_id field set to the requested key;
|
1998-01-16 22:15:24 +01:00
|
|
|
* 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
|
1998-01-25 19:56:33 +01:00
|
|
|
walk_sigrecs( SIGREC_CONTEXT *c, int create )
|
1998-01-16 22:15:24 +01:00
|
|
|
{
|
|
|
|
int rc=0;
|
|
|
|
TRUSTREC *r;
|
|
|
|
ulong rnum;
|
|
|
|
|
|
|
|
if( c->ctl.eof )
|
|
|
|
return -1;
|
|
|
|
r = &c->ctl.rec;
|
1998-01-31 22:24:36 +01:00
|
|
|
if( !c->ctl.init_done ) {
|
|
|
|
c->ctl.init_done = 1;
|
|
|
|
if( !c->sigrec ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
rc = tdbio_read_record( c->local_id, r, RECTYPE_DIR );
|
1998-01-25 19:56:33 +01:00
|
|
|
if( rc ) {
|
1998-04-20 16:47:21 +02:00
|
|
|
log_error(_("%lu: error reading dir record: %s\n"),
|
1998-01-31 22:24:36 +01:00
|
|
|
c->local_id, g10_errstr(rc));
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
c->sigrec = r->r.dir.sigrec;
|
|
|
|
if( !c->sigrec && create && !r->r.dir.no_sigs ) {
|
|
|
|
rc = build_sigrecs( c->local_id );
|
|
|
|
if( rc ) {
|
1998-02-02 15:36:06 +01:00
|
|
|
if( rc == G10ERR_BAD_CERT )
|
|
|
|
rc = -1; /* maybe no selcficnature */
|
1998-01-31 22:24:36 +01:00
|
|
|
if( rc != -1 )
|
1998-04-20 16:47:21 +02:00
|
|
|
log_info(_("%lu: error building sigs on the fly: %s\n"),
|
1998-01-31 22:24:36 +01:00
|
|
|
c->local_id, g10_errstr(rc) );
|
|
|
|
c->ctl.eof = 1;
|
|
|
|
return rc;
|
|
|
|
}
|
1998-07-09 15:37:17 +02:00
|
|
|
rc = tdbio_read_record( c->local_id, r, RECTYPE_DIR );
|
1998-01-31 22:24:36 +01:00
|
|
|
if( rc ) {
|
1998-04-20 16:47:21 +02:00
|
|
|
log_error(_("%lu: error re-reading dir record: %s\n"),
|
1998-01-31 22:24:36 +01:00
|
|
|
c->local_id, g10_errstr(rc));
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
c->sigrec = r->r.dir.sigrec;
|
|
|
|
}
|
|
|
|
if( !c->sigrec ) {
|
|
|
|
c->ctl.eof = 1;
|
|
|
|
return -1;
|
1998-01-25 19:56:33 +01:00
|
|
|
}
|
1998-01-16 22:15:24 +01:00
|
|
|
}
|
1998-01-31 22:24:36 +01:00
|
|
|
/* force a read */
|
|
|
|
c->ctl.index = SIGS_PER_RECORD;
|
|
|
|
r->r.sig.chain = c->sigrec;
|
1998-01-16 22:15:24 +01:00
|
|
|
}
|
1998-01-31 22:24:36 +01:00
|
|
|
|
1998-01-16 22:15:24 +01:00
|
|
|
/* enter loop to skip deleted sigs */
|
|
|
|
do {
|
|
|
|
if( c->ctl.index >= SIGS_PER_RECORD ) {
|
1998-01-31 22:24:36 +01:00
|
|
|
/* read the record */
|
|
|
|
rnum = r->r.sig.chain;
|
|
|
|
if( !rnum ) {
|
1998-01-16 22:15:24 +01:00
|
|
|
c->ctl.eof = 1;
|
|
|
|
return -1; /* return eof */
|
|
|
|
}
|
1998-07-09 15:37:17 +02:00
|
|
|
rc = tdbio_read_record( rnum, r, RECTYPE_SIG );
|
1998-01-16 22:15:24 +01:00
|
|
|
if( rc ) {
|
1998-04-20 16:47:21 +02:00
|
|
|
log_error(_("error reading sigrec: %s\n"), g10_errstr(rc));
|
1998-01-16 22:15:24 +01:00
|
|
|
c->ctl.eof = 1;
|
|
|
|
return rc;
|
|
|
|
}
|
1998-01-31 22:24:36 +01:00
|
|
|
if( r->r.sig.owner != c->local_id ) {
|
1998-04-20 16:47:21 +02:00
|
|
|
log_error(_("chained sigrec %lu has a wrong owner\n"), rnum );
|
1998-01-16 22:15:24 +01:00
|
|
|
c->ctl.eof = 1;
|
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
}
|
|
|
|
c->ctl.index = 0;
|
|
|
|
}
|
1998-01-31 22:24:36 +01:00
|
|
|
} while( !r->r.sig.sig[c->ctl.index++].local_id );
|
|
|
|
c->sig_id = r->r.sig.sig[c->ctl.index-1].local_id;
|
|
|
|
c->sig_flag = r->r.sig.sig[c->ctl.index-1].flag;
|
1998-01-16 22:15:24 +01:00
|
|
|
return 0;
|
|
|
|
}
|
1998-01-12 11:18:17 +01:00
|
|
|
|
1998-01-16 22:15:24 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
1998-01-30 21:25:31 +01:00
|
|
|
/***********************************************
|
|
|
|
************* Trust stuff ******************
|
|
|
|
***********************************************/
|
1998-01-16 22:15:24 +01:00
|
|
|
|
|
|
|
|
1998-01-13 20:04:23 +01:00
|
|
|
/****************
|
1998-04-14 19:51:16 +02:00
|
|
|
* Verify that all our public keys are in the trustDB.
|
1998-01-13 20:04:23 +01:00
|
|
|
*/
|
|
|
|
static int
|
1998-06-29 14:30:57 +02:00
|
|
|
verify_own_keys()
|
1998-01-13 20:04:23 +01:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
void *enum_context = NULL;
|
1998-06-29 14:30:57 +02:00
|
|
|
PKT_secret_key *sk = m_alloc_clear( sizeof *sk );
|
|
|
|
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
|
1998-01-13 20:04:23 +01:00
|
|
|
u32 keyid[2];
|
|
|
|
|
1998-06-29 14:30:57 +02:00
|
|
|
while( !(rc=enum_secret_keys( &enum_context, sk) ) ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
/* To be sure that it is a secret key of our own,
|
|
|
|
* we should check it, but this needs a passphrase
|
|
|
|
* for every key and this is boring for the user.
|
|
|
|
* Anyway, access to the seret keyring should be
|
|
|
|
* granted to the user only as it is poosible to
|
|
|
|
* crack it with dictionary attacks.
|
1998-01-13 20:04:23 +01:00
|
|
|
*/
|
1998-06-29 14:30:57 +02:00
|
|
|
keyid_from_sk( sk, keyid );
|
1998-01-13 20:04:23 +01:00
|
|
|
|
|
|
|
if( DBG_TRUST )
|
1998-07-09 15:37:17 +02:00
|
|
|
log_debug("key %08lX: checking secret key\n", (ulong)keyid[1] );
|
1998-01-13 20:04:23 +01:00
|
|
|
|
1998-04-14 19:51:16 +02:00
|
|
|
/* see whether we can access the public key of this secret key */
|
1998-06-29 14:30:57 +02:00
|
|
|
memset( pk, 0, sizeof *pk );
|
|
|
|
rc = get_pubkey( pk, keyid );
|
1998-01-13 20:04:23 +01:00
|
|
|
if( rc ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
log_error(_("key %08lX: secret key without public key\n"),
|
1998-01-13 20:04:23 +01:00
|
|
|
(ulong)keyid[1] );
|
|
|
|
goto leave;
|
|
|
|
}
|
1998-06-29 14:30:57 +02:00
|
|
|
if( cmp_public_secret_key( pk, sk ) ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
log_error(_("key %08lX: secret and public key don't match\n"),
|
1998-01-13 20:04:23 +01:00
|
|
|
(ulong)keyid[1] );
|
|
|
|
rc = G10ERR_GENERAL;
|
|
|
|
goto leave;
|
|
|
|
}
|
1998-01-24 17:32:27 +01:00
|
|
|
|
|
|
|
/* make sure that the pubkey is in the trustdb */
|
1998-06-29 14:30:57 +02:00
|
|
|
rc = query_trust_record( pk );
|
1998-01-24 17:32:27 +01:00
|
|
|
if( rc == -1 ) { /* put it into the trustdb */
|
1998-06-29 14:30:57 +02:00
|
|
|
rc = insert_trust_record( pk );
|
1998-01-24 17:32:27 +01:00
|
|
|
if( rc ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
log_error(_("key %08lX: can't put it into the trustdb\n"),
|
1998-01-24 17:32:27 +01:00
|
|
|
(ulong)keyid[1] );
|
|
|
|
goto leave;
|
|
|
|
}
|
1998-01-13 20:04:23 +01:00
|
|
|
}
|
1998-01-24 17:32:27 +01:00
|
|
|
else if( rc ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
log_error(_("key %08lX: query record failed\n"), (ulong)keyid[1] );
|
1998-01-24 17:32:27 +01:00
|
|
|
goto leave;
|
|
|
|
|
1998-01-16 22:15:24 +01:00
|
|
|
}
|
|
|
|
|
1998-01-19 19:54:44 +01:00
|
|
|
if( DBG_TRUST )
|
1998-07-09 15:37:17 +02:00
|
|
|
log_debug("key %08lX.%lu: stored into ultikey_table\n",
|
1998-06-29 14:30:57 +02:00
|
|
|
(ulong)keyid[1], pk->local_id );
|
|
|
|
if( ins_lid_table_item( ultikey_table, pk->local_id, 0 ) )
|
1998-07-09 15:37:17 +02:00
|
|
|
log_error(_("key %08lX: already in ultikey_table\n"),
|
1998-01-19 19:54:44 +01:00
|
|
|
(ulong)keyid[1]);
|
1998-01-13 20:04:23 +01:00
|
|
|
|
1998-01-24 17:32:27 +01:00
|
|
|
|
1998-06-29 14:30:57 +02:00
|
|
|
release_secret_key_parts( sk );
|
|
|
|
release_public_key_parts( pk );
|
1998-01-13 20:04:23 +01:00
|
|
|
}
|
|
|
|
if( rc != -1 )
|
1998-04-20 16:47:21 +02:00
|
|
|
log_error(_("enum_secret_keys failed: %s\n"), g10_errstr(rc) );
|
1998-01-13 20:04:23 +01:00
|
|
|
else
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
leave:
|
1998-06-29 14:30:57 +02:00
|
|
|
free_secret_key( sk );
|
|
|
|
free_public_key( pk );
|
1998-01-13 20:04:23 +01:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
1998-01-30 21:25:31 +01:00
|
|
|
|
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('\"');
|
1998-03-09 22:44:06 +01:00
|
|
|
print_string( stdout, p, n, 0 );
|
1998-01-16 22:15:24 +01:00
|
|
|
putchar('\"');
|
|
|
|
putchar('\n');
|
|
|
|
m_free(p);
|
|
|
|
}
|
|
|
|
|
1998-07-09 15:37:17 +02:00
|
|
|
static void
|
|
|
|
print_keyid( FILE *fp, ulong lid )
|
|
|
|
{
|
|
|
|
u32 ki[2];
|
|
|
|
if( keyid_from_trustdb( lid, ki ) )
|
|
|
|
fprintf(fp, "????????.%lu", lid );
|
|
|
|
else
|
|
|
|
fprintf(fp, "%08lX.%lu", (ulong)ki[1], lid );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_trust( FILE *fp, unsigned trust )
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
switch( trust ) {
|
|
|
|
case TRUST_UNKNOWN: c = 'o'; break;
|
|
|
|
case TRUST_EXPIRED: c = 'e'; break;
|
|
|
|
case TRUST_UNDEFINED: c = 'q'; break;
|
|
|
|
case TRUST_NEVER: c = 'n'; break;
|
|
|
|
case TRUST_MARGINAL: c = 'm'; break;
|
|
|
|
case TRUST_FULLY: c = 'f'; break;
|
|
|
|
case TRUST_ULTIMATE: c = 'u'; break;
|
|
|
|
default: fprintf(fp, "%02x", trust ); return;
|
|
|
|
}
|
|
|
|
putc(c, fp);
|
|
|
|
}
|
|
|
|
|
1998-01-16 22:15:24 +01:00
|
|
|
/* (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 );
|
1998-01-30 21:25:31 +01:00
|
|
|
sx.local_id = pubkey;
|
1998-01-16 22:15:24 +01:00
|
|
|
for(;;) {
|
1998-01-25 19:56:33 +01:00
|
|
|
rc = walk_sigrecs( &sx, 0 );
|
1998-01-16 22:15:24 +01:00
|
|
|
if( rc )
|
|
|
|
break;
|
|
|
|
rc = keyid_from_local_id( sx.sig_id, keyid );
|
|
|
|
if( rc ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
printf("%6u: %*s????????.%lu:%02x\n", *lineno, depth*4, "",
|
1998-01-16 22:15:24 +01:00
|
|
|
sx.sig_id, sx.sig_flag );
|
|
|
|
++*lineno;
|
|
|
|
}
|
|
|
|
else {
|
1998-07-09 15:37:17 +02:00
|
|
|
printf("%6u: %*s%08lX.%lu:%02x ", *lineno, depth*4, "",
|
1998-01-16 22:15:24 +01:00
|
|
|
(ulong)keyid[1], sx.sig_id, sx.sig_flag );
|
1998-04-14 19:51:16 +02:00
|
|
|
/* check whether 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;
|
|
|
|
}
|
1998-07-09 15:37:17 +02:00
|
|
|
printf("Signatures of %08lX.%lu ", (ulong)keyid[1], pubkey_id );
|
1998-01-16 22:15:24 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
1998-01-30 21:25:31 +01:00
|
|
|
/****************
|
|
|
|
* Function to collect all trustpaths
|
|
|
|
*/
|
1998-01-16 22:15:24 +01:00
|
|
|
static int
|
1998-01-24 17:32:27 +01:00
|
|
|
do_list_path( TRUST_INFO *stack, int depth, int max_depth,
|
1998-01-19 19:54:44 +01:00
|
|
|
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 ) {
|
1998-04-14 19:51:16 +02:00
|
|
|
/*printf("%2lu/%d: too 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 );
|
1998-01-30 21:25:31 +01:00
|
|
|
sx.local_id = stack[depth-1].lid;
|
1998-01-25 19:56:33 +01:00
|
|
|
/* loop over all signatures. If we do not have any, try to
|
|
|
|
* create them */
|
|
|
|
while( !(rc = walk_sigrecs( &sx, 1 )) ) {
|
1998-01-19 19:54:44 +01:00
|
|
|
TRUST_SEG_LIST tsl, t2, tl;
|
1998-01-16 22:15:24 +01:00
|
|
|
int i;
|
|
|
|
|
1998-01-24 17:32:27 +01:00
|
|
|
stack[depth].lid = sx.sig_id;
|
|
|
|
stack[depth].trust = 0;
|
1998-01-19 19:54:44 +01:00
|
|
|
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 */
|
1998-01-24 17:32:27 +01:00
|
|
|
tsl = m_alloc( sizeof *tsl + depth*sizeof(TRUST_INFO) );
|
1998-01-19 19:54:44 +01:00
|
|
|
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
|
1998-01-30 21:25:31 +01:00
|
|
|
* as checked. Valid signatures which are duplicates are
|
|
|
|
* also marked [shall we check them at all?]
|
1998-04-14 19:51:16 +02:00
|
|
|
* FIXME: what shall we do if we have duplicate signatures where only
|
1998-01-30 21:25:31 +01:00
|
|
|
* some of them are bad?
|
1998-01-13 20:04:23 +01:00
|
|
|
*/
|
|
|
|
static int
|
1998-02-18 14:58:46 +01:00
|
|
|
check_sigs( KBNODE keyblock, int *selfsig_okay, int *revoked )
|
1998-01-13 20:04:23 +01:00
|
|
|
{
|
|
|
|
KBNODE node;
|
|
|
|
int rc;
|
1998-01-30 21:25:31 +01:00
|
|
|
LOCAL_ID_INFO *dups = NULL;
|
1998-01-13 20:04:23 +01:00
|
|
|
|
1998-01-16 22:15:24 +01:00
|
|
|
*selfsig_okay = 0;
|
1998-02-18 14:58:46 +01:00
|
|
|
*revoked = 0;
|
|
|
|
for( node=keyblock; node; node = node->next ) {
|
1998-01-13 20:04:23 +01:00
|
|
|
if( node->pkt->pkttype == PKT_SIGNATURE
|
1998-02-18 14:58:46 +01:00
|
|
|
&& ( (node->pkt->pkt.signature->sig_class&~3) == 0x10
|
|
|
|
|| node->pkt->pkt.signature->sig_class == 0x20
|
|
|
|
|| node->pkt->pkt.signature->sig_class == 0x30) ) {
|
1998-01-16 22:15:24 +01:00
|
|
|
int selfsig;
|
|
|
|
rc = check_key_signature( keyblock, node, &selfsig );
|
|
|
|
if( !rc ) {
|
1998-02-02 15:36:06 +01:00
|
|
|
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));
|
1998-01-16 22:15:24 +01:00
|
|
|
if( selfsig ) {
|
|
|
|
node->flag |= 2; /* mark signature valid */
|
|
|
|
*selfsig_okay = 1;
|
|
|
|
}
|
1998-02-18 14:58:46 +01:00
|
|
|
else if( node->pkt->pkt.signature->sig_class == 0x20 )
|
|
|
|
*revoked = 1;
|
1998-01-16 22:15:24 +01:00
|
|
|
else
|
|
|
|
node->flag |= 1; /* mark signature valid */
|
1998-02-18 14:58:46 +01:00
|
|
|
|
|
|
|
if( node->pkt->pkt.signature->sig_class != 0x20 ) {
|
|
|
|
if( !dups )
|
|
|
|
dups = new_lid_table();
|
|
|
|
if( ins_lid_table_item( dups,
|
|
|
|
node->pkt->pkt.signature->local_id, 0) )
|
|
|
|
node->flag |= 4; /* mark as duplicate */
|
|
|
|
}
|
1998-01-16 22:15:24 +01:00
|
|
|
}
|
1998-01-13 20:04:23 +01:00
|
|
|
if( DBG_TRUST )
|
1998-07-09 15:37:17 +02:00
|
|
|
log_debug("trustdb: sig from %08lX.%lu: %s%s\n",
|
1998-01-16 22:15:24 +01:00
|
|
|
(ulong)node->pkt->pkt.signature->keyid[1],
|
1998-02-02 15:36:06 +01:00
|
|
|
node->pkt->pkt.signature->local_id,
|
|
|
|
g10_errstr(rc), (node->flag&4)?" (dup)":"" );
|
1998-01-13 20:04:23 +01:00
|
|
|
}
|
|
|
|
}
|
1998-01-30 21:25:31 +01:00
|
|
|
if( dups )
|
|
|
|
release_lid_table(dups);
|
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-31 22:24:36 +01:00
|
|
|
build_sigrecs( ulong pubkeyid )
|
1998-01-14 13:34:05 +01:00
|
|
|
{
|
1998-01-30 21:25:31 +01:00
|
|
|
TRUSTREC rec, krec, rec2;
|
1998-01-16 22:15:24 +01:00
|
|
|
KBNODE keyblock = NULL;
|
|
|
|
KBNODE node;
|
|
|
|
int rc=0;
|
1998-02-18 14:58:46 +01:00
|
|
|
int i, selfsig, revoked;
|
1998-01-16 22:15:24 +01:00
|
|
|
ulong rnum, rnum2;
|
1998-02-02 15:36:06 +01:00
|
|
|
ulong first_sigrec = 0;
|
1998-01-16 22:15:24 +01:00
|
|
|
|
|
|
|
if( DBG_TRUST )
|
|
|
|
log_debug("trustdb: build_sigrecs for pubkey %lu\n", (ulong)pubkeyid );
|
|
|
|
|
|
|
|
/* get the keyblock */
|
1998-07-09 15:37:17 +02:00
|
|
|
if( (rc=tdbio_read_record( pubkeyid, &rec, RECTYPE_DIR )) ) {
|
1998-04-20 16:47:21 +02:00
|
|
|
log_error(_("%lu: build_sigrecs: can't read dir record\n"), pubkeyid );
|
1998-01-16 22:15:24 +01:00
|
|
|
goto leave;
|
|
|
|
}
|
1998-07-09 15:37:17 +02:00
|
|
|
if( (rc=tdbio_read_record( rec.r.dir.keyrec, &krec, RECTYPE_KEY )) ) {
|
1998-04-20 16:47:21 +02:00
|
|
|
log_error(_("%lu: build_sigrecs: can't read key record\n"), pubkeyid);
|
1998-01-30 21:25:31 +01:00
|
|
|
goto leave;
|
|
|
|
}
|
1998-06-13 19:00:02 +02:00
|
|
|
rc = get_keyblock_byfprint( &keyblock, krec.r.key.fingerprint,
|
|
|
|
krec.r.key.fingerprint_len );
|
1998-01-16 22:15:24 +01:00
|
|
|
if( rc ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
log_error(_("build_sigrecs: get_keyblock_byfprint failed: %s\n"),
|
|
|
|
g10_errstr(rc) );
|
1998-01-16 22:15:24 +01:00
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
/* check all key signatures */
|
1998-02-18 14:58:46 +01:00
|
|
|
rc = check_sigs( keyblock, &selfsig, &revoked );
|
1998-01-16 22:15:24 +01:00
|
|
|
if( rc ) {
|
1998-04-20 16:47:21 +02:00
|
|
|
log_error(_("build_sigrecs: check_sigs failed\n") );
|
1998-01-16 22:15:24 +01:00
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
if( !selfsig ) {
|
1998-06-29 14:30:57 +02:00
|
|
|
log_error(_("build_sigrecs: self-signature missing\n") );
|
1998-02-02 15:36:06 +01:00
|
|
|
update_no_sigs( pubkeyid, 2 );
|
1998-01-16 22:15:24 +01:00
|
|
|
rc = G10ERR_BAD_CERT;
|
|
|
|
goto leave;
|
|
|
|
}
|
1998-02-18 14:58:46 +01:00
|
|
|
if( revoked ) {
|
1998-04-20 16:47:21 +02:00
|
|
|
log_info(_("build_sigrecs: key has been revoked\n") );
|
1998-02-18 14:58:46 +01:00
|
|
|
update_no_sigs( pubkeyid, 3 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
update_no_sigs( pubkeyid, 0 ); /* assume we have sigs */
|
1998-01-31 22:24:36 +01:00
|
|
|
|
1998-01-16 22:15:24 +01:00
|
|
|
/* valid key signatures are now marked; we can now build the
|
|
|
|
* sigrecs */
|
|
|
|
memset( &rec, 0, sizeof rec );
|
1998-01-30 21:25:31 +01:00
|
|
|
rec.rectype = RECTYPE_SIG;
|
1998-01-16 22:15:24 +01:00
|
|
|
i = 0;
|
|
|
|
rnum = rnum2 = 0;
|
1998-02-18 14:58:46 +01:00
|
|
|
for( node=keyblock; node; node = node->next ) {
|
1998-01-30 21:25:31 +01:00
|
|
|
/* insert sigs which are not a selfsig nor a duplicate */
|
|
|
|
if( (node->flag & 1) && !(node->flag & 4) ) {
|
1998-01-16 22:15:24 +01:00
|
|
|
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
|
1998-04-14 19:51:16 +02:00
|
|
|
* this can fail are I/O errors of the trustdb or a
|
1998-01-25 19:56:33 +01:00
|
|
|
* remove operation on the pubkey database - which should
|
1998-07-09 15:37:17 +02:00
|
|
|
* not disturb us, because we have to change them anyway. */
|
1998-01-16 22:15:24 +01:00
|
|
|
rc = set_signature_packets_local_id( node->pkt->pkt.signature );
|
|
|
|
if( rc )
|
1998-04-20 16:47:21 +02:00
|
|
|
log_fatal(_("set_signature_packets_local_id failed: %s\n"),
|
1998-01-16 22:15:24 +01:00
|
|
|
g10_errstr(rc));
|
|
|
|
}
|
|
|
|
if( i == SIGS_PER_RECORD ) {
|
|
|
|
/* write the record */
|
1998-07-09 15:37:17 +02:00
|
|
|
rnum = tdbio_new_recnum();
|
1998-01-16 22:15:24 +01:00
|
|
|
if( rnum2 ) { /* write the stored record */
|
1998-01-30 21:25:31 +01:00
|
|
|
rec2.r.sig.owner = pubkeyid;
|
|
|
|
rec2.r.sig.chain = rnum; /* the next record number */
|
1998-07-09 15:37:17 +02:00
|
|
|
rc = tdbio_write_record( rnum2, &rec2 );
|
1998-01-16 22:15:24 +01:00
|
|
|
if( rc ) {
|
1998-04-20 16:47:21 +02:00
|
|
|
log_error(_("build_sigrecs: write_record failed\n") );
|
1998-01-16 22:15:24 +01:00
|
|
|
goto leave;
|
|
|
|
}
|
1998-02-02 15:36:06 +01:00
|
|
|
if( !first_sigrec )
|
|
|
|
first_sigrec = rnum2;
|
1998-01-16 22:15:24 +01:00
|
|
|
}
|
|
|
|
rec2 = rec;
|
|
|
|
rnum2 = rnum;
|
|
|
|
memset( &rec, 0, sizeof rec );
|
1998-01-30 21:25:31 +01:00
|
|
|
rec.rectype = RECTYPE_SIG;
|
1998-01-16 22:15:24 +01:00
|
|
|
i = 0;
|
|
|
|
}
|
1998-01-30 21:25:31 +01:00
|
|
|
rec.r.sig.sig[i].local_id = node->pkt->pkt.signature->local_id;
|
|
|
|
rec.r.sig.sig[i].flag = 0;
|
1998-01-16 22:15:24 +01:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( i || rnum2 ) {
|
|
|
|
/* write the record */
|
1998-07-09 15:37:17 +02:00
|
|
|
rnum = tdbio_new_recnum();
|
1998-01-16 22:15:24 +01:00
|
|
|
if( rnum2 ) { /* write the stored record */
|
1998-01-30 21:25:31 +01:00
|
|
|
rec2.r.sig.owner = pubkeyid;
|
|
|
|
rec2.r.sig.chain = rnum;
|
1998-07-09 15:37:17 +02:00
|
|
|
rc = tdbio_write_record( rnum2, &rec2 );
|
1998-01-16 22:15:24 +01:00
|
|
|
if( rc ) {
|
1998-04-20 16:47:21 +02:00
|
|
|
log_error(_("build_sigrecs: write_record failed\n") );
|
1998-01-16 22:15:24 +01:00
|
|
|
goto leave;
|
|
|
|
}
|
1998-02-02 15:36:06 +01:00
|
|
|
if( !first_sigrec )
|
|
|
|
first_sigrec = rnum2;
|
1998-01-16 22:15:24 +01:00
|
|
|
}
|
|
|
|
if( i ) { /* write the pending record */
|
1998-01-30 21:25:31 +01:00
|
|
|
rec.r.sig.owner = pubkeyid;
|
|
|
|
rec.r.sig.chain = 0;
|
1998-07-09 15:37:17 +02:00
|
|
|
rc = tdbio_write_record( rnum, &rec );
|
1998-01-16 22:15:24 +01:00
|
|
|
if( rc ) {
|
1998-04-20 16:47:21 +02:00
|
|
|
log_error(_("build_sigrecs: write_record failed\n") );
|
1998-01-16 22:15:24 +01:00
|
|
|
goto leave;
|
|
|
|
}
|
1998-02-02 15:36:06 +01:00
|
|
|
if( !first_sigrec )
|
|
|
|
first_sigrec = rnum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( first_sigrec ) {
|
|
|
|
/* update the dir record */
|
1998-07-09 15:37:17 +02:00
|
|
|
if( (rc =tdbio_read_record( pubkeyid, &rec, RECTYPE_DIR )) ) {
|
1998-04-20 16:47:21 +02:00
|
|
|
log_error(_("update_dir_record: read failed\n"));
|
1998-02-02 15:36:06 +01:00
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
rec.r.dir.sigrec = first_sigrec;
|
1998-07-09 15:37:17 +02:00
|
|
|
if( (rc=tdbio_write_record( pubkeyid, &rec )) ) {
|
1998-04-20 16:47:21 +02:00
|
|
|
log_error(_("update_dir_record: write failed\n"));
|
1998-02-02 15:36:06 +01:00
|
|
|
goto leave;
|
1998-01-16 22:15:24 +01:00
|
|
|
}
|
|
|
|
}
|
1998-02-02 15:36:06 +01:00
|
|
|
else
|
1998-02-18 14:58:46 +01:00
|
|
|
update_no_sigs( pubkeyid, revoked? 3:1 ); /* no signatures */
|
1998-01-16 22:15:24 +01:00
|
|
|
|
|
|
|
leave:
|
|
|
|
release_kbnode( keyblock );
|
|
|
|
if( DBG_TRUST )
|
1998-04-20 16:47:21 +02:00
|
|
|
log_debug(_("trustdb: build_sigrecs: %s\n"), g10_errstr(rc) );
|
1998-01-16 22:15:24 +01:00
|
|
|
return rc;
|
1998-01-14 13:34:05 +01:00
|
|
|
}
|
|
|
|
|
1998-01-24 17:32:27 +01:00
|
|
|
/****************
|
|
|
|
* Make a list of trust paths
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
make_tsl( ulong pubkey_id, TRUST_SEG_LIST *ret_tslist )
|
|
|
|
{
|
|
|
|
int i, rc;
|
|
|
|
LOCAL_ID_INFO *lids = new_lid_table();
|
|
|
|
TRUST_INFO stack[MAX_LIST_SIGS_DEPTH];
|
|
|
|
TRUST_SEG_LIST tsl, tslist;
|
|
|
|
int max_depth = 4;
|
|
|
|
|
|
|
|
tslist = *ret_tslist = NULL;
|
|
|
|
|
|
|
|
if( !qry_lid_table_flag( ultikey_table, pubkey_id, NULL ) ) {
|
|
|
|
tslist = m_alloc( sizeof *tslist );
|
|
|
|
tslist->nseg = 1;
|
|
|
|
tslist->dup = 0;
|
|
|
|
tslist->seg[0].lid = pubkey_id;
|
|
|
|
tslist->seg[0].trust = 0;
|
|
|
|
tslist->next = NULL;
|
|
|
|
rc = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
stack[0].lid = pubkey_id;
|
|
|
|
stack[0].trust = 0;
|
|
|
|
rc = do_list_path( stack, 1, max_depth, lids, &tslist );
|
|
|
|
}
|
|
|
|
if( !rc ) { /* wipe out duplicates */
|
|
|
|
LOCAL_ID_INFO *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].lid, 0 ) ) {
|
|
|
|
tsl->dup = 1; /* mark as duplicate */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
release_lid_table(work);
|
|
|
|
*ret_tslist = tslist;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
; /* FIXME: release tslist */
|
|
|
|
release_lid_table(lids);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
1998-01-14 13:34:05 +01:00
|
|
|
|
1998-01-24 17:32:27 +01:00
|
|
|
/****************
|
|
|
|
* Given a trust segment list tslist, walk over all paths and fill in
|
|
|
|
* the trust information for each segment. What this function does is
|
|
|
|
* to assign a trustvalue to the first segment (which is the requested key)
|
|
|
|
* of each path.
|
|
|
|
*
|
1998-04-14 19:51:16 +02:00
|
|
|
* FIXME: We have to do more thinking here. e.g. we should never increase
|
1998-01-24 17:32:27 +01:00
|
|
|
* the trust value.
|
|
|
|
*
|
|
|
|
* Do not do it for duplicates.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
propagate_trust( TRUST_SEG_LIST tslist )
|
|
|
|
{
|
|
|
|
int i, rc;
|
1998-02-02 15:36:06 +01:00
|
|
|
unsigned trust, tr;
|
1998-01-24 17:32:27 +01:00
|
|
|
TRUST_SEG_LIST tsl;
|
1998-01-14 13:34:05 +01:00
|
|
|
|
1998-01-24 17:32:27 +01:00
|
|
|
for(tsl = tslist; tsl; tsl = tsl->next ) {
|
|
|
|
if( tsl->dup )
|
|
|
|
continue;
|
|
|
|
assert( tsl->nseg );
|
1998-04-14 19:51:16 +02:00
|
|
|
/* the last segment is always an ultimately trusted one, so we can
|
1998-01-24 17:32:27 +01:00
|
|
|
* assign a fully trust to the next one */
|
|
|
|
i = tsl->nseg-1;
|
|
|
|
tsl->seg[i].trust = TRUST_ULTIMATE;
|
|
|
|
trust = TRUST_FULLY;
|
|
|
|
for(i-- ; i >= 0; i-- ) {
|
|
|
|
tsl->seg[i].trust = trust;
|
|
|
|
if( i > 0 ) {
|
|
|
|
/* get the trust of this pubkey */
|
1998-02-02 15:36:06 +01:00
|
|
|
rc = get_ownertrust( tsl->seg[i].lid, &tr );
|
1998-01-24 17:32:27 +01:00
|
|
|
if( rc )
|
|
|
|
return rc;
|
1998-02-02 15:36:06 +01:00
|
|
|
if( tr < trust )
|
|
|
|
trust = tr;
|
1998-01-24 17:32:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
1998-01-14 13:34:05 +01:00
|
|
|
|
1998-01-13 20:04:23 +01:00
|
|
|
|
|
|
|
/****************
|
1998-03-19 16:27:29 +01:00
|
|
|
* we have the pubkey record but nothing more is known.
|
|
|
|
* (function may re-read dr)
|
1998-01-13 20:04:23 +01:00
|
|
|
*/
|
|
|
|
static int
|
1998-01-31 22:24:36 +01:00
|
|
|
do_check( ulong pubkeyid, TRUSTREC *dr, unsigned *trustlevel )
|
1998-01-13 20:04:23 +01:00
|
|
|
{
|
1998-01-24 17:32:27 +01:00
|
|
|
int i, rc=0;
|
|
|
|
TRUST_SEG_LIST tsl, tsl2, tslist;
|
|
|
|
int marginal, fully;
|
1998-01-25 19:56:33 +01:00
|
|
|
int fully_needed = opt.completes_needed;
|
|
|
|
int marginal_needed = opt.marginals_needed;
|
1998-02-18 14:58:46 +01:00
|
|
|
unsigned tflags = 0;
|
1998-01-25 19:56:33 +01:00
|
|
|
|
|
|
|
assert( fully_needed > 0 && marginal_needed > 1 );
|
|
|
|
|
1998-01-24 17:32:27 +01:00
|
|
|
|
|
|
|
*trustlevel = TRUST_UNDEFINED;
|
1998-01-16 22:15:24 +01:00
|
|
|
|
|
|
|
/* verify the cache */
|
|
|
|
|
|
|
|
/* do we have sigrecs */
|
1998-01-31 22:24:36 +01:00
|
|
|
if( !dr->r.dir.sigrec && !dr->r.dir.no_sigs) {
|
|
|
|
/* no sigrecs, so build them */
|
|
|
|
rc = build_sigrecs( pubkeyid );
|
1998-01-16 22:15:24 +01:00
|
|
|
if( !rc ) /* and read again */
|
1998-07-09 15:37:17 +02:00
|
|
|
rc = tdbio_read_record( pubkeyid, dr, RECTYPE_DIR );
|
1998-01-16 22:15:24 +01:00
|
|
|
}
|
1998-02-18 14:58:46 +01:00
|
|
|
|
|
|
|
if( dr->r.dir.no_sigs == 3 )
|
|
|
|
tflags |= TRUST_FLAG_REVOKED;
|
|
|
|
|
1998-02-02 15:36:06 +01:00
|
|
|
if( !rc && !dr->r.dir.sigrec ) {
|
1998-04-14 19:51:16 +02:00
|
|
|
/* See whether this is our own key */
|
1998-03-03 09:43:28 +01:00
|
|
|
if( !qry_lid_table_flag( ultikey_table, pubkeyid, NULL ) )
|
1998-02-18 14:58:46 +01:00
|
|
|
*trustlevel = tflags | TRUST_ULTIMATE;
|
1998-03-03 09:43:28 +01:00
|
|
|
return 0;
|
1998-02-02 15:36:06 +01:00
|
|
|
}
|
1998-01-16 22:15:24 +01:00
|
|
|
if( rc )
|
|
|
|
return rc; /* error while looking for sigrec or building sigrecs */
|
1998-01-14 13:34:05 +01:00
|
|
|
|
1998-01-24 17:32:27 +01:00
|
|
|
/* fixme: take it from the cache if it is valid */
|
|
|
|
|
|
|
|
/* Make a list of all possible trust-paths */
|
|
|
|
rc = make_tsl( pubkeyid, &tslist );
|
|
|
|
if( rc )
|
|
|
|
return rc;
|
|
|
|
rc = propagate_trust( tslist );
|
|
|
|
if( rc )
|
|
|
|
return rc;
|
|
|
|
for(tsl = tslist; tsl; tsl = tsl->next ) {
|
|
|
|
if( tsl->dup )
|
|
|
|
continue;
|
|
|
|
|
1998-02-12 00:22:09 +01:00
|
|
|
if( opt.verbose ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
log_info("trust path:" );
|
|
|
|
for(i=0; i < tsl->nseg; i++ ) {
|
|
|
|
putc(' ',stderr);
|
|
|
|
print_keyid( stderr, tsl->seg[i].lid );
|
|
|
|
putc(':',stderr);
|
|
|
|
print_trust( stderr, tsl->seg[i].trust );
|
|
|
|
}
|
1998-02-12 00:22:09 +01:00
|
|
|
putc('\n',stderr);
|
|
|
|
}
|
1998-01-24 17:32:27 +01:00
|
|
|
}
|
|
|
|
|
1998-04-14 19:51:16 +02:00
|
|
|
/* and see whether there is a trusted path.
|
1998-01-24 17:32:27 +01:00
|
|
|
* We only have to look at the first segment, because
|
|
|
|
* propagate_trust has investigated all other segments */
|
|
|
|
marginal = fully = 0;
|
|
|
|
for(tsl = tslist; tsl; tsl = tsl->next ) {
|
|
|
|
if( tsl->dup )
|
|
|
|
continue;
|
|
|
|
if( tsl->seg[0].trust == TRUST_ULTIMATE ) {
|
1998-02-18 14:58:46 +01:00
|
|
|
*trustlevel = tflags | TRUST_ULTIMATE; /* our own key */
|
1998-01-24 17:32:27 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( tsl->seg[0].trust == TRUST_FULLY ) {
|
|
|
|
marginal++;
|
|
|
|
fully++;
|
|
|
|
}
|
|
|
|
else if( tsl->seg[0].trust == TRUST_MARGINAL )
|
|
|
|
marginal++;
|
|
|
|
|
|
|
|
if( fully >= fully_needed ) {
|
1998-02-18 14:58:46 +01:00
|
|
|
*trustlevel = tflags | TRUST_FULLY;
|
1998-01-24 17:32:27 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( !tsl && marginal >= marginal_needed )
|
1998-02-18 14:58:46 +01:00
|
|
|
*trustlevel = tflags | TRUST_MARGINAL;
|
1998-01-24 17:32:27 +01:00
|
|
|
|
|
|
|
/* cache the tslist */
|
|
|
|
if( last_trust_web_key ) {
|
|
|
|
for( tsl = last_trust_web_tslist; tsl; tsl = tsl2 ) {
|
|
|
|
tsl2 = tsl->next;
|
|
|
|
m_free(tsl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
last_trust_web_key = pubkeyid;
|
|
|
|
last_trust_web_tslist = tslist;
|
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
|
|
|
|
1998-04-14 19:51:16 +02:00
|
|
|
/***********************************************
|
1998-04-20 16:47:21 +02:00
|
|
|
**************** API ************************
|
1998-04-14 19:51:16 +02:00
|
|
|
***********************************************/
|
1998-01-12 11:18:17 +01:00
|
|
|
|
|
|
|
/****************
|
|
|
|
* 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-02-02 15:36:06 +01:00
|
|
|
init_trustdb( int level, const char *dbname )
|
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 ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
rc = tdbio_set_dbname( dbname, !!level );
|
|
|
|
if( rc )
|
|
|
|
return rc;
|
1998-01-16 22:15:24 +01:00
|
|
|
if( !level )
|
|
|
|
return 0;
|
|
|
|
|
1998-07-06 12:23:57 +02:00
|
|
|
/* verify that our own keys are in the trustDB
|
|
|
|
* or move them to the trustdb. */
|
|
|
|
rc = verify_own_keys();
|
1998-01-13 20:04:23 +01:00
|
|
|
|
1998-07-06 12:23:57 +02:00
|
|
|
/* should we check whether there is no other ultimately trusted
|
|
|
|
* key in the database? */
|
1998-01-13 20:04:23 +01:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-01-30 21:25:31 +01:00
|
|
|
void
|
|
|
|
list_trustdb( const char *username )
|
|
|
|
{
|
|
|
|
TRUSTREC rec;
|
|
|
|
|
|
|
|
if( username ) {
|
1998-06-29 14:30:57 +02:00
|
|
|
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
|
1998-01-30 21:25:31 +01:00
|
|
|
int rc;
|
|
|
|
|
1998-06-29 14:30:57 +02:00
|
|
|
if( (rc = get_pubkey_byname( pk, username )) )
|
1998-01-30 21:25:31 +01:00
|
|
|
log_error("user '%s' not found: %s\n", username, g10_errstr(rc) );
|
1998-07-09 15:37:17 +02:00
|
|
|
else if( (rc=tdbio_search_record( pk, &rec )) && rc != -1 )
|
1998-01-30 21:25:31 +01:00
|
|
|
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);
|
1998-06-29 14:30:57 +02:00
|
|
|
else if( (rc = list_sigs( pk->local_id )) )
|
1998-01-30 21:25:31 +01:00
|
|
|
log_error("user '%s' list problem: %s\n", username, g10_errstr(rc));
|
1998-06-29 14:30:57 +02:00
|
|
|
free_public_key( pk );
|
1998-01-30 21:25:31 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
ulong recnum;
|
|
|
|
int i;
|
|
|
|
|
1998-07-09 15:37:17 +02:00
|
|
|
printf("TrustDB: %s\n", tdbio_get_dbname() );
|
|
|
|
for(i=9+strlen(tdbio_get_dbname()); i > 0; i-- )
|
1998-01-30 21:25:31 +01:00
|
|
|
putchar('-');
|
|
|
|
putchar('\n');
|
1998-07-09 15:37:17 +02:00
|
|
|
for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ )
|
|
|
|
tdbio_dump_record( recnum, &rec, stdout );
|
1998-01-30 21:25:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-07-06 12:23:57 +02:00
|
|
|
/****************
|
|
|
|
* make a list of all owner trust value.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
list_ownertrust()
|
|
|
|
{
|
|
|
|
TRUSTREC rec;
|
|
|
|
ulong recnum;
|
|
|
|
int i;
|
|
|
|
byte *p;
|
|
|
|
|
1998-07-09 15:37:17 +02:00
|
|
|
for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
|
1998-07-06 12:23:57 +02:00
|
|
|
if( rec.rectype == RECTYPE_KEY ) {
|
|
|
|
p = rec.r.key.fingerprint;
|
|
|
|
for(i=0; i < rec.r.key.fingerprint_len; i++, p++ )
|
|
|
|
printf("%02X", *p );
|
|
|
|
printf(":%u:\n", (unsigned)rec.r.key.ownertrust );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-01-30 21:25:31 +01:00
|
|
|
void
|
|
|
|
list_trust_path( int max_depth, const char *username )
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
int wipe=0;
|
|
|
|
int i;
|
|
|
|
TRUSTREC rec;
|
1998-06-29 14:30:57 +02:00
|
|
|
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
|
1998-01-30 21:25:31 +01:00
|
|
|
|
|
|
|
if( max_depth < 0 ) {
|
|
|
|
wipe = 1;
|
|
|
|
max_depth = -max_depth;
|
|
|
|
}
|
|
|
|
|
1998-06-29 14:30:57 +02:00
|
|
|
if( (rc = get_pubkey_byname( pk, username )) )
|
1998-01-30 21:25:31 +01:00
|
|
|
log_error("user '%s' not found: %s\n", username, g10_errstr(rc) );
|
1998-07-09 15:37:17 +02:00
|
|
|
else if( (rc=tdbio_search_record( pk, &rec )) && rc != -1 )
|
1998-01-30 21:25:31 +01:00
|
|
|
log_error("problem finding '%s' in trustdb: %s\n",
|
|
|
|
username, g10_errstr(rc));
|
|
|
|
else if( rc == -1 ) {
|
|
|
|
log_info("user '%s' not in trustdb - inserting\n", username);
|
1998-06-29 14:30:57 +02:00
|
|
|
rc = insert_trust_record( pk );
|
1998-01-30 21:25:31 +01:00
|
|
|
if( rc )
|
|
|
|
log_error("failed to put '%s' into trustdb: %s\n", username, g10_errstr(rc));
|
|
|
|
else {
|
1998-06-29 14:30:57 +02:00
|
|
|
assert( pk->local_id );
|
1998-01-30 21:25:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !rc ) {
|
|
|
|
TRUST_SEG_LIST tsl, tslist = NULL;
|
|
|
|
|
1998-06-29 14:30:57 +02:00
|
|
|
if( !qry_lid_table_flag( ultikey_table, pk->local_id, NULL ) ) {
|
1998-01-30 21:25:31 +01:00
|
|
|
tslist = m_alloc( sizeof *tslist );
|
|
|
|
tslist->nseg = 1;
|
|
|
|
tslist->dup = 0;
|
1998-06-29 14:30:57 +02:00
|
|
|
tslist->seg[0].lid = pk->local_id;
|
1998-01-30 21:25:31 +01:00
|
|
|
tslist->seg[0].trust = 0;
|
|
|
|
tslist->next = NULL;
|
|
|
|
rc = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
LOCAL_ID_INFO *lids = new_lid_table();
|
|
|
|
TRUST_INFO stack[MAX_LIST_SIGS_DEPTH];
|
|
|
|
|
1998-06-29 14:30:57 +02:00
|
|
|
stack[0].lid = pk->local_id;
|
1998-01-30 21:25:31 +01:00
|
|
|
stack[0].trust = 0;
|
|
|
|
rc = do_list_path( stack, 1, max_depth, lids, &tslist );
|
|
|
|
if( wipe ) { /* wipe out duplicates */
|
|
|
|
LOCAL_ID_INFO *work;
|
|
|
|
|
|
|
|
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].lid, 0 ) ) {
|
|
|
|
tsl->dup = 1; /* mark as duplicate */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
release_lid_table(work);
|
|
|
|
}
|
|
|
|
release_lid_table(lids);
|
1998-01-31 22:24:36 +01:00
|
|
|
}
|
1998-01-30 21:25:31 +01:00
|
|
|
if( rc )
|
|
|
|
log_error("user '%s' list problem: %s\n", username, g10_errstr(rc));
|
|
|
|
rc = propagate_trust( tslist );
|
|
|
|
if( rc )
|
|
|
|
log_error("user '%s' trust problem: %s\n", username, g10_errstr(rc));
|
|
|
|
for(tsl = tslist; tsl; tsl = tsl->next ) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if( tsl->dup )
|
|
|
|
continue;
|
|
|
|
printf("trust path:" );
|
1998-07-09 15:37:17 +02:00
|
|
|
for(i=0; i < tsl->nseg; i++ ) {
|
|
|
|
putc(' ',stdout);
|
|
|
|
print_keyid( stdout, tsl->seg[i].lid );
|
|
|
|
putc(':',stdout);
|
|
|
|
print_trust( stdout, tsl->seg[i].trust );
|
|
|
|
}
|
1998-01-30 21:25:31 +01:00
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-06-29 14:30:57 +02:00
|
|
|
free_public_key( pk );
|
1998-01-30 21:25:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-01-12 11:18:17 +01:00
|
|
|
/****************
|
1998-06-29 14:30:57 +02:00
|
|
|
* Get the trustlevel for this PK.
|
1998-01-12 11:18:17 +01:00
|
|
|
* Note: This does not ask any questions
|
|
|
|
* Returns: 0 okay of an errorcode
|
|
|
|
*
|
|
|
|
* It operates this way:
|
1998-06-29 14:30:57 +02:00
|
|
|
* locate the pk in the trustdb
|
1998-01-12 11:18:17 +01:00
|
|
|
* 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-06-29 14:30:57 +02:00
|
|
|
check_trust( PKT_public_key *pk, unsigned *r_trustlevel )
|
1998-01-12 11:18:17 +01:00
|
|
|
{
|
1998-01-13 20:04:23 +01:00
|
|
|
TRUSTREC rec;
|
1998-01-24 17:32:27 +01:00
|
|
|
unsigned trustlevel = TRUST_UNKNOWN;
|
1998-01-13 20:04:23 +01:00
|
|
|
int rc=0;
|
1998-06-25 12:19:08 +02:00
|
|
|
u32 cur_time;
|
1998-07-09 15:37:17 +02:00
|
|
|
u32 keyid[2];
|
|
|
|
|
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-07-09 15:37:17 +02:00
|
|
|
keyid_from_pk( pk, keyid );
|
1998-01-12 11:18:17 +01:00
|
|
|
|
1998-01-13 20:04:23 +01:00
|
|
|
/* get the pubkey record */
|
1998-06-29 14:30:57 +02:00
|
|
|
if( pk->local_id ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
if( tdbio_read_record( pk->local_id, &rec, RECTYPE_DIR ) ) {
|
|
|
|
log_error(_("check_trust: read dir record failed\n"));
|
1998-01-13 20:04:23 +01:00
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { /* no local_id: scan the trustdb */
|
1998-07-09 15:37:17 +02:00
|
|
|
if( (rc=tdbio_search_record( pk, &rec )) && rc != -1 ) {
|
1998-04-20 16:47:21 +02:00
|
|
|
log_error(_("check_trust: search_record 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-06-29 14:30:57 +02:00
|
|
|
rc = insert_trust_record( pk );
|
1998-01-25 19:56:33 +01:00
|
|
|
if( rc ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
log_error(_("key %08lX: insert trust record failed: %s\n"),
|
|
|
|
keyid[1], g10_errstr(rc));
|
1998-01-25 19:56:33 +01:00
|
|
|
goto leave;
|
|
|
|
}
|
1998-07-09 15:37:17 +02:00
|
|
|
log_info(_("key %08lX.%lu: inserted into trustdb\n"),
|
|
|
|
keyid[1], pk->local_id );
|
1998-01-13 20:04:23 +01:00
|
|
|
}
|
|
|
|
}
|
1998-04-02 12:30:03 +02:00
|
|
|
cur_time = make_timestamp();
|
1998-06-29 14:30:57 +02:00
|
|
|
if( pk->timestamp > cur_time ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
log_info(_("key %08lX.%lu: created in future "
|
|
|
|
"(time warp or clock problem)\n"),
|
|
|
|
keyid[1], pk->local_id );
|
1998-03-19 16:27:29 +01:00
|
|
|
return G10ERR_TIME_CONFLICT;
|
|
|
|
}
|
|
|
|
|
1998-06-29 14:30:57 +02:00
|
|
|
if( pk->valid_days && add_days_to_timestamp(pk->timestamp,
|
|
|
|
pk->valid_days) < cur_time ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
log_info(_("key %08lX.%lu: expired at %s\n"),
|
|
|
|
keyid[1], pk->local_id,
|
|
|
|
strtimestamp( add_days_to_timestamp(pk->timestamp,
|
|
|
|
pk->valid_days)));
|
1998-04-02 12:30:03 +02:00
|
|
|
trustlevel = TRUST_EXPIRED;
|
|
|
|
}
|
|
|
|
else {
|
1998-06-29 14:30:57 +02:00
|
|
|
rc = do_check( pk->local_id, &rec, &trustlevel );
|
1998-04-02 12:30:03 +02:00
|
|
|
if( rc ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
log_error(_("key %08lX.%lu: trust check failed: %s\n"),
|
|
|
|
keyid[1], pk->local_id, g10_errstr(rc));
|
1998-04-02 12:30:03 +02:00
|
|
|
return rc;
|
|
|
|
}
|
1998-01-16 22:15:24 +01:00
|
|
|
}
|
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 )
|
1998-07-09 15:37:17 +02:00
|
|
|
log_debug("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-05-29 13:53:54 +02:00
|
|
|
int
|
1998-06-29 14:30:57 +02:00
|
|
|
query_trust_info( PKT_public_key *pk )
|
1998-05-29 13:53:54 +02:00
|
|
|
{
|
|
|
|
unsigned trustlevel;
|
|
|
|
int c;
|
|
|
|
|
1998-06-29 14:30:57 +02:00
|
|
|
if( check_trust( pk, &trustlevel ) )
|
1998-05-29 13:53:54 +02:00
|
|
|
return '?';
|
|
|
|
if( trustlevel & TRUST_FLAG_REVOKED )
|
|
|
|
return 'r';
|
|
|
|
switch( (trustlevel & TRUST_MASK) ) {
|
|
|
|
case TRUST_UNKNOWN: c = 'o'; break;
|
|
|
|
case TRUST_EXPIRED: c = 'e'; break;
|
|
|
|
case TRUST_UNDEFINED: c = 'q'; break;
|
|
|
|
case TRUST_NEVER: c = 'n'; break;
|
|
|
|
case TRUST_MARGINAL: c = 'm'; break;
|
|
|
|
case TRUST_FULLY: c = 'f'; break;
|
|
|
|
case TRUST_ULTIMATE: c = 'u'; break;
|
|
|
|
default: BUG();
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
1998-01-24 17:32:27 +01:00
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
* Enumerate all keys, which are needed to build all trust paths for
|
1998-01-31 22:24:36 +01:00
|
|
|
* the given key. This function does not return the key itself or
|
1998-01-24 17:32:27 +01:00
|
|
|
* the ultimate key.
|
|
|
|
*
|
|
|
|
* 1) create a void pointer and initialize it to NULL
|
|
|
|
* 2) pass this void pointer by reference to this function.
|
|
|
|
* Set lid to the key you want to enumerate and pass it by reference.
|
|
|
|
* 3) call this function as long as it does not return -1
|
|
|
|
* to indicate EOF. LID does contain the next key used to build the web
|
|
|
|
* 4) Always call this function a last time with LID set to NULL,
|
1998-04-14 19:51:16 +02:00
|
|
|
* so that it can free its context.
|
1998-01-24 17:32:27 +01:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
enum_trust_web( void **context, ulong *lid )
|
|
|
|
{
|
|
|
|
ENUM_TRUST_WEB_CONTEXT *c = *context;
|
|
|
|
|
|
|
|
if( !c ) { /* make a new context */
|
|
|
|
c = m_alloc_clear( sizeof *c );
|
|
|
|
*context = c;
|
1998-03-03 09:43:28 +01:00
|
|
|
if( *lid != last_trust_web_key && last_trust_web_key )
|
|
|
|
log_bug("enum_trust_web: nyi\n"); /* <--- FIXME */
|
1998-01-24 17:32:27 +01:00
|
|
|
c->tsl = last_trust_web_tslist;
|
|
|
|
c->index = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !lid ) { /* free the context */
|
|
|
|
m_free( c );
|
|
|
|
*context = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
while( c->tsl ) {
|
|
|
|
if( !c->tsl->dup && c->index < c->tsl->nseg-1 ) {
|
|
|
|
*lid = c->tsl->seg[c->index].lid;
|
|
|
|
c->index++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
c->index = 1;
|
|
|
|
c->tsl = c->tsl->next;
|
|
|
|
}
|
|
|
|
return -1; /* eof */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
* Return the assigned ownertrust value for the given LID
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
get_ownertrust( ulong lid, unsigned *r_otrust )
|
|
|
|
{
|
|
|
|
TRUSTREC rec;
|
|
|
|
|
1998-07-09 15:37:17 +02:00
|
|
|
if( tdbio_read_record( lid, &rec, RECTYPE_DIR ) ) {
|
1998-01-31 22:24:36 +01:00
|
|
|
log_error("get_ownertrust: read dir record failed\n");
|
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
}
|
1998-07-09 15:37:17 +02:00
|
|
|
if( tdbio_read_record( rec.r.dir.keyrec, &rec, RECTYPE_KEY ) ) {
|
1998-01-31 22:24:36 +01:00
|
|
|
log_error("get_ownertrust: read key record failed\n");
|
1998-01-24 17:32:27 +01:00
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
}
|
|
|
|
if( r_otrust )
|
1998-01-31 22:24:36 +01:00
|
|
|
*r_otrust = rec.r.key.ownertrust;
|
1998-01-24 17:32:27 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
keyid_from_trustdb( ulong lid, u32 *keyid )
|
|
|
|
{
|
|
|
|
TRUSTREC rec;
|
|
|
|
|
1998-07-09 15:37:17 +02:00
|
|
|
if( tdbio_read_record( lid, &rec, RECTYPE_DIR ) ) {
|
1998-01-24 17:32:27 +01:00
|
|
|
log_error("keyid_from_trustdb: read record failed\n");
|
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
}
|
|
|
|
if( keyid ) {
|
1998-01-31 22:24:36 +01:00
|
|
|
keyid[0] = rec.r.dir.keyid[0];
|
|
|
|
keyid[1] = rec.r.dir.keyid[1];
|
1998-01-24 17:32:27 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-01-31 22:24:36 +01:00
|
|
|
/****************
|
|
|
|
* This function simply looks for the key in the trustdb
|
1998-06-29 14:30:57 +02:00
|
|
|
* and sets PK->local_id.
|
1998-01-31 22:24:36 +01:00
|
|
|
* Return: 0 = found
|
|
|
|
* -1 = not found
|
|
|
|
* other = error
|
|
|
|
*/
|
1998-01-16 22:15:24 +01:00
|
|
|
int
|
1998-06-29 14:30:57 +02:00
|
|
|
query_trust_record( PKT_public_key *pk )
|
1998-01-16 22:15:24 +01:00
|
|
|
{
|
|
|
|
TRUSTREC rec;
|
1998-01-24 17:32:27 +01:00
|
|
|
int rc=0;
|
1998-01-16 22:15:24 +01:00
|
|
|
|
1998-06-29 14:30:57 +02:00
|
|
|
if( pk->local_id ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
if( tdbio_read_record( pk->local_id, &rec, RECTYPE_DIR ) ) {
|
1998-01-24 17:32:27 +01:00
|
|
|
log_error("query_trust_record: read record failed\n");
|
1998-01-16 22:15:24 +01:00
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { /* no local_id: scan the trustdb */
|
1998-07-09 15:37:17 +02:00
|
|
|
if( (rc=tdbio_search_record( pk, &rec )) && rc != -1 ) {
|
1998-01-31 22:24:36 +01:00
|
|
|
log_error("query_trust_record: search_record failed: %s\n",
|
1998-01-16 22:15:24 +01:00
|
|
|
g10_errstr(rc));
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
1998-01-31 22:24:36 +01:00
|
|
|
return rc;
|
1998-01-16 22:15:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-01-13 20:04:23 +01:00
|
|
|
/****************
|
|
|
|
* Insert a trust record into the TrustDB
|
1998-04-14 19:51:16 +02:00
|
|
|
* This function fails if this record already exists.
|
1998-01-13 20:04:23 +01:00
|
|
|
*/
|
|
|
|
int
|
1998-06-29 14:30:57 +02:00
|
|
|
insert_trust_record( PKT_public_key *pk )
|
1998-01-13 20:04:23 +01:00
|
|
|
{
|
|
|
|
TRUSTREC rec;
|
|
|
|
u32 keyid[2];
|
1998-01-31 22:24:36 +01:00
|
|
|
ulong knum, dnum;
|
1998-01-13 20:04:23 +01:00
|
|
|
byte *fingerprint;
|
|
|
|
size_t fingerlen;
|
|
|
|
|
|
|
|
|
1998-06-29 14:30:57 +02:00
|
|
|
if( pk->local_id )
|
|
|
|
log_bug("pk->local_id=%lu\n", (ulong)pk->local_id );
|
1998-01-13 20:04:23 +01:00
|
|
|
|
1998-06-29 14:30:57 +02:00
|
|
|
keyid_from_pk( pk, keyid );
|
|
|
|
fingerprint = fingerprint_from_pk( pk, &fingerlen );
|
1998-01-13 20:04:23 +01:00
|
|
|
|
1998-07-09 15:37:17 +02:00
|
|
|
/* fixme: assert that we do not have this record. */
|
1998-01-13 20:04:23 +01:00
|
|
|
|
1998-07-09 15:37:17 +02:00
|
|
|
dnum = tdbio_new_recnum();
|
|
|
|
knum = tdbio_new_recnum();
|
1998-01-31 22:24:36 +01:00
|
|
|
/* build dir record */
|
1998-01-13 20:04:23 +01:00
|
|
|
memset( &rec, 0, sizeof rec );
|
1998-01-31 22:24:36 +01:00
|
|
|
rec.rectype = RECTYPE_DIR;
|
|
|
|
rec.r.dir.local_id = dnum;
|
|
|
|
rec.r.dir.keyid[0] = keyid[0];
|
|
|
|
rec.r.dir.keyid[1] = keyid[1];
|
|
|
|
rec.r.dir.keyrec = knum;
|
|
|
|
rec.r.dir.no_sigs = 0;
|
1998-07-09 15:37:17 +02:00
|
|
|
if( tdbio_write_record( dnum, &rec ) ) {
|
1998-01-31 22:24:36 +01:00
|
|
|
log_error("writing dir record failed\n");
|
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
}
|
|
|
|
/* and the key record */
|
|
|
|
memset( &rec, 0, sizeof rec );
|
|
|
|
rec.rectype = RECTYPE_KEY;
|
|
|
|
rec.r.key.owner = dnum;
|
|
|
|
rec.r.key.keyid[0] = keyid[0];
|
|
|
|
rec.r.key.keyid[1] = keyid[1];
|
1998-06-29 14:30:57 +02:00
|
|
|
rec.r.key.pubkey_algo = pk->pubkey_algo;
|
1998-06-13 19:00:02 +02:00
|
|
|
rec.r.key.fingerprint_len = fingerlen;
|
1998-01-31 22:24:36 +01:00
|
|
|
memcpy(rec.r.key.fingerprint, fingerprint, fingerlen );
|
|
|
|
rec.r.key.ownertrust = 0;
|
1998-07-09 15:37:17 +02:00
|
|
|
if( tdbio_write_record( knum, &rec ) ) {
|
1998-01-31 22:24:36 +01:00
|
|
|
log_error("wrinting key record failed\n");
|
1998-01-13 20:04:23 +01:00
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
}
|
1998-07-09 15:37:17 +02:00
|
|
|
/* and store the LID */
|
1998-06-29 14:30:57 +02:00
|
|
|
pk->local_id = dnum;
|
1998-01-13 20:04:23 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
1998-01-24 17:32:27 +01:00
|
|
|
update_ownertrust( ulong lid, unsigned new_trust )
|
1998-01-13 20:04:23 +01:00
|
|
|
{
|
|
|
|
TRUSTREC rec;
|
1998-01-31 22:24:36 +01:00
|
|
|
ulong recnum;
|
1998-01-13 20:04:23 +01:00
|
|
|
|
1998-07-09 15:37:17 +02:00
|
|
|
if( tdbio_read_record( lid, &rec, RECTYPE_DIR ) ) {
|
1998-01-31 22:24:36 +01:00
|
|
|
log_error("update_ownertrust: read dir failed\n");
|
1998-01-13 20:04:23 +01:00
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
}
|
1998-01-31 22:24:36 +01:00
|
|
|
recnum = rec.r.dir.keyrec;
|
1998-07-09 15:37:17 +02:00
|
|
|
if( tdbio_read_record( recnum, &rec, RECTYPE_KEY ) ) {
|
1998-01-31 22:24:36 +01:00
|
|
|
log_error("update_ownertrust: read key failed\n");
|
1998-01-24 17:32:27 +01:00
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
}
|
1998-01-31 22:24:36 +01:00
|
|
|
/* check keyid, fingerprint etc ? */
|
1998-01-13 20:04:23 +01:00
|
|
|
|
1998-01-31 22:24:36 +01:00
|
|
|
rec.r.key.ownertrust = new_trust;
|
1998-07-09 15:37:17 +02:00
|
|
|
if( tdbio_write_record( recnum, &rec ) ) {
|
1998-01-24 17:32:27 +01:00
|
|
|
log_error("update_ownertrust: write failed\n");
|
1998-01-25 19:56:33 +01:00
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
* Kludge to prevent duplicate build_sigrecs() due to an invalid
|
|
|
|
* certificate (no selfsignature or something like this)
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
update_no_sigs( ulong lid, int no_sigs )
|
|
|
|
{
|
|
|
|
TRUSTREC rec;
|
|
|
|
|
1998-07-09 15:37:17 +02:00
|
|
|
if( tdbio_read_record( lid, &rec, RECTYPE_DIR ) ) {
|
1998-01-25 19:56:33 +01:00
|
|
|
log_error("update_no_sigs: read failed\n");
|
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
}
|
|
|
|
|
1998-02-02 15:36:06 +01:00
|
|
|
rec.r.dir.no_sigs = no_sigs;
|
1998-07-09 15:37:17 +02:00
|
|
|
if( tdbio_write_record( lid, &rec ) ) {
|
1998-01-25 19:56:33 +01:00
|
|
|
log_error("update_no_sigs: write failed\n");
|
1998-01-13 20:04:23 +01:00
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|