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-12-23 13:41:40 +01:00
|
|
|
|
* This file is part of GnuPG.
|
1998-01-02 21:40:10 +01:00
|
|
|
|
*
|
1998-12-23 13:41:40 +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-12-23 13:41:40 +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>
|
1998-07-29 21:35:05 +02:00
|
|
|
|
#include <ctype.h>
|
1998-01-02 21:40:10 +01:00
|
|
|
|
#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-07-14 19:10:28 +02:00
|
|
|
|
#if MAX_FINGERPRINT_LEN > 20
|
|
|
|
|
#error Must change structure of trustdb
|
|
|
|
|
#endif
|
|
|
|
|
|
1998-12-08 13:20:53 +01:00
|
|
|
|
struct keyid_list {
|
|
|
|
|
struct keyid_list *next;
|
|
|
|
|
u32 keyid[2];
|
|
|
|
|
};
|
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
struct local_id_item {
|
|
|
|
|
struct local_id_item *next;
|
1998-01-16 22:15:24 +01:00
|
|
|
|
ulong lid;
|
|
|
|
|
unsigned flag;
|
|
|
|
|
};
|
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
struct local_id_table {
|
|
|
|
|
struct local_id_table *next; /* only used to keep a list of unused tables */
|
|
|
|
|
struct local_id_item *items[16];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct local_id_table *LOCAL_ID_TABLE;
|
|
|
|
|
|
1998-01-16 22:15:24 +01:00
|
|
|
|
|
1998-01-24 17:32:27 +01:00
|
|
|
|
typedef struct trust_info TRUST_INFO;
|
|
|
|
|
struct trust_info {
|
|
|
|
|
ulong lid;
|
1998-11-03 20:38:58 +01:00
|
|
|
|
byte otrust; /* ownertrust (assigned trust) */
|
1998-11-13 20:41:41 +01:00
|
|
|
|
byte trust; /* calculated trust (validity) */
|
1998-01-24 17:32:27 +01:00
|
|
|
|
};
|
|
|
|
|
|
1998-01-19 19:54:44 +01:00
|
|
|
|
typedef struct trust_seg_list *TRUST_SEG_LIST;
|
|
|
|
|
struct trust_seg_list {
|
|
|
|
|
TRUST_SEG_LIST next;
|
1998-11-03 20:38:58 +01:00
|
|
|
|
int pathlen;
|
|
|
|
|
TRUST_INFO path[1];
|
1998-01-19 19:54:44 +01:00
|
|
|
|
};
|
|
|
|
|
|
1998-01-12 11:18:17 +01:00
|
|
|
|
|
1998-12-17 18:36:05 +01:00
|
|
|
|
struct enum_cert_paths_ctx {
|
|
|
|
|
int init;
|
|
|
|
|
TRUST_SEG_LIST tsl_head;
|
|
|
|
|
TRUST_SEG_LIST tsl;
|
|
|
|
|
int idx;
|
|
|
|
|
};
|
|
|
|
|
|
1998-01-24 17:32:27 +01:00
|
|
|
|
|
1998-10-07 15:30:43 +02:00
|
|
|
|
struct recno_list_struct {
|
|
|
|
|
struct recno_list_struct *next;
|
|
|
|
|
ulong recno;
|
|
|
|
|
int type;
|
|
|
|
|
};
|
|
|
|
|
typedef struct recno_list_struct *RECNO_LIST;
|
|
|
|
|
|
|
|
|
|
|
1998-10-12 22:16:38 +02:00
|
|
|
|
static int walk_sigrecs( SIGREC_CONTEXT *c );
|
1998-01-16 22:15:24 +01:00
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
static LOCAL_ID_TABLE new_lid_table(void);
|
|
|
|
|
static void release_lid_table( LOCAL_ID_TABLE tbl );
|
|
|
|
|
static int ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag );
|
|
|
|
|
static int qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag );
|
1998-01-16 22:15:24 +01:00
|
|
|
|
|
1999-02-10 17:22:40 +01:00
|
|
|
|
|
|
|
|
|
|
1998-01-16 22:15:24 +01:00
|
|
|
|
static void print_user_id( const char *text, u32 *keyid );
|
1998-12-17 18:36:05 +01:00
|
|
|
|
static void sort_tsl_list( TRUST_SEG_LIST *trust_seg_list );
|
1998-01-16 22:15:24 +01:00
|
|
|
|
static int list_sigs( ulong pubkey_id );
|
1998-07-14 19:10:28 +02:00
|
|
|
|
static int do_check( TRUSTREC *drec, unsigned *trustlevel );
|
1998-10-12 22:16:38 +02:00
|
|
|
|
static int get_dir_record( PKT_public_key *pk, TRUSTREC *rec );
|
1998-01-16 22:15:24 +01:00
|
|
|
|
|
1998-11-05 19:00:08 +01:00
|
|
|
|
static void upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig );
|
|
|
|
|
static void upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
|
|
|
|
|
TRUSTREC *drec, RECNO_LIST *recno_list, int recheck,
|
1999-02-16 14:16:33 +01:00
|
|
|
|
TRUSTREC *urec, const byte *uidhash, int revoked );
|
1998-11-05 19:00:08 +01:00
|
|
|
|
|
1998-12-08 13:20:53 +01:00
|
|
|
|
static struct keyid_list *trusted_key_list;
|
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
|
1998-12-08 13:20:53 +01:00
|
|
|
|
* which are the ones from our secrings and the trusted keys */
|
1998-11-03 20:38:58 +01:00
|
|
|
|
static LOCAL_ID_TABLE ultikey_table;
|
1998-01-13 20:04:23 +01:00
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
/* list of unused lid items and tables */
|
|
|
|
|
static LOCAL_ID_TABLE unused_lid_tables;
|
|
|
|
|
static struct local_id_item *unused_lid_items;
|
1998-01-24 17:32:27 +01:00
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
static struct {
|
|
|
|
|
int init;
|
|
|
|
|
int level;
|
|
|
|
|
char *dbname;
|
|
|
|
|
} trustdb_args;
|
|
|
|
|
#define INIT_TRUSTDB() do { if( !trustdb_args.init ) \
|
|
|
|
|
do_init_trustdb(); \
|
|
|
|
|
} while(0)
|
|
|
|
|
static void do_init_trustdb(void);
|
1998-01-12 11:18:17 +01:00
|
|
|
|
|
1998-07-29 21:35:05 +02:00
|
|
|
|
#define HEXTOBIN(a) ( (a) >= '0' && (a) <= '9' ? ((a)-'0') : \
|
|
|
|
|
(a) >= 'A' && (a) <= 'F' ? ((a)-'A'+10) : ((a)-'a'+10))
|
1998-10-07 15:30:43 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************
|
|
|
|
|
*********** record read write **************
|
|
|
|
|
**********************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
1999-02-16 14:16:33 +01:00
|
|
|
|
die_invalid_db(void)
|
1998-10-07 15:30:43 +02:00
|
|
|
|
{
|
|
|
|
|
log_error(_(
|
1998-12-29 14:47:31 +01:00
|
|
|
|
"The trustdb is corrupted; please run \"gpgm --fix-trustdb\".\n") );
|
1998-10-07 15:30:43 +02:00
|
|
|
|
g10_exit(2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
|
* Read a record but die if it does not exist
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
read_record( ulong recno, TRUSTREC *rec, int rectype )
|
|
|
|
|
{
|
|
|
|
|
int rc = tdbio_read_record( recno, rec, rectype );
|
|
|
|
|
if( !rc )
|
|
|
|
|
return;
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("trust record %lu, req type %d: read failed: %s\n"),
|
1998-10-07 15:30:43 +02:00
|
|
|
|
recno, rectype, g10_errstr(rc) );
|
|
|
|
|
die_invalid_db();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
|
* Wirte a record but die on error
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
write_record( TRUSTREC *rec )
|
|
|
|
|
{
|
|
|
|
|
int rc = tdbio_write_record( rec );
|
|
|
|
|
if( !rc )
|
|
|
|
|
return;
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("trust record %lu, type %d: write failed: %s\n"),
|
1998-10-07 15:30:43 +02:00
|
|
|
|
rec->recnum, rec->rectype, g10_errstr(rc) );
|
|
|
|
|
die_invalid_db();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
|
* Delete a record but die on error
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
delete_record( ulong recno )
|
|
|
|
|
{
|
|
|
|
|
int rc = tdbio_delete_record( recno );
|
|
|
|
|
if( !rc )
|
|
|
|
|
return;
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("trust record %lu: delete failed: %s\n"),
|
1998-10-07 15:30:43 +02:00
|
|
|
|
recno, g10_errstr(rc) );
|
|
|
|
|
die_invalid_db();
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-16 18:00:17 +02:00
|
|
|
|
/****************
|
|
|
|
|
* sync the db
|
|
|
|
|
*/
|
|
|
|
|
static void
|
1999-02-16 14:16:33 +01:00
|
|
|
|
do_sync(void)
|
1998-10-16 18:00:17 +02:00
|
|
|
|
{
|
|
|
|
|
int rc = tdbio_sync();
|
|
|
|
|
if( !rc )
|
|
|
|
|
return;
|
1998-12-29 14:47:31 +01:00
|
|
|
|
log_error(_("trustdb: sync failed: %s\n"), g10_errstr(rc) );
|
1998-10-16 18:00:17 +02:00
|
|
|
|
g10_exit(2);
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-07 15:30:43 +02:00
|
|
|
|
|
1998-09-28 21:25:31 +02:00
|
|
|
|
|
1998-01-30 21:25:31 +01:00
|
|
|
|
/**********************************************
|
|
|
|
|
************* list helpers *******************
|
|
|
|
|
**********************************************/
|
|
|
|
|
|
1998-10-07 15:30:43 +02:00
|
|
|
|
/****************
|
|
|
|
|
* Insert a new item into a recno list
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
ins_recno_list( RECNO_LIST *head, ulong recno, int type )
|
|
|
|
|
{
|
|
|
|
|
RECNO_LIST item = m_alloc( sizeof *item );
|
|
|
|
|
|
|
|
|
|
item->recno = recno;
|
|
|
|
|
item->type = type;
|
|
|
|
|
item->next = *head;
|
|
|
|
|
*head = item;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static RECNO_LIST
|
|
|
|
|
qry_recno_list( RECNO_LIST list, ulong recno, int type )
|
|
|
|
|
{
|
|
|
|
|
for( ; list; list = list->next ) {
|
|
|
|
|
if( list->recno == recno && (!type || list->type == type) )
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
rel_recno_list( RECNO_LIST *head )
|
|
|
|
|
{
|
|
|
|
|
RECNO_LIST r, r2;
|
|
|
|
|
|
|
|
|
|
for(r = *head; r; r = r2 ) {
|
|
|
|
|
r2 = r->next;
|
|
|
|
|
m_free(r);
|
|
|
|
|
}
|
|
|
|
|
*head = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
static LOCAL_ID_TABLE
|
1998-01-30 21:25:31 +01:00
|
|
|
|
new_lid_table(void)
|
|
|
|
|
{
|
1998-11-03 20:38:58 +01:00
|
|
|
|
LOCAL_ID_TABLE a;
|
|
|
|
|
|
|
|
|
|
a = unused_lid_tables;
|
|
|
|
|
if( a ) {
|
|
|
|
|
unused_lid_tables = a->next;
|
1998-11-10 13:59:59 +01:00
|
|
|
|
memset( a, 0, sizeof *a );
|
1998-11-03 20:38:58 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
a = m_alloc_clear( sizeof *a );
|
|
|
|
|
return a;
|
1998-01-30 21:25:31 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
1998-11-03 20:38:58 +01:00
|
|
|
|
release_lid_table( LOCAL_ID_TABLE tbl )
|
1998-01-30 21:25:31 +01:00
|
|
|
|
{
|
1998-11-03 20:38:58 +01:00
|
|
|
|
struct local_id_item *a, *a2;
|
1998-01-30 21:25:31 +01:00
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for(i=0; i < 16; i++ ) {
|
1998-11-03 20:38:58 +01:00
|
|
|
|
for(a=tbl->items[i]; a; a = a2 ) {
|
1998-01-30 21:25:31 +01:00
|
|
|
|
a2 = a->next;
|
1998-11-03 20:38:58 +01:00
|
|
|
|
a->next = unused_lid_items;
|
|
|
|
|
unused_lid_items = a;
|
1998-01-30 21:25:31 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-11-03 20:38:58 +01:00
|
|
|
|
tbl->next = unused_lid_tables;
|
|
|
|
|
unused_lid_tables = tbl;
|
1998-01-30 21:25:31 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
|
* Add a new item to the table or return 1 if we already have this item
|
|
|
|
|
*/
|
|
|
|
|
static int
|
1998-11-03 20:38:58 +01:00
|
|
|
|
ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag )
|
1998-01-30 21:25:31 +01:00
|
|
|
|
{
|
1998-11-03 20:38:58 +01:00
|
|
|
|
struct local_id_item *a;
|
1998-01-30 21:25:31 +01:00
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
for( a = tbl->items[lid & 0x0f]; a; a = a->next )
|
1998-01-30 21:25:31 +01:00
|
|
|
|
if( a->lid == lid )
|
|
|
|
|
return 1;
|
1998-11-03 20:38:58 +01:00
|
|
|
|
a = unused_lid_items;
|
|
|
|
|
if( a )
|
|
|
|
|
unused_lid_items = a->next;
|
|
|
|
|
else
|
|
|
|
|
a = m_alloc( sizeof *a );
|
1998-01-30 21:25:31 +01:00
|
|
|
|
a->lid = lid;
|
|
|
|
|
a->flag = flag;
|
1998-11-03 20:38:58 +01:00
|
|
|
|
a->next = tbl->items[lid & 0x0f];
|
|
|
|
|
tbl->items[lid & 0x0f] = a;
|
1998-01-30 21:25:31 +01:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
1998-11-03 20:38:58 +01:00
|
|
|
|
qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag )
|
1998-01-30 21:25:31 +01:00
|
|
|
|
{
|
1998-11-03 20:38:58 +01:00
|
|
|
|
struct local_id_item *a;
|
1998-01-30 21:25:31 +01:00
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
for( a = tbl->items[lid & 0x0f]; a; a = a->next )
|
1998-01-30 21:25:31 +01:00
|
|
|
|
if( a->lid == lid ) {
|
|
|
|
|
if( flag )
|
|
|
|
|
*flag = a->flag;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1998-07-21 14:53:38 +02:00
|
|
|
|
/****************
|
|
|
|
|
* Return the keyid from the primary key identified by LID.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
keyid_from_lid( ulong lid, u32 *keyid )
|
1998-01-30 21:25:31 +01:00
|
|
|
|
{
|
|
|
|
|
TRUSTREC rec;
|
|
|
|
|
int rc;
|
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-10-25 20:00:01 +01:00
|
|
|
|
rc = tdbio_read_record( lid, &rec, 0 );
|
1998-01-30 21:25:31 +01:00
|
|
|
|
if( rc ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("error reading dir record for LID %lu: %s\n"),
|
1998-01-30 21:25:31 +01:00
|
|
|
|
lid, g10_errstr(rc));
|
|
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
|
}
|
1998-10-25 20:00:01 +01:00
|
|
|
|
if( rec.rectype == RECTYPE_SDIR )
|
|
|
|
|
return 0;
|
|
|
|
|
if( rec.rectype != RECTYPE_DIR ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("lid %lu: expected dir record, got type %d\n"),
|
1998-10-25 20:00:01 +01:00
|
|
|
|
lid, rec.rectype );
|
|
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
|
}
|
1998-07-21 14:53:38 +02:00
|
|
|
|
if( !rec.r.dir.keylist ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("no primary key for LID %lu\n"), lid );
|
1998-01-30 21:25:31 +01:00
|
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
|
}
|
1998-07-21 14:53:38 +02:00
|
|
|
|
rc = tdbio_read_record( rec.r.dir.keylist, &rec, RECTYPE_KEY );
|
|
|
|
|
if( rc ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("error reading primary key for LID %lu: %s\n"),
|
1998-07-21 14:53:38 +02:00
|
|
|
|
lid, g10_errstr(rc));
|
|
|
|
|
return G10ERR_TRUSTDB;
|
|
|
|
|
}
|
|
|
|
|
keyid_from_fingerprint( rec.r.key.fingerprint, rec.r.key.fingerprint_len,
|
|
|
|
|
keyid );
|
|
|
|
|
|
1998-01-30 21:25:31 +01:00
|
|
|
|
return 0;
|
1998-01-16 22:15:24 +01:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-12 22:16:38 +02:00
|
|
|
|
|
|
|
|
|
ulong
|
|
|
|
|
lid_from_keyblock( KBNODE keyblock )
|
|
|
|
|
{
|
|
|
|
|
KBNODE node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
|
|
|
|
|
PKT_public_key *pk;
|
|
|
|
|
if( !node )
|
|
|
|
|
BUG();
|
|
|
|
|
pk = node->pkt->pkt.public_key;
|
|
|
|
|
if( !pk->local_id ) {
|
|
|
|
|
TRUSTREC rec;
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-10-12 22:16:38 +02:00
|
|
|
|
|
|
|
|
|
get_dir_record( pk, &rec );
|
|
|
|
|
}
|
|
|
|
|
return pk->local_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1998-09-28 21:25:31 +02:00
|
|
|
|
|
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-10-12 22:16:38 +02:00
|
|
|
|
walk_sigrecs( SIGREC_CONTEXT *c )
|
1998-01-16 22:15:24 +01:00
|
|
|
|
{
|
|
|
|
|
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;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
read_record( c->lid, r, 0 );
|
|
|
|
|
if( r->rectype != RECTYPE_DIR ) {
|
|
|
|
|
c->ctl.eof = 1;
|
|
|
|
|
return -1; /* return eof */
|
|
|
|
|
}
|
1998-07-21 14:53:38 +02:00
|
|
|
|
c->ctl.nextuid = r->r.dir.uidlist;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
/* force a read */
|
1998-07-21 14:53:38 +02:00
|
|
|
|
c->ctl.index = SIGS_PER_RECORD;
|
|
|
|
|
r->r.sig.next = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* need a loop to skip over deleted sigs */
|
|
|
|
|
do {
|
|
|
|
|
if( c->ctl.index >= SIGS_PER_RECORD ) { /* read the record */
|
|
|
|
|
rnum = r->r.sig.next;
|
|
|
|
|
if( !rnum && c->ctl.nextuid ) { /* read next uid record */
|
1998-10-07 15:30:43 +02:00
|
|
|
|
read_record( c->ctl.nextuid, r, RECTYPE_UID );
|
1998-07-21 14:53:38 +02:00
|
|
|
|
c->ctl.nextuid = r->r.uid.next;
|
|
|
|
|
rnum = r->r.uid.siglist;
|
1998-01-25 19:56:33 +01:00
|
|
|
|
}
|
1998-01-31 22:24:36 +01:00
|
|
|
|
if( !rnum ) {
|
1998-01-16 22:15:24 +01:00
|
|
|
|
c->ctl.eof = 1;
|
|
|
|
|
return -1; /* return eof */
|
|
|
|
|
}
|
1998-10-07 15:30:43 +02:00
|
|
|
|
read_record( rnum, r, RECTYPE_SIG );
|
1998-07-21 14:53:38 +02:00
|
|
|
|
if( r->r.sig.lid != c->lid ) {
|
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;
|
1998-10-07 15:30:43 +02:00
|
|
|
|
die_invalid_db();
|
1998-01-16 22:15:24 +01:00
|
|
|
|
}
|
|
|
|
|
c->ctl.index = 0;
|
|
|
|
|
}
|
1998-07-21 14:53:38 +02:00
|
|
|
|
} while( !r->r.sig.sig[c->ctl.index++].lid );
|
|
|
|
|
|
|
|
|
|
c->sig_lid = r->r.sig.sig[c->ctl.index-1].lid;
|
1998-01-31 22:24:36 +01:00
|
|
|
|
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-09-28 21:25:31 +02:00
|
|
|
|
|
1998-01-30 21:25:31 +01:00
|
|
|
|
/***********************************************
|
|
|
|
|
************* Trust stuff ******************
|
|
|
|
|
***********************************************/
|
1998-01-16 22:15:24 +01:00
|
|
|
|
|
1998-11-18 20:59:06 +01:00
|
|
|
|
static int
|
|
|
|
|
trust_letter( unsigned value )
|
|
|
|
|
{
|
|
|
|
|
switch( value ) {
|
|
|
|
|
case TRUST_UNKNOWN: return '-';
|
|
|
|
|
case TRUST_EXPIRED: return 'e';
|
|
|
|
|
case TRUST_UNDEFINED: return 'q';
|
|
|
|
|
case TRUST_NEVER: return 'n';
|
|
|
|
|
case TRUST_MARGINAL: return 'm';
|
|
|
|
|
case TRUST_FULLY: return 'f';
|
|
|
|
|
case TRUST_ULTIMATE: return 'u';
|
|
|
|
|
default: return 0 ;
|
|
|
|
|
}
|
|
|
|
|
}
|
1998-01-16 22:15:24 +01:00
|
|
|
|
|
1998-12-08 13:20:53 +01:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
register_trusted_key( const char *string )
|
|
|
|
|
{
|
|
|
|
|
u32 keyid[2];
|
|
|
|
|
struct keyid_list *r;
|
|
|
|
|
|
|
|
|
|
if( classify_user_id( string, keyid, NULL, NULL, NULL ) != 11 ) {
|
|
|
|
|
log_error(_("'%s' is not a valid long keyID\n"), string );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for( r = trusted_key_list; r; r = r->next )
|
|
|
|
|
if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] )
|
|
|
|
|
return;
|
|
|
|
|
r = m_alloc( sizeof *r );
|
|
|
|
|
r->keyid[0] = keyid[0];
|
|
|
|
|
r->keyid[1] = keyid[1];
|
|
|
|
|
r->next = trusted_key_list;
|
|
|
|
|
trusted_key_list = r;
|
|
|
|
|
}
|
|
|
|
|
|
1998-01-13 20:04:23 +01:00
|
|
|
|
/****************
|
1998-12-08 13:20:53 +01:00
|
|
|
|
* Verify that all our public keys are in the trustdb.
|
1998-01-13 20:04:23 +01:00
|
|
|
|
*/
|
|
|
|
|
static int
|
1999-02-16 14:16:33 +01:00
|
|
|
|
verify_own_keys(void)
|
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-12-08 13:20:53 +01:00
|
|
|
|
struct keyid_list *kl;
|
|
|
|
|
|
|
|
|
|
/* put the trusted keys into the trusted key table */
|
|
|
|
|
for( kl = trusted_key_list; kl; kl = kl->next ) {
|
|
|
|
|
keyid[0] = kl->keyid[0];
|
|
|
|
|
keyid[1] = kl->keyid[1];
|
|
|
|
|
/* get the public key */
|
|
|
|
|
memset( pk, 0, sizeof *pk );
|
|
|
|
|
rc = get_pubkey( pk, keyid );
|
|
|
|
|
if( rc ) {
|
|
|
|
|
log_info(_("key %08lX: no public key for trusted key - skipped\n"),
|
|
|
|
|
(ulong)keyid[1] );
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* make sure that the pubkey is in the trustdb */
|
|
|
|
|
rc = query_trust_record( pk );
|
|
|
|
|
if( rc == -1 ) { /* put it into the trustdb */
|
|
|
|
|
rc = insert_trust_record( pk );
|
|
|
|
|
if( rc ) {
|
|
|
|
|
log_error(_("key %08lX: can't put it into the trustdb\n"),
|
|
|
|
|
(ulong)keyid[1] );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( rc ) {
|
|
|
|
|
log_error(_("key %08lX: query record failed\n"),
|
|
|
|
|
(ulong)keyid[1] );
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if( ins_lid_table_item( ultikey_table, pk->local_id, 0 ) )
|
|
|
|
|
log_error(_("key %08lX: already in trusted key table\n"),
|
|
|
|
|
(ulong)keyid[1]);
|
|
|
|
|
else if( opt.verbose > 1 )
|
|
|
|
|
log_info(_("key %08lX: accepted as trusted key.\n"),
|
|
|
|
|
(ulong)keyid[1]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
release_public_key_parts( pk );
|
|
|
|
|
}
|
1998-01-13 20:04:23 +01:00
|
|
|
|
|
1998-09-11 07:47:32 +02:00
|
|
|
|
while( !(rc=enum_secret_keys( &enum_context, sk, 0 ) ) ) {
|
1998-12-08 13:20:53 +01:00
|
|
|
|
int have_pk = 0;
|
|
|
|
|
|
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-09-28 21:25:31 +02:00
|
|
|
|
if( is_secret_key_protected( sk ) < 1 )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info(_("NOTE: secret key %08lX is NOT protected.\n"),
|
1998-09-28 21:25:31 +02:00
|
|
|
|
(ulong)keyid[1] );
|
|
|
|
|
|
1998-12-08 13:20:53 +01:00
|
|
|
|
for( kl = trusted_key_list; kl; kl = kl->next ) {
|
|
|
|
|
if( kl->keyid[0] == keyid[0] && kl->keyid[1] == keyid[1] )
|
|
|
|
|
goto skip; /* already in trusted key table */
|
|
|
|
|
}
|
|
|
|
|
|
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-10-16 18:00:17 +02:00
|
|
|
|
log_info(_("key %08lX: secret key without public key - skipped\n"),
|
1998-01-13 20:04:23 +01:00
|
|
|
|
(ulong)keyid[1] );
|
1998-10-16 18:00:17 +02:00
|
|
|
|
goto skip;
|
1998-01-13 20:04:23 +01:00
|
|
|
|
}
|
1998-12-08 13:20:53 +01:00
|
|
|
|
have_pk=1;
|
1998-10-16 18:00:17 +02:00
|
|
|
|
|
1998-06-29 14:30:57 +02:00
|
|
|
|
if( cmp_public_secret_key( pk, sk ) ) {
|
1998-10-16 18:00:17 +02:00
|
|
|
|
log_info(_("key %08lX: secret and public key don't match\n"),
|
1998-01-13 20:04:23 +01:00
|
|
|
|
(ulong)keyid[1] );
|
1998-10-16 18:00:17 +02:00
|
|
|
|
goto skip;
|
1998-01-13 20:04:23 +01:00
|
|
|
|
}
|
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] );
|
1998-10-16 18:00:17 +02:00
|
|
|
|
goto skip;
|
1998-01-24 17:32:27 +01:00
|
|
|
|
}
|
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-10-16 18:00:17 +02:00
|
|
|
|
goto skip;
|
1998-01-24 17:32:27 +01:00
|
|
|
|
|
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-12-08 13:20:53 +01:00
|
|
|
|
log_error(_("key %08lX: already in trusted key table\n"),
|
1998-01-19 19:54:44 +01:00
|
|
|
|
(ulong)keyid[1]);
|
1998-11-10 13:59:59 +01:00
|
|
|
|
else if( opt.verbose > 1 )
|
1998-12-08 13:20:53 +01:00
|
|
|
|
log_info(_("key %08lX: accepted as trusted key.\n"),
|
1998-10-16 18:00:17 +02:00
|
|
|
|
(ulong)keyid[1]);
|
|
|
|
|
skip:
|
1998-06-29 14:30:57 +02:00
|
|
|
|
release_secret_key_parts( sk );
|
1998-12-08 13:20:53 +01:00
|
|
|
|
if( have_pk )
|
|
|
|
|
release_public_key_parts( pk );
|
1998-01-13 20:04:23 +01:00
|
|
|
|
}
|
|
|
|
|
if( rc != -1 )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("enumerate secret keys failed: %s\n"), g10_errstr(rc) );
|
1998-01-13 20:04:23 +01:00
|
|
|
|
else
|
|
|
|
|
rc = 0;
|
|
|
|
|
|
1998-12-08 13:20:53 +01:00
|
|
|
|
/* release the trusted keyid table */
|
|
|
|
|
{ struct keyid_list *kl2;
|
|
|
|
|
for( kl = trusted_key_list; kl; kl = kl2 ) {
|
|
|
|
|
kl2 = kl->next;
|
|
|
|
|
m_free( kl );
|
|
|
|
|
}
|
|
|
|
|
trusted_key_list = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-06 14:10:02 +02:00
|
|
|
|
enum_secret_keys( &enum_context, NULL, 0 ); /* free context */
|
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-11-03 20:38:58 +01:00
|
|
|
|
#if 0
|
1998-10-25 20:00:01 +01:00
|
|
|
|
static int
|
1998-07-09 15:37:17 +02:00
|
|
|
|
print_keyid( FILE *fp, ulong lid )
|
|
|
|
|
{
|
|
|
|
|
u32 ki[2];
|
1998-07-21 14:53:38 +02:00
|
|
|
|
if( keyid_from_lid( lid, ki ) )
|
1998-10-25 20:00:01 +01:00
|
|
|
|
return fprintf(fp, "????????.%lu", lid );
|
1998-07-09 15:37:17 +02:00
|
|
|
|
else
|
1998-10-25 20:00:01 +01:00
|
|
|
|
return fprintf(fp, "%08lX.%lu", (ulong)ki[1], lid );
|
1998-07-09 15:37:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-25 20:00:01 +01:00
|
|
|
|
static int
|
1998-07-09 15:37:17 +02:00
|
|
|
|
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;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
default: fprintf(fp, "%02x", trust ); return 2;
|
1998-07-09 15:37:17 +02:00
|
|
|
|
}
|
|
|
|
|
putc(c, fp);
|
1998-10-25 20:00:01 +01:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
1998-11-03 20:38:58 +01:00
|
|
|
|
#endif
|
1998-10-25 20:00:01 +01:00
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
print_sigflags( FILE *fp, unsigned flags )
|
|
|
|
|
{
|
|
|
|
|
if( flags & SIGF_CHECKED ) {
|
|
|
|
|
fprintf(fp,"%c%c%c",
|
|
|
|
|
(flags & SIGF_VALID) ? 'V':'-',
|
|
|
|
|
(flags & SIGF_EXPIRED) ? 'E':'-',
|
|
|
|
|
(flags & SIGF_REVOKED) ? 'R':'-');
|
|
|
|
|
}
|
|
|
|
|
else if( flags & SIGF_NOPUBKEY)
|
|
|
|
|
fputs("?--", fp);
|
|
|
|
|
else
|
|
|
|
|
fputs("---", fp);
|
|
|
|
|
return 3;
|
1998-07-09 15:37:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
1998-01-16 22:15:24 +01:00
|
|
|
|
/* (a non-recursive algorithm would be easier) */
|
|
|
|
|
static int
|
1998-10-25 20:00:01 +01:00
|
|
|
|
do_list_sigs( ulong root, ulong pk_lid, int depth,
|
1998-11-03 20:38:58 +01:00
|
|
|
|
LOCAL_ID_TABLE lids, unsigned *lineno )
|
1998-01-16 22:15:24 +01:00
|
|
|
|
{
|
|
|
|
|
SIGREC_CONTEXT sx;
|
|
|
|
|
int rc;
|
|
|
|
|
u32 keyid[2];
|
|
|
|
|
|
|
|
|
|
memset( &sx, 0, sizeof sx );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
sx.lid = pk_lid;
|
1998-01-16 22:15:24 +01:00
|
|
|
|
for(;;) {
|
1998-11-03 20:38:58 +01:00
|
|
|
|
rc = walk_sigrecs( &sx ); /* should we replace it and use */
|
|
|
|
|
if( rc ) /* use a loop like in collect_paths ??*/
|
1998-01-16 22:15:24 +01:00
|
|
|
|
break;
|
1998-07-21 14:53:38 +02:00
|
|
|
|
rc = keyid_from_lid( sx.sig_lid, keyid );
|
1998-01-16 22:15:24 +01:00
|
|
|
|
if( rc ) {
|
1998-10-25 20:00:01 +01:00
|
|
|
|
printf("%6u: %*s????????.%lu:", *lineno, depth*4, "", sx.sig_lid );
|
|
|
|
|
print_sigflags( stdout, sx.sig_flag );
|
|
|
|
|
putchar('\n');
|
1998-01-16 22:15:24 +01:00
|
|
|
|
++*lineno;
|
|
|
|
|
}
|
|
|
|
|
else {
|
1998-10-25 20:00:01 +01:00
|
|
|
|
printf("%6u: %*s%08lX.%lu:", *lineno, depth*4, "",
|
|
|
|
|
(ulong)keyid[1], sx.sig_lid );
|
|
|
|
|
print_sigflags( stdout, sx.sig_flag );
|
|
|
|
|
putchar(' ');
|
|
|
|
|
/* check whether we already checked this pk_lid */
|
1998-07-21 14:53:38 +02:00
|
|
|
|
if( !qry_lid_table_flag( ultikey_table, sx.sig_lid, NULL ) ) {
|
1998-01-16 22:15:24 +01:00
|
|
|
|
print_user_id("[ultimately trusted]", keyid);
|
|
|
|
|
++*lineno;
|
|
|
|
|
}
|
1998-10-25 20:00:01 +01:00
|
|
|
|
else if( sx.sig_lid == pk_lid ) {
|
1998-01-16 22:15:24 +01:00
|
|
|
|
printf("[self-signature]\n");
|
|
|
|
|
++*lineno;
|
|
|
|
|
}
|
1998-07-21 14:53:38 +02:00
|
|
|
|
else if( sx.sig_lid == root ) {
|
1998-01-16 22:15:24 +01:00
|
|
|
|
printf("[closed]\n");
|
|
|
|
|
++*lineno;
|
|
|
|
|
}
|
1998-07-21 14:53:38 +02:00
|
|
|
|
else if( ins_lid_table_item( lids, sx.sig_lid, *lineno ) ) {
|
1998-01-16 22:15:24 +01:00
|
|
|
|
unsigned refline;
|
1998-07-21 14:53:38 +02:00
|
|
|
|
qry_lid_table_flag( lids, sx.sig_lid, &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;
|
1998-07-21 14:53:38 +02:00
|
|
|
|
rc = do_list_sigs( root, sx.sig_lid, depth+1, lids, lineno );
|
1998-01-16 22:15:24 +01:00
|
|
|
|
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];
|
1998-11-03 20:38:58 +01:00
|
|
|
|
LOCAL_ID_TABLE lids;
|
1998-01-16 22:15:24 +01:00
|
|
|
|
unsigned lineno = 1;
|
|
|
|
|
|
1998-07-21 14:53:38 +02:00
|
|
|
|
rc = keyid_from_lid( pubkey_id, keyid );
|
|
|
|
|
if( rc )
|
1998-01-16 22:15:24 +01:00
|
|
|
|
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-07-21 14:53:38 +02:00
|
|
|
|
/****************
|
|
|
|
|
* List all records of a public key
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
list_records( ulong lid )
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
TRUSTREC dr, ur, rec;
|
|
|
|
|
ulong recno;
|
|
|
|
|
|
|
|
|
|
rc = tdbio_read_record( lid, &dr, RECTYPE_DIR );
|
|
|
|
|
if( rc ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("lid %lu: read dir record failed: %s\n"),
|
|
|
|
|
lid, g10_errstr(rc));
|
1998-07-21 14:53:38 +02:00
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
tdbio_dump_record( &dr, stdout );
|
|
|
|
|
|
|
|
|
|
for( recno=dr.r.dir.keylist; recno; recno = rec.r.key.next ) {
|
1998-10-25 20:00:01 +01:00
|
|
|
|
rc = tdbio_read_record( recno, &rec, 0 );
|
1998-07-21 14:53:38 +02:00
|
|
|
|
if( rc ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("lid %lu: read key record failed: %s\n"),
|
1998-07-21 14:53:38 +02:00
|
|
|
|
lid, g10_errstr(rc));
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
tdbio_dump_record( &rec, stdout );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for( recno=dr.r.dir.uidlist; recno; recno = ur.r.uid.next ) {
|
|
|
|
|
rc = tdbio_read_record( recno, &ur, RECTYPE_UID );
|
|
|
|
|
if( rc ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("lid %lu: read uid record failed: %s\n"),
|
1998-07-21 14:53:38 +02:00
|
|
|
|
lid, g10_errstr(rc));
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
tdbio_dump_record( &ur, stdout );
|
|
|
|
|
/* preference records */
|
|
|
|
|
for(recno=ur.r.uid.prefrec; recno; recno = rec.r.pref.next ) {
|
|
|
|
|
rc = tdbio_read_record( recno, &rec, RECTYPE_PREF );
|
|
|
|
|
if( rc ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("lid %lu: read pref record failed: %s\n"),
|
1998-07-21 14:53:38 +02:00
|
|
|
|
lid, g10_errstr(rc));
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
tdbio_dump_record( &rec, stdout );
|
|
|
|
|
}
|
|
|
|
|
/* sig records */
|
|
|
|
|
for(recno=ur.r.uid.siglist; recno; recno = rec.r.sig.next ) {
|
|
|
|
|
rc = tdbio_read_record( recno, &rec, RECTYPE_SIG );
|
|
|
|
|
if( rc ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("lid %lu: read sig record failed: %s\n"),
|
1998-07-21 14:53:38 +02:00
|
|
|
|
lid, g10_errstr(rc));
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
tdbio_dump_record( &rec, stdout );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* add cache record dump here */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
1998-01-16 22:15:24 +01:00
|
|
|
|
|
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
|
1998-01-30 21:25:31 +01:00
|
|
|
|
/****************
|
1998-11-03 20:38:58 +01:00
|
|
|
|
* stack is an array of (max_path+1) elements. If trust_seg_head is not
|
|
|
|
|
* NULL it is a pointer to a variable which will receive a linked list
|
|
|
|
|
* of trust paths - The caller has to free the memory.
|
1998-01-30 21:25:31 +01:00
|
|
|
|
*/
|
1998-01-16 22:15:24 +01:00
|
|
|
|
static int
|
1998-11-03 20:38:58 +01:00
|
|
|
|
collect_paths( int depth, int max_depth, int all, TRUSTREC *drec,
|
|
|
|
|
TRUST_INFO *stack, TRUST_SEG_LIST *trust_seg_head )
|
1998-01-16 22:15:24 +01:00
|
|
|
|
{
|
1998-10-25 20:00:01 +01:00
|
|
|
|
ulong rn, uidrn;
|
|
|
|
|
int marginal=0;
|
|
|
|
|
int fully=0;
|
1999-02-10 17:22:40 +01:00
|
|
|
|
/*LOCAL_ID_TABLE sigs_seen = NULL;*/
|
1998-10-25 20:00:01 +01:00
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
if( depth >= max_depth ) /* max cert_depth reached */
|
1998-10-25 20:00:01 +01:00
|
|
|
|
return TRUST_UNDEFINED;
|
1998-11-18 20:59:06 +01:00
|
|
|
|
|
1998-10-25 20:00:01 +01:00
|
|
|
|
/* loop over all user-ids */
|
1999-02-10 17:22:40 +01:00
|
|
|
|
/*if( !all ) sigs_seen = new_lid_table();*/
|
1998-10-25 20:00:01 +01:00
|
|
|
|
for( rn = drec->r.dir.uidlist; rn; rn = uidrn ) {
|
|
|
|
|
TRUSTREC rec; /* used for uids and sigs */
|
|
|
|
|
ulong sigrn;
|
|
|
|
|
|
|
|
|
|
read_record( rn, &rec, RECTYPE_UID );
|
|
|
|
|
uidrn = rec.r.uid.next;
|
1998-11-05 19:00:08 +01:00
|
|
|
|
if( !(rec.r.uid.uidflags & UIDF_CHECKED) )
|
|
|
|
|
continue; /* user id has not been checked */
|
|
|
|
|
if( !(rec.r.uid.uidflags & UIDF_VALID) )
|
|
|
|
|
continue; /* user id is not valid */
|
|
|
|
|
if( (rec.r.uid.uidflags & UIDF_REVOKED) )
|
|
|
|
|
continue; /* user id has been revoked */
|
1998-10-25 20:00:01 +01:00
|
|
|
|
|
1999-02-10 17:22:40 +01:00
|
|
|
|
stack[depth].lid = drec->r.dir.lid;
|
|
|
|
|
stack[depth].otrust = drec->r.dir.ownertrust;
|
|
|
|
|
stack[depth].trust = 0;
|
|
|
|
|
{ int i;
|
|
|
|
|
|
|
|
|
|
for(i=0; i < depth; i++ )
|
|
|
|
|
if( stack[i].lid == drec->r.dir.lid )
|
|
|
|
|
return TRUST_UNDEFINED; /* closed (we already visited this lid) */
|
|
|
|
|
}
|
|
|
|
|
if( !qry_lid_table_flag( ultikey_table, drec->r.dir.lid, NULL ) ) {
|
|
|
|
|
/* we are at the end of a path */
|
|
|
|
|
TRUST_SEG_LIST tsl;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
stack[depth].trust = TRUST_ULTIMATE;
|
|
|
|
|
stack[depth].otrust = TRUST_ULTIMATE;
|
|
|
|
|
if( trust_seg_head ) {
|
|
|
|
|
/* we can now put copy our current stack to the trust_seg_list */
|
|
|
|
|
tsl = m_alloc( sizeof *tsl + (depth+1)*sizeof( TRUST_INFO ) );
|
|
|
|
|
for(i=0; i <= depth; i++ )
|
|
|
|
|
tsl->path[i] = stack[i];
|
|
|
|
|
tsl->pathlen = i;
|
|
|
|
|
tsl->next = *trust_seg_head;
|
|
|
|
|
*trust_seg_head = tsl;
|
|
|
|
|
}
|
|
|
|
|
return TRUST_ULTIMATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* loop over all signature records of this user id */
|
1998-10-25 20:00:01 +01:00
|
|
|
|
for( rn = rec.r.uid.siglist; rn; rn = sigrn ) {
|
|
|
|
|
int i;
|
1998-01-16 22:15:24 +01:00
|
|
|
|
|
1998-10-25 20:00:01 +01:00
|
|
|
|
read_record( rn, &rec, RECTYPE_SIG );
|
|
|
|
|
sigrn = rec.r.sig.next;
|
1998-01-19 19:54:44 +01:00
|
|
|
|
|
1998-10-25 20:00:01 +01:00
|
|
|
|
for(i=0; i < SIGS_PER_RECORD; i++ ) {
|
|
|
|
|
TRUSTREC tmp;
|
|
|
|
|
int ot, nt;
|
1998-12-17 18:36:05 +01:00
|
|
|
|
int unchecked = 0;
|
1998-01-16 22:15:24 +01:00
|
|
|
|
|
1998-10-25 20:00:01 +01:00
|
|
|
|
if( !rec.r.sig.sig[i].lid )
|
|
|
|
|
continue; /* skip deleted sigs */
|
1998-12-17 18:36:05 +01:00
|
|
|
|
if( !(rec.r.sig.sig[i].flag & SIGF_CHECKED) ) {
|
|
|
|
|
if( !all )
|
|
|
|
|
continue; /* skip unchecked signatures */
|
|
|
|
|
unchecked = 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if( !(rec.r.sig.sig[i].flag & SIGF_VALID) )
|
|
|
|
|
continue; /* skip invalid signatures */
|
|
|
|
|
if( (rec.r.sig.sig[i].flag & SIGF_EXPIRED) )
|
|
|
|
|
continue; /* skip expired signatures */
|
|
|
|
|
if( (rec.r.sig.sig[i].flag & SIGF_REVOKED) )
|
|
|
|
|
continue; /* skip revoked signatures */
|
|
|
|
|
}
|
1998-10-25 20:00:01 +01:00
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
/* visit every signer only once (a signer may have
|
1999-02-10 17:22:40 +01:00
|
|
|
|
* signed more than one user ID)
|
|
|
|
|
* if( sigs_seen && ins_lid_table_item( sigs_seen,
|
|
|
|
|
* rec.r.sig.sig[i].lid, 0) )
|
|
|
|
|
* continue; we already have this one
|
|
|
|
|
*/
|
1998-11-03 20:38:58 +01:00
|
|
|
|
read_record( rec.r.sig.sig[i].lid, &tmp, 0 );
|
|
|
|
|
if( tmp.rectype != RECTYPE_DIR ) {
|
1998-11-13 20:41:41 +01:00
|
|
|
|
if( tmp.rectype != RECTYPE_SDIR )
|
|
|
|
|
log_info("oops: lid %lu: sig %lu has rectype %d"
|
1998-11-03 20:38:58 +01:00
|
|
|
|
" - skipped\n",
|
|
|
|
|
drec->r.dir.lid, tmp.recnum, tmp.rectype );
|
|
|
|
|
continue;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
}
|
1998-11-03 20:38:58 +01:00
|
|
|
|
ot = tmp.r.dir.ownertrust & TRUST_MASK;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
if( ot >= TRUST_FULLY )
|
|
|
|
|
ot = TRUST_FULLY; /* just in case */
|
1998-11-03 20:38:58 +01:00
|
|
|
|
nt = collect_paths( depth+1, max_depth, all, &tmp, stack,
|
|
|
|
|
trust_seg_head );
|
|
|
|
|
nt &= TRUST_MASK;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
|
1998-12-17 18:36:05 +01:00
|
|
|
|
if( nt < TRUST_MARGINAL || unchecked ) {
|
1998-10-25 20:00:01 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
1998-01-19 19:54:44 +01:00
|
|
|
|
|
1998-10-25 20:00:01 +01:00
|
|
|
|
if( nt == TRUST_ULTIMATE ) {
|
|
|
|
|
/* we have signed this key and only in this special case
|
1998-11-03 20:38:58 +01:00
|
|
|
|
* we assume that this one is fully trusted */
|
|
|
|
|
if( !all ) {
|
1999-02-10 17:22:40 +01:00
|
|
|
|
/*if( sigs_seen ) release_lid_table( sigs_seen );*/
|
1998-11-03 20:38:58 +01:00
|
|
|
|
return (stack[depth].trust = TRUST_FULLY);
|
|
|
|
|
}
|
1998-10-25 20:00:01 +01:00
|
|
|
|
}
|
|
|
|
|
|
1998-11-18 20:59:06 +01:00
|
|
|
|
if( nt > ot )
|
|
|
|
|
nt = ot;
|
|
|
|
|
|
1998-10-25 20:00:01 +01:00
|
|
|
|
if( nt >= TRUST_FULLY )
|
|
|
|
|
fully++;
|
|
|
|
|
if( nt >= TRUST_MARGINAL )
|
|
|
|
|
marginal++;
|
|
|
|
|
|
|
|
|
|
if( fully >= opt.completes_needed
|
|
|
|
|
|| marginal >= opt.marginals_needed ) {
|
1998-11-03 20:38:58 +01:00
|
|
|
|
if( !all ) {
|
1999-02-10 17:22:40 +01:00
|
|
|
|
/*if( sigs_seen ) release_lid_table( sigs_seen );*/
|
1998-11-03 20:38:58 +01:00
|
|
|
|
return (stack[depth].trust = TRUST_FULLY);
|
|
|
|
|
}
|
1998-10-25 20:00:01 +01:00
|
|
|
|
}
|
1998-01-16 22:15:24 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-01-19 19:54:44 +01:00
|
|
|
|
}
|
1999-02-10 17:22:40 +01:00
|
|
|
|
/*if( sigs_seen ) release_lid_table( sigs_seen ); */
|
1998-11-03 20:38:58 +01:00
|
|
|
|
if( all && ( fully >= opt.completes_needed
|
|
|
|
|
|| marginal >= opt.marginals_needed ) ) {
|
|
|
|
|
return (stack[depth].trust = TRUST_FULLY );
|
|
|
|
|
}
|
1998-10-25 20:00:01 +01:00
|
|
|
|
if( marginal ) {
|
1998-11-03 20:38:58 +01:00
|
|
|
|
return (stack[depth].trust = TRUST_MARGINAL);
|
1998-10-25 20:00:01 +01:00
|
|
|
|
}
|
1998-11-03 20:38:58 +01:00
|
|
|
|
return (stack[depth].trust=TRUST_UNDEFINED);
|
1998-01-16 22:15:24 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1999-02-10 17:22:40 +01:00
|
|
|
|
typedef struct {
|
|
|
|
|
ulong lid;
|
|
|
|
|
ulong uid;
|
|
|
|
|
} CERT_ITEM;
|
|
|
|
|
|
|
|
|
|
/* structure to hold certification chains. Item[nitems-1] is the
|
|
|
|
|
* ultimateley trusted key, item[0] is the key which
|
|
|
|
|
* is introduced, indices [1,(nitems-2)] are all introducers.
|
|
|
|
|
*/
|
|
|
|
|
typedef struct cert_chain *CERT_CHAIN;
|
|
|
|
|
struct cert_chain {
|
|
|
|
|
CERT_CHAIN next;
|
|
|
|
|
int dups;
|
|
|
|
|
int nitems;
|
|
|
|
|
CERT_ITEM items[1];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
|
* Copy all items to the set SET_HEAD in a way that the requirements
|
|
|
|
|
* of a CERT_CHAIN are met.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
add_cert_items_to_set( CERT_CHAIN *set_head, CERT_ITEM *items, int nitems )
|
|
|
|
|
{
|
|
|
|
|
CERT_CHAIN ac;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
ac = m_alloc_clear( sizeof *ac + (nitems-1)*sizeof(CERT_ITEM) );
|
|
|
|
|
ac->nitems = nitems;
|
|
|
|
|
for(i=0; i < nitems; i++ )
|
|
|
|
|
ac->items[i] = items[i];
|
|
|
|
|
ac->next = *set_head;
|
|
|
|
|
*set_head = ac;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
|
* Find all certification paths of a given LID.
|
|
|
|
|
* Limit the search to MAX_DEPTH. stack is a helper variable which
|
|
|
|
|
* should have been allocated with size max_depth, stack[0] should
|
|
|
|
|
* be setup to the key we are investigating, so the minimal depth
|
|
|
|
|
* we should ever see in this function is 1.
|
|
|
|
|
* Returns: -1 max_depth reached
|
|
|
|
|
* 0 no paths found
|
|
|
|
|
* 1 ultimately trusted key found
|
|
|
|
|
* certchain_set must be a valid set or point to NULL; this function
|
|
|
|
|
* may modifiy it.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
find_cert_chain( ulong lid, int depth, int max_depth,
|
|
|
|
|
CERT_ITEM *stack, CERT_CHAIN *cert_chain_set )
|
|
|
|
|
{
|
|
|
|
|
TRUSTREC dirrec;
|
|
|
|
|
TRUSTREC uidrec;
|
|
|
|
|
ulong uidrno;
|
|
|
|
|
|
|
|
|
|
if( depth >= max_depth )
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
stack[depth].lid = lid;
|
|
|
|
|
stack[depth].uid = 0;
|
|
|
|
|
|
|
|
|
|
if( !qry_lid_table_flag( ultikey_table, lid, NULL ) ) {
|
|
|
|
|
/* this is an ultimately trusted key;
|
|
|
|
|
* which means that we have found the end of the chain:
|
|
|
|
|
* copy the chain to the set */
|
|
|
|
|
add_cert_items_to_set( cert_chain_set, stack, depth+1 );
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
read_record( lid, &dirrec, 0 );
|
|
|
|
|
if( dirrec.rectype != RECTYPE_DIR ) {
|
|
|
|
|
if( dirrec.rectype != RECTYPE_SDIR )
|
|
|
|
|
log_debug("lid %lu, has rectype %d"
|
|
|
|
|
" - skipped\n", lid, dirrec.rectype );
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* Performance hint: add stuff to ignore this one when the
|
|
|
|
|
* assigned validity of the key is bad */
|
|
|
|
|
|
|
|
|
|
/* loop over all user ids */
|
|
|
|
|
for( uidrno = dirrec.r.dir.uidlist; uidrno; uidrno = uidrec.r.uid.next ) {
|
|
|
|
|
TRUSTREC sigrec;
|
|
|
|
|
ulong sigrno;
|
|
|
|
|
|
|
|
|
|
stack[depth].uid = uidrno;
|
|
|
|
|
read_record( uidrno, &uidrec, RECTYPE_UID );
|
|
|
|
|
|
|
|
|
|
if( !(uidrec.r.uid.uidflags & UIDF_CHECKED) )
|
|
|
|
|
continue; /* user id has not been checked */
|
|
|
|
|
if( !(uidrec.r.uid.uidflags & UIDF_VALID) )
|
|
|
|
|
continue; /* user id is not valid */
|
|
|
|
|
if( (uidrec.r.uid.uidflags & UIDF_REVOKED) )
|
|
|
|
|
continue; /* user id has been revoked */
|
|
|
|
|
|
|
|
|
|
/* loop over all signature records */
|
|
|
|
|
for(sigrno=uidrec.r.uid.siglist; sigrno; sigrno = sigrec.r.sig.next ) {
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
read_record( sigrno, &sigrec, RECTYPE_SIG );
|
|
|
|
|
|
|
|
|
|
for(i=0; i < SIGS_PER_RECORD; i++ ) {
|
|
|
|
|
if( !sigrec.r.sig.sig[i].lid )
|
|
|
|
|
continue; /* skip deleted sigs */
|
|
|
|
|
if( !(sigrec.r.sig.sig[i].flag & SIGF_CHECKED) )
|
|
|
|
|
continue; /* skip unchecked signatures */
|
|
|
|
|
if( !(sigrec.r.sig.sig[i].flag & SIGF_VALID) )
|
|
|
|
|
continue; /* skip invalid signatures */
|
|
|
|
|
if( (sigrec.r.sig.sig[i].flag & SIGF_EXPIRED) )
|
|
|
|
|
continue; /* skip expired signatures */
|
|
|
|
|
if( (sigrec.r.sig.sig[i].flag & SIGF_REVOKED) )
|
|
|
|
|
continue; /* skip revoked signatures */
|
|
|
|
|
for(j=0; j < depth; j++ ) {
|
|
|
|
|
if( stack[j].lid == sigrec.r.sig.sig[i].lid )
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if( j < depth )
|
|
|
|
|
continue; /* avoid cycles as soon as possible */
|
|
|
|
|
|
|
|
|
|
if( find_cert_chain( sigrec.r.sig.sig[i].lid,
|
|
|
|
|
depth+1, max_depth,
|
|
|
|
|
stack, cert_chain_set ) > 0 ) {
|
|
|
|
|
/* ultimately trusted key found:
|
|
|
|
|
* no need to check more signatures of this uid */
|
|
|
|
|
sigrec.r.sig.next = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} /* end loop over sig recs */
|
|
|
|
|
} /* end loop over user ids */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
/****************
|
|
|
|
|
* Given the directory record of a key, check whether we can
|
|
|
|
|
* find a path to an ultimately trusted key. We do this by
|
|
|
|
|
* checking all key signatures up to a some depth.
|
|
|
|
|
*/
|
1998-01-24 17:32:27 +01:00
|
|
|
|
static int
|
1998-11-03 20:38:58 +01:00
|
|
|
|
verify_key( int max_depth, TRUSTREC *drec )
|
1998-01-24 17:32:27 +01:00
|
|
|
|
{
|
1998-11-03 20:38:58 +01:00
|
|
|
|
TRUST_INFO *tmppath = m_alloc_clear( (max_depth+1)* sizeof *tmppath );
|
|
|
|
|
int tr;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
tr = collect_paths( 0, max_depth, 0, drec, tmppath, NULL );
|
|
|
|
|
m_free( tmppath );
|
|
|
|
|
return tr;
|
|
|
|
|
}
|
1998-10-25 20:00:01 +01:00
|
|
|
|
|
|
|
|
|
|
1998-01-14 13:34:05 +01:00
|
|
|
|
|
1998-01-13 20:04:23 +01:00
|
|
|
|
|
1998-07-14 19:10:28 +02:00
|
|
|
|
/****************
|
|
|
|
|
* we have the pubkey record and all needed informations are in the trustdb
|
|
|
|
|
* but nothing more is known.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
1998-11-13 20:41:41 +01:00
|
|
|
|
do_check( TRUSTREC *dr, unsigned *validity )
|
1998-01-13 20:04:23 +01:00
|
|
|
|
{
|
1998-07-14 19:10:28 +02:00
|
|
|
|
if( !dr->r.dir.keylist ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("Ooops, no keys\n"));
|
1998-07-21 14:53:38 +02:00
|
|
|
|
return G10ERR_TRUSTDB;
|
1998-07-14 19:10:28 +02:00
|
|
|
|
}
|
|
|
|
|
if( !dr->r.dir.uidlist ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("Ooops, no user ids\n"));
|
1998-07-21 14:53:38 +02:00
|
|
|
|
return G10ERR_TRUSTDB;
|
1998-01-16 22:15:24 +01:00
|
|
|
|
}
|
1998-02-18 14:58:46 +01:00
|
|
|
|
|
1998-11-13 20:41:41 +01:00
|
|
|
|
if( tdbio_db_matches_options()
|
|
|
|
|
&& (dr->r.dir.dirflags & DIRF_VALVALID)
|
|
|
|
|
&& dr->r.dir.validity )
|
|
|
|
|
*validity = dr->r.dir.validity;
|
|
|
|
|
else {
|
|
|
|
|
*validity = verify_key( opt.max_cert_depth, dr );
|
|
|
|
|
if( (*validity & TRUST_MASK) >= TRUST_UNDEFINED
|
|
|
|
|
&& tdbio_db_matches_options() ) {
|
|
|
|
|
/* update the cached validity value */
|
|
|
|
|
dr->r.dir.validity = (*validity & TRUST_MASK);
|
|
|
|
|
dr->r.dir.dirflags |= DIRF_VALVALID;
|
|
|
|
|
write_record( dr );
|
|
|
|
|
}
|
|
|
|
|
}
|
1998-07-14 19:10:28 +02:00
|
|
|
|
|
1998-07-21 14:53:38 +02:00
|
|
|
|
if( dr->r.dir.dirflags & DIRF_REVOKED )
|
1998-11-13 20:41:41 +01:00
|
|
|
|
*validity |= TRUST_FLAG_REVOKED;
|
1998-01-24 17:32:27 +01:00
|
|
|
|
|
1998-01-16 22:15:24 +01:00
|
|
|
|
return 0;
|
1998-01-13 20:04:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
1998-09-28 21:25:31 +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 )
|
1999-02-24 11:12:32 +01:00
|
|
|
|
{
|
|
|
|
|
/* just store the args */
|
|
|
|
|
if( trustdb_args.init )
|
|
|
|
|
return 0;
|
|
|
|
|
trustdb_args.level = level;
|
|
|
|
|
trustdb_args.dbname = dbname? m_strdup(dbname): NULL;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
do_init_trustdb()
|
1998-01-12 11:18:17 +01:00
|
|
|
|
{
|
1998-01-13 20:04:23 +01:00
|
|
|
|
int rc=0;
|
1999-02-24 11:12:32 +01:00
|
|
|
|
int level = trustdb_args.level;
|
|
|
|
|
const char* dbname = trustdb_args.dbname;
|
|
|
|
|
|
|
|
|
|
trustdb_args.init = 1;
|
1998-01-13 20:04:23 +01:00
|
|
|
|
|
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 );
|
1999-02-24 11:12:32 +01:00
|
|
|
|
if( !rc ) {
|
|
|
|
|
if( !level )
|
|
|
|
|
return;
|
1998-01-13 20:04:23 +01:00
|
|
|
|
|
1999-02-24 11:12:32 +01: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
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
/* should we check whether 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();
|
1999-02-24 11:12:32 +01:00
|
|
|
|
if( rc )
|
|
|
|
|
log_fatal("can't init trustdb: %s\n", g10_errstr(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;
|
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
|
|
|
|
|
1998-07-29 21:35:05 +02:00
|
|
|
|
if( username && *username == '#' ) {
|
|
|
|
|
int rc;
|
|
|
|
|
ulong lid = atoi(username+1);
|
|
|
|
|
|
|
|
|
|
if( (rc = list_records( lid)) )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("user '%s' read problem: %s\n"),
|
|
|
|
|
username, g10_errstr(rc));
|
1998-07-29 21:35:05 +02:00
|
|
|
|
else if( (rc = list_sigs( lid )) )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("user '%s' list problem: %s\n"),
|
|
|
|
|
username, g10_errstr(rc));
|
1998-07-29 21:35:05 +02:00
|
|
|
|
}
|
|
|
|
|
else 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-11-08 18:23:14 +01:00
|
|
|
|
if( (rc = get_pubkey_byname( NULL, pk, username, NULL )) )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("user '%s' not found: %s\n"), username, g10_errstr(rc) );
|
1998-07-30 19:37:03 +02:00
|
|
|
|
else if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("problem finding '%s' in trustdb: %s\n"),
|
1998-01-30 21:25:31 +01:00
|
|
|
|
username, g10_errstr(rc));
|
|
|
|
|
else if( rc == -1 )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("user '%s' not in trustdb\n"), username);
|
1998-07-21 14:53:38 +02:00
|
|
|
|
else if( (rc = list_records( pk->local_id)) )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("user '%s' read problem: %s\n"),
|
|
|
|
|
username, g10_errstr(rc));
|
1998-06-29 14:30:57 +02:00
|
|
|
|
else if( (rc = list_sigs( pk->local_id )) )
|
1998-11-10 13:59:59 +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++ )
|
1998-07-21 14:53:38 +02:00
|
|
|
|
tdbio_dump_record( &rec, stdout );
|
1998-01-30 21:25:31 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1998-07-06 12:23:57 +02:00
|
|
|
|
/****************
|
1998-07-29 21:35:05 +02:00
|
|
|
|
* Print a list of all defined owner trust value.
|
1998-07-06 12:23:57 +02:00
|
|
|
|
*/
|
|
|
|
|
void
|
1998-07-29 21:35:05 +02:00
|
|
|
|
export_ownertrust()
|
1998-07-06 12:23:57 +02:00
|
|
|
|
{
|
|
|
|
|
TRUSTREC rec;
|
1998-07-21 14:53:38 +02:00
|
|
|
|
TRUSTREC rec2;
|
1998-07-06 12:23:57 +02:00
|
|
|
|
ulong recnum;
|
|
|
|
|
int i;
|
|
|
|
|
byte *p;
|
1998-07-21 14:53:38 +02:00
|
|
|
|
int rc;
|
1998-07-06 12:23:57 +02:00
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-11-10 13:59:59 +01:00
|
|
|
|
printf(_("# List of assigned trustvalues, created %s\n"
|
|
|
|
|
"# (Use \"gpgm --import-ownertrust\" to restore them)\n"),
|
1998-10-25 20:00:01 +01:00
|
|
|
|
asctimestamp( make_timestamp() ) );
|
1998-07-09 15:37:17 +02:00
|
|
|
|
for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
|
1998-07-21 14:53:38 +02:00
|
|
|
|
if( rec.rectype == RECTYPE_DIR ) {
|
|
|
|
|
if( !rec.r.dir.keylist ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("directory record w/o primary key\n"));
|
1998-07-21 14:53:38 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if( !rec.r.dir.ownertrust )
|
|
|
|
|
continue;
|
|
|
|
|
rc = tdbio_read_record( rec.r.dir.keylist, &rec2, RECTYPE_KEY);
|
|
|
|
|
if( rc ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("error reading key record: %s\n"), g10_errstr(rc));
|
1998-07-21 14:53:38 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
p = rec2.r.key.fingerprint;
|
|
|
|
|
for(i=0; i < rec2.r.key.fingerprint_len; i++, p++ )
|
1998-07-06 12:23:57 +02:00
|
|
|
|
printf("%02X", *p );
|
1998-07-21 14:53:38 +02:00
|
|
|
|
printf(":%u:\n", (unsigned)rec.r.dir.ownertrust );
|
1998-07-06 12:23:57 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1998-07-29 21:35:05 +02:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
import_ownertrust( const char *fname )
|
|
|
|
|
{
|
|
|
|
|
FILE *fp;
|
|
|
|
|
int is_stdin=0;
|
|
|
|
|
char line[256];
|
|
|
|
|
char *p;
|
|
|
|
|
size_t n, fprlen;
|
|
|
|
|
unsigned otrust;
|
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-07-29 21:35:05 +02:00
|
|
|
|
if( !fname || (*fname == '-' && !fname[1]) ) {
|
|
|
|
|
fp = stdin;
|
|
|
|
|
fname = "[stdin]";
|
|
|
|
|
is_stdin = 1;
|
|
|
|
|
}
|
|
|
|
|
else if( !(fp = fopen( fname, "r" )) ) {
|
|
|
|
|
log_error_f(fname, _("can't open file: %s\n"), strerror(errno) );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while( fgets( line, DIM(line)-1, fp ) ) {
|
1998-07-30 19:37:03 +02:00
|
|
|
|
TRUSTREC rec;
|
|
|
|
|
int rc;
|
|
|
|
|
|
1998-07-29 21:35:05 +02:00
|
|
|
|
if( !*line || *line == '#' )
|
|
|
|
|
continue;
|
|
|
|
|
n = strlen(line);
|
|
|
|
|
if( line[n-1] != '\n' ) {
|
1998-12-17 18:36:05 +01:00
|
|
|
|
log_error_f(fname, _("line too long\n") );
|
1998-11-03 20:38:58 +01:00
|
|
|
|
/* ... or last line does not have a LF */
|
1998-07-29 21:35:05 +02:00
|
|
|
|
break; /* can't continue */
|
|
|
|
|
}
|
|
|
|
|
for(p = line; *p && *p != ':' ; p++ )
|
|
|
|
|
if( !isxdigit(*p) )
|
|
|
|
|
break;
|
|
|
|
|
if( *p != ':' ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error_f(fname, _("error: missing colon\n") );
|
1998-07-29 21:35:05 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
fprlen = p - line;
|
|
|
|
|
if( fprlen != 32 && fprlen != 40 ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error_f(fname, _("error: invalid fingerprint\n") );
|
1998-07-29 21:35:05 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if( sscanf(p, ":%u:", &otrust ) != 1 ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error_f(fname, _("error: no ownertrust value\n") );
|
1998-07-29 21:35:05 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if( !otrust )
|
|
|
|
|
continue; /* no otrust defined - no need to update or insert */
|
|
|
|
|
/* convert the ascii fingerprint to binary */
|
|
|
|
|
for(p=line, fprlen=0; *p != ':'; p += 2 )
|
|
|
|
|
line[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]);
|
|
|
|
|
line[fprlen] = 0;
|
|
|
|
|
|
1998-07-30 19:37:03 +02:00
|
|
|
|
repeat:
|
|
|
|
|
rc = tdbio_search_dir_byfpr( line, fprlen, 0, &rec );
|
|
|
|
|
if( !rc ) { /* found: update */
|
|
|
|
|
if( rec.r.dir.ownertrust )
|
1998-12-29 14:47:31 +01:00
|
|
|
|
log_info("LID %lu: changing trust from %u to %u\n",
|
1998-07-30 19:37:03 +02:00
|
|
|
|
rec.r.dir.lid, rec.r.dir.ownertrust, otrust );
|
|
|
|
|
else
|
1998-12-29 14:47:31 +01:00
|
|
|
|
log_info("LID %lu: setting trust to %u\n",
|
1998-07-30 19:37:03 +02:00
|
|
|
|
rec.r.dir.lid, otrust );
|
|
|
|
|
rec.r.dir.ownertrust = otrust;
|
1998-10-07 15:30:43 +02:00
|
|
|
|
write_record( &rec );
|
1998-07-30 19:37:03 +02:00
|
|
|
|
}
|
|
|
|
|
else if( rc == -1 ) { /* not found; get the key from the ring */
|
|
|
|
|
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
|
|
|
|
|
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info_f(fname, _("key not in trustdb, searching ring.\n"));
|
1998-07-30 19:37:03 +02:00
|
|
|
|
rc = get_pubkey_byfprint( pk, line, fprlen );
|
|
|
|
|
if( rc )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info_f(fname, _("key not in ring: %s\n"), g10_errstr(rc));
|
1998-07-30 19:37:03 +02:00
|
|
|
|
else {
|
|
|
|
|
rc = query_trust_record( pk ); /* only as assertion */
|
|
|
|
|
if( rc != -1 )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error_f(fname, _("Oops: key is now in trustdb???\n"));
|
1998-07-30 19:37:03 +02:00
|
|
|
|
else {
|
|
|
|
|
rc = insert_trust_record( pk );
|
|
|
|
|
if( !rc )
|
|
|
|
|
goto repeat; /* update the ownertrust */
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error_f(fname, _("insert trust record failed: %s\n"),
|
1998-07-30 19:37:03 +02:00
|
|
|
|
g10_errstr(rc) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else /* error */
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error_f(fname, _("error finding dir record: %s\n"),
|
1998-07-30 19:37:03 +02:00
|
|
|
|
g10_errstr(rc));
|
1998-07-29 21:35:05 +02:00
|
|
|
|
}
|
|
|
|
|
if( ferror(fp) )
|
|
|
|
|
log_error_f(fname, _("read error: %s\n"), strerror(errno) );
|
|
|
|
|
if( !is_stdin )
|
|
|
|
|
fclose(fp);
|
1998-10-16 18:00:17 +02:00
|
|
|
|
do_sync();
|
1998-07-29 21:35:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
1998-12-17 18:36:05 +01:00
|
|
|
|
print_path( int pathlen, TRUST_INFO *path, FILE *fp, ulong highlight )
|
1998-11-03 20:38:58 +01:00
|
|
|
|
{
|
1998-11-18 20:59:06 +01:00
|
|
|
|
int rc, c, i;
|
1998-11-03 20:38:58 +01:00
|
|
|
|
u32 keyid[2];
|
1998-11-18 20:59:06 +01:00
|
|
|
|
char *p;
|
|
|
|
|
size_t n;
|
1998-11-03 20:38:58 +01:00
|
|
|
|
|
|
|
|
|
for( i = 0; i < pathlen; i++ ) {
|
1998-12-17 18:36:05 +01:00
|
|
|
|
if( highlight )
|
|
|
|
|
fputs(highlight == path[i].lid? "* ":" ", fp );
|
1998-11-03 20:38:58 +01:00
|
|
|
|
rc = keyid_from_lid( path[i].lid, keyid );
|
|
|
|
|
if( rc )
|
1998-12-17 18:36:05 +01:00
|
|
|
|
fprintf(fp, "????????.%lu:", path[i].lid );
|
1998-11-03 20:38:58 +01:00
|
|
|
|
else
|
1998-12-17 18:36:05 +01:00
|
|
|
|
fprintf(fp,"%08lX.%lu:", (ulong)keyid[1], path[i].lid );
|
1998-11-18 20:59:06 +01:00
|
|
|
|
c = trust_letter(path[i].otrust);
|
|
|
|
|
if( c )
|
1998-12-17 18:36:05 +01:00
|
|
|
|
putc( c, fp );
|
1998-11-18 20:59:06 +01:00
|
|
|
|
else
|
1998-12-17 18:36:05 +01:00
|
|
|
|
fprintf( fp, "%02x", path[i].otrust );
|
|
|
|
|
putc('/', fp);
|
1998-11-18 20:59:06 +01:00
|
|
|
|
c = trust_letter(path[i].trust);
|
|
|
|
|
if( c )
|
1998-12-17 18:36:05 +01:00
|
|
|
|
putc( c, fp );
|
1998-11-18 20:59:06 +01:00
|
|
|
|
else
|
1998-12-17 18:36:05 +01:00
|
|
|
|
fprintf( fp, "%02x", path[i].trust );
|
|
|
|
|
putc(' ', fp);
|
1998-11-18 20:59:06 +01:00
|
|
|
|
p = get_user_id( keyid, &n );
|
1998-12-17 18:36:05 +01:00
|
|
|
|
putc(' ', fp);
|
|
|
|
|
putc('\"', fp);
|
|
|
|
|
print_string( fp, p, n > 40? 40:n, 0 );
|
|
|
|
|
putc('\"', fp);
|
1998-11-18 20:59:06 +01:00
|
|
|
|
m_free(p);
|
1998-12-17 18:36:05 +01:00
|
|
|
|
putc('\n', fp );
|
1998-11-03 20:38:58 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1998-12-17 18:36:05 +01:00
|
|
|
|
static int
|
|
|
|
|
cmp_tsl_array( const void *xa, const void *xb )
|
|
|
|
|
{
|
|
|
|
|
TRUST_SEG_LIST a = *(TRUST_SEG_LIST*)xa;
|
|
|
|
|
TRUST_SEG_LIST b = *(TRUST_SEG_LIST*)xb;
|
|
|
|
|
return a->pathlen - b->pathlen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
sort_tsl_list( TRUST_SEG_LIST *trust_seg_list )
|
|
|
|
|
{
|
|
|
|
|
TRUST_SEG_LIST *array, *tail, tsl;
|
|
|
|
|
size_t n;
|
|
|
|
|
|
|
|
|
|
for(n=0, tsl = *trust_seg_list; tsl; tsl = tsl->next )
|
|
|
|
|
n++;
|
|
|
|
|
array = m_alloc( (n+1) * sizeof *array );
|
|
|
|
|
for(n=0, tsl = *trust_seg_list; tsl; tsl = tsl->next )
|
|
|
|
|
array[n++] = tsl;
|
|
|
|
|
array[n] = NULL;
|
|
|
|
|
qsort( array, n, sizeof *array, cmp_tsl_array );
|
|
|
|
|
*trust_seg_list = NULL;
|
|
|
|
|
tail = trust_seg_list;
|
|
|
|
|
for(n=0; (tsl=array[n]); n++ ) {
|
|
|
|
|
*tail = tsl;
|
|
|
|
|
tail = &tsl->next;
|
|
|
|
|
}
|
|
|
|
|
m_free( array );
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
|
1998-01-30 21:25:31 +01:00
|
|
|
|
void
|
1998-11-18 20:59:06 +01:00
|
|
|
|
list_trust_path( const char *username )
|
1998-01-30 21:25:31 +01:00
|
|
|
|
{
|
|
|
|
|
int rc;
|
1999-02-10 17:22:40 +01:00
|
|
|
|
ulong lid;
|
1998-01-30 21:25:31 +01:00
|
|
|
|
TRUSTREC rec;
|
1999-02-25 18:51:55 +01:00
|
|
|
|
#if 0
|
1998-11-03 20:38:58 +01:00
|
|
|
|
TRUST_INFO *tmppath;
|
|
|
|
|
TRUST_SEG_LIST trust_seg_list, tsl, tsl2;
|
1999-02-25 18:51:55 +01:00
|
|
|
|
#endif
|
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
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-11-08 18:23:14 +01:00
|
|
|
|
if( (rc = get_pubkey_byname(NULL, pk, username, NULL )) )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("user '%s' not found: %s\n"), username, g10_errstr(rc) );
|
1998-07-30 19:37:03 +02:00
|
|
|
|
else if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("problem finding '%s' in trustdb: %s\n"),
|
1998-01-30 21:25:31 +01:00
|
|
|
|
username, g10_errstr(rc));
|
|
|
|
|
else if( rc == -1 ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
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 )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("failed to put '%s' into trustdb: %s\n"),
|
|
|
|
|
username, g10_errstr(rc));
|
1998-01-30 21:25:31 +01:00
|
|
|
|
else {
|
1998-06-29 14:30:57 +02:00
|
|
|
|
assert( pk->local_id );
|
1998-01-30 21:25:31 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
1999-02-10 17:22:40 +01:00
|
|
|
|
lid = pk->local_id;
|
1998-11-03 20:38:58 +01:00
|
|
|
|
free_public_key( pk );
|
1998-01-30 21:25:31 +01:00
|
|
|
|
|
1999-02-10 17:22:40 +01:00
|
|
|
|
#if 0
|
1998-11-03 20:38:58 +01:00
|
|
|
|
/* collect the paths */
|
1998-11-18 20:59:06 +01:00
|
|
|
|
tmppath = m_alloc_clear( (opt.max_cert_depth+1)* sizeof *tmppath );
|
1998-11-03 20:38:58 +01:00
|
|
|
|
trust_seg_list = NULL;
|
1998-11-18 20:59:06 +01:00
|
|
|
|
collect_paths( 0, opt.max_cert_depth, 1, &rec, tmppath, &trust_seg_list );
|
1998-11-03 20:38:58 +01:00
|
|
|
|
m_free( tmppath );
|
1998-12-17 18:36:05 +01:00
|
|
|
|
sort_tsl_list( &trust_seg_list );
|
1998-11-03 20:38:58 +01:00
|
|
|
|
/* and now print them */
|
|
|
|
|
for(tsl = trust_seg_list; tsl; tsl = tsl->next ) {
|
1998-12-17 18:36:05 +01:00
|
|
|
|
print_path( tsl->pathlen, tsl->path, stdout, 0 );
|
|
|
|
|
if( tsl->next )
|
|
|
|
|
putchar('\n');
|
1998-11-03 20:38:58 +01:00
|
|
|
|
}
|
1998-01-30 21:25:31 +01:00
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
/* release the list */
|
|
|
|
|
for(tsl = trust_seg_list; tsl; tsl = tsl2 ) {
|
|
|
|
|
tsl2 = tsl->next;
|
|
|
|
|
m_free( tsl );
|
|
|
|
|
}
|
|
|
|
|
trust_seg_list = NULL;
|
1999-02-10 17:22:40 +01:00
|
|
|
|
#else /* test code */
|
|
|
|
|
{
|
|
|
|
|
CERT_ITEM *stack;
|
|
|
|
|
CERT_CHAIN chains, r;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
chains = NULL;
|
|
|
|
|
stack = m_alloc_clear( (opt.max_cert_depth+1)* sizeof *stack );
|
|
|
|
|
find_cert_chain( lid, 0, opt.max_cert_depth, stack, &chains);
|
|
|
|
|
m_free( stack );
|
|
|
|
|
/* dump chains */
|
|
|
|
|
for(r=chains; r ; r = r->next ) {
|
|
|
|
|
printf("chain:" );
|
|
|
|
|
for(i=0; i < r->nitems; i++ )
|
|
|
|
|
printf(" %4lu/%-4lu", r->items[i].lid, r->items[i].uid );
|
|
|
|
|
putchar('\n');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endif
|
1998-01-30 21:25:31 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1998-07-21 14:53:38 +02:00
|
|
|
|
/****************
|
1998-10-12 22:16:38 +02:00
|
|
|
|
* Check the complete trustdb or only the entries for the given username.
|
1998-11-18 20:59:06 +01:00
|
|
|
|
* We check the complete database. If a username is given or the special
|
|
|
|
|
* username "*" is used, a complete recheck is done. With no user ID
|
|
|
|
|
* only the records which are not yet checkd are now checked.
|
1998-07-21 14:53:38 +02:00
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
check_trustdb( const char *username )
|
|
|
|
|
{
|
|
|
|
|
TRUSTREC rec;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
KBNODE keyblock = NULL;
|
|
|
|
|
KBPOS kbpos;
|
1998-07-21 14:53:38 +02:00
|
|
|
|
int rc;
|
1998-11-18 20:59:06 +01:00
|
|
|
|
int recheck = username && *username == '*' && !username[1];
|
1998-07-21 14:53:38 +02:00
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-11-18 20:59:06 +01:00
|
|
|
|
if( username && !recheck ) {
|
1998-10-12 22:16:38 +02:00
|
|
|
|
rc = find_keyblock_byname( &kbpos, username );
|
|
|
|
|
if( !rc )
|
|
|
|
|
rc = read_keyblock( &kbpos, &keyblock );
|
|
|
|
|
if( rc ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("%s: keyblock read problem: %s\n"),
|
1998-10-12 22:16:38 +02:00
|
|
|
|
username, g10_errstr(rc));
|
|
|
|
|
}
|
|
|
|
|
else {
|
1998-10-25 20:00:01 +01:00
|
|
|
|
int modified;
|
|
|
|
|
|
1998-11-18 20:59:06 +01:00
|
|
|
|
rc = update_trust_record( keyblock, 1, &modified );
|
1998-10-12 22:16:38 +02:00
|
|
|
|
if( rc == -1 ) { /* not yet in trustdb: insert */
|
|
|
|
|
rc = insert_trust_record(
|
|
|
|
|
find_kbnode( keyblock, PKT_PUBLIC_KEY
|
|
|
|
|
) ->pkt->pkt.public_key );
|
1998-07-29 21:35:05 +02:00
|
|
|
|
|
1998-10-12 22:16:38 +02:00
|
|
|
|
}
|
|
|
|
|
if( rc )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("%s: update failed: %s\n"),
|
1998-10-12 22:16:38 +02:00
|
|
|
|
username, g10_errstr(rc) );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
else if( modified )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info(_("%s: updated\n"), username );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
else
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info(_("%s: okay\n"), username );
|
1998-07-21 14:53:38 +02:00
|
|
|
|
|
1998-10-12 22:16:38 +02:00
|
|
|
|
}
|
|
|
|
|
release_kbnode( keyblock ); keyblock = NULL;
|
1998-07-21 14:53:38 +02:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
ulong recnum;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
ulong count=0, upd_count=0, err_count=0, skip_count=0;
|
1998-07-21 14:53:38 +02:00
|
|
|
|
|
|
|
|
|
for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
|
|
|
|
|
if( rec.rectype == RECTYPE_DIR ) {
|
1998-10-12 22:16:38 +02:00
|
|
|
|
TRUSTREC tmp;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
int modified;
|
|
|
|
|
|
1998-10-12 22:16:38 +02:00
|
|
|
|
if( !rec.r.dir.keylist ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info(_("lid %lu: dir record w/o key - skipped\n"),
|
|
|
|
|
recnum);
|
1998-10-25 20:00:01 +01:00
|
|
|
|
count++;
|
|
|
|
|
skip_count++;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
read_record( rec.r.dir.keylist, &tmp, RECTYPE_KEY );
|
|
|
|
|
|
|
|
|
|
rc = get_keyblock_byfprint( &keyblock,
|
|
|
|
|
tmp.r.key.fingerprint,
|
|
|
|
|
tmp.r.key.fingerprint_len );
|
|
|
|
|
if( rc ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("lid %lu: keyblock not found: %s\n"),
|
1998-10-12 22:16:38 +02:00
|
|
|
|
recnum, g10_errstr(rc) );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
count++;
|
|
|
|
|
skip_count++;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
1998-10-25 20:00:01 +01:00
|
|
|
|
|
1998-11-18 20:59:06 +01:00
|
|
|
|
rc = update_trust_record( keyblock, recheck, &modified );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
if( rc ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("lid %lu: update failed: %s\n"),
|
1998-07-21 14:53:38 +02:00
|
|
|
|
recnum, g10_errstr(rc) );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
err_count++;
|
|
|
|
|
}
|
|
|
|
|
else if( modified ) {
|
|
|
|
|
if( opt.verbose )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info(_("lid %lu: updated\n"), recnum );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
upd_count++;
|
|
|
|
|
}
|
|
|
|
|
else if( opt.verbose > 1 )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info(_("lid %lu: okay\n"), recnum );
|
1998-10-12 22:16:38 +02:00
|
|
|
|
|
|
|
|
|
release_kbnode( keyblock ); keyblock = NULL;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
if( !(++count % 100) )
|
|
|
|
|
log_info(_("%lu keys so far processed\n"), count);
|
1998-07-21 14:53:38 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-10-25 20:00:01 +01:00
|
|
|
|
log_info(_("%lu keys processed\n"), count);
|
|
|
|
|
if( skip_count )
|
|
|
|
|
log_info(_("\t%lu keys skipped\n"), skip_count);
|
|
|
|
|
if( err_count )
|
|
|
|
|
log_info(_("\t%lu keys with errors\n"), err_count);
|
|
|
|
|
if( upd_count )
|
|
|
|
|
log_info(_("\t%lu keys updated\n"), upd_count);
|
1998-10-16 18:00:17 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-10-12 22:16:38 +02:00
|
|
|
|
|
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
/****************
|
|
|
|
|
* Put new entries from the pubrings into the trustdb.
|
|
|
|
|
* This function honors the sig flags to speed up the check.
|
|
|
|
|
*/
|
1998-10-16 18:00:17 +02:00
|
|
|
|
void
|
|
|
|
|
update_trustdb( )
|
|
|
|
|
{
|
|
|
|
|
KBNODE keyblock = NULL;
|
|
|
|
|
KBPOS kbpos;
|
|
|
|
|
int rc;
|
|
|
|
|
|
1999-02-25 18:51:55 +01:00
|
|
|
|
if( opt.dry_run )
|
|
|
|
|
return;
|
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-10-16 18:00:17 +02:00
|
|
|
|
rc = enum_keyblocks( 0, &kbpos, &keyblock );
|
|
|
|
|
if( !rc ) {
|
1998-10-25 20:00:01 +01:00
|
|
|
|
ulong count=0, upd_count=0, err_count=0, new_count=0;
|
|
|
|
|
|
1998-10-16 18:00:17 +02:00
|
|
|
|
while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
|
1998-10-25 20:00:01 +01:00
|
|
|
|
int modified;
|
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
rc = update_trust_record( keyblock, 1, &modified );
|
1998-10-16 18:00:17 +02:00
|
|
|
|
if( rc == -1 ) { /* not yet in trustdb: insert */
|
|
|
|
|
PKT_public_key *pk =
|
|
|
|
|
find_kbnode( keyblock, PKT_PUBLIC_KEY
|
|
|
|
|
) ->pkt->pkt.public_key;
|
|
|
|
|
rc = insert_trust_record( pk );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
if( rc && !pk->local_id ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("lid ?: insert failed: %s\n"),
|
1998-10-16 18:00:17 +02:00
|
|
|
|
g10_errstr(rc) );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
err_count++;
|
|
|
|
|
}
|
|
|
|
|
else if( rc ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("lid %lu: insert failed: %s\n"),
|
1998-10-16 18:00:17 +02:00
|
|
|
|
pk->local_id, g10_errstr(rc) );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
err_count++;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if( opt.verbose )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info(_("lid %lu: inserted\n"), pk->local_id );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
new_count++;
|
|
|
|
|
}
|
1998-10-16 18:00:17 +02:00
|
|
|
|
}
|
1998-10-25 20:00:01 +01:00
|
|
|
|
else if( rc ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("lid %lu: update failed: %s\n"),
|
1998-10-16 18:00:17 +02:00
|
|
|
|
lid_from_keyblock(keyblock), g10_errstr(rc) );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
err_count++;
|
|
|
|
|
}
|
|
|
|
|
else if( modified ) {
|
|
|
|
|
if( opt.verbose )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info(_("lid %lu: updated\n"), lid_from_keyblock(keyblock));
|
1998-10-25 20:00:01 +01:00
|
|
|
|
upd_count++;
|
|
|
|
|
}
|
|
|
|
|
else if( opt.verbose > 1 )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info(_("lid %lu: okay\n"), lid_from_keyblock(keyblock) );
|
1998-10-21 19:34:36 +02:00
|
|
|
|
|
|
|
|
|
release_kbnode( keyblock ); keyblock = NULL;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
if( !(++count % 100) )
|
|
|
|
|
log_info(_("%lu keys so far processed\n"), count);
|
1998-10-16 18:00:17 +02:00
|
|
|
|
}
|
1998-10-25 20:00:01 +01:00
|
|
|
|
log_info(_("%lu keys processed\n"), count);
|
|
|
|
|
if( err_count )
|
|
|
|
|
log_info(_("\t%lu keys with errors\n"), err_count);
|
|
|
|
|
if( upd_count )
|
|
|
|
|
log_info(_("\t%lu keys updated\n"), upd_count);
|
|
|
|
|
if( new_count )
|
|
|
|
|
log_info(_("\t%lu keys inserted\n"), new_count);
|
1998-07-21 14:53:38 +02:00
|
|
|
|
}
|
1998-10-16 18:00:17 +02:00
|
|
|
|
if( rc && rc != -1 )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("enumerate keyblocks failed: %s\n"), g10_errstr(rc));
|
1998-10-16 18:00:17 +02:00
|
|
|
|
|
|
|
|
|
enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
|
|
|
|
|
release_kbnode( keyblock );
|
1998-07-21 14:53:38 +02:00
|
|
|
|
}
|
|
|
|
|
|
1998-09-28 21:25:31 +02: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:
|
1998-07-14 19:10:28 +02:00
|
|
|
|
* try to insert the pubkey into the trustdb and check again
|
1998-01-12 11:18:17 +01:00
|
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
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-10-07 15:30:43 +02:00
|
|
|
|
read_record( pk->local_id, &rec, RECTYPE_DIR );
|
1998-01-13 20:04:23 +01:00
|
|
|
|
}
|
|
|
|
|
else { /* no local_id: scan the trustdb */
|
1998-07-30 19:37:03 +02:00
|
|
|
|
if( (rc=tdbio_search_dir_bypk( pk, &rec )) && rc != -1 ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("check_trust: search dir 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
|
|
|
|
}
|
1998-07-14 19:10:28 +02:00
|
|
|
|
else if( rc == -1 ) { /* not found - insert */
|
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"),
|
1998-09-28 21:25:31 +02:00
|
|
|
|
(ulong)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"),
|
1998-09-28 21:25:31 +02:00
|
|
|
|
(ulong)keyid[1], pk->local_id );
|
1998-08-11 19:29:34 +02:00
|
|
|
|
/* and re-read the dir record */
|
1998-10-07 15:30:43 +02:00
|
|
|
|
read_record( pk->local_id, &rec, RECTYPE_DIR );
|
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"),
|
1998-09-28 21:25:31 +02:00
|
|
|
|
(ulong)keyid[1], pk->local_id );
|
1998-03-19 16:27:29 +01:00
|
|
|
|
return G10ERR_TIME_CONFLICT;
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-16 18:00:17 +02:00
|
|
|
|
if( pk->expiredate && pk->expiredate <= cur_time ) {
|
1998-07-09 15:37:17 +02:00
|
|
|
|
log_info(_("key %08lX.%lu: expired at %s\n"),
|
1998-09-28 21:25:31 +02:00
|
|
|
|
(ulong)keyid[1], pk->local_id,
|
1998-10-16 18:00:17 +02:00
|
|
|
|
asctimestamp( pk->expiredate) );
|
1998-04-02 12:30:03 +02:00
|
|
|
|
trustlevel = TRUST_EXPIRED;
|
|
|
|
|
}
|
|
|
|
|
else {
|
1998-07-14 19:10:28 +02:00
|
|
|
|
rc = do_check( &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"),
|
1998-09-28 21:25:31 +02:00
|
|
|
|
(ulong)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-11-18 20:59:06 +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;
|
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
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';
|
1998-11-18 20:59:06 +01:00
|
|
|
|
c = trust_letter( (trustlevel & TRUST_MASK) );
|
|
|
|
|
if( !c )
|
|
|
|
|
c = '?';
|
1998-05-29 13:53:54 +02:00
|
|
|
|
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-11-13 20:41:41 +01:00
|
|
|
|
* the ultimate key (the last point in cerificate chain). Only
|
|
|
|
|
* certificate chains which ends up at an ultimately trusted key
|
|
|
|
|
* are listed. If ownertrust or validity is not NULL, the corresponding
|
|
|
|
|
* value for the returned LID is also returned in these variable(s).
|
1998-01-24 17:32:27 +01:00
|
|
|
|
*
|
|
|
|
|
* 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-11-13 20:41:41 +01:00
|
|
|
|
*
|
|
|
|
|
* Returns: -1 on EOF or the level of the returned LID
|
1998-01-24 17:32:27 +01:00
|
|
|
|
*/
|
|
|
|
|
int
|
1998-11-13 20:41:41 +01:00
|
|
|
|
enum_cert_paths( void **context, ulong *lid,
|
|
|
|
|
unsigned *ownertrust, unsigned *validity )
|
1998-01-24 17:32:27 +01:00
|
|
|
|
{
|
1998-12-17 18:36:05 +01:00
|
|
|
|
struct enum_cert_paths_ctx *ctx;
|
1998-11-13 20:41:41 +01:00
|
|
|
|
TRUST_SEG_LIST tsl;
|
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-11-13 20:41:41 +01:00
|
|
|
|
if( !lid ) { /* release the context */
|
|
|
|
|
if( *context ) {
|
|
|
|
|
TRUST_SEG_LIST tsl2;
|
|
|
|
|
|
|
|
|
|
ctx = *context;
|
|
|
|
|
for(tsl = ctx->tsl_head; tsl; tsl = tsl2 ) {
|
|
|
|
|
tsl2 = tsl->next;
|
|
|
|
|
m_free( tsl );
|
|
|
|
|
}
|
|
|
|
|
*context = NULL;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
1998-09-14 17:49:56 +02:00
|
|
|
|
|
1998-11-10 13:59:59 +01:00
|
|
|
|
if( !*context ) {
|
1998-11-13 20:41:41 +01:00
|
|
|
|
TRUST_INFO *tmppath;
|
|
|
|
|
TRUSTREC rec;
|
|
|
|
|
|
1998-11-18 20:59:06 +01:00
|
|
|
|
if( !*lid )
|
1998-11-13 20:41:41 +01:00
|
|
|
|
return -1;
|
1998-11-10 13:59:59 +01:00
|
|
|
|
|
|
|
|
|
ctx = m_alloc_clear( sizeof *ctx );
|
|
|
|
|
*context = ctx;
|
|
|
|
|
/* collect the paths */
|
|
|
|
|
read_record( *lid, &rec, RECTYPE_DIR );
|
1998-11-13 20:41:41 +01:00
|
|
|
|
tmppath = m_alloc_clear( (opt.max_cert_depth+1)* sizeof *tmppath );
|
|
|
|
|
tsl = NULL;
|
|
|
|
|
collect_paths( 0, opt.max_cert_depth, 1, &rec, tmppath, &tsl );
|
1998-11-10 13:59:59 +01:00
|
|
|
|
m_free( tmppath );
|
1998-12-17 18:36:05 +01:00
|
|
|
|
sort_tsl_list( &tsl );
|
|
|
|
|
/* setup the context */
|
1998-11-13 20:41:41 +01:00
|
|
|
|
ctx->tsl_head = tsl;
|
|
|
|
|
ctx->tsl = ctx->tsl_head;
|
|
|
|
|
ctx->idx = 0;
|
1998-11-10 13:59:59 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
ctx = *context;
|
|
|
|
|
|
1998-11-18 20:59:06 +01:00
|
|
|
|
while( ctx->tsl && ctx->idx >= ctx->tsl->pathlen ) {
|
1998-11-13 20:41:41 +01:00
|
|
|
|
ctx->tsl = ctx->tsl->next;
|
|
|
|
|
ctx->idx = 0;
|
|
|
|
|
}
|
|
|
|
|
tsl = ctx->tsl;
|
|
|
|
|
if( !tsl )
|
|
|
|
|
return -1; /* eof */
|
|
|
|
|
|
|
|
|
|
if( ownertrust )
|
|
|
|
|
*ownertrust = tsl->path[ctx->idx].otrust;
|
|
|
|
|
if( validity )
|
|
|
|
|
*validity = tsl->path[ctx->idx].trust;
|
|
|
|
|
*lid = tsl->path[ctx->idx].lid;
|
|
|
|
|
ctx->idx++;
|
|
|
|
|
return ctx->idx-1;
|
1998-01-24 17:32:27 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1998-12-17 18:36:05 +01:00
|
|
|
|
/****************
|
|
|
|
|
* Print the current path
|
|
|
|
|
*/
|
1999-01-09 18:59:58 +01:00
|
|
|
|
void
|
1998-12-23 13:41:40 +01:00
|
|
|
|
enum_cert_paths_print( void **context, FILE *fp,
|
|
|
|
|
int refresh, ulong selected_lid )
|
1998-12-17 18:36:05 +01:00
|
|
|
|
{
|
|
|
|
|
struct enum_cert_paths_ctx *ctx;
|
|
|
|
|
TRUST_SEG_LIST tsl;
|
|
|
|
|
|
|
|
|
|
if( !*context )
|
|
|
|
|
return;
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-12-17 18:36:05 +01:00
|
|
|
|
ctx = *context;
|
|
|
|
|
if( !ctx->tsl )
|
|
|
|
|
return;
|
1998-12-23 13:41:40 +01:00
|
|
|
|
tsl = ctx->tsl;
|
1998-12-17 18:36:05 +01:00
|
|
|
|
|
|
|
|
|
if( !fp )
|
|
|
|
|
fp = stderr;
|
|
|
|
|
|
1998-12-23 13:41:40 +01:00
|
|
|
|
if( refresh ) { /* update the ownertrust and if possible the validity */
|
|
|
|
|
int i;
|
|
|
|
|
int match = tdbio_db_matches_options();
|
|
|
|
|
|
|
|
|
|
for( i = 0; i < tsl->pathlen; i++ ) {
|
|
|
|
|
TRUSTREC rec;
|
|
|
|
|
|
|
|
|
|
read_record( tsl->path[i].lid, &rec, RECTYPE_DIR );
|
|
|
|
|
tsl->path[i].otrust = rec.r.dir.ownertrust;
|
|
|
|
|
/* update validity only if we have it in the cache
|
|
|
|
|
* calculation is too time consuming */
|
|
|
|
|
if( match && (rec.r.dir.dirflags & DIRF_VALVALID)
|
|
|
|
|
&& rec.r.dir.validity ) {
|
|
|
|
|
tsl->path[i].trust = rec.r.dir.validity;
|
|
|
|
|
if( rec.r.dir.dirflags & DIRF_REVOKED )
|
|
|
|
|
tsl->path[i].trust = TRUST_FLAG_REVOKED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
print_path( tsl->pathlen, tsl->path, fp, selected_lid );
|
1998-12-17 18:36:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1998-01-24 17:32:27 +01:00
|
|
|
|
/****************
|
|
|
|
|
* Return the assigned ownertrust value for the given LID
|
|
|
|
|
*/
|
1998-10-07 15:30:43 +02:00
|
|
|
|
unsigned
|
|
|
|
|
get_ownertrust( ulong lid )
|
1998-01-24 17:32:27 +01:00
|
|
|
|
{
|
|
|
|
|
TRUSTREC rec;
|
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-10-07 15:30:43 +02:00
|
|
|
|
read_record( lid, &rec, RECTYPE_DIR );
|
|
|
|
|
return rec.r.dir.ownertrust;
|
1998-01-24 17:32:27 +01:00
|
|
|
|
}
|
|
|
|
|
|
1998-07-30 19:37:03 +02:00
|
|
|
|
int
|
|
|
|
|
get_ownertrust_info( ulong lid )
|
|
|
|
|
{
|
|
|
|
|
unsigned otrust;
|
|
|
|
|
int c;
|
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-10-07 15:30:43 +02:00
|
|
|
|
otrust = get_ownertrust( lid );
|
1998-11-18 20:59:06 +01:00
|
|
|
|
c = trust_letter( (otrust & TRUST_MASK) );
|
|
|
|
|
if( !c )
|
|
|
|
|
c = '?';
|
1998-07-30 19:37:03 +02:00
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-18 20:59:06 +01:00
|
|
|
|
/*
|
|
|
|
|
* Return an allocated buffer with the preference values for
|
|
|
|
|
* the key with LID and the userid which is identified by the
|
|
|
|
|
* HAMEHASH or the firstone if namehash is NULL. ret_n receives
|
|
|
|
|
* the length of the allcoated buffer. Structure of the buffer is
|
|
|
|
|
* a repeated sequences of 2 bytes; where the first byte describes the
|
|
|
|
|
* type of the preference and the second one the value. The constants
|
|
|
|
|
* PREFTYPE_xxxx should be used to reference a type.
|
|
|
|
|
*/
|
1998-08-05 18:51:59 +02:00
|
|
|
|
byte *
|
|
|
|
|
get_pref_data( ulong lid, const byte *namehash, size_t *ret_n )
|
|
|
|
|
{
|
|
|
|
|
TRUSTREC rec;
|
|
|
|
|
ulong recno;
|
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-10-07 15:30:43 +02:00
|
|
|
|
read_record( lid, &rec, RECTYPE_DIR );
|
1998-08-05 18:51:59 +02:00
|
|
|
|
for( recno=rec.r.dir.uidlist; recno; recno = rec.r.uid.next ) {
|
1998-10-07 15:30:43 +02:00
|
|
|
|
read_record( recno, &rec, RECTYPE_UID );
|
1998-08-05 18:51:59 +02:00
|
|
|
|
if( rec.r.uid.prefrec
|
|
|
|
|
&& ( !namehash || !memcmp(namehash, rec.r.uid.namehash, 20) )) {
|
|
|
|
|
byte *buf;
|
|
|
|
|
/* found the correct one or the first one */
|
1998-10-07 15:30:43 +02:00
|
|
|
|
read_record( rec.r.uid.prefrec, &rec, RECTYPE_PREF );
|
1998-08-05 18:51:59 +02:00
|
|
|
|
if( rec.r.pref.next )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info(_("WARNING: can't yet handle long pref records\n"));
|
1998-08-05 18:51:59 +02:00
|
|
|
|
buf = m_alloc( ITEMS_PER_PREF_RECORD );
|
|
|
|
|
memcpy( buf, rec.r.pref.data, ITEMS_PER_PREF_RECORD );
|
|
|
|
|
*ret_n = ITEMS_PER_PREF_RECORD;
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
|
* Check whether the algorithm is in one of the pref records
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
is_algo_in_prefs( ulong lid, int preftype, int algo )
|
|
|
|
|
{
|
|
|
|
|
TRUSTREC rec;
|
|
|
|
|
ulong recno;
|
1998-10-07 15:30:43 +02:00
|
|
|
|
int i;
|
1998-08-05 18:51:59 +02:00
|
|
|
|
byte *pref;
|
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-10-07 15:30:43 +02:00
|
|
|
|
read_record( lid, &rec, RECTYPE_DIR );
|
1998-08-05 18:51:59 +02:00
|
|
|
|
for( recno=rec.r.dir.uidlist; recno; recno = rec.r.uid.next ) {
|
1998-10-07 15:30:43 +02:00
|
|
|
|
read_record( recno, &rec, RECTYPE_UID );
|
1998-08-05 18:51:59 +02:00
|
|
|
|
if( rec.r.uid.prefrec ) {
|
1998-10-07 15:30:43 +02:00
|
|
|
|
read_record( rec.r.uid.prefrec, &rec, RECTYPE_PREF );
|
1998-08-05 18:51:59 +02:00
|
|
|
|
if( rec.r.pref.next )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info(_("WARNING: can't yet handle long pref records\n"));
|
1998-08-05 18:51:59 +02:00
|
|
|
|
pref = rec.r.pref.data;
|
|
|
|
|
for(i=0; i+1 < ITEMS_PER_PREF_RECORD; i+=2 ) {
|
|
|
|
|
if( pref[i] == preftype && pref[i+1] == algo )
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
1998-01-24 17:32:27 +01:00
|
|
|
|
|
1998-10-01 09:23:00 +02:00
|
|
|
|
static int
|
|
|
|
|
get_dir_record( PKT_public_key *pk, TRUSTREC *rec )
|
|
|
|
|
{
|
|
|
|
|
int rc=0;
|
|
|
|
|
|
|
|
|
|
if( pk->local_id ) {
|
1998-10-07 15:30:43 +02:00
|
|
|
|
read_record( pk->local_id, rec, RECTYPE_DIR );
|
1998-10-01 09:23:00 +02:00
|
|
|
|
}
|
|
|
|
|
else { /* no local_id: scan the trustdb */
|
|
|
|
|
if( (rc=tdbio_search_dir_bypk( pk, rec )) && rc != -1 )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("get_dir_record: search_record failed: %s\n"),
|
1998-10-01 09:23:00 +02:00
|
|
|
|
g10_errstr(rc));
|
|
|
|
|
}
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1998-01-31 22:24:36 +01:00
|
|
|
|
/****************
|
|
|
|
|
* This function simply looks for the key in the trustdb
|
1998-12-08 13:20:53 +01:00
|
|
|
|
* and makes sure that pk->local_id is set to the correct value.
|
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;
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-10-01 09:23:00 +02:00
|
|
|
|
return get_dir_record( pk, &rec );
|
1998-01-16 22:15:24 +01:00
|
|
|
|
}
|
|
|
|
|
|
1998-11-13 20:41:41 +01:00
|
|
|
|
|
1998-09-14 17:49:56 +02:00
|
|
|
|
int
|
|
|
|
|
clear_trust_checked_flag( PKT_public_key *pk )
|
|
|
|
|
{
|
|
|
|
|
TRUSTREC rec;
|
|
|
|
|
int rc;
|
|
|
|
|
|
1999-02-25 18:51:55 +01:00
|
|
|
|
if( opt.dry_run )
|
|
|
|
|
return 0;
|
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-10-01 09:23:00 +02:00
|
|
|
|
rc = get_dir_record( pk, &rec );
|
|
|
|
|
if( rc )
|
1998-09-14 17:49:56 +02:00
|
|
|
|
return rc;
|
|
|
|
|
|
1998-11-13 20:41:41 +01:00
|
|
|
|
/* check whether they are already reset */
|
|
|
|
|
if( !(rec.r.dir.dirflags & DIRF_CHECKED)
|
|
|
|
|
&& !(rec.r.dir.dirflags & DIRF_VALVALID) )
|
1998-09-14 17:49:56 +02:00
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* reset the flag */
|
|
|
|
|
rec.r.dir.dirflags &= ~DIRF_CHECKED;
|
1998-11-13 20:41:41 +01:00
|
|
|
|
rec.r.dir.dirflags &= ~DIRF_VALVALID;
|
1998-10-07 15:30:43 +02:00
|
|
|
|
write_record( &rec );
|
1998-10-16 18:00:17 +02:00
|
|
|
|
do_sync();
|
1998-09-14 17:49:56 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
1998-07-15 20:05:01 +02:00
|
|
|
|
|
1998-10-01 09:23:00 +02:00
|
|
|
|
|
1998-10-12 22:16:38 +02:00
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash,
|
|
|
|
|
TRUSTREC *sigrec, int sigidx, ulong hint_owner )
|
|
|
|
|
{
|
|
|
|
|
KBNODE node;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
int rc, state;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
byte uhash[20];
|
|
|
|
|
int is_selfsig;
|
|
|
|
|
PKT_signature *sigpkt = NULL;
|
1998-10-16 18:00:17 +02:00
|
|
|
|
TRUSTREC tmp;
|
|
|
|
|
u32 sigkid[2];
|
1999-02-16 14:16:33 +01:00
|
|
|
|
int revoked = 0;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
|
|
|
|
|
if( sigrec->r.sig.sig[sigidx].flag & SIGF_CHECKED )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info(_("NOTE: sig rec %lu[%d] in hintlist "
|
1998-10-12 22:16:38 +02:00
|
|
|
|
"of %lu but marked as checked\n"),
|
|
|
|
|
sigrec->recnum, sigidx, hint_owner );
|
|
|
|
|
if( !(sigrec->r.sig.sig[sigidx].flag & SIGF_NOPUBKEY) )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info(_("NOTE: sig rec %lu[%d] in hintlist "
|
1998-10-12 22:16:38 +02:00
|
|
|
|
"of %lu but not marked\n"),
|
|
|
|
|
sigrec->recnum, sigidx, hint_owner );
|
|
|
|
|
|
1998-10-16 18:00:17 +02:00
|
|
|
|
read_record( sigrec->r.sig.sig[sigidx].lid, &tmp, 0 );
|
|
|
|
|
if( tmp.rectype != RECTYPE_DIR ) {
|
|
|
|
|
/* we need the dir record */
|
|
|
|
|
log_error(_("sig rec %lu[%d] in hintlist "
|
1998-11-05 19:00:08 +01:00
|
|
|
|
"of %lu does not point to a dir record\n"),
|
1998-10-16 18:00:17 +02:00
|
|
|
|
sigrec->recnum, sigidx, hint_owner );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if( !tmp.r.dir.keylist ) {
|
|
|
|
|
log_error(_("lid %lu: no primary key\n"), tmp.r.dir.lid );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
read_record(tmp.r.dir.keylist, &tmp, RECTYPE_KEY );
|
|
|
|
|
keyid_from_fingerprint( tmp.r.key.fingerprint,
|
|
|
|
|
tmp.r.key.fingerprint_len, sigkid );
|
|
|
|
|
|
|
|
|
|
|
1998-10-12 22:16:38 +02:00
|
|
|
|
/* find the correct signature packet */
|
1998-10-25 20:00:01 +01:00
|
|
|
|
state = 0;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
for( node=keyblock; node; node = node->next ) {
|
|
|
|
|
if( node->pkt->pkttype == PKT_USER_ID ) {
|
|
|
|
|
PKT_user_id *uidpkt = node->pkt->pkt.user_id;
|
|
|
|
|
|
|
|
|
|
if( state )
|
|
|
|
|
break;
|
|
|
|
|
rmd160_hash_buffer( uhash, uidpkt->name, uidpkt->len );
|
|
|
|
|
if( !memcmp( uhash, uidrec_hash, 20 ) )
|
|
|
|
|
state = 1;
|
|
|
|
|
}
|
|
|
|
|
else if( state && node->pkt->pkttype == PKT_SIGNATURE ) {
|
|
|
|
|
sigpkt = node->pkt->pkt.signature;
|
1998-10-16 18:00:17 +02:00
|
|
|
|
if( sigpkt->keyid[0] == sigkid[0]
|
|
|
|
|
&& sigpkt->keyid[1] == sigkid[1]
|
1998-11-05 19:00:08 +01:00
|
|
|
|
&& ( (sigpkt->sig_class&~3) == 0x10
|
1999-02-16 14:16:33 +01:00
|
|
|
|
|| ( revoked = (sigpkt->sig_class == 0x30)) ) ) {
|
1998-10-25 20:00:01 +01:00
|
|
|
|
state = 2;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
break; /* found */
|
1998-10-25 20:00:01 +01:00
|
|
|
|
}
|
1998-10-12 22:16:38 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !node ) {
|
1998-10-25 20:00:01 +01:00
|
|
|
|
log_info(_("lid %lu: user id not found in keyblock\n"), lid );
|
|
|
|
|
return ;
|
|
|
|
|
}
|
|
|
|
|
if( state != 2 ) {
|
|
|
|
|
log_info(_("lid %lu: user id without signature\n"), lid );
|
1998-10-12 22:16:38 +02:00
|
|
|
|
return ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* and check the sig */
|
|
|
|
|
rc = check_key_signature( keyblock, node, &is_selfsig );
|
|
|
|
|
if( is_selfsig ) {
|
|
|
|
|
log_error(_("lid %lu: self-signature in hintlist\n"), lid );
|
1998-10-16 18:00:17 +02:00
|
|
|
|
return;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
}
|
1998-11-05 19:00:08 +01:00
|
|
|
|
|
|
|
|
|
/* FiXME: handling fo SIGF_REVOKED is not correct! */
|
|
|
|
|
|
1998-10-12 22:16:38 +02:00
|
|
|
|
if( !rc ) { /* valid signature */
|
1998-10-16 18:00:17 +02:00
|
|
|
|
if( opt.verbose )
|
1998-11-05 19:00:08 +01:00
|
|
|
|
log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
|
1998-10-16 18:00:17 +02:00
|
|
|
|
(ulong)keyid[1], lid, uhash[18], uhash[19],
|
1998-11-05 19:00:08 +01:00
|
|
|
|
(ulong)sigpkt->keyid[1],
|
1999-02-16 14:16:33 +01:00
|
|
|
|
revoked? _("Valid certificate revocation")
|
|
|
|
|
: _("Good certificate") );
|
1998-10-12 22:16:38 +02:00
|
|
|
|
sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED | SIGF_VALID;
|
1999-02-16 14:16:33 +01:00
|
|
|
|
if( revoked )
|
1998-11-05 19:00:08 +01:00
|
|
|
|
sigrec->r.sig.sig[sigidx].flag |= SIGF_REVOKED;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
}
|
|
|
|
|
else if( rc == G10ERR_NO_PUBKEY ) {
|
1998-11-05 19:00:08 +01:00
|
|
|
|
log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
|
1998-10-12 22:16:38 +02:00
|
|
|
|
(ulong)keyid[1], lid, uhash[18], uhash[19],
|
1998-11-05 19:00:08 +01:00
|
|
|
|
(ulong)sigpkt->keyid[1],
|
|
|
|
|
_("very strange: no public key\n") );
|
1998-10-12 22:16:38 +02:00
|
|
|
|
sigrec->r.sig.sig[sigidx].flag = SIGF_NOPUBKEY;
|
|
|
|
|
}
|
|
|
|
|
else {
|
1998-11-05 19:00:08 +01:00
|
|
|
|
log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
|
1998-10-16 18:00:17 +02:00
|
|
|
|
(ulong)keyid[1], lid, uhash[18], uhash[19],
|
|
|
|
|
(ulong)sigpkt->keyid[1], g10_errstr(rc) );
|
1998-10-12 22:16:38 +02:00
|
|
|
|
sigrec->r.sig.sig[sigidx].flag = SIGF_CHECKED;
|
|
|
|
|
}
|
|
|
|
|
sigrec->dirty = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
|
* Process a hintlist.
|
|
|
|
|
* Fixme: this list is not anymore anchored to another
|
|
|
|
|
* record, so it should be put elsewehere in case of an error
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
process_hintlist( ulong hintlist, ulong hint_owner )
|
|
|
|
|
{
|
|
|
|
|
ulong hlst_rn;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
for( hlst_rn = hintlist; hlst_rn; ) {
|
|
|
|
|
TRUSTREC hlstrec;
|
|
|
|
|
int hlst_idx;
|
|
|
|
|
|
|
|
|
|
read_record( hlst_rn, &hlstrec, RECTYPE_HLST );
|
|
|
|
|
|
|
|
|
|
for( hlst_idx=0; hlst_idx < ITEMS_PER_HLST_RECORD; hlst_idx++ ) {
|
|
|
|
|
TRUSTREC dirrec;
|
|
|
|
|
TRUSTREC uidrec;
|
|
|
|
|
TRUSTREC tmprec;
|
|
|
|
|
KBNODE keyblock = NULL;
|
|
|
|
|
u32 keyid[2];
|
|
|
|
|
ulong lid;
|
|
|
|
|
ulong r1, r2;
|
|
|
|
|
|
|
|
|
|
lid = hlstrec.r.hlst.rnum[hlst_idx];
|
|
|
|
|
if( !lid )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
read_record( lid, &dirrec, 0 );
|
|
|
|
|
/* make sure it points to a dir record:
|
|
|
|
|
* this should be true because it only makes sense to
|
|
|
|
|
* call this function if the dir record is available */
|
|
|
|
|
if( dirrec.rectype != RECTYPE_DIR ) {
|
|
|
|
|
log_error(_("hintlist %lu[%d] of %lu "
|
|
|
|
|
"does not point to a dir record\n"),
|
|
|
|
|
hlst_rn, hlst_idx, hint_owner );
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if( !dirrec.r.dir.keylist ) {
|
|
|
|
|
log_error(_("lid %lu does not have a key\n"), lid );
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* get the keyblock */
|
|
|
|
|
read_record( dirrec.r.dir.keylist, &tmprec, RECTYPE_KEY );
|
|
|
|
|
rc = get_keyblock_byfprint( &keyblock,
|
|
|
|
|
tmprec.r.key.fingerprint,
|
|
|
|
|
tmprec.r.key.fingerprint_len );
|
|
|
|
|
if( rc ) {
|
|
|
|
|
log_error(_("lid %lu: can't get keyblock: %s\n"),
|
|
|
|
|
lid, g10_errstr(rc) );
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
keyid_from_fingerprint( tmprec.r.key.fingerprint,
|
|
|
|
|
tmprec.r.key.fingerprint_len, keyid );
|
|
|
|
|
|
|
|
|
|
/* Walk over all user ids and their signatures and check all
|
|
|
|
|
* the signature which are created by hint_owner */
|
|
|
|
|
for( r1 = dirrec.r.dir.uidlist; r1; r1 = uidrec.r.uid.next ) {
|
|
|
|
|
TRUSTREC sigrec;
|
|
|
|
|
|
|
|
|
|
read_record( r1, &uidrec, RECTYPE_UID );
|
|
|
|
|
for( r2 = uidrec.r.uid.siglist; r2; r2 = sigrec.r.sig.next ) {
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
read_record( r2, &sigrec, RECTYPE_SIG );
|
|
|
|
|
sigrec.dirty = 0;
|
|
|
|
|
for(i=0; i < SIGS_PER_RECORD; i++ ) {
|
|
|
|
|
if( !sigrec.r.sig.sig[i].lid )
|
|
|
|
|
continue; /* skip deleted sigs */
|
|
|
|
|
if( sigrec.r.sig.sig[i].lid != hint_owner )
|
|
|
|
|
continue; /* not for us */
|
|
|
|
|
/* some diagnostic messages */
|
|
|
|
|
/* and do the signature check */
|
|
|
|
|
check_hint_sig( lid, keyblock, keyid,
|
|
|
|
|
uidrec.r.uid.namehash,
|
|
|
|
|
&sigrec, i, hint_owner );
|
|
|
|
|
}
|
|
|
|
|
if( sigrec.dirty )
|
|
|
|
|
write_record( &sigrec );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
release_kbnode( keyblock );
|
|
|
|
|
} /* loop over hlst entries */
|
|
|
|
|
|
|
|
|
|
/* delete this hlst record */
|
|
|
|
|
hlst_rn = hlstrec.r.hlst.next;
|
|
|
|
|
delete_record( hlstrec.recnum );
|
|
|
|
|
} /* loop over hintlist */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1998-10-25 20:00:01 +01:00
|
|
|
|
/****************
|
|
|
|
|
* Create or update shadow dir record and return the LID of the record
|
|
|
|
|
*/
|
|
|
|
|
static ulong
|
|
|
|
|
create_shadow_dir( PKT_signature *sig, ulong lid )
|
|
|
|
|
{
|
|
|
|
|
TRUSTREC sdir, hlst, tmphlst;
|
|
|
|
|
ulong recno, newlid;
|
1998-11-08 18:23:14 +01:00
|
|
|
|
int tmpidx=0; /* avoids gcc warnign - this is controlled by tmphlst */
|
1998-10-25 20:00:01 +01:00
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
/* first see whether we already have such a record */
|
|
|
|
|
rc = tdbio_search_sdir( sig->keyid, sig->pubkey_algo, &sdir );
|
|
|
|
|
if( rc && rc != -1 ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("tdbio_search_dir failed: %s\n"), g10_errstr(rc));
|
1998-10-25 20:00:01 +01:00
|
|
|
|
die_invalid_db();
|
|
|
|
|
}
|
|
|
|
|
if( rc == -1 ) { /* not found: create */
|
|
|
|
|
memset( &sdir, 0, sizeof sdir );
|
|
|
|
|
sdir.recnum = tdbio_new_recnum();
|
|
|
|
|
sdir.rectype= RECTYPE_SDIR;
|
|
|
|
|
sdir.r.sdir.lid = sdir.recnum;
|
|
|
|
|
sdir.r.sdir.keyid[0] = sig->keyid[0];
|
|
|
|
|
sdir.r.sdir.keyid[1] = sig->keyid[1];
|
|
|
|
|
sdir.r.sdir.pubkey_algo = sig->pubkey_algo;
|
|
|
|
|
sdir.r.sdir.hintlist = 0;
|
|
|
|
|
write_record( &sdir );
|
|
|
|
|
}
|
|
|
|
|
newlid = sdir.recnum;
|
|
|
|
|
/* Put the record number into the hintlist.
|
|
|
|
|
* (It is easier to use the lid and not the record number of the
|
|
|
|
|
* key to save some space (assuming that a signator has
|
|
|
|
|
* signed more than one user id - and it is easier to implement.)
|
|
|
|
|
*/
|
|
|
|
|
tmphlst.recnum = 0;
|
|
|
|
|
for( recno=sdir.r.sdir.hintlist; recno; recno = hlst.r.hlst.next) {
|
|
|
|
|
int i;
|
|
|
|
|
read_record( recno, &hlst, RECTYPE_HLST );
|
|
|
|
|
for( i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
|
|
|
|
|
if( !hlst.r.hlst.rnum[i] ) {
|
|
|
|
|
if( !tmphlst.recnum ) {
|
|
|
|
|
tmphlst = hlst;
|
|
|
|
|
tmpidx = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( hlst.r.hlst.rnum[i] == lid )
|
|
|
|
|
return newlid; /* the signature is already in the hintlist */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* not yet in the hint list, write it */
|
|
|
|
|
if( tmphlst.recnum ) { /* we have an empty slot */
|
|
|
|
|
tmphlst.r.hlst.rnum[tmpidx] = lid;
|
|
|
|
|
write_record( &tmphlst );
|
|
|
|
|
}
|
|
|
|
|
else { /* must append a new hlst record */
|
|
|
|
|
memset( &hlst, 0, sizeof hlst );
|
|
|
|
|
hlst.recnum = tdbio_new_recnum();
|
|
|
|
|
hlst.rectype = RECTYPE_HLST;
|
|
|
|
|
hlst.r.hlst.next = sdir.r.sdir.hintlist;
|
|
|
|
|
hlst.r.hlst.rnum[0] = lid;
|
|
|
|
|
write_record( &hlst );
|
|
|
|
|
sdir.r.sdir.hintlist = hlst.recnum;
|
|
|
|
|
write_record( &sdir );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return newlid;
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-12 22:16:38 +02:00
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
/****************
|
|
|
|
|
* This function checks the given public key and inserts or updates
|
|
|
|
|
* the keyrecord from the trustdb. Revocation certificates
|
|
|
|
|
* are handled here and the keybinding of subkeys is checked.
|
|
|
|
|
* Hmmm: Should we check here, that the key has at least one valid
|
|
|
|
|
* user ID or do we allow keys w/o user ID?
|
|
|
|
|
*
|
|
|
|
|
* keyblock points to the first node in the keyblock,
|
|
|
|
|
* keynode is the node with the public key to check
|
|
|
|
|
* (either primary or secondary), keyid is the keyid of
|
|
|
|
|
* the primary key, drec is the directory record and recno_list
|
|
|
|
|
* is a list used to keep track of visited records.
|
|
|
|
|
* Existing keyflags are recalculated if recheck is true.
|
|
|
|
|
*/
|
1998-10-12 22:16:38 +02:00
|
|
|
|
static void
|
1998-11-03 20:38:58 +01:00
|
|
|
|
upd_key_record( KBNODE keyblock, KBNODE keynode, u32 *keyid,
|
|
|
|
|
TRUSTREC *drec, RECNO_LIST *recno_list, int recheck )
|
1998-10-12 22:16:38 +02:00
|
|
|
|
{
|
|
|
|
|
TRUSTREC krec;
|
1998-11-03 20:38:58 +01:00
|
|
|
|
KBNODE node;
|
1998-11-05 19:00:08 +01:00
|
|
|
|
PKT_public_key *pk = keynode->pkt->pkt.public_key;
|
|
|
|
|
ulong lid = drec->recnum;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
byte fpr[MAX_FINGERPRINT_LEN];
|
|
|
|
|
size_t fprlen;
|
|
|
|
|
ulong recno, newrecno;
|
1998-11-03 20:38:58 +01:00
|
|
|
|
int keybind_seen = 0;
|
|
|
|
|
int revoke_seen = 0;
|
|
|
|
|
int rc;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
|
|
|
|
|
fingerprint_from_pk( pk, fpr, &fprlen );
|
|
|
|
|
/* do we already have this key? */
|
|
|
|
|
for( recno=drec->r.dir.keylist; recno; recno = krec.r.key.next ) {
|
|
|
|
|
read_record( recno, &krec, RECTYPE_KEY );
|
|
|
|
|
if( krec.r.key.fingerprint_len == fprlen
|
|
|
|
|
&& !memcmp( krec.r.key.fingerprint, fpr, fprlen ) )
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if( recno ) { /* yes */
|
|
|
|
|
ins_recno_list( recno_list, recno, RECTYPE_KEY );
|
|
|
|
|
}
|
|
|
|
|
else { /* no: insert this new key */
|
1998-11-03 20:38:58 +01:00
|
|
|
|
recheck = 1;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
memset( &krec, 0, sizeof(krec) );
|
|
|
|
|
krec.rectype = RECTYPE_KEY;
|
1998-11-03 20:38:58 +01:00
|
|
|
|
krec.r.key.lid = lid;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
krec.r.key.pubkey_algo = pk->pubkey_algo;
|
|
|
|
|
krec.r.key.fingerprint_len = fprlen;
|
|
|
|
|
memcpy(krec.r.key.fingerprint, fpr, fprlen );
|
|
|
|
|
krec.recnum = newrecno = tdbio_new_recnum();
|
|
|
|
|
write_record( &krec );
|
|
|
|
|
ins_recno_list( recno_list, newrecno, RECTYPE_KEY );
|
|
|
|
|
/* and put this new record at the end of the keylist */
|
|
|
|
|
if( !(recno=drec->r.dir.keylist) ) {
|
|
|
|
|
/* this is the first key */
|
|
|
|
|
drec->r.dir.keylist = newrecno;
|
|
|
|
|
drec->dirty = 1;
|
|
|
|
|
}
|
1998-11-03 20:38:58 +01:00
|
|
|
|
else { /* we already have a key, append the new one */
|
|
|
|
|
TRUSTREC save = krec;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
for( ; recno; recno = krec.r.key.next )
|
|
|
|
|
read_record( recno, &krec, RECTYPE_KEY );
|
|
|
|
|
krec.r.key.next = newrecno;
|
|
|
|
|
write_record( &krec );
|
1998-11-03 20:38:58 +01:00
|
|
|
|
krec = save;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-11-03 20:38:58 +01:00
|
|
|
|
|
|
|
|
|
if( !recheck && (krec.r.key.keyflags & KEYF_CHECKED) )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* check keybindings and revocations */
|
|
|
|
|
krec.r.key.keyflags = 0;
|
|
|
|
|
if( keynode->pkt->pkttype == PKT_PUBLIC_KEY ) {
|
|
|
|
|
/* we assume that a primary key is always valid
|
|
|
|
|
* and check later whether we have a revocation */
|
|
|
|
|
krec.r.key.keyflags |= KEYF_CHECKED | KEYF_VALID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for( node=keynode->next; node; node = node->next ) {
|
1998-11-05 19:00:08 +01:00
|
|
|
|
PKT_signature *sig;
|
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
|
|
|
|
|
break; /* ready */
|
1998-11-05 19:00:08 +01:00
|
|
|
|
else if( node->pkt->pkttype != PKT_SIGNATURE )
|
|
|
|
|
continue;
|
1998-11-03 20:38:58 +01:00
|
|
|
|
|
1998-11-05 19:00:08 +01:00
|
|
|
|
sig = node->pkt->pkt.signature;
|
|
|
|
|
|
|
|
|
|
if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
|
|
|
|
|
continue; /* not a self signature */
|
|
|
|
|
if( sig->sig_class == 0x18 && !keybind_seen ) { /* a keybinding */
|
|
|
|
|
if( keynode->pkt->pkttype == PKT_PUBLIC_KEY )
|
|
|
|
|
continue; /* oops, not for a main key */
|
|
|
|
|
/* we check until we find a valid keybinding */
|
|
|
|
|
rc = check_key_signature( keyblock, node, NULL );
|
|
|
|
|
if( !rc ) {
|
|
|
|
|
if( opt.verbose )
|
1998-11-03 20:38:58 +01:00
|
|
|
|
log_info(_(
|
1998-11-05 19:00:08 +01:00
|
|
|
|
"key %08lX.%lu: Good subkey binding\n"),
|
|
|
|
|
(ulong)keyid_from_pk(pk,NULL), lid );
|
|
|
|
|
krec.r.key.keyflags |= KEYF_CHECKED | KEYF_VALID;
|
1998-11-03 20:38:58 +01:00
|
|
|
|
}
|
1998-11-05 19:00:08 +01:00
|
|
|
|
else {
|
|
|
|
|
log_info(_(
|
|
|
|
|
"key %08lX.%lu: Invalid subkey binding: %s\n"),
|
|
|
|
|
(ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
|
|
|
|
|
krec.r.key.keyflags |= KEYF_CHECKED;
|
|
|
|
|
krec.r.key.keyflags &= ~KEYF_VALID;
|
|
|
|
|
}
|
|
|
|
|
keybind_seen = 1;
|
|
|
|
|
}
|
|
|
|
|
else if( sig->sig_class == 0x20 && !revoke_seen ) {
|
|
|
|
|
if( keynode->pkt->pkttype == PKT_PUBLIC_SUBKEY )
|
|
|
|
|
continue; /* a subkey is not expected here */
|
|
|
|
|
/* This is a key revocation certificate: check it */
|
|
|
|
|
rc = check_key_signature( keyblock, node, NULL );
|
|
|
|
|
if( !rc ) {
|
|
|
|
|
if( opt.verbose )
|
1998-11-03 20:38:58 +01:00
|
|
|
|
log_info(_(
|
1998-11-05 19:00:08 +01:00
|
|
|
|
"key %08lX.%lu: Valid key revocation\n"),
|
|
|
|
|
(ulong)keyid_from_pk(pk,NULL), lid );
|
|
|
|
|
krec.r.key.keyflags |= KEYF_REVOKED;
|
1998-11-03 20:38:58 +01:00
|
|
|
|
}
|
1998-11-05 19:00:08 +01:00
|
|
|
|
else {
|
|
|
|
|
log_info(_(
|
|
|
|
|
"key %08lX.%lu: Invalid key revocation: %s\n"),
|
|
|
|
|
(ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
|
|
|
|
|
}
|
|
|
|
|
revoke_seen = 1;
|
|
|
|
|
}
|
|
|
|
|
else if( sig->sig_class == 0x28 && !revoke_seen ) {
|
|
|
|
|
if( keynode->pkt->pkttype == PKT_PUBLIC_KEY )
|
|
|
|
|
continue; /* a mainkey is not expected here */
|
|
|
|
|
/* This is a subkey revocation certificate: check it */
|
|
|
|
|
/* fixme: we should also check the revocation
|
|
|
|
|
* is newer than the key (OpenPGP) */
|
|
|
|
|
rc = check_key_signature( keyblock, node, NULL );
|
|
|
|
|
if( !rc ) {
|
|
|
|
|
if( opt.verbose )
|
1998-11-03 20:38:58 +01:00
|
|
|
|
log_info(_(
|
1998-11-05 19:00:08 +01:00
|
|
|
|
"key %08lX.%lu: Valid subkey revocation\n"),
|
|
|
|
|
(ulong)keyid_from_pk(pk,NULL), lid );
|
|
|
|
|
krec.r.key.keyflags |= KEYF_REVOKED;
|
1998-11-03 20:38:58 +01:00
|
|
|
|
}
|
1998-11-05 19:00:08 +01:00
|
|
|
|
else {
|
|
|
|
|
log_info(_(
|
|
|
|
|
"key %08lX.%lu: Invalid subkey binding: %s\n"),
|
|
|
|
|
(ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
|
|
|
|
|
}
|
|
|
|
|
revoke_seen = 1;
|
|
|
|
|
}
|
1998-11-03 20:38:58 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
write_record( &krec );
|
1998-10-12 22:16:38 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
/****************
|
|
|
|
|
* This function checks the given user ID and inserts or updates
|
|
|
|
|
* the uid record of the trustdb. Revocation certificates
|
|
|
|
|
* are handled here.
|
|
|
|
|
*
|
|
|
|
|
* keyblock points to the first node in the keyblock,
|
|
|
|
|
* uidnode is the node with the user id to check
|
|
|
|
|
* keyid is the keyid of
|
|
|
|
|
* the primary key, drec is the directory record and recno_list
|
|
|
|
|
* is a list used to keep track of visited records.
|
|
|
|
|
* Existing uidflags are recalculated if recheck is true.
|
|
|
|
|
*/
|
1998-10-12 22:16:38 +02:00
|
|
|
|
static void
|
1998-11-03 20:38:58 +01:00
|
|
|
|
upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
|
|
|
|
|
TRUSTREC *drec, RECNO_LIST *recno_list, int recheck )
|
1998-10-12 22:16:38 +02:00
|
|
|
|
{
|
1998-11-03 20:38:58 +01:00
|
|
|
|
ulong lid = drec->recnum;
|
|
|
|
|
PKT_user_id *uid = uidnode->pkt->pkt.user_id;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
TRUSTREC urec;
|
1998-11-05 19:00:08 +01:00
|
|
|
|
PKT_signature *selfsig = NULL;
|
1998-11-03 20:38:58 +01:00
|
|
|
|
byte uidhash[20];
|
1998-11-05 19:00:08 +01:00
|
|
|
|
KBNODE node;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
ulong recno, newrecno;
|
1998-11-05 19:00:08 +01:00
|
|
|
|
int rc;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
/* see whether we already have an uid record */
|
1998-10-12 22:16:38 +02:00
|
|
|
|
rmd160_hash_buffer( uidhash, uid->name, uid->len );
|
|
|
|
|
for( recno=drec->r.dir.uidlist; recno; recno = urec.r.uid.next ) {
|
|
|
|
|
read_record( recno, &urec, RECTYPE_UID );
|
|
|
|
|
if( !memcmp( uidhash, urec.r.uid.namehash, 20 ) )
|
|
|
|
|
break;
|
|
|
|
|
}
|
1998-11-05 19:00:08 +01:00
|
|
|
|
if( recno ) { /* we already have this record */
|
1998-10-12 22:16:38 +02:00
|
|
|
|
ins_recno_list( recno_list, recno, RECTYPE_UID );
|
|
|
|
|
}
|
|
|
|
|
else { /* new user id */
|
1998-11-05 19:00:08 +01:00
|
|
|
|
recheck = 1;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
memset( &urec, 0 , sizeof(urec) );
|
|
|
|
|
urec.rectype = RECTYPE_UID;
|
|
|
|
|
urec.r.uid.lid = drec->recnum;
|
|
|
|
|
memcpy(urec.r.uid.namehash, uidhash, 20 );
|
|
|
|
|
urec.recnum = newrecno = tdbio_new_recnum();
|
|
|
|
|
write_record( &urec );
|
|
|
|
|
ins_recno_list( recno_list, newrecno, RECTYPE_UID );
|
|
|
|
|
/* and put this new record at the end of the uidlist */
|
|
|
|
|
if( !(recno=drec->r.dir.uidlist) ) { /* this is the first uid */
|
|
|
|
|
drec->r.dir.uidlist = newrecno;
|
|
|
|
|
drec->dirty = 1;
|
|
|
|
|
}
|
|
|
|
|
else { /* we already have an uid, append it to the list */
|
1998-11-05 19:00:08 +01:00
|
|
|
|
TRUSTREC save = urec;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
for( ; recno; recno = urec.r.key.next )
|
|
|
|
|
read_record( recno, &urec, RECTYPE_UID );
|
|
|
|
|
urec.r.uid.next = newrecno;
|
|
|
|
|
write_record( &urec );
|
1998-11-05 19:00:08 +01:00
|
|
|
|
urec = save;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-11-05 19:00:08 +01:00
|
|
|
|
|
|
|
|
|
if( recheck || !(urec.r.uid.uidflags & UIDF_CHECKED) ) {
|
|
|
|
|
/* check self signatures */
|
|
|
|
|
urec.r.uid.uidflags = 0;
|
|
|
|
|
for( node=uidnode->next; node; node = node->next ) {
|
|
|
|
|
PKT_signature *sig;
|
|
|
|
|
|
|
|
|
|
if( node->pkt->pkttype == PKT_USER_ID )
|
|
|
|
|
break; /* ready */
|
|
|
|
|
if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
|
|
|
|
|
break; /* ready */
|
|
|
|
|
if( node->pkt->pkttype != PKT_SIGNATURE )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
sig = node->pkt->pkt.signature;
|
|
|
|
|
|
|
|
|
|
if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
|
|
|
|
|
continue; /* not a self signature */
|
|
|
|
|
|
|
|
|
|
if( (sig->sig_class&~3) == 0x10 ) { /* regular self signature */
|
|
|
|
|
rc = check_key_signature( keyblock, node, NULL );
|
|
|
|
|
if( !rc ) {
|
|
|
|
|
if( opt.verbose )
|
|
|
|
|
log_info( "uid %08lX.%lu/%02X%02X: %s\n",
|
|
|
|
|
(ulong)keyid[1], lid, uidhash[18], uidhash[19],
|
|
|
|
|
_("Good self-signature") );
|
|
|
|
|
urec.r.uid.uidflags |= UIDF_CHECKED | UIDF_VALID;
|
|
|
|
|
if( !selfsig )
|
|
|
|
|
selfsig = sig; /* use the first valid sig */
|
1998-12-08 13:20:53 +01:00
|
|
|
|
else if( sig->timestamp > selfsig->timestamp
|
|
|
|
|
&& sig->sig_class >= selfsig->sig_class )
|
|
|
|
|
selfsig = sig; /* but this one is newer */
|
1998-11-05 19:00:08 +01:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
log_info( "uid %08lX/%02X%02X: %s: %s\n",
|
|
|
|
|
(ulong)keyid[1], uidhash[18], uidhash[19],
|
|
|
|
|
_("Invalid self-signature"),
|
|
|
|
|
g10_errstr(rc) );
|
|
|
|
|
urec.r.uid.uidflags |= UIDF_CHECKED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( sig->sig_class == 0x30 ) { /* cert revocation */
|
|
|
|
|
rc = check_key_signature( keyblock, node, NULL );
|
1998-12-08 13:20:53 +01:00
|
|
|
|
if( !rc && selfsig && selfsig->timestamp > sig->timestamp ) {
|
|
|
|
|
log_info( "uid %08lX.%lu/%02X%02X: %s\n",
|
|
|
|
|
(ulong)keyid[1], lid, uidhash[18], uidhash[19],
|
|
|
|
|
_("Valid user ID revocation skipped "
|
|
|
|
|
"due to a newer self signature\n") );
|
|
|
|
|
}
|
|
|
|
|
else if( !rc ) {
|
1998-11-05 19:00:08 +01:00
|
|
|
|
if( opt.verbose )
|
|
|
|
|
log_info( "uid %08lX.%lu/%02X%02X: %s\n",
|
|
|
|
|
(ulong)keyid[1], lid, uidhash[18], uidhash[19],
|
|
|
|
|
_("Valid user ID revocation\n") );
|
|
|
|
|
urec.r.uid.uidflags |= UIDF_CHECKED | UIDF_VALID;
|
|
|
|
|
urec.r.uid.uidflags |= UIDF_REVOKED;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
log_info("uid %08lX/%02X%02X: %s: %s\n",
|
|
|
|
|
(ulong)keyid[1], uidhash[18], uidhash[19],
|
|
|
|
|
_("Invalid user ID revocation"),
|
|
|
|
|
g10_errstr(rc) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
write_record( &urec );
|
|
|
|
|
} /* end check self-signatures */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( (urec.r.uid.uidflags & (UIDF_CHECKED|UIDF_VALID))
|
|
|
|
|
!= (UIDF_CHECKED|UIDF_VALID) )
|
|
|
|
|
return; /* user ID is not valid, so no need to check more things */
|
|
|
|
|
|
|
|
|
|
/* check the preferences */
|
|
|
|
|
if( selfsig )
|
|
|
|
|
upd_pref_record( &urec, keyid, selfsig );
|
|
|
|
|
|
|
|
|
|
/* check non-self signatures */
|
|
|
|
|
for( node=uidnode->next; node; node = node->next ) {
|
|
|
|
|
PKT_signature *sig;
|
|
|
|
|
|
|
|
|
|
if( node->pkt->pkttype == PKT_USER_ID )
|
|
|
|
|
break; /* ready */
|
|
|
|
|
if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
|
|
|
|
|
break; /* ready */
|
|
|
|
|
if( node->pkt->pkttype != PKT_SIGNATURE )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
sig = node->pkt->pkt.signature;
|
|
|
|
|
|
|
|
|
|
if( keyid[0] == sig->keyid[0] || keyid[1] == sig->keyid[1] )
|
|
|
|
|
continue; /* skip self signature */
|
|
|
|
|
|
|
|
|
|
if( (sig->sig_class&~3) == 0x10 ) { /* regular certification */
|
|
|
|
|
upd_cert_record( keyblock, node, keyid, drec, recno_list,
|
|
|
|
|
recheck, &urec, uidhash, 0 );
|
|
|
|
|
}
|
|
|
|
|
else if( sig->sig_class == 0x30 ) { /* cert revocation */
|
|
|
|
|
upd_cert_record( keyblock, node, keyid, drec, recno_list,
|
|
|
|
|
recheck, &urec, uidhash, 1 );
|
|
|
|
|
}
|
|
|
|
|
} /* end check certificates */
|
|
|
|
|
|
|
|
|
|
write_record( &urec );
|
1998-10-12 22:16:38 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1998-11-05 19:00:08 +01:00
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*/
|
1998-10-12 22:16:38 +02:00
|
|
|
|
static void
|
1998-11-05 19:00:08 +01:00
|
|
|
|
upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig )
|
1998-10-12 22:16:38 +02:00
|
|
|
|
{
|
|
|
|
|
static struct {
|
|
|
|
|
sigsubpkttype_t subpkttype;
|
|
|
|
|
int preftype;
|
1998-11-05 19:00:08 +01:00
|
|
|
|
} ptable[] = {
|
1998-10-12 22:16:38 +02:00
|
|
|
|
{ SIGSUBPKT_PREF_SYM, PREFTYPE_SYM },
|
|
|
|
|
{ SIGSUBPKT_PREF_HASH, PREFTYPE_HASH },
|
|
|
|
|
{ SIGSUBPKT_PREF_COMPR, PREFTYPE_COMPR },
|
|
|
|
|
{ 0, 0 }
|
|
|
|
|
};
|
1998-10-16 18:00:17 +02:00
|
|
|
|
TRUSTREC prec;
|
1998-11-05 19:00:08 +01:00
|
|
|
|
ulong lid = urec->r.uid.lid ;
|
|
|
|
|
const byte *uidhash = urec->r.uid.namehash;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
const byte *s;
|
|
|
|
|
size_t n;
|
|
|
|
|
int k, i;
|
|
|
|
|
ulong recno;
|
1998-11-05 19:00:08 +01:00
|
|
|
|
byte prefs_sig[200];
|
|
|
|
|
int n_prefs_sig = 0;
|
|
|
|
|
byte prefs_rec[200];
|
|
|
|
|
int n_prefs_rec = 0;
|
|
|
|
|
|
|
|
|
|
/* check for changed preferences */
|
|
|
|
|
for(k=0; ptable[k].subpkttype; k++ ) {
|
|
|
|
|
s = parse_sig_subpkt2( sig, ptable[k].subpkttype, &n );
|
|
|
|
|
if( s ) {
|
1998-11-18 20:59:06 +01:00
|
|
|
|
for( ; n; n--, s++ ) {
|
|
|
|
|
if( n_prefs_sig >= DIM(prefs_sig)-1 ) {
|
|
|
|
|
log_info("uid %08lX.%lu/%02X%02X: %s\n",
|
|
|
|
|
(ulong)keyid[1], lid, uidhash[18], uidhash[19],
|
|
|
|
|
_("Too many preferences") );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
prefs_sig[n_prefs_sig++] = ptable[k].preftype;
|
|
|
|
|
prefs_sig[n_prefs_sig++] = *s;
|
1998-11-05 19:00:08 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for( recno=urec->r.uid.prefrec; recno; recno = prec.r.pref.next ) {
|
|
|
|
|
read_record( recno, &prec, RECTYPE_PREF );
|
|
|
|
|
for(i = 0; i < ITEMS_PER_PREF_RECORD; i +=2 ) {
|
|
|
|
|
if( n_prefs_rec >= DIM(prefs_rec)-1 ) {
|
|
|
|
|
log_info("uid %08lX.%lu/%02X%02X: %s\n",
|
|
|
|
|
(ulong)keyid[1], lid, uidhash[18], uidhash[19],
|
1998-11-10 13:59:59 +01:00
|
|
|
|
_("Too many preference items") );
|
1998-11-05 19:00:08 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
1998-11-18 20:59:06 +01:00
|
|
|
|
if( prec.r.pref.data[i] ) {
|
|
|
|
|
prefs_rec[n_prefs_rec++] = prec.r.pref.data[i];
|
|
|
|
|
prefs_rec[n_prefs_rec++] = prec.r.pref.data[i+1];
|
|
|
|
|
}
|
1998-11-05 19:00:08 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if( n_prefs_sig == n_prefs_rec
|
|
|
|
|
&& !memcmp( prefs_sig, prefs_rec, n_prefs_sig ) )
|
1998-11-18 20:59:06 +01:00
|
|
|
|
return; /* not changed */
|
1998-10-12 22:16:38 +02:00
|
|
|
|
|
1998-11-05 19:00:08 +01:00
|
|
|
|
/* Preferences have changed: Delete all pref records
|
1998-10-12 22:16:38 +02:00
|
|
|
|
* This is much simpler than checking whether we have to
|
1998-10-25 20:00:01 +01:00
|
|
|
|
* do update the record at all - the record cache may care about it
|
1998-11-05 19:00:08 +01:00
|
|
|
|
*/
|
1998-10-16 18:00:17 +02:00
|
|
|
|
for( recno=urec->r.uid.prefrec; recno; recno = prec.r.pref.next ) {
|
1998-10-12 22:16:38 +02:00
|
|
|
|
read_record( recno, &prec, RECTYPE_PREF );
|
|
|
|
|
delete_record( recno );
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-05 19:00:08 +01:00
|
|
|
|
if( n_prefs_sig > ITEMS_PER_PREF_RECORD )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info(_("WARNING: can't yet handle long pref records\n"));
|
1998-11-05 19:00:08 +01:00
|
|
|
|
|
|
|
|
|
memset( &prec, 0, sizeof prec );
|
|
|
|
|
prec.recnum = tdbio_new_recnum();
|
|
|
|
|
prec.rectype = RECTYPE_PREF;
|
|
|
|
|
prec.r.pref.lid = lid;
|
|
|
|
|
if( n_prefs_sig <= ITEMS_PER_PREF_RECORD )
|
|
|
|
|
memcpy( prec.r.pref.data, prefs_sig, n_prefs_sig );
|
|
|
|
|
else { /* need more than one pref record */
|
|
|
|
|
TRUSTREC tmp;
|
|
|
|
|
ulong nextrn;
|
|
|
|
|
byte *pp = prefs_sig;
|
|
|
|
|
|
1999-02-16 14:16:33 +01:00
|
|
|
|
n = n_prefs_sig;
|
1998-11-05 19:00:08 +01:00
|
|
|
|
memcpy( prec.r.pref.data, pp, ITEMS_PER_PREF_RECORD );
|
|
|
|
|
n -= ITEMS_PER_PREF_RECORD;
|
|
|
|
|
pp += ITEMS_PER_PREF_RECORD;
|
|
|
|
|
nextrn = prec.r.pref.next = tdbio_new_recnum();
|
|
|
|
|
do {
|
|
|
|
|
memset( &tmp, 0, sizeof tmp );
|
|
|
|
|
tmp.recnum = nextrn;
|
|
|
|
|
tmp.rectype = RECTYPE_PREF;
|
|
|
|
|
tmp.r.pref.lid = lid;
|
|
|
|
|
if( n <= ITEMS_PER_PREF_RECORD ) {
|
|
|
|
|
memcpy( tmp.r.pref.data, pp, n );
|
|
|
|
|
n = 0;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
}
|
1998-11-05 19:00:08 +01:00
|
|
|
|
else {
|
|
|
|
|
memcpy( tmp.r.pref.data, pp, ITEMS_PER_PREF_RECORD );
|
|
|
|
|
n -= ITEMS_PER_PREF_RECORD;
|
|
|
|
|
pp += ITEMS_PER_PREF_RECORD;
|
|
|
|
|
nextrn = tmp.r.pref.next = tdbio_new_recnum();
|
|
|
|
|
}
|
|
|
|
|
write_record( &tmp );
|
|
|
|
|
} while( n );
|
1998-10-12 22:16:38 +02:00
|
|
|
|
}
|
1998-11-05 19:00:08 +01:00
|
|
|
|
write_record( &prec );
|
|
|
|
|
urec->r.uid.prefrec = prec.recnum;
|
1998-10-16 18:00:17 +02:00
|
|
|
|
urec->dirty = 1;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
|
1998-10-25 20:00:01 +01:00
|
|
|
|
static void
|
1998-11-05 19:00:08 +01:00
|
|
|
|
upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
|
|
|
|
|
TRUSTREC *drec, RECNO_LIST *recno_list, int recheck,
|
1999-02-16 14:16:33 +01:00
|
|
|
|
TRUSTREC *urec, const byte *uidhash, int revoked )
|
1998-10-25 20:00:01 +01:00
|
|
|
|
{
|
|
|
|
|
/* We simply insert the signature into the sig records but
|
|
|
|
|
* avoid duplicate ones. We do not check them here because
|
|
|
|
|
* there is a big chance, that we import required public keys
|
|
|
|
|
* later. The problem with this is that we must somewhere store
|
|
|
|
|
* the information about this signature (we need a record id).
|
|
|
|
|
* We do this by using the record type shadow dir, which will
|
|
|
|
|
* be converted to a dir record as soon as a new public key is
|
|
|
|
|
* inserted into the trustdb.
|
|
|
|
|
*/
|
1998-11-05 19:00:08 +01:00
|
|
|
|
ulong lid = drec->recnum;
|
|
|
|
|
PKT_signature *sig = signode->pkt->pkt.signature;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
TRUSTREC rec;
|
|
|
|
|
ulong recno;
|
|
|
|
|
TRUSTREC delrec;
|
1998-11-08 18:23:14 +01:00
|
|
|
|
int delrecidx=0;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
int newflag = 0;
|
|
|
|
|
ulong newlid = 0;
|
|
|
|
|
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
|
|
|
|
|
ulong pk_lid = 0;
|
|
|
|
|
int found_sig = 0;
|
|
|
|
|
int found_delrec = 0;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
delrec.recnum = 0;
|
|
|
|
|
|
|
|
|
|
/* get the LID of the pubkey of the signature under verification */
|
|
|
|
|
rc = get_pubkey( pk, sig->keyid );
|
|
|
|
|
if( !rc ) {
|
|
|
|
|
if( pk->local_id )
|
|
|
|
|
pk_lid = pk->local_id;
|
|
|
|
|
else {
|
|
|
|
|
rc = tdbio_search_dir_bypk( pk, &rec );
|
|
|
|
|
if( !rc )
|
|
|
|
|
pk_lid = rec.recnum;
|
|
|
|
|
else if( rc == -1 ) { /* see whether there is a sdir instead */
|
|
|
|
|
u32 akid[2];
|
|
|
|
|
|
|
|
|
|
keyid_from_pk( pk, akid );
|
|
|
|
|
rc = tdbio_search_sdir( akid, pk->pubkey_algo, &rec );
|
|
|
|
|
if( !rc )
|
|
|
|
|
pk_lid = rec.recnum;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free_public_key( pk ); pk = NULL;
|
|
|
|
|
|
|
|
|
|
/* Loop over all signatures just in case one is not correctly
|
|
|
|
|
* marked. If we see the correct signature, set a flag.
|
|
|
|
|
* delete duplicate signatures (should not happen but...) */
|
|
|
|
|
for( recno = urec->r.uid.siglist; recno; recno = rec.r.sig.next ) {
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
read_record( recno, &rec, RECTYPE_SIG );
|
|
|
|
|
for(i=0; i < SIGS_PER_RECORD; i++ ) {
|
|
|
|
|
TRUSTREC tmp;
|
|
|
|
|
if( !rec.r.sig.sig[i].lid ) {
|
|
|
|
|
if( !found_delrec && !delrec.recnum ) {
|
|
|
|
|
delrec = rec;
|
|
|
|
|
delrecidx = i;
|
|
|
|
|
found_delrec=1;
|
|
|
|
|
}
|
|
|
|
|
continue; /* skip deleted sigs */
|
|
|
|
|
}
|
|
|
|
|
if( rec.r.sig.sig[i].lid == pk_lid ) {
|
1999-02-10 17:22:40 +01:00
|
|
|
|
#if 0 /* must take uid into account */
|
1998-10-25 20:00:01 +01:00
|
|
|
|
if( found_sig ) {
|
1998-11-05 19:00:08 +01:00
|
|
|
|
log_info( "sig %08lX.%lu/%02X%02X/%08lX: %s\n",
|
|
|
|
|
(ulong)keyid[1], lid, uidhash[18],
|
|
|
|
|
uidhash[19], (ulong)sig->keyid[1],
|
1999-02-10 17:22:40 +01:00
|
|
|
|
_("duplicated certificate - deleted") );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
rec.r.sig.sig[i].lid = 0;
|
|
|
|
|
rec.dirty = 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
1999-02-10 17:22:40 +01:00
|
|
|
|
#endif
|
1998-10-25 20:00:01 +01:00
|
|
|
|
found_sig = 1;
|
|
|
|
|
}
|
1999-02-16 14:16:33 +01:00
|
|
|
|
if( !recheck && !revoked && (rec.r.sig.sig[i].flag & SIGF_CHECKED) )
|
1998-10-25 20:00:01 +01:00
|
|
|
|
continue; /* we already checked this signature */
|
1998-11-05 19:00:08 +01:00
|
|
|
|
if( !recheck && (rec.r.sig.sig[i].flag & SIGF_NOPUBKEY) )
|
1998-10-25 20:00:01 +01:00
|
|
|
|
continue; /* we do not have the public key */
|
|
|
|
|
|
|
|
|
|
read_record( rec.r.sig.sig[i].lid, &tmp, 0 );
|
|
|
|
|
if( tmp.rectype == RECTYPE_DIR ) {
|
|
|
|
|
/* In this case we should now be able to check the signature */
|
|
|
|
|
rc = check_key_signature( keyblock, signode, NULL );
|
|
|
|
|
if( !rc ) { /* valid signature */
|
|
|
|
|
if( opt.verbose )
|
1998-11-05 19:00:08 +01:00
|
|
|
|
log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
|
1998-10-25 20:00:01 +01:00
|
|
|
|
(ulong)keyid[1], lid, uidhash[18],
|
1998-11-05 19:00:08 +01:00
|
|
|
|
uidhash[19], (ulong)sig->keyid[1],
|
1999-02-16 14:16:33 +01:00
|
|
|
|
revoked? _("Valid certificate revocation")
|
|
|
|
|
: _("Good certificate") );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
rec.r.sig.sig[i].flag = SIGF_CHECKED | SIGF_VALID;
|
1999-02-16 14:16:33 +01:00
|
|
|
|
if( revoked )
|
1998-11-05 19:00:08 +01:00
|
|
|
|
rec.r.sig.sig[i].flag |= SIGF_REVOKED;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
}
|
|
|
|
|
else if( rc == G10ERR_NO_PUBKEY ) {
|
1998-12-08 13:20:53 +01:00
|
|
|
|
#if 0 /* fixme: For some reason this really happens? */
|
1998-11-03 20:38:58 +01:00
|
|
|
|
if( (rec.r.sig.sig[i].flag & SIGF_CHECKED) )
|
1998-11-05 19:00:08 +01:00
|
|
|
|
log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
|
1998-11-03 20:38:58 +01:00
|
|
|
|
(ulong)keyid[1], lid, uidhash[18],
|
1998-11-05 19:00:08 +01:00
|
|
|
|
uidhash[19], (ulong)sig->keyid[1],
|
1998-11-10 13:59:59 +01:00
|
|
|
|
_("Hmmm, public key lost?") );
|
1998-12-08 13:20:53 +01:00
|
|
|
|
#endif
|
1998-10-25 20:00:01 +01:00
|
|
|
|
rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
|
1999-02-16 14:16:33 +01:00
|
|
|
|
if( revoked )
|
1998-11-05 19:00:08 +01:00
|
|
|
|
rec.r.sig.sig[i].flag |= SIGF_REVOKED;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
}
|
|
|
|
|
else {
|
1998-11-05 19:00:08 +01:00
|
|
|
|
log_info("sig %08lX.%lu/%02X%02X/%08lX: %s: %s\n",
|
1998-10-25 20:00:01 +01:00
|
|
|
|
(ulong)keyid[1], lid, uidhash[18],
|
|
|
|
|
uidhash[19], (ulong)sig->keyid[1],
|
1999-02-16 14:16:33 +01:00
|
|
|
|
revoked? _("Invalid certificate revocation")
|
|
|
|
|
: _("Invalid certificate"),
|
1998-10-25 20:00:01 +01:00
|
|
|
|
g10_errstr(rc));
|
|
|
|
|
rec.r.sig.sig[i].flag = SIGF_CHECKED;
|
1999-02-16 14:16:33 +01:00
|
|
|
|
if( revoked )
|
1998-11-05 19:00:08 +01:00
|
|
|
|
rec.r.sig.sig[i].flag |= SIGF_REVOKED;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
}
|
|
|
|
|
rec.dirty = 1;
|
|
|
|
|
}
|
|
|
|
|
else if( tmp.rectype == RECTYPE_SDIR ) {
|
|
|
|
|
/* must check that it is the right one */
|
|
|
|
|
if( tmp.r.sdir.keyid[0] == sig->keyid[0]
|
|
|
|
|
&& tmp.r.sdir.keyid[1] == sig->keyid[1]
|
|
|
|
|
&& (!tmp.r.sdir.pubkey_algo
|
|
|
|
|
|| tmp.r.sdir.pubkey_algo == sig->pubkey_algo )) {
|
1998-11-03 20:38:58 +01:00
|
|
|
|
if( !(rec.r.sig.sig[i].flag & SIGF_NOPUBKEY) )
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_info(_("uid %08lX.%lu/%02X%02X: "
|
|
|
|
|
"has shadow dir %lu but is not yet marked.\n"),
|
1998-10-25 20:00:01 +01:00
|
|
|
|
(ulong)keyid[1], lid,
|
|
|
|
|
uidhash[18], uidhash[19], tmp.recnum );
|
|
|
|
|
rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
|
1999-02-16 14:16:33 +01:00
|
|
|
|
if( revoked )
|
1998-11-05 19:00:08 +01:00
|
|
|
|
rec.r.sig.sig[i].flag |= SIGF_REVOKED;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
rec.dirty = 1;
|
|
|
|
|
/* fixme: should we verify that the record is
|
|
|
|
|
* in the hintlist? - This case here should anyway
|
|
|
|
|
* never occur */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("sig record %lu[%d] points to wrong record.\n"),
|
1998-10-25 20:00:01 +01:00
|
|
|
|
rec.r.sig.sig[i].lid, i );
|
|
|
|
|
die_invalid_db();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if( found_delrec && delrec.recnum ) {
|
|
|
|
|
delrec = rec;
|
|
|
|
|
found_delrec = 0; /* we only want the first one */
|
|
|
|
|
}
|
|
|
|
|
if( rec.dirty ) {
|
|
|
|
|
write_record( &rec );
|
|
|
|
|
rec.dirty = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-02-10 17:22:40 +01:00
|
|
|
|
if( found_sig ) /* fixme: uid stuff */
|
1998-10-25 20:00:01 +01:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* at this point, we have verified, that the signature is not in
|
|
|
|
|
* our list of signatures. Add a new record with that signature
|
|
|
|
|
* and if the public key is there, check the signature. */
|
|
|
|
|
|
|
|
|
|
if( !pk_lid ) /* we have already seen that there is no pubkey */
|
|
|
|
|
rc = G10ERR_NO_PUBKEY;
|
|
|
|
|
else
|
|
|
|
|
rc = check_key_signature( keyblock, signode, NULL );
|
|
|
|
|
|
|
|
|
|
if( !rc ) { /* valid signature */
|
|
|
|
|
if( opt.verbose )
|
1998-11-05 19:00:08 +01:00
|
|
|
|
log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
|
1998-10-25 20:00:01 +01:00
|
|
|
|
(ulong)keyid[1], lid, uidhash[18],
|
1998-11-05 19:00:08 +01:00
|
|
|
|
uidhash[19], (ulong)sig->keyid[1],
|
1999-02-16 14:16:33 +01:00
|
|
|
|
revoked? _("Valid certificate revocation")
|
|
|
|
|
: _("Good certificate") );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
newlid = pk_lid; /* this is the pk of the signature */
|
|
|
|
|
newflag = SIGF_CHECKED | SIGF_VALID;
|
1999-02-16 14:16:33 +01:00
|
|
|
|
if( revoked )
|
1998-11-05 19:00:08 +01:00
|
|
|
|
newflag |= SIGF_REVOKED;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
}
|
|
|
|
|
else if( rc == G10ERR_NO_PUBKEY ) {
|
|
|
|
|
if( opt.verbose > 1 )
|
1998-11-05 19:00:08 +01:00
|
|
|
|
log_info("sig %08lX.%lu/%02X%02X/%08lX: %s\n",
|
|
|
|
|
(ulong)keyid[1], lid, uidhash[18],
|
|
|
|
|
uidhash[19], (ulong)sig->keyid[1], g10_errstr(rc) );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
newlid = create_shadow_dir( sig, lid );
|
|
|
|
|
newflag = SIGF_NOPUBKEY;
|
1999-02-16 14:16:33 +01:00
|
|
|
|
if( revoked )
|
1998-11-05 19:00:08 +01:00
|
|
|
|
newflag |= SIGF_REVOKED;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
}
|
|
|
|
|
else {
|
1998-11-05 19:00:08 +01:00
|
|
|
|
log_info( "sig %08lX.%lu/%02X%02X/%08lX: %s: %s\n",
|
1998-10-25 20:00:01 +01:00
|
|
|
|
(ulong)keyid[1], lid, uidhash[18], uidhash[19],
|
1998-11-05 19:00:08 +01:00
|
|
|
|
(ulong)sig->keyid[1],
|
1999-02-16 14:16:33 +01:00
|
|
|
|
revoked? _("Invalid certificate revocation")
|
|
|
|
|
: _("Invalid certificate"),
|
1998-11-05 19:00:08 +01:00
|
|
|
|
g10_errstr(rc));
|
1998-10-25 20:00:01 +01:00
|
|
|
|
newlid = create_shadow_dir( sig, lid );
|
|
|
|
|
newflag = SIGF_CHECKED;
|
1999-02-16 14:16:33 +01:00
|
|
|
|
if( revoked )
|
1998-11-05 19:00:08 +01:00
|
|
|
|
newflag |= SIGF_REVOKED;
|
1998-10-25 20:00:01 +01:00
|
|
|
|
}
|
|
|
|
|
|
1998-11-05 19:00:08 +01:00
|
|
|
|
if( delrec.recnum ) { /* we can reuse a deleted/unused slot */
|
1998-10-25 20:00:01 +01:00
|
|
|
|
delrec.r.sig.sig[delrecidx].lid = newlid;
|
|
|
|
|
delrec.r.sig.sig[delrecidx].flag= newflag;
|
|
|
|
|
write_record( &delrec );
|
|
|
|
|
}
|
|
|
|
|
else { /* must insert a new sig record */
|
|
|
|
|
TRUSTREC tmp;
|
|
|
|
|
|
|
|
|
|
memset( &tmp, 0, sizeof tmp );
|
|
|
|
|
tmp.recnum = tdbio_new_recnum();
|
|
|
|
|
tmp.rectype = RECTYPE_SIG;
|
|
|
|
|
tmp.r.sig.lid = lid;
|
|
|
|
|
tmp.r.sig.next = urec->r.uid.siglist;
|
|
|
|
|
tmp.r.sig.sig[0].lid = newlid;
|
|
|
|
|
tmp.r.sig.sig[0].flag= newflag;
|
|
|
|
|
write_record( &tmp );
|
|
|
|
|
urec->r.uid.siglist = tmp.recnum;
|
|
|
|
|
urec->dirty = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1998-10-12 22:16:38 +02:00
|
|
|
|
/****************
|
|
|
|
|
* Update all the info from the public keyblock.
|
|
|
|
|
* The key must already exist in the keydb.
|
|
|
|
|
* This function is responsible for checking the signatures in cases
|
1998-11-03 20:38:58 +01:00
|
|
|
|
* where the public key is already available. If we do not have the public
|
1998-10-12 22:16:38 +02:00
|
|
|
|
* key, the check is done by some special code in insert_trust_record().
|
1998-10-01 09:23:00 +02:00
|
|
|
|
*/
|
|
|
|
|
int
|
1998-11-03 20:38:58 +01:00
|
|
|
|
update_trust_record( KBNODE keyblock, int recheck, int *modified )
|
1998-10-01 09:23:00 +02:00
|
|
|
|
{
|
|
|
|
|
PKT_public_key *primary_pk;
|
|
|
|
|
KBNODE node;
|
|
|
|
|
TRUSTREC drec;
|
1998-10-07 15:30:43 +02:00
|
|
|
|
TRUSTREC krec;
|
|
|
|
|
TRUSTREC urec;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
TRUSTREC prec;
|
1998-10-07 15:30:43 +02:00
|
|
|
|
TRUSTREC helprec;
|
1998-10-01 09:23:00 +02:00
|
|
|
|
int rc = 0;
|
1998-10-07 15:30:43 +02:00
|
|
|
|
u32 keyid[2]; /* keyid of primary key */
|
1998-10-12 22:16:38 +02:00
|
|
|
|
ulong recno, lastrecno;
|
1998-10-07 15:30:43 +02:00
|
|
|
|
RECNO_LIST recno_list = NULL; /* list of verified records */
|
1998-10-21 19:34:36 +02:00
|
|
|
|
/* fixme: replace recno_list by a lookup on node->recno */
|
1998-10-01 09:23:00 +02:00
|
|
|
|
|
1999-02-25 18:51:55 +01:00
|
|
|
|
if( opt.dry_run )
|
|
|
|
|
return 0;
|
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-10-25 20:00:01 +01:00
|
|
|
|
if( modified )
|
|
|
|
|
*modified = 0;
|
|
|
|
|
|
1998-10-01 09:23:00 +02:00
|
|
|
|
node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
|
|
|
|
|
primary_pk = node->pkt->pkt.public_key;
|
|
|
|
|
rc = get_dir_record( primary_pk, &drec );
|
|
|
|
|
if( rc )
|
|
|
|
|
return rc;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
if( !primary_pk->local_id )
|
|
|
|
|
primary_pk->local_id = drec.recnum;
|
1998-10-07 15:30:43 +02:00
|
|
|
|
|
|
|
|
|
keyid_from_pk( primary_pk, keyid );
|
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
/* fixme: check that the keyblock has a valid structure */
|
|
|
|
|
|
1998-10-25 20:00:01 +01:00
|
|
|
|
rc = tdbio_begin_transaction();
|
|
|
|
|
if( rc )
|
|
|
|
|
return rc;
|
|
|
|
|
|
1998-11-03 20:38:58 +01:00
|
|
|
|
/* update the keys */
|
1998-10-06 14:10:02 +02:00
|
|
|
|
for( node=keyblock; node; node = node->next ) {
|
1998-11-03 20:38:58 +01:00
|
|
|
|
if( node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
|
|
|
|
|
upd_key_record( keyblock, node, keyid,
|
|
|
|
|
&drec, &recno_list, recheck );
|
|
|
|
|
}
|
|
|
|
|
/* update the user IDs */
|
|
|
|
|
for( node=keyblock; node; node = node->next ) {
|
|
|
|
|
if( node->pkt->pkttype == PKT_USER_ID )
|
|
|
|
|
upd_uid_record( keyblock, node, keyid,
|
|
|
|
|
&drec, &recno_list, recheck );
|
|
|
|
|
}
|
1998-10-01 09:23:00 +02:00
|
|
|
|
|
1998-10-12 22:16:38 +02:00
|
|
|
|
/* delete keyrecords from the trustdb which are not anymore used */
|
1998-11-03 20:38:58 +01:00
|
|
|
|
/* should we really do this, or is it better to keep them and */
|
|
|
|
|
/* mark as unused? */
|
1998-12-29 19:58:27 +01:00
|
|
|
|
/* And set the revocation flag into the dir record */
|
|
|
|
|
drec.r.dir.dirflags &= ~DIRF_REVOKED;
|
1998-10-07 15:30:43 +02:00
|
|
|
|
lastrecno = 0;
|
|
|
|
|
for( recno=drec.r.dir.keylist; recno; recno = krec.r.key.next ) {
|
|
|
|
|
read_record( recno, &krec, RECTYPE_KEY );
|
1998-12-29 19:58:27 +01:00
|
|
|
|
if( recno == drec.r.dir.keylist ) { /* this is the primary key */
|
|
|
|
|
if( (krec.r.key.keyflags & KEYF_REVOKED) ) {
|
|
|
|
|
drec.r.dir.dirflags |= DIRF_REVOKED;
|
|
|
|
|
drec.dirty = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-07 15:30:43 +02:00
|
|
|
|
if( !qry_recno_list( recno_list, recno, RECTYPE_KEY ) ) {
|
|
|
|
|
/* delete this one */
|
|
|
|
|
if( !lastrecno ) {
|
|
|
|
|
drec.r.dir.keylist = krec.r.key.next;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
drec.dirty = 1;
|
1998-10-07 15:30:43 +02:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
read_record( lastrecno, &helprec, RECTYPE_KEY );
|
|
|
|
|
helprec.r.key.next = krec.r.key.next;
|
|
|
|
|
write_record( &helprec );
|
|
|
|
|
}
|
|
|
|
|
delete_record( recno );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
lastrecno = recno;
|
|
|
|
|
}
|
1998-10-12 22:16:38 +02:00
|
|
|
|
/* delete uid records and sig and their pref records from the
|
1998-10-07 15:30:43 +02:00
|
|
|
|
* trustdb which are not anymore used */
|
|
|
|
|
lastrecno = 0;
|
|
|
|
|
for( recno=drec.r.dir.uidlist; recno; recno = urec.r.uid.next ) {
|
|
|
|
|
read_record( recno, &urec, RECTYPE_UID );
|
|
|
|
|
if( !qry_recno_list( recno_list, recno, RECTYPE_UID ) ) {
|
|
|
|
|
ulong r2;
|
|
|
|
|
/* delete this one */
|
|
|
|
|
if( !lastrecno ) {
|
|
|
|
|
drec.r.dir.uidlist = urec.r.uid.next;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
drec.dirty = 1;
|
1998-10-07 15:30:43 +02:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
read_record( lastrecno, &helprec, RECTYPE_UID );
|
|
|
|
|
helprec.r.uid.next = urec.r.uid.next;
|
|
|
|
|
write_record( &helprec );
|
|
|
|
|
}
|
|
|
|
|
for(r2=urec.r.uid.prefrec ; r2; r2 = prec.r.pref.next ) {
|
|
|
|
|
read_record( r2, &prec, RECTYPE_PREF );
|
|
|
|
|
delete_record( r2 );
|
|
|
|
|
}
|
1998-10-12 22:16:38 +02:00
|
|
|
|
for(r2=urec.r.uid.siglist ; r2; r2 = helprec.r.sig.next ) {
|
|
|
|
|
read_record( r2, &helprec, RECTYPE_SIG );
|
|
|
|
|
delete_record( r2 );
|
|
|
|
|
}
|
1998-10-07 15:30:43 +02:00
|
|
|
|
delete_record( recno );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
lastrecno = recno;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1998-10-06 14:10:02 +02:00
|
|
|
|
if( rc )
|
1998-10-25 20:00:01 +01:00
|
|
|
|
rc = tdbio_cancel_transaction();
|
|
|
|
|
else {
|
1998-12-29 19:58:27 +01:00
|
|
|
|
if( modified && tdbio_is_dirty() )
|
|
|
|
|
*modified = 1;
|
1998-11-13 20:41:41 +01:00
|
|
|
|
drec.r.dir.dirflags |= DIRF_CHECKED;
|
|
|
|
|
drec.r.dir.dirflags &= ~DIRF_VALVALID;
|
1998-11-05 19:00:08 +01:00
|
|
|
|
write_record( &drec );
|
1998-10-25 20:00:01 +01:00
|
|
|
|
rc = tdbio_end_transaction();
|
1998-10-01 09:23:00 +02:00
|
|
|
|
}
|
1998-10-07 15:30:43 +02:00
|
|
|
|
rel_recno_list( &recno_list );
|
1998-10-01 09:23:00 +02:00
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
1998-07-15 20:05:01 +02:00
|
|
|
|
|
1998-01-13 20:04:23 +01:00
|
|
|
|
/****************
|
|
|
|
|
* Insert a trust record into the TrustDB
|
1998-10-12 22:16:38 +02:00
|
|
|
|
* This function assumes that the record does not yet exist.
|
1998-01-13 20:04:23 +01:00
|
|
|
|
*/
|
|
|
|
|
int
|
1998-10-07 15:30:43 +02:00
|
|
|
|
insert_trust_record( PKT_public_key *pk )
|
1998-01-13 20:04:23 +01:00
|
|
|
|
{
|
1998-10-07 15:30:43 +02:00
|
|
|
|
TRUSTREC dirrec;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
TRUSTREC shadow;
|
1998-07-14 19:10:28 +02:00
|
|
|
|
KBNODE keyblock = NULL;
|
|
|
|
|
KBNODE node;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
byte fingerprint[MAX_FINGERPRINT_LEN];
|
1998-01-13 20:04:23 +01:00
|
|
|
|
size_t fingerlen;
|
1998-07-14 19:10:28 +02:00
|
|
|
|
int rc = 0;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
ulong hintlist = 0;
|
1998-01-13 20:04:23 +01:00
|
|
|
|
|
1999-02-25 18:51:55 +01:00
|
|
|
|
|
|
|
|
|
if( opt.dry_run )
|
|
|
|
|
return 0;
|
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
|
|
|
|
|
1998-10-07 15:30:43 +02:00
|
|
|
|
if( pk->local_id )
|
|
|
|
|
log_bug("pk->local_id=%lu\n", pk->local_id );
|
1998-01-13 20:04:23 +01:00
|
|
|
|
|
1998-10-12 22:16:38 +02:00
|
|
|
|
fingerprint_from_pk( pk, fingerprint, &fingerlen );
|
1998-07-14 19:10:28 +02:00
|
|
|
|
|
|
|
|
|
/* fixme: assert that we do not have this record.
|
|
|
|
|
* we can do this by searching for the primary keyid
|
1998-10-12 22:16:38 +02:00
|
|
|
|
*
|
|
|
|
|
* fixme: If there is no such key we should look whether one
|
|
|
|
|
* of the subkeys has been used to sign another key and in this case
|
|
|
|
|
* we got the key anyway. Because a secondary key can't be used
|
|
|
|
|
* without a primary key (it is needed to bind the secondary one
|
|
|
|
|
* to the primary one which has the user ids etc.)
|
1998-07-14 19:10:28 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* get the keyblock which has the key */
|
|
|
|
|
rc = get_keyblock_byfprint( &keyblock, fingerprint, fingerlen );
|
|
|
|
|
if( rc ) { /* that should never happen */
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error( _("insert_trust_record: keyblock not found: %s\n"),
|
1998-07-14 19:10:28 +02:00
|
|
|
|
g10_errstr(rc) );
|
1998-07-15 20:05:01 +02:00
|
|
|
|
goto leave;
|
1998-07-14 19:10:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-12 22:16:38 +02:00
|
|
|
|
/* check that we used the primary key (we are little bit paranoid) */
|
|
|
|
|
{ PKT_public_key *a_pk;
|
1998-10-16 18:00:17 +02:00
|
|
|
|
u32 akid[2], bkid[2];
|
|
|
|
|
|
1998-10-12 22:16:38 +02:00
|
|
|
|
node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
|
|
|
|
|
a_pk = node->pkt->pkt.public_key;
|
1998-10-16 18:00:17 +02:00
|
|
|
|
|
|
|
|
|
/* we can't use cmp_public_keys here because some parts (expiredate)
|
|
|
|
|
* might not be set in pk <--- but why (fixme) */
|
|
|
|
|
keyid_from_pk( a_pk, akid );
|
|
|
|
|
keyid_from_pk( pk, bkid );
|
|
|
|
|
|
|
|
|
|
if( akid[0] != bkid[0] || akid[1] != bkid[1] ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("did not use primary key for insert_trust_record()\n"));
|
1998-10-12 22:16:38 +02:00
|
|
|
|
rc = G10ERR_GENERAL;
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We have to look for a shadow dir record which must be reused
|
|
|
|
|
* as the dir record. And: check all signatures which are listed
|
|
|
|
|
* in the hintlist of the shadow dir record.
|
|
|
|
|
*/
|
|
|
|
|
rc = tdbio_search_sdir( pk->keyid, pk->pubkey_algo, &shadow );
|
|
|
|
|
if( rc && rc != -1 ) {
|
1998-11-10 13:59:59 +01:00
|
|
|
|
log_error(_("tdbio_search_dir failed: %s\n"), g10_errstr(rc));
|
1998-10-12 22:16:38 +02:00
|
|
|
|
die_invalid_db();
|
|
|
|
|
}
|
1998-10-07 15:30:43 +02:00
|
|
|
|
memset( &dirrec, 0, sizeof dirrec );
|
|
|
|
|
dirrec.rectype = RECTYPE_DIR;
|
1998-10-12 22:16:38 +02:00
|
|
|
|
if( !rc ) {
|
|
|
|
|
/* hey, great: this key has already signed other keys
|
|
|
|
|
* convert this to a real directory entry */
|
|
|
|
|
hintlist = shadow.r.sdir.hintlist;
|
|
|
|
|
dirrec.recnum = shadow.recnum;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
dirrec.recnum = tdbio_new_recnum();
|
|
|
|
|
}
|
1998-07-15 20:05:01 +02:00
|
|
|
|
dirrec.r.dir.lid = dirrec.recnum;
|
1998-10-07 15:30:43 +02:00
|
|
|
|
write_record( &dirrec );
|
1998-07-14 19:10:28 +02:00
|
|
|
|
|
1998-10-07 15:30:43 +02:00
|
|
|
|
/* store the LID */
|
|
|
|
|
pk->local_id = dirrec.r.dir.lid;
|
1998-07-21 14:53:38 +02:00
|
|
|
|
for( node=keyblock; node; node = node->next ) {
|
|
|
|
|
if( node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
|
1999-02-16 14:16:33 +01:00
|
|
|
|
PKT_public_key *a_pk = node->pkt->pkt.public_key;
|
|
|
|
|
a_pk->local_id = dirrec.r.dir.lid;
|
1998-07-21 14:53:38 +02:00
|
|
|
|
}
|
|
|
|
|
else if( node->pkt->pkttype == PKT_SIGNATURE ) {
|
1999-02-16 14:16:33 +01:00
|
|
|
|
PKT_signature *a_sig = node->pkt->pkt.signature;
|
|
|
|
|
a_sig->local_id = dirrec.r.dir.lid;
|
1998-07-21 14:53:38 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-07 15:30:43 +02:00
|
|
|
|
/* and put all the other stuff into the keydb */
|
1998-12-08 13:20:53 +01:00
|
|
|
|
rc = update_trust_record( keyblock, 1, NULL );
|
1998-10-12 22:16:38 +02:00
|
|
|
|
if( !rc )
|
|
|
|
|
process_hintlist( hintlist, dirrec.r.dir.lid );
|
1998-07-15 20:05:01 +02:00
|
|
|
|
|
1998-10-07 15:30:43 +02:00
|
|
|
|
leave:
|
1998-10-12 22:16:38 +02:00
|
|
|
|
if( rc && hintlist )
|
|
|
|
|
; /* fixme: the hintlist is not anymore anchored */
|
1998-10-07 15:30:43 +02:00
|
|
|
|
release_kbnode( keyblock );
|
1998-10-16 18:00:17 +02:00
|
|
|
|
do_sync();
|
1998-07-15 20:05:01 +02:00
|
|
|
|
return rc;
|
1998-01-13 20:04:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
1999-02-24 11:12:32 +01:00
|
|
|
|
INIT_TRUSTDB();
|
1998-10-07 15:30:43 +02:00
|
|
|
|
read_record( lid, &rec, RECTYPE_DIR );
|
1998-07-21 14:53:38 +02:00
|
|
|
|
rec.r.dir.ownertrust = new_trust;
|
1998-10-07 15:30:43 +02:00
|
|
|
|
write_record( &rec );
|
1998-10-16 18:00:17 +02:00
|
|
|
|
do_sync();
|
1998-01-25 19:56:33 +01:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|