diff options
author | Werner Koch <[email protected]> | 1998-02-11 03:25:44 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 1998-02-11 03:25:44 +0000 |
commit | 4c0c155922b70b62793905490e210e9af4e3b18d (patch) | |
tree | a0d8d84a89cfd4579817a993715e750917961c3e /g10/ringedit.c | |
parent | release 0.2.3 (diff) | |
download | gnupg-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.c | 324 |
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; } |