aboutsummaryrefslogtreecommitdiffstats
path: root/g10/ringedit.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>1998-02-11 03:25:44 +0000
committerWerner Koch <[email protected]>1998-02-11 03:25:44 +0000
commit4c0c155922b70b62793905490e210e9af4e3b18d (patch)
treea0d8d84a89cfd4579817a993715e750917961c3e /g10/ringedit.c
parentrelease 0.2.3 (diff)
downloadgnupg-4c0c155922b70b62793905490e210e9af4e3b18d.tar.gz
gnupg-4c0c155922b70b62793905490e210e9af4e3b18d.zip
a couple of changes; but some parts are now broken
Diffstat (limited to 'g10/ringedit.c')
-rw-r--r--g10/ringedit.c324
1 files changed, 168 insertions, 156 deletions
diff --git a/g10/ringedit.c b/g10/ringedit.c
index 61f915c17..141d8cf7f 100644
--- a/g10/ringedit.c
+++ b/g10/ringedit.c
@@ -35,7 +35,6 @@
*
* - Delete a key block
*
- * FIXME: Add backup stuff
* FIXME: Keep track of all nodes, so that a change is propagated
* to all nodes. (or use shallow copies and ref-counting?)
*/
@@ -46,6 +45,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <assert.h>
#include "util.h"
#include "packet.h"
@@ -75,8 +77,7 @@ static int keyring_search( PACKET *pkt, KBPOS *kbpos, IOBUF iobuf );
static int keyring_search2( PUBKEY_FIND_INFO info, KBPOS *kbpos,
const char *fname);
static int keyring_read( KBPOS *kbpos, KBNODE *ret_root );
-static int keyring_insert( KBPOS *kbpos, KBNODE root );
-static int keyring_delete( KBPOS *kbpos );
+static int keyring_copy( KBPOS *kbpos, int mode, KBNODE root );
@@ -308,7 +309,7 @@ insert_keyblock( KBPOS *kbpos, KBNODE root )
if( !check_pos(kbpos) )
return G10ERR_GENERAL;
- rc = keyring_insert( kbpos, root );
+ rc = keyring_copy( kbpos, 1, root );
return rc;
}
@@ -327,7 +328,7 @@ delete_keyblock( KBPOS *kbpos )
if( !check_pos(kbpos) )
return G10ERR_GENERAL;
- rc = keyring_delete( kbpos );
+ rc = keyring_copy( kbpos, 2, NULL );
return rc;
}
@@ -340,14 +341,11 @@ int
update_keyblock( KBPOS *kbpos, KBNODE root )
{
int rc;
- KBPOS kbpos2;
- /* we do it the simple way: */
- memset( &kbpos2, 0, sizeof kbpos2 );
- kbpos2.resno = kbpos->resno;
- rc = insert_keyblock( &kbpos2, root );
- if( !rc )
- rc = delete_keyblock( kbpos );
+ if( !check_pos(kbpos) )
+ return G10ERR_GENERAL;
+
+ rc = keyring_copy( kbpos, 3, root );
return rc;
}
@@ -451,20 +449,12 @@ keyring_search2( PUBKEY_FIND_INFO info, KBPOS *kbpos, const char *fname )
init_packet(&pkt);
save_mode = set_packet_list_mode(0);
- #if 0
- if( iobuf_seek( iobuf, 0 ) ) {
- log_error("can't rewind keyring file: %s\n", g10_errstr(rc));
- rc = G10ERR_KEYRING_OPEN;
- goto leave;
- }
- #else
iobuf = iobuf_open( fname );
if( !iobuf ) {
log_error("can't open '%s'\n", fname );
rc = G10ERR_OPEN_FILE;
goto leave;
}
- #endif
while( !(rc=search_packet(iobuf, &pkt, PKT_PUBLIC_CERT, &offset)) ) {
PKT_public_cert *pkc = pkt.pkt.public_cert;
@@ -505,9 +495,8 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
int rc;
RESTBL *rentry;
KBNODE root = NULL;
- KBNODE node, n1, n2;
IOBUF a;
- u32 offset, last_offset;
+ int in_cert = 0;
if( !(rentry=check_pos(kbpos)) )
return G10ERR_GENERAL;
@@ -526,77 +515,37 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
pkt = m_alloc( sizeof *pkt );
init_packet(pkt);
+ kbpos->count=0;
while( (rc=parse_packet(a, pkt)) != -1 ) {
if( rc ) { /* ignore errors */
+ if( rc != G10ERR_UNKNOWN_PACKET ) {
+ log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
+ rc = G10ERR_INV_KEYRING;
+ goto ready;
+ }
+ kbpos->count++;
free_packet( pkt );
continue;
}
- if( root && ( pkt->pkttype == PKT_PUBLIC_CERT
- || pkt->pkttype == PKT_SECRET_CERT ) )
- goto ready;
- offset = iobuf_tell(a);
+ /* make a linked list of all packets */
switch( pkt->pkttype ) {
case PKT_PUBLIC_CERT:
case PKT_SECRET_CERT:
- root = new_kbnode( pkt );
- pkt = m_alloc( sizeof *pkt );
- init_packet(pkt);
- break;
-
- case PKT_USER_ID:
- if( !root ) {
- log_error("read_keyblock: orphaned user id\n" );
- rc = G10ERR_INV_KEYRING; /* or wrong kbpos */
+ if( in_cert )
goto ready;
- }
- offset = last_offset;
- /* append the user id */
- node = new_kbnode( pkt );
- if( !(n1=root->child) )
- root->child = node;
- else {
- for( ; n1->next; n1 = n1->next)
- ;
- n1->next = node;
- }
+ in_cert = 1;
+ default:
+ kbpos->count++;
+ if( !root )
+ root = new_kbnode( pkt );
+ else
+ add_kbnode( root, new_kbnode( pkt ) );
pkt = m_alloc( sizeof *pkt );
init_packet(pkt);
break;
-
- case PKT_SIGNATURE:
- if( !root ) {
- log_error("read_keyblock: no root for signature\n" );
- rc = G10ERR_INV_KEYRING; /* or wrong kbpos */
- break;
- }
- if( !root->child ) {
- log_error("read_keyblock: no userid for signature\n" );
- rc = G10ERR_INV_KEYRING;
- break;
- }
- /* goto the last user id */
- for(n1=root->child; n1->next; n1 = n1->next )
- ;
- /* append the signature node */
- node = new_kbnode( pkt );
- if( !(n2=n1->child) )
- n1->child = node;
- else {
- for( ; n2->next; n2 = n2->next)
- ;
- n2->next = node;
- }
- pkt = m_alloc( sizeof *pkt );
- init_packet(pkt);
- break;
-
- default: /* ignore all other packets. FIXME: we should not do this */
- free_packet( pkt );
- break;
}
}
ready:
- kbpos->last_block = rc == -1; /* flag, that this is the last block */
if( rc == -1 && root )
rc = 0;
@@ -604,7 +553,6 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
release_kbnode( root );
else {
*ret_root = root;
- kbpos->length = offset - kbpos->offset;
}
free_packet( pkt );
m_free( pkt );
@@ -613,111 +561,175 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
}
+
/****************
- * Insert the keyblock described by ROOT into the keyring described
- * by KBPOS. This actually appends the data to the keyfile.
+ * Peromf insert/delete/update operation.
+ * mode 1 = insert
+ * 2 = delete
+ * 3 = update
*/
static int
-keyring_insert( KBPOS *kbpos, KBNODE root )
+keyring_copy( KBPOS *kbpos, int mode, KBNODE root )
{
RESTBL *rentry;
- IOBUF fp;
- KBNODE kbctx, node;
+ IOBUF fp, newfp;
int rc;
+ char *bakfname = NULL;
+ char *tmpfname = NULL;
if( !(rentry = check_pos( kbpos )) )
return G10ERR_GENERAL;
- /* FIXME: we must close the file if it's already open, due to
- * 2 reasons:
- * - cannot open the same file twice on DOSish OSes
- * - must sync with iobufs somehow
- */
- /* open the file for append */
- fp = iobuf_append( rentry->fname );
- if( !fp ) {
- log_error("can't append to '%s'\n", rentry->fname );
- return G10ERR_OPEN_FILE;
- }
+ /* open the source file */
+ fp = iobuf_open( rentry->fname );
+ if( mode == 1 && !fp && errno == ENOENT ) { /* no file yet */
+ KBNODE kbctx, node;
- kbctx=NULL;
- while( (node = walk_kbtree( root, &kbctx )) ) {
- if( (rc = build_packet( fp, node->pkt )) ) {
- log_error("build_packet(%d) failed: %s\n",
- node->pkt->pkttype, g10_errstr(rc) );
+ /* insert: create a new file */
+ newfp = iobuf_create( rentry->fname );
+ if( !newfp ) {
+ log_error("%s: can't create: %s\n", rentry->fname, strerror(errno));
+ return G10ERR_OPEN_FILE;
+ }
+
+ 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, g10_errstr(rc) );
+ iobuf_cancel(newfp);
+ return G10ERR_WRITE_FILE;
+ }
+ }
+ if( iobuf_close(newfp) ) {
+ log_error("%s: close failed: %s\n", rentry->fname, strerror(errno));
+ return G10ERR_CLOSE_FILE;
+ }
+ if( chmod( rentry->fname, S_IRUSR | S_IWUSR ) ) {
+ log_error("%s: chmod failed: %s\n",
+ rentry->fname, strerror(errno) );
return G10ERR_WRITE_FILE;
}
+ return 0;
}
- iobuf_close(fp);
-
- return 0;
-}
-
-static int
-keyring_delete( KBPOS *kbpos )
-{
- RESTBL *rentry;
- IOBUF fp;
- int rc;
- u32 len;
- int ctb;
-
- if( !(rentry = check_pos( kbpos )) )
- return G10ERR_GENERAL;
-
-
- /* open the file for read/write */
- fp = iobuf_openrw( rentry->fname );
if( !fp ) {
- log_error("can't open '%s' for writing\n", rentry->fname );
- return G10ERR_OPEN_FILE;
+ log_error("%s: can't open: %s\n", rentry->fname, strerror(errno) );
+ rc = G10ERR_OPEN_FILE;
+ goto leave;
}
- if( iobuf_seek( fp, kbpos->offset ) ) {
- log_error("can't seek to %lu: %s\n", kbpos->offset, g10_errstr(rc));
+ /* create the new file */
+ bakfname = m_alloc( strlen( rentry->fname ) + 2 );
+ strcpy(stpcpy(bakfname,rentry->fname),"~");
+ tmpfname = m_alloc( strlen( rentry->fname ) + 5 );
+ strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
+ newfp = iobuf_create( tmpfname );
+ if( !newfp ) {
+ log_error("%s: can't create: %s\n", tmpfname, strerror(errno) );
iobuf_close(fp);
- return G10ERR_WRITE_FILE;
+ rc = G10ERR_OPEN_FILE;
+ goto leave;
}
- len = kbpos->length;
- assert( len < 100000 ); /* there is a bug somewhere */
- /*log_debug("writing a dummy packet of length %lu\n", (ulong)len);*/
-
- if( len < 2 )
- BUG();
-
- if( len < 256 ) {
- ctb = 0x80;
- len -= 2;
- }
- else if( len < 65536 ) {
- ctb = 0x81;
- len -= 3;
- }
- else {
- ctb = 0x82;
- len -= 5;
+ 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, g10_errstr(rc) );
+ iobuf_close(fp);
+ iobuf_cancel(newfp);
+ goto leave;
+ }
+ rc = 0;
}
- iobuf_put(fp, ctb );
- if( ctb & 2 ) {
- iobuf_put(fp, len >> 24 );
- iobuf_put(fp, len >> 16 );
+
+ 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, g10_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, g10_errstr(rc));
+ iobuf_close(fp);
+ iobuf_cancel(newfp);
+ goto leave;
+ }
}
- if( ctb & 3 )
- iobuf_put(fp, len >> 8 );
- if( iobuf_put(fp, len ) ) {
- iobuf_close(fp);
- return G10ERR_WRITE_FILE;
+
+ 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, g10_errstr(rc) );
+ iobuf_close(fp);
+ iobuf_cancel(newfp);
+ rc = G10ERR_WRITE_FILE;
+ goto leave;
+ }
+ }
}
- for( ; len; len-- )
- if( iobuf_put(fp, 0xff ) ) {
+
+ 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, g10_errstr(rc) );
iobuf_close(fp);
- return G10ERR_WRITE_FILE;
+ iobuf_cancel(newfp);
+ goto leave;
}
+ rc = 0;
+ }
+ /* close both files */
iobuf_close(fp);
+ if( iobuf_close(newfp) ) {
+ log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
+ rc = G10ERR_CLOSE_FILE;
+ goto leave;
+ }
+ /* if the new file is a secring, restrict the permissions */
+ if( rentry->secret ) {
+ if( chmod( tmpfname, S_IRUSR | S_IWUSR ) ) {
+ log_error("%s: chmod failed: %s\n",
+ tmpfname, strerror(errno) );
+ rc = G10ERR_WRITE_FILE;
+ goto leave;
+ }
+ }
+ /* rename and make backup file */
+ if( rename( rentry->fname, bakfname ) ) {
+ log_error("%s: rename to %s failed: %s\n",
+ rentry->fname, bakfname, strerror(errno) );
+ rc = G10ERR_RENAME_FILE;
+ goto leave;
+ }
+ if( rename( tmpfname, rentry->fname ) ) {
+ log_error("%s: rename to %s failed: %s\n",
+ tmpfname, rentry->fname,strerror(errno) );
+ rc = G10ERR_RENAME_FILE;
+ goto leave;
+ }
- return 0;
+ leave:
+ m_free(bakfname);
+ m_free(tmpfname);
+ return rc;
}