1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-02 22:46:30 +02:00

See ChangeLog: Mon Mar 13 19:22:46 CET 2000 Werner Koch

This commit is contained in:
Werner Koch 2000-03-13 18:19:12 +00:00
parent d1b6e0ce0d
commit 14a2e006bc
19 changed files with 1042 additions and 159 deletions

View file

@ -1,3 +1,11 @@
Mon Mar 13 19:22:46 CET 2000 Werner Koch <wk@openit.de>
* build-paket.c (do_user_id): Save offset where name has been stored.
* ringedit.c : Add new access method KBXF
* kbxfile.c: New.
Mon Feb 21 22:43:01 CET 2000 Werner Koch <wk@>
* kbx.h: New.

View file

@ -4,7 +4,9 @@ INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl
EXTRA_DIST = OPTIONS pubring.asc options.skel
OMIT_DEPENDENCIES = zlib.h zconf.h
LDFLAGS = -static @LDFLAGS@ @DYNLINK_LDFLAGS@
needed_libs = ../util/libutil.la ../gcrypt/libgcrypt.la ../jnlib/libjnlib.la
# we need to add libutil.la a second time because we have to resolve
# gpg_log_ in some libjnlib modules. - very ugly - should be removed soon.
needed_libs = ../util/libutil.la ../gcrypt/libgcrypt.la ../jnlib/libjnlib.la ../util/libutil.la
#noinst_PROGRAMS = gpgd
bin_PROGRAMS = gpg
@ -22,6 +24,9 @@ common_source = \
skclist.c \
ringedit.c \
kbnode.c \
kbx.h \
kbxblob.c \
kbxfile.c \
main.h \
mainproc.c \
armor.c \

View file

@ -196,6 +196,7 @@ static int
do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
{
write_header(out, ctb, uid->len);
uid->stored_at = iobuf_tell( out ); /* what a hack */
if( iobuf_write( out, uid->name, uid->len ) )
return GPGERR_WRITE_FILE;
return 0;

View file

@ -21,6 +21,12 @@
#ifndef GPG_KBX_H
#define GPG_KBX_H 1
#include "keydb.h"
typedef struct kbxblob *KBXBLOB;
int kbx_create_blob ( KBXBLOB *retkbx, KBNODE keyblock );
void kbx_release_blob ( KBXBLOB blob );
#endif /*GPG_KBX_H*/

View file

@ -16,27 +16,6 @@
* 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
*
***********************************************
* adler_cksum() is based on the zlib code with these conditions:
*
* Copyright (C) 1995-1998 Mark Adler
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
@ -51,9 +30,11 @@ the beginning of the Blob.
The first record of a plain KBX file has a special format:
u32 length of the first record
u32 magic 'KBXf'
byte Blob type (1)
byte version number (1)
b[3] reserved
byte reserved
byte reserved
u32 magic 'KBXf'
byte marginals used for validity calculation of this file
byte completes ditto.
byte cert_depth ditto.
@ -61,8 +42,8 @@ The first record of a plain KBX file has a special format:
The standard KBX Blob looks like this:
u32 length of this blob (including these 4 bytes)
byte version number (1)
byte reserved
byte Blob type (2)
byte version number of this blob type (1)
u16 Blob flags
bit 0 = contains secret key material
@ -98,6 +79,8 @@ The standard KBX Blob looks like this:
u8 all_validity
u16 reserved
u32 recheck_after
u32 Newest timestamp in the keyblock (useful for KS syncronsiation?)
u32 Blob created at
u32 size of reserved space (not including this field)
reserved space
@ -107,7 +90,7 @@ The standard KBX Blob looks like this:
maybe we put a sigture here later.
u32 adler checksum
b16 MD5 checksum (useful for KS syncronsiation)
*
*/
@ -120,6 +103,8 @@ The standard KBX Blob looks like this:
#include <assert.h>
#include <gcrypt.h>
#include "iobuf.h"
#include "util.h"
#include "kbx.h"
/* special values of the signature status */
@ -135,22 +120,21 @@ The standard KBX Blob looks like this:
struct kbxblob_key {
char fpr[20];
u32 off_kid;
ulong off_kid_addr; /* where it is stored in the datablock */
ulong off_kid_addr;
u16 flags;
};
struct kbxblob_uid {
u32 off;
ulong off_addr; /* where it is stored in the datablock */
ulong off_addr;
u32 len;
u16 flags;
byte validity
byte validity;
};
struct keyid_list {
struct keyid_list *next;
int seqno;
char kid[8];
}
byte kid[8];
};
struct kbxblob {
int nkeys;
@ -161,49 +145,10 @@ struct kbxblob {
u32 *sigs;
struct keyid_list *temp_kids;
} *KBXBLOB;
IOBUF buf; /* the KBX is stored here */
};
static u32
adler_cksum ( const byte *buf, size_t len )
{
unsigned long s1 = 1;
unsigned long s2 = 0;
#define X_BASE 65521L /* largest prime smaller than 65536 */
#define X_NMAX 5552 /* largest n such that */
/* 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
#define X_DO1(buf,i) {s1 += buf[i]; s2 += s1;}
#define X_DO2(buf,i) X_DO1(buf,i); X_DO1(buf,i+1);
#define X_DO4(buf,i) X_DO2(buf,i); X_DO2(buf,i+2);
#define X_DO8(buf,i) X_DO4(buf,i); X_DO4(buf,i+4);
#define X_DO16(buf) X_DO8(buf,0); X_DO8(buf,8);
while ( len ) {
int k = len < NMAX ? len : NMAX;
len -= k;
while ( k >= 16 ) {
DO16(buf);
buf += 16;
k -= 16;
}
if ( k ) {
do {
s1 += *buf++;
s2 += s1;
} while ( --k );
}
s1 %= BASE;
s2 %= BASE;
}
#undef X_BASE
#undef X_NMAX
#undef X_DO1
#undef X_DO2
#undef X_DO4
#undef X_DO8
#undef X_DO16
return ( s2 << 16 ) | s1;
}
/* Note: this functions are only used for temportay iobufs and therefore
@ -211,14 +156,14 @@ adler_cksum ( const byte *buf, size_t len )
static void
put8 ( IOBUF out, byte a )
{
iobuf_put ( out, a )
iobuf_put ( out, a );
}
static void
put16 ( IOBUF out, u16 a )
{
iobuf_put ( out, a>>8 );
iobuf_put ( out, a )
iobuf_put ( out, a );
}
static void
@ -227,7 +172,7 @@ put32 ( IOBUF out, u32 a )
iobuf_put (out, a>> 24);
iobuf_put (out, a>> 16);
iobuf_put (out, a>> 8);
iobuf_put (out, a) )
iobuf_put (out, a );
}
static void
@ -245,7 +190,7 @@ static void
put32at ( IOBUF out, u32 a, size_t pos )
{
size_t n;
byte *p,
byte *p;
iobuf_flush_temp ( out );
p = iobuf_get_temp_buffer( out );
@ -269,37 +214,44 @@ temp_store_kid ( KBXBLOB blob, PKT_public_key *pk )
struct keyid_list *k, *r;
k = gcry_xmalloc ( sizeof *k );
k->kid = pk->keyid;
k->kid[0] = pk->keyid[0] >> 24 ;
k->kid[1] = pk->keyid[0] >> 16 ;
k->kid[2] = pk->keyid[0] >> 8 ;
k->kid[3] = pk->keyid[0] ;
k->kid[4] = pk->keyid[0] >> 24 ;
k->kid[5] = pk->keyid[0] >> 16 ;
k->kid[6] = pk->keyid[0] >> 8 ;
k->kid[7] = pk->keyid[0] ;
k->seqno = 0;
k->next = blob->temp_kids;
blob->temp_kids = k;
for ( r=k; r; r = r->next ) {
k->seqno++
k->seqno++;
}
return k->seqno;
}
static void
put_stored_kid( IOBUF a, KBXBLOB blob, int seqno )
put_stored_kid( KBXBLOB blob, int seqno )
{
struct keyid_list *r;
for ( r = blob->temp_kids; r; r = r->next ) {
if( r->seqno == seqno ) {
putn ( a, r->kid, 8 );
putn ( blob->buf, r->kid, 8 );
return;
}
}
BUG();
}
static int
static void
release_kid_list ( struct keyid_list *kl )
{
struct keyid_list *r, *r2;
for ( r = blob->temp_kids; r; r = r2 ) {
for ( r = kl; r; r = r2 ) {
r2 = r->next;
gcry_free( r );
}
@ -310,19 +262,18 @@ static int
create_key_part( KBXBLOB blob, KBNODE keyblock )
{
KBNODE node;
byte fpr[MAX_FINGERPRINT_LEN];
size_t fprlen;
int n;
for ( n=0, node = keyblock; node; node = node->next ) {
if ( node->pkt->pkttype == PKT_PUBLIC_KEY:
if ( node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
PKT_public_key *pk = node->pkt->pkt.public_key;
fingerprint_from_pk( pk, blob->keys[n].fpr, &fprlen );
if ( fprlen != 20 ) { /*v3 fpr - shift right and fill with zeroes*/
assert( fprlen == 16 );
memmove( blob->keys[n]+4, blob->keys[n].fpr, 16);
memmove( blob->keys[n].fpr+4, blob->keys[n].fpr, 16);
memset( blob->keys[n].fpr, 0, 4 );
blob->keys[n].off_kid = temp_store_kid( blob, pk );
}
@ -351,7 +302,6 @@ create_uid_part( KBXBLOB blob, KBNODE keyblock )
if ( node->pkt->pkttype == PKT_USER_ID ) {
PKT_user_id *u = node->pkt->pkt.user_id;
blob->uids[n].off = 0; /* must calculate this later */
blob->uids[n].len = u->len;
blob->uids[n].flags = 0;
blob->uids[n].validity = 0;
@ -382,13 +332,14 @@ create_sig_part( KBXBLOB blob, KBNODE keyblock )
static int
create_blob_header( IOBUF a, KBXBLOB blob )
create_blob_header( KBXBLOB blob )
{
IOBUF a = blob->buf;
int i;
put32 ( a, 0 ); /* blob length, needs fixup */
put8 ( a, 1 ); /* version number */
put8 ( a, 0 ); /* reserved */
put8 ( a, 2 ); /* blob type */
put8 ( a, 1 ); /* blob type version */
put16 ( a, 0 ); /* blob flags */
put32 ( a, 0 ); /* offset to the keyblock, needs fixup */
@ -398,7 +349,7 @@ create_blob_header( IOBUF a, KBXBLOB blob )
put16 ( a, 20 + 8 + 2 + 2 ); /* size of key info */
for ( i=0; i < blob->nkeys; i++ ) {
putn ( a, blob->keys[i].fpr, 20 );
blob->keys[i].off_kid_addr = iobuf_tell ( out );
blob->keys[i].off_kid_addr = iobuf_tell ( a );
put32 ( a, 0 ); /* offset to keyid, fixed up later */
put16 ( a, blob->keys[i].flags );
put16 ( a, 0 ); /* reserved */
@ -407,7 +358,7 @@ create_blob_header( IOBUF a, KBXBLOB blob )
put16 ( a, blob->nuids );
put16 ( a, 4 + 4 + 2 + 1 + 1 ); /* size of uid info */
for ( i=0; i < blob->nuids; i++ ) {
blob->uids[i].off_addr = iobuf_tell ( out );
blob->uids[i].off_addr = iobuf_tell ( a );
put32 ( a, 0 ); /* offset to userid, fixed up later */
put32 ( a, blob->uids[i].len );
put16 ( a, blob->uids[i].flags );
@ -425,16 +376,18 @@ create_blob_header( IOBUF a, KBXBLOB blob )
put8 ( a, 0 ); /* validity of all user IDs */
put16 ( a, 0 ); /* reserved */
put32 ( a, 0 ); /* time of next recheck */
put32 ( a, 0 ); /* newest timestamp (none) */
put32 ( a, make_timestamp() ); /* creation time */
put32 ( a, 0 ); /* size of reserved space */
/* reserved space (which is currently 0) */
/* reserved space (which is currently of size 0) */
/* We need to store the keyids for all v3 keys because those key IDs are
* not part of the fingerprint. While we are doing that, we fixup all
* the keyID offsets */
for ( i=0; i < blob->nkeys; i++ ) {
if ( blob->keys[i].off_kid ) { /* this is a v3 one */
put32at ( a, iobuf_tell(), blob->keys[i].off_kid_addr );
put_stored_kid ( a, blob, blob->keys[i].off_kid );
put32at ( a, iobuf_tell(a), blob->keys[i].off_kid_addr );
put_stored_kid ( blob, blob->keys[i].off_kid );
}
else { /* the better v4 key IDs - just store an offset 8 bytes back */
put32at ( a, blob->keys[i].off_kid_addr-8,
@ -447,38 +400,60 @@ create_blob_header( IOBUF a, KBXBLOB blob )
}
static int
create_blob_keyblock( IOBUF a, KBXBLOB blob, KBNODE keyblock )
create_blob_keyblock( KBXBLOB blob, KBNODE keyblock )
{
IOBUF a = blob->buf;
KBNODE node;
int rc;
int nsig;
for ( node = keyblock; node; node = node->next ) {
/* we must get some offset into thge keyblock and do some
* fixups */
rc = build_packet ( fp, node->pkt );
for ( nsig = 0, node = keyblock; node; node = node->next ) {
rc = build_packet ( a, node->pkt );
if ( rc ) {
log_error("build_packet(%d) for kbxblob failed: %s\n",
gpg_log_error("build_packet(%d) for kbxblob failed: %s\n",
node->pkt->pkttype, gpg_errstr(rc) );
return GPGERR_WRITE_FILE;
}
if ( node->pkt->pkttype == PKT_USER_ID ) {
PKT_user_id *u = node->pkt->pkt.user_id;
/* build_packet has set the offset of the name into u ;
* now we can do the fixup */
put32at ( a, u->stored_at, blob->uids[nsig].off_addr );
nsig++;
}
}
assert( nsig == blob->nsigs );
return 0;
}
static int
create_blob_trailer( IOBUF a, KBXBLOB blob )
create_blob_trailer( KBXBLOB blob )
{
IOBUF a = blob->buf;
return 0;
}
static int
create_blob_finish( IOBUF a, KBXBLOB blob )
create_blob_finish( KBXBLOB blob )
{
IOBUF a = blob->buf;
byte *p;
size_t n;
/* write a placeholder for the checksum */
put32( a, 0 ); put32( a, 0 ); put32( a, 0 ); put32( a, 0 );
/* get the memory area */
iobuf_flush_temp ( a );
p = iobuf_get_temp_buffer ( a );
n = iobuf_get_temp_length ( a );
assert( n >= 20 );
/* fixup the length */
/* optionally we could sign the whole stuff at this point */
/* write the checksum */
put32at ( a, 0, n );
/* calculate and store the MD5 checksum */
gcry_md_hash_buffer( GCRY_MD_MD5, p + n - 16, p, n - 16 );
return 0;
}
@ -488,9 +463,7 @@ kbx_create_blob ( KBXBLOB *retkbx, KBNODE keyblock )
{
int rc = 0;
KBNODE node;
struct kbxblob *blob;
int nkey, nuid, nsig;
IOBUF a = NULL;
KBXBLOB blob;
*retkbx = NULL;
blob = gcry_calloc (1, sizeof *blob );
@ -507,56 +480,63 @@ kbx_create_blob ( KBXBLOB *retkbx, KBNODE keyblock )
case PKT_PUBLIC_SUBKEY:
case PKT_SECRET_SUBKEY: blob->nkeys++; break;
case PKT_USER_ID: blob->nuids++; break;
case PKT_SIGNATURE: blob->nsigs++, break;
case PKT_SIGNATURE: blob->nsigs++; break;
default: break;
}
}
blob->nkeys = gcry_calloc ( blob->nkeys, sizeof ( blob->keys ) );
blob->nuids = gcry_calloc ( blob->nuids, sizeof ( blob->uids ) );
blob->nsigs = gcry_calloc ( blob->nsigs, sizeof ( blob->sigs ) );
if ( !blob->nkeys || !blob->nuids || !blob->nsigs ) {
blob->keys = gcry_calloc ( blob->nkeys, sizeof ( blob->keys ) );
blob->uids = gcry_calloc ( blob->nuids, sizeof ( blob->uids ) );
blob->sigs = gcry_calloc ( blob->nsigs, sizeof ( blob->sigs ) );
if ( !blob->keys || !blob->uids || !blob->sigs ) {
rc = GCRYERR_NO_MEM;
goto leave;
}
rc = create_key_part ( blob, keyblock ),
rc = create_key_part ( blob, keyblock );
if( rc )
goto leave;
rc = create_uid_part ( blob, keyblock ),
rc = create_uid_part ( blob, keyblock );
if( rc )
goto leave;
rc = create_sig_part ( blob, keyblock ),
rc = create_sig_part ( blob, keyblock );
if( rc )
goto leave;
a = iobuf_temp();
rc = create_blob_header ( a, blob );
blob->buf = iobuf_temp();
rc = create_blob_header ( blob );
if( rc )
goto leave;
rc = create_blob_keyblock ( a, blob, keyblock );
rc = create_blob_keyblock ( blob, keyblock );
if( rc )
goto leave;
rc = create_blob_trailer ( a, blob );
rc = create_blob_trailer ( blob );
if( rc )
goto leave;
rc = create_blob_finish ( a, blob );
rc = create_blob_finish ( blob );
if( rc )
goto leave;
/* now we take the iobuf and copy it to the output */
*retkbx = blob;
failure:
if( a )
iobuf_cancel( a );
leave:
release_kid_list( blob->temp_kids );
blob->temp_kids = NULL;
if ( rc ) {
gcry_free( blob->nkeys );
gcry_free( blob->nuids );
gcry_free( blob->nsigs );
gcry_free( blob );
kbx_release_blob ( blob );
}
return rc;
}
void
kbx_release_blob ( KBXBLOB blob )
{
if( !blob )
return;
if( blob->buf )
iobuf_cancel( blob->buf );
gcry_free( blob->keys );
gcry_free( blob->uids );
gcry_free( blob->sigs );
gcry_free( blob );
}

45
g10/kbxfile.c Normal file
View file

@ -0,0 +1,45 @@
/* kbxfile.c - KBX file handling
* Copyright (C) 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/****************
* We will change the whole system to use only KBX. This file here
* will implements the methods needed to operate on plain KBXfiles.
* Most stuff from getkey and ringedit will be replaced by stuff here.
* To make things even mor easier we will only allow one updateable kbxfile
* and optionally some read-only files.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <gcrypt.h>
#include "kbx.h"
int
kbxfile_search_by_fpr( void )
{
return -1;
}

View file

@ -57,7 +57,8 @@ struct kbnode_struct {
enum resource_type {
rt_UNKNOWN = 0,
rt_RING = 1,
rt_GDBM = 2
rt_GDBM = 2,
rt_KBXF = 3
};

View file

@ -162,6 +162,8 @@ typedef struct {
} PKT_comment;
typedef struct {
ulong stored_at; /* the stream offset where it was stored
* by build-packet */
int len; /* length of the name */
char name[1];
} PKT_user_id;

View file

@ -60,6 +60,7 @@
#include "options.h"
#include "main.h"
#include "i18n.h"
#include "kbx.h"
#ifdef MKDIR_TAKES_ONE_ARG
@ -96,6 +97,12 @@ static int keyring_read( KBPOS *kbpos, KBNODE *ret_root );
static int keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs );
static int keyring_copy( KBPOS *kbpos, int mode, KBNODE root );
static int do_kbxf_search( PACKET *pkt, KBPOS *kbpos, IOBUF iobuf,
const char *fname );
static int do_kbxf_read( KBPOS *kbpos, KBNODE *ret_root );
static int do_kbxf_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs );
static int do_kbxf_copy( KBPOS *kbpos, int mode, KBNODE root );
#ifdef HAVE_LIBGDBM
static int do_gdbm_store( KBPOS *kbpos, KBNODE root, int update );
static int do_gdbm_locate( GDBM_FILE dbf, KBPOS *kbpos,
@ -206,6 +213,7 @@ add_keyblock_resource( const char *url, int force, int secret )
/* Do we have an URL?
* gnupg-gdbm:filename := this is a GDBM resource
* gnupg-kbxf:filename := this is a KBX file resource
* gnupg-ring:filename := this is a plain keyring
* filename := See what is is, but create as plain keyring.
*/
@ -214,6 +222,10 @@ add_keyblock_resource( const char *url, int force, int secret )
rt = rt_RING;
resname += 11;
}
else if( !strncmp( resname, "gnupg-kbxf:", 11 ) ) {
rt = rt_KBXF;
resname += 11;
}
else if( !strncmp( resname, "gnupg-gdbm:", 11 ) ) {
rt = rt_GDBM;
resname += 11;
@ -259,8 +271,17 @@ add_keyblock_resource( const char *url, int force, int secret )
rt = rt_GDBM;
else if( magic == 0xce9a5713 )
log_error("%s: endianess does not match\n", url );
else
else {
char buf[8];
rt = rt_RING;
if( fread( buf, 8, 1, fp) == 1 ) {
if( !memcmp( buf+4, "KBXf", 4 )
&& buf[0] == 1 && buf[1] == 1 ) {
rt = rt_KBXF;
}
}
}
}
else /* maybe empty: assume ring */
rt = rt_RING;
@ -277,6 +298,7 @@ add_keyblock_resource( const char *url, int force, int secret )
goto leave;
case rt_RING:
case rt_KBXF:
iobuf = iobuf_open( filename );
if( !iobuf && !force ) {
rc = GPGERR_OPEN_FILE;
@ -341,6 +363,7 @@ add_keyblock_resource( const char *url, int force, int secret )
#endif
break;
#ifdef HAVE_LIBGDBM
case rt_GDBM:
resource_table[i].dbf = gdbm_open( filename, 0,
@ -458,6 +481,10 @@ search( PACKET *pkt, KBPOS *kbpos, int secret )
rc = keyring_search( pkt, kbpos, resource_table[i].iobuf,
resource_table[i].fname );
break;
case rt_KBXF:
rc = do_kbxf_search( pkt, kbpos, resource_table[i].iobuf,
resource_table[i].fname );
break;
#ifdef HAVE_LIBGDBM
case rt_GDBM: {
PKT_public_key *req_pk = pkt->pkt.public_key;
@ -706,6 +733,8 @@ read_keyblock( KBPOS *kbpos, KBNODE *ret_root )
switch( kbpos->rt ) {
case rt_RING:
return keyring_read( kbpos, ret_root );
case rt_KBXF:
return do_kbxf_read( kbpos, ret_root );
#ifdef HAVE_LIBGDBM
case rt_GDBM:
return do_gdbm_read( kbpos, ret_root );
@ -762,6 +791,7 @@ enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root )
kbpos->valid = 0;
switch( kbpos->rt ) {
case rt_RING:
case rt_KBXF:
kbpos->fp = iobuf_open( rentry->fname );
if( !kbpos->fp ) {
log_error("can't open `%s'\n", rentry->fname );
@ -788,6 +818,11 @@ enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root )
return GPGERR_GENERAL;
rc = keyring_enum( kbpos, ret_root, mode == 11 );
break;
case rt_KBXF:
if( !kbpos->fp )
return GPGERR_GENERAL;
rc = do_kbxf_enum( kbpos, ret_root, mode == 11 );
break;
#ifdef HAVE_LIBGDBM
case rt_GDBM:
rc = do_gdbm_enum( kbpos, ret_root );
@ -812,6 +847,7 @@ enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root )
else {
switch( kbpos->rt ) {
case rt_RING:
case rt_KBXF:
if( kbpos->fp ) {
iobuf_close( kbpos->fp );
kbpos->fp = NULL;
@ -852,6 +888,9 @@ insert_keyblock( KBPOS *kbpos, KBNODE root )
case rt_RING:
rc = keyring_copy( kbpos, 1, root );
break;
case rt_KBXF:
rc = do_kbxf_copy( kbpos, 1, root );
break;
#ifdef HAVE_LIBGDBM
case rt_GDBM:
rc = do_gdbm_store( kbpos, root, 0 );
@ -881,6 +920,9 @@ delete_keyblock( KBPOS *kbpos )
case rt_RING:
rc = keyring_copy( kbpos, 2, NULL );
break;
case rt_KBXF:
rc = do_kbxf_copy( kbpos, 2, NULL );
break;
#ifdef HAVE_LIBGDBM
case rt_GDBM:
log_debug("deleting gdbm keyblock is not yet implemented\n");
@ -909,6 +951,9 @@ update_keyblock( KBPOS *kbpos, KBNODE root )
case rt_RING:
rc = keyring_copy( kbpos, 3, root );
break;
case rt_KBXF:
rc = do_kbxf_copy( kbpos, 3, root );
break;
#ifdef HAVE_LIBGDBM
case rt_GDBM:
rc = do_gdbm_store( kbpos, root, 1 );
@ -1543,6 +1588,478 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root )
return rc;
}
/****************************************************************
********** Functions which operate on KBX files ****************
****************************************************************/
/****************
* search a KBX file return 0 if found, -1 if not found or an errorcode.
*/
static int
do_kbxf_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname )
{
int rc;
PACKET pkt;
int save_mode;
ulong offset;
int pkttype = req->pkttype;
PKT_public_key *req_pk = req->pkt.public_key;
PKT_secret_key *req_sk = req->pkt.secret_key;
init_packet(&pkt);
save_mode = set_packet_list_mode(0);
kbpos->rt = rt_RING;
kbpos->valid = 0;
#if HAVE_DOSISH_SYSTEM || 1
assert(!iobuf);
iobuf = iobuf_open( fname );
if( !iobuf ) {
log_error("%s: can't open keyring file\n", fname);
rc = GPGERR_KEYRING_OPEN;
goto leave;
}
#else
if( iobuf_seek( iobuf, 0 ) ) {
log_error("can't rewind keyring file\n");
rc = GPGERR_KEYRING_OPEN;
goto leave;
}
#endif
while( !(rc=search_packet(iobuf, &pkt, pkttype, &offset)) ) {
if( pkt.pkttype == PKT_SECRET_KEY ) {
PKT_secret_key *sk = pkt.pkt.secret_key;
if( req_sk->timestamp == sk->timestamp
&& req_sk->pubkey_algo == sk->pubkey_algo
&& !cmp_seckey( req_sk, sk) )
break; /* found */
}
else if( pkt.pkttype == PKT_PUBLIC_KEY ) {
PKT_public_key *pk = pkt.pkt.public_key;
if( req_pk->timestamp == pk->timestamp
&& req_pk->pubkey_algo == pk->pubkey_algo
&& !cmp_pubkey( req_pk, pk ) )
break; /* found */
}
else
BUG();
free_packet(&pkt);
}
if( !rc ) {
kbpos->offset = offset;
kbpos->valid = 1;
}
leave:
free_packet(&pkt);
set_packet_list_mode(save_mode);
#if HAVE_DOSISH_SYSTEM || 1
iobuf_close(iobuf);
#endif
return rc;
}
static int
do_kbxf_read( KBPOS *kbpos, KBNODE *ret_root )
{
PACKET *pkt;
int rc;
RESTBL *rentry;
KBNODE root = NULL;
IOBUF a;
int in_cert = 0;
if( !(rentry=check_pos(kbpos)) )
return GPGERR_GENERAL;
a = iobuf_open( rentry->fname );
if( !a ) {
log_error("can't open `%s'\n", rentry->fname );
return GPGERR_OPEN_FILE;
}
if( !kbpos->valid )
log_debug("kbpos not valid in keyring_read, want %d\n", (int)kbpos->offset );
if( iobuf_seek( a, kbpos->offset ) ) {
log_error("can't seek to %lu\n", kbpos->offset);
iobuf_close(a);
return GPGERR_KEYRING_OPEN;
}
pkt = gcry_xmalloc( sizeof *pkt );
init_packet(pkt);
kbpos->count=0;
while( (rc=parse_packet(a, pkt)) != -1 ) {
if( rc ) { /* ignore errors */
if( rc != GPGERR_UNKNOWN_PACKET ) {
log_error("read_keyblock: read error: %s\n", gpg_errstr(rc) );
rc = GPGERR_INV_KEYRING;
goto ready;
}
kbpos->count++;
free_packet( pkt );
init_packet( pkt );
continue;
}
/* make a linked list of all packets */
switch( pkt->pkttype ) {
case PKT_COMPRESSED:
log_error("skipped compressed packet in keyring\n" );
free_packet(pkt);
init_packet(pkt);
break;
case PKT_PUBLIC_KEY:
case PKT_SECRET_KEY:
if( in_cert )
goto ready;
in_cert = 1;
default:
kbpos->count++;
if( !root )
root = new_kbnode( pkt );
else
add_kbnode( root, new_kbnode( pkt ) );
pkt = gcry_xmalloc( sizeof *pkt );
init_packet(pkt);
break;
}
}
ready:
kbpos->valid = 0;
if( rc == -1 && root )
rc = 0;
if( rc )
release_kbnode( root );
else
*ret_root = root;
free_packet( pkt );
gcry_free( pkt );
iobuf_close(a);
return rc;
}
static int
do_kbxf_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs )
{
PACKET *pkt;
int rc;
RESTBL *rentry;
KBNODE root = NULL;
if( !(rentry=check_pos(kbpos)) )
return GPGERR_GENERAL;
if( kbpos->pkt ) {
root = new_kbnode( kbpos->pkt );
kbpos->pkt = NULL;
}
pkt = gcry_xmalloc( sizeof *pkt );
init_packet(pkt);
while( (rc=parse_packet(kbpos->fp, pkt)) != -1 ) {
if( rc ) { /* ignore errors */
if( rc != GPGERR_UNKNOWN_PACKET ) {
log_error("read_keyblock: read error: %s\n", gpg_errstr(rc) );
rc = GPGERR_INV_KEYRING;
goto ready;
}
free_packet( pkt );
init_packet( pkt );
continue;
}
/* make a linked list of all packets */
switch( pkt->pkttype ) {
case PKT_COMPRESSED:
log_error("skipped compressed packet in keyring\n" );
free_packet(pkt);
init_packet(pkt);
break;
case PKT_PUBLIC_KEY:
case PKT_SECRET_KEY:
if( root ) { /* store this packet */
kbpos->pkt = pkt;
pkt = NULL;
goto ready;
}
root = new_kbnode( pkt );
pkt = gcry_xmalloc( sizeof *pkt );
init_packet(pkt);
break;
default:
/* skip pakets at the beginning of a keyring, until we find
* a start packet; issue a warning if it is not a comment */
if( !root && pkt->pkttype != PKT_COMMENT
&& pkt->pkttype != PKT_OLD_COMMENT ) {
break;
}
if( !root || (skipsigs && ( pkt->pkttype == PKT_SIGNATURE
||pkt->pkttype == PKT_COMMENT
||pkt->pkttype == PKT_OLD_COMMENT )) ) {
init_packet(pkt);
break;
}
add_kbnode( root, new_kbnode( pkt ) );
pkt = gcry_xmalloc( sizeof *pkt );
init_packet(pkt);
break;
}
}
ready:
if( rc == -1 && root )
rc = 0;
if( rc )
release_kbnode( root );
else
*ret_root = root;
free_packet( pkt );
gcry_free( pkt );
return rc;
}
/****************
* Perform insert/delete/update operation.
* mode 1 = insert
* 2 = delete
* 3 = update
*/
static int
do_kbxf_copy( KBPOS *kbpos, int mode, KBNODE root )
{
RESTBL *rentry;
IOBUF fp, newfp;
int rc=0;
char *bakfname = NULL;
char *tmpfname = NULL;
if( !(rentry = check_pos( kbpos )) )
return GPGERR_GENERAL;
if( kbpos->fp )
BUG(); /* not allowed with such a handle */
if( opt.dry_run )
return 0;
lock_rentry( rentry );
/* open the source file */
fp = iobuf_open( rentry->fname );
if( mode == 1 && !fp && errno == ENOENT ) { /* no file yet */
KBNODE kbctx, node;
/* insert: create a new file */
newfp = iobuf_create( rentry->fname );
if( !newfp ) {
log_error(_("%s: can't create: %s\n"), rentry->fname, strerror(errno));
unlock_rentry( rentry );
return GPGERR_OPEN_FILE;
}
else if( !opt.quiet )
log_info(_("%s: keyring created\n"), rentry->fname );
kbctx=NULL;
while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
if( (rc = build_packet( newfp, node->pkt )) ) {
log_error("build_packet(%d) failed: %s\n",
node->pkt->pkttype, gpg_errstr(rc) );
iobuf_cancel(newfp);
unlock_rentry( rentry );
return GPGERR_WRITE_FILE;
}
}
if( iobuf_close(newfp) ) {
log_error("%s: close failed: %s\n", rentry->fname, strerror(errno));
unlock_rentry( rentry );
return GPGERR_CLOSE_FILE;
}
if( chmod( rentry->fname, S_IRUSR | S_IWUSR ) ) {
log_error("%s: chmod failed: %s\n",
rentry->fname, strerror(errno) );
unlock_rentry( rentry );
return GPGERR_WRITE_FILE;
}
return 0;
}
if( !fp ) {
log_error("%s: can't open: %s\n", rentry->fname, strerror(errno) );
rc = GPGERR_OPEN_FILE;
goto leave;
}
/* create the new file */
#ifdef USE_ONLY_8DOT3
/* Here is another Windoze bug?:
* you cant rename("pubring.gpg.tmp", "pubring.gpg");
* but rename("pubring.gpg.tmp", "pubring.aaa");
* works. So we replace .gpg by .bak or .tmp
*/
if( strlen(rentry->fname) > 4
&& !strcmp(rentry->fname+strlen(rentry->fname)-4, ".gpg") ) {
bakfname = gcry_xmalloc( strlen( rentry->fname ) + 1 );
strcpy(bakfname,rentry->fname);
strcpy(bakfname+strlen(rentry->fname)-4, ".bak");
tmpfname = gcry_xmalloc( strlen( rentry->fname ) + 1 );
strcpy(tmpfname,rentry->fname);
strcpy(tmpfname+strlen(rentry->fname)-4, ".tmp");
}
else { /* file does not end with gpg; hmmm */
bakfname = gcry_xmalloc( strlen( rentry->fname ) + 5 );
strcpy(stpcpy(bakfname,rentry->fname),".bak");
tmpfname = gcry_xmalloc( strlen( rentry->fname ) + 5 );
strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
}
#else
bakfname = gcry_xmalloc( strlen( rentry->fname ) + 2 );
strcpy(stpcpy(bakfname,rentry->fname),"~");
tmpfname = gcry_xmalloc( strlen( rentry->fname ) + 5 );
strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
#endif
newfp = iobuf_create( tmpfname );
if( !newfp ) {
log_error("%s: can't create: %s\n", tmpfname, strerror(errno) );
iobuf_close(fp);
rc = GPGERR_OPEN_FILE;
goto leave;
}
if( mode == 1 ) { /* insert */
/* copy everything to the new file */
rc = copy_all_packets( fp, newfp );
if( rc != -1 ) {
log_error("%s: copy to %s failed: %s\n",
rentry->fname, tmpfname, gpg_errstr(rc) );
iobuf_close(fp);
iobuf_cancel(newfp);
goto leave;
}
rc = 0;
}
if( mode == 2 || mode == 3 ) { /* delete or update */
/* copy first part to the new file */
rc = copy_some_packets( fp, newfp, kbpos->offset );
if( rc ) { /* should never get EOF here */
log_error("%s: copy to %s failed: %s\n",
rentry->fname, tmpfname, gpg_errstr(rc) );
iobuf_close(fp);
iobuf_cancel(newfp);
goto leave;
}
/* skip this keyblock */
assert( kbpos->count );
rc = skip_some_packets( fp, kbpos->count );
if( rc ) {
log_error("%s: skipping %u packets failed: %s\n",
rentry->fname, kbpos->count, gpg_errstr(rc));
iobuf_close(fp);
iobuf_cancel(newfp);
goto leave;
}
}
if( mode == 1 || mode == 3 ) { /* insert or update */
KBNODE kbctx, node;
/* append the new data */
kbctx=NULL;
while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
if( (rc = build_packet( newfp, node->pkt )) ) {
log_error("build_packet(%d) failed: %s\n",
node->pkt->pkttype, gpg_errstr(rc) );
iobuf_close(fp);
iobuf_cancel(newfp);
rc = GPGERR_WRITE_FILE;
goto leave;
}
}
kbpos->valid = 0;
}
if( mode == 2 || mode == 3 ) { /* delete or update */
/* copy the rest */
rc = copy_all_packets( fp, newfp );
if( rc != -1 ) {
log_error("%s: copy to %s failed: %s\n",
rentry->fname, tmpfname, gpg_errstr(rc) );
iobuf_close(fp);
iobuf_cancel(newfp);
goto leave;
}
rc = 0;
}
/* close both files */
if( iobuf_close(fp) ) {
log_error("%s: close failed: %s\n", rentry->fname, strerror(errno) );
rc = GPGERR_CLOSE_FILE;
goto leave;
}
if( iobuf_close(newfp) ) {
log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
rc = GPGERR_CLOSE_FILE;
goto leave;
}
/* if the new file is a secring, restrict the permissions */
#ifndef HAVE_DOSISH_SYSTEM
if( rentry->secret ) {
if( chmod( tmpfname, S_IRUSR | S_IWUSR ) ) {
log_error("%s: chmod failed: %s\n",
tmpfname, strerror(errno) );
rc = GPGERR_WRITE_FILE;
goto leave;
}
}
#endif
/* rename and make backup file */
if( !rentry->secret ) { /* but not for secret keyrings */
#ifdef HAVE_DOSISH_SYSTEM
remove( bakfname );
#endif
if( rename( rentry->fname, bakfname ) ) {
log_error("%s: rename to %s failed: %s\n",
rentry->fname, bakfname, strerror(errno) );
rc = GPGERR_RENAME_FILE;
goto leave;
}
}
#ifdef HAVE_DOSISH_SYSTEM
remove( rentry->fname );
#endif
if( rename( tmpfname, rentry->fname ) ) {
log_error("%s: rename to %s failed: %s\n",
tmpfname, rentry->fname,strerror(errno) );
rc = GPGERR_RENAME_FILE;
if( rentry->secret ) {
log_info(_(
"WARNING: 2 files with confidential information exists.\n"));
log_info(_("%s is the unchanged one\n"), rentry->fname );
log_info(_("%s is the new one\n"), tmpfname );
log_info(_("Please fix this possible security flaw\n"));
}
goto leave;
}
leave:
unlock_rentry( rentry );
gcry_free(bakfname);
gcry_free(tmpfname);
return rc;
}
#ifdef HAVE_LIBGDBM
/****************************************************************