a whole bunch of internal cleanups
[gnupg.git] / g10 / ringedit.c
1 /* ringedit.c -  Function for key ring editing
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GNUPG.
5  *
6  * GNUPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GNUPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21
22 /****************
23  * This module supplies function for:
24  *
25  *  - Search for a key block (pubkey and all other stuff) and return a
26  *    handle for it.
27  *
28  *  - Lock/Unlock a key block
29  *
30  *  - Read a key block into a tree
31  *
32  *  - Update a key block
33  *
34  *  - Insert a new key block
35  *
36  *  - Delete a key block
37  *
38  * FIXME:  Keep track of all nodes, so that a change is propagated
39  *         to all nodes. (or use shallow copies and ref-counting?)
40  */
41
42
43
44 #include <config.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <errno.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <assert.h>
52 #include "util.h"
53 #include "packet.h"
54 #include "memory.h"
55 #include "mpi.h"
56 #include "iobuf.h"
57 #include "keydb.h"
58 #include <unistd.h> /* for truncate */
59
60
61 struct resource_table_struct {
62     int used;
63     int secret; /* this is a secret keyring */
64     char *fname;
65     IOBUF iobuf;
66 };
67 typedef struct resource_table_struct RESTBL;
68
69 #define MAX_RESOURCES 10
70 static RESTBL resource_table[MAX_RESOURCES];
71
72
73 static int search( PACKET *pkt, KBPOS *kbpos, int secret );
74
75
76 static int keyring_search( PACKET *pkt, KBPOS *kbpos, IOBUF iobuf,
77                                                 const char *fname );
78 static int keyring_read( KBPOS *kbpos, KBNODE *ret_root );
79 static int keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs );
80 static int keyring_copy( KBPOS *kbpos, int mode, KBNODE root );
81
82
83
84 static RESTBL *
85 check_pos( KBPOS *kbpos )
86 {
87     if( kbpos->resno < 0 || kbpos->resno >= MAX_RESOURCES )
88         return NULL;
89     if( !resource_table[kbpos->resno].used )
90         return NULL;
91     return resource_table + kbpos->resno;
92 }
93
94
95
96 /****************************************************************
97  ****************** public functions ****************************
98  ****************************************************************/
99
100 /****************
101  * Register a resource (which currently may only be a keyring file).
102  */
103 int
104 add_keyblock_resource( const char *filename, int force, int secret )
105 {
106     IOBUF iobuf;
107     int i;
108
109     for(i=0; i < MAX_RESOURCES; i++ )
110         if( !resource_table[i].used )
111             break;
112     if( i == MAX_RESOURCES )
113         return G10ERR_RESOURCE_LIMIT;
114
115   #if __MINGW32__
116     iobuf = NULL;
117   #else
118     iobuf = iobuf_open( filename );
119     if( !iobuf && !force )
120         return G10ERR_OPEN_FILE;
121   #endif
122     resource_table[i].used = 1;
123     resource_table[i].secret = !!secret;
124     resource_table[i].fname = m_strdup(filename);
125     resource_table[i].iobuf = iobuf;
126     return 0;
127 }
128
129 /****************
130  * Return the resource name of the keyblock associated with KBPOS.
131  */
132 const char *
133 keyblock_resource_name( KBPOS *kbpos )
134 {
135     RESTBL *rentry;
136
137     if( !(rentry = check_pos( kbpos )) || !rentry->fname )
138         log_bug("no name for keyblock resource %d\n", kbpos->resno );
139     return rentry->fname;
140 }
141
142
143 /****************
144  * Get a keyblock handle KBPOS from a filename. This can be used
145  * to get a handle for insert_keyblock for a new keyblock.
146  * Using a filename of NULL returns the default resource
147  */
148 int
149 get_keyblock_handle( const char *filename, int secret, KBPOS *kbpos )
150 {
151     int i;
152
153     for(i=0; i < MAX_RESOURCES; i++ )
154         if( resource_table[i].used && !resource_table[i].secret == !secret ) {
155             /* fixme: dos needs case insensitive file compare */
156             if( !filename || !strcmp( resource_table[i].fname, filename ) ) {
157                 memset( kbpos, 0, sizeof *kbpos );
158                 kbpos->resno = i;
159                 return 0;
160             }
161         }
162     return -1; /* not found */
163 }
164
165
166
167 /****************
168  * Search a keyblock which starts with the given packet and puts all
169  * information into KBPOS, which can be used later to access this key block.
170  * This function looks into all registered keyblock sources.
171  * PACKET must be a packet with either a secret_cert or a public_cert
172  *
173  * This function is intended to check whether a given certificate
174  * is already in a keyring or to prepare it for editing.
175  *
176  * Returns: 0 if found, -1 if not found or an errorcode.
177  */
178 static int
179 search( PACKET *pkt, KBPOS *kbpos, int secret )
180 {
181     int i, rc, last_rc=-1;
182
183     for(i=0; i < MAX_RESOURCES; i++ ) {
184         if( resource_table[i].used && !resource_table[i].secret == !secret ) {
185             /* note: here we have to add different search functions,
186              * depending on the type of the resource */
187             rc = keyring_search( pkt, kbpos, resource_table[i].iobuf,
188                                              resource_table[i].fname );
189             if( !rc ) {
190                 kbpos->resno = i;
191                 kbpos->fp = NULL;
192                 return 0;
193             }
194             if( rc != -1 ) {
195                 log_error("error searching resource %d: %s\n",
196                                                   i, g10_errstr(rc));
197                 last_rc = rc;
198             }
199         }
200     }
201     return last_rc;
202 }
203
204
205 /****************
206  * Combined function to search for a username and get the position
207  * of the keyblock.
208  */
209 int
210 find_keyblock_byname( KBPOS *kbpos, const char *username )
211 {
212     PACKET pkt;
213     PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
214     int rc;
215
216     rc = get_pubkey_byname( pkc, username );
217     if( rc ) {
218         free_public_cert(pkc);
219         return rc;
220     }
221
222     init_packet( &pkt );
223     pkt.pkttype = PKT_PUBLIC_CERT;
224     pkt.pkt.public_cert = pkc;
225     rc = search( &pkt, kbpos, 0 );
226     free_public_cert(pkc);
227     return rc;
228 }
229
230
231 /****************
232  * Combined function to search for a key and get the position
233  * of the keyblock.
234  */
235 int
236 find_keyblock_bypkc( KBPOS *kbpos, PKT_public_cert *pkc )
237 {
238     PACKET pkt;
239     int rc;
240
241     init_packet( &pkt );
242     pkt.pkttype = PKT_PUBLIC_CERT;
243     pkt.pkt.public_cert = pkc;
244     rc = search( &pkt, kbpos, 0 );
245     return rc;
246 }
247
248
249 /****************
250  * Combined function to search for a username and get the position
251  * of the keyblock. This function does not unprotect the secret key.
252  */
253 int
254 find_secret_keyblock_byname( KBPOS *kbpos, const char *username )
255 {
256     PACKET pkt;
257     PKT_secret_cert *skc = m_alloc_clear( sizeof *skc );
258     int rc;
259
260     rc = get_seckey_byname( skc, username, 0 );
261     if( rc ) {
262         free_secret_cert(skc);
263         return rc;
264     }
265
266     init_packet( &pkt );
267     pkt.pkttype = PKT_SECRET_CERT;
268     pkt.pkt.secret_cert = skc;
269     rc = search( &pkt, kbpos, 1 );
270     free_secret_cert(skc);
271     return rc;
272 }
273
274
275
276 /****************
277  * Lock the keyblock; wait until it's available
278  * This function may change the internal data in kbpos, in cases
279  * when the keyblock to be locked has been modified.
280  * fixme: remove this function and add an option to search()?
281  */
282 int
283 lock_keyblock( KBPOS *kbpos )
284 {
285     if( !check_pos(kbpos) )
286         return G10ERR_GENERAL;
287     return 0;
288 }
289
290 /****************
291  * Release a lock on a keyblock
292  */
293 void
294 unlock_keyblock( KBPOS *kbpos )
295 {
296     if( !check_pos(kbpos) )
297         BUG();
298 }
299
300 /****************
301  * Read a complete keyblock and return the root in ret_root.
302  */
303 int
304 read_keyblock( KBPOS *kbpos, KBNODE *ret_root )
305 {
306     if( !check_pos(kbpos) )
307         return G10ERR_GENERAL;
308     return keyring_read( kbpos, ret_root );
309 }
310
311
312 /****************
313  * This functions can be used to read through a complete keyring.
314  * Mode is: 0 = open
315  *          1 = read
316  *          2 = close
317  *          5 = open secret keyrings
318  *          11 = read but skip signature and comment packets.
319  *          all others are reserved!
320  * Note that you do not need a search prior to this function,
321  * only a handle is needed.
322  * NOTE: It is not allowed to do an insert/update/delte with this
323  *       keyblock, if you want to do this, use search/read!
324  */
325 int
326 enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root )
327 {
328     int rc = 0;
329     RESTBL *rentry;
330
331     if( !mode || mode == 5 || mode == 100 ) {
332         int i;
333         kbpos->fp = NULL;
334         if( !mode ) {
335             kbpos->secret = 0;
336             i = 0;
337         }
338         else if( mode == 5 ) {
339             kbpos->secret = 1;
340             mode = 0;
341             i = 0;
342         }
343         else
344             i = kbpos->resno+1;
345         for(; i < MAX_RESOURCES; i++ )
346             if( resource_table[i].used
347                 && !resource_table[i].secret == !kbpos->secret )
348                 break;
349         if( i == MAX_RESOURCES )
350             return -1; /* no resources */
351         kbpos->resno = i;
352         rentry = check_pos( kbpos );
353         kbpos->fp = iobuf_open( rentry->fname );
354         if( !kbpos->fp ) {
355             log_error("can't open '%s'\n", rentry->fname );
356             return G10ERR_OPEN_FILE;
357         }
358         kbpos->pkt = NULL;
359     }
360     else if( mode == 1 || mode == 11 ) {
361         int cont;
362         do {
363             cont = 0;
364             if( !kbpos->fp )
365                 return G10ERR_GENERAL;
366             rc = keyring_enum( kbpos, ret_root, mode == 11 );
367             if( rc == -1 ) {
368                 assert( !kbpos->pkt );
369                 rentry = check_pos( kbpos );
370                 assert(rentry);
371                 /* close */
372                 enum_keyblocks(2, kbpos, ret_root );
373                 /* and open the next one */
374                 rc = enum_keyblocks(100, kbpos, ret_root );
375                 if( !rc )
376                     cont = 1;
377             }
378         } while(cont);
379     }
380     else if( kbpos->fp ) {
381         iobuf_close( kbpos->fp );
382         kbpos->fp = NULL;
383         /* release pending packet */
384         free_packet( kbpos->pkt );
385         m_free( kbpos->pkt );
386     }
387     return rc;
388 }
389
390
391
392
393 /****************
394  * Insert the keyblock described by ROOT into the keyring described
395  * by KBPOS.  This actually appends the data to the keyfile.
396  */
397 int
398 insert_keyblock( KBPOS *kbpos, KBNODE root )
399 {
400     int rc;
401
402     if( !check_pos(kbpos) )
403         return G10ERR_GENERAL;
404
405     rc = keyring_copy( kbpos, 1, root );
406
407     return rc;
408 }
409
410 /****************
411  * Delete the keyblock described by KBPOS.
412  * The current code simply changes the keyblock in the keyring
413  * to packet of type 0 with the correct length.  To help detect errors,
414  * zero bytes are written.
415  */
416 int
417 delete_keyblock( KBPOS *kbpos )
418 {
419     int rc;
420
421     if( !check_pos(kbpos) )
422         return G10ERR_GENERAL;
423
424     rc = keyring_copy( kbpos, 2, NULL );
425
426     return rc;
427 }
428
429
430 /****************
431  * Update the keyblock at KBPOS with the one in ROOT.
432  */
433 int
434 update_keyblock( KBPOS *kbpos, KBNODE root )
435 {
436     int rc;
437
438     if( !check_pos(kbpos) )
439         return G10ERR_GENERAL;
440
441     rc = keyring_copy( kbpos, 3, root );
442
443     return rc;
444 }
445
446
447 /****************************************************************
448  ********** Functions which operates on regular keyrings ********
449  ****************************************************************/
450
451 static int
452 cmp_seckey( PKT_secret_cert *req_skc, PKT_secret_cert *skc )
453 {
454     int n,i;
455
456     assert( req_skc->pubkey_algo == skc->pubkey_algo );
457
458     n = pubkey_get_nskey( req_skc->pubkey_algo );
459     for(i=0; i < n; i++ ) {
460         if( mpi_cmp( req_skc->skey[i], skc->skey[i] ) )
461             return -1;
462     }
463     return 0;
464 }
465
466 static int
467 cmp_pubkey( PKT_public_cert *req_pkc, PKT_public_cert *pkc )
468 {
469     int n, i;
470
471     assert( req_pkc->pubkey_algo == pkc->pubkey_algo );
472
473     n = pubkey_get_npkey( req_pkc->pubkey_algo );
474     for(i=0; i < n; i++ ) {
475         if( mpi_cmp( req_pkc->pkey[i], pkc->pkey[i] )  )
476             return -1;
477     }
478     return 0;
479 }
480
481 /****************
482  * search one keyring, return 0 if found, -1 if not found or an errorcode.
483  */
484 static int
485 keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname )
486 {
487     int rc;
488     PACKET pkt;
489     int save_mode;
490     ulong offset;
491     int pkttype = req->pkttype;
492     PKT_public_cert *req_pkc = req->pkt.public_cert;
493     PKT_secret_cert *req_skc = req->pkt.secret_cert;
494
495     init_packet(&pkt);
496     save_mode = set_packet_list_mode(0);
497
498   #if __MINGW32__
499     assert(!iobuf);
500     iobuf = iobuf_open( fname );
501     if( !iobuf ) {
502         log_error("%s: can't open keyring file\n", fname);
503         rc = G10ERR_KEYRING_OPEN;
504         goto leave;
505     }
506   #else
507     if( iobuf_seek( iobuf, 0 ) ) {
508         log_error("can't rewind keyring file\n");
509         rc = G10ERR_KEYRING_OPEN;
510         goto leave;
511     }
512   #endif
513
514     while( !(rc=search_packet(iobuf, &pkt, pkttype, &offset)) ) {
515         if( pkt.pkttype == PKT_SECRET_CERT ) {
516             PKT_secret_cert *skc = pkt.pkt.secret_cert;
517
518             if(   req_skc->timestamp == skc->timestamp
519                && req_skc->valid_days == skc->valid_days
520                && req_skc->pubkey_algo == skc->pubkey_algo
521                && !cmp_seckey( req_skc, skc) )
522                 break; /* found */
523         }
524         else if( pkt.pkttype == PKT_PUBLIC_CERT ) {
525             PKT_public_cert *pkc = pkt.pkt.public_cert;
526
527             if(   req_pkc->timestamp == pkc->timestamp
528                && req_pkc->valid_days == pkc->valid_days
529                && req_pkc->pubkey_algo == pkc->pubkey_algo
530                && !cmp_pubkey( req_pkc, pkc ) )
531                 break; /* found */
532         }
533         else
534             BUG();
535         free_packet(&pkt);
536     }
537     if( !rc )
538         kbpos->offset = offset;
539
540   leave:
541     free_packet(&pkt);
542     set_packet_list_mode(save_mode);
543   #if __MINGW32__
544     iobuf_close(iobuf);
545   #endif
546     return rc;
547 }
548
549
550 static int
551 keyring_read( KBPOS *kbpos, KBNODE *ret_root )
552 {
553     PACKET *pkt;
554     int rc;
555     RESTBL *rentry;
556     KBNODE root = NULL;
557     IOBUF a;
558     int in_cert = 0;
559
560     if( !(rentry=check_pos(kbpos)) )
561         return G10ERR_GENERAL;
562
563     a = iobuf_open( rentry->fname );
564     if( !a ) {
565         log_error("can't open '%s'\n", rentry->fname );
566         return G10ERR_OPEN_FILE;
567     }
568
569     if( iobuf_seek( a, kbpos->offset ) ) {
570         log_error("can't seek to %lu\n", kbpos->offset);
571         iobuf_close(a);
572         return G10ERR_KEYRING_OPEN;
573     }
574
575     pkt = m_alloc( sizeof *pkt );
576     init_packet(pkt);
577     kbpos->count=0;
578     while( (rc=parse_packet(a, pkt)) != -1 ) {
579         if( rc ) {  /* ignore errors */
580             if( rc != G10ERR_UNKNOWN_PACKET ) {
581                 log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
582                 rc = G10ERR_INV_KEYRING;
583                 goto ready;
584             }
585                 log_info("read_keyblock: read error: %s\n", g10_errstr(rc) );
586             kbpos->count++;
587             free_packet( pkt );
588             init_packet( pkt );
589             continue;
590         }
591         /* make a linked list of all packets */
592         switch( pkt->pkttype ) {
593           case PKT_PUBLIC_CERT:
594           case PKT_SECRET_CERT:
595             if( in_cert )
596                 goto ready;
597             in_cert = 1;
598           default:
599             kbpos->count++;
600             if( !root )
601                 root = new_kbnode( pkt );
602             else
603                 add_kbnode( root, new_kbnode( pkt ) );
604             pkt = m_alloc( sizeof *pkt );
605             init_packet(pkt);
606             break;
607         }
608     }
609   ready:
610     if( rc == -1 && root )
611         rc = 0;
612
613     if( rc )
614         release_kbnode( root );
615     else
616         *ret_root = root;
617     free_packet( pkt );
618     m_free( pkt );
619     iobuf_close(a);
620     return rc;
621 }
622
623
624 static int
625 keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs )
626 {
627     PACKET *pkt;
628     int rc;
629     RESTBL *rentry;
630     KBNODE root = NULL;
631
632     if( !(rentry=check_pos(kbpos)) )
633         return G10ERR_GENERAL;
634
635     if( kbpos->pkt ) {
636         root = new_kbnode( kbpos->pkt );
637         kbpos->pkt = NULL;
638     }
639
640     pkt = m_alloc( sizeof *pkt );
641     init_packet(pkt);
642     while( (rc=parse_packet(kbpos->fp, pkt)) != -1 ) {
643         if( rc ) {  /* ignore errors */
644             if( rc != G10ERR_UNKNOWN_PACKET ) {
645                 log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
646                 rc = G10ERR_INV_KEYRING;
647                 goto ready;
648             }
649             free_packet( pkt );
650             init_packet( pkt );
651             continue;
652         }
653         /* make a linked list of all packets */
654         switch( pkt->pkttype ) {
655           case PKT_PUBLIC_CERT:
656           case PKT_SECRET_CERT:
657             if( root ) { /* store this packet */
658                 kbpos->pkt = pkt;
659                 pkt = NULL;
660                 goto ready;
661             }
662             root = new_kbnode( pkt );
663             pkt = m_alloc( sizeof *pkt );
664             init_packet(pkt);
665             break;
666
667           default:
668             /* skip pakets at the beginning of a keyring, until we find
669              * a start packet; issue a warning if it is not a comment */
670             if( !root && pkt->pkttype != PKT_COMMENT
671                       && pkt->pkttype != PKT_OLD_COMMENT )
672                 log_info("keyring_enum: skipped packet of type %d\n",
673                             pkt->pkttype );
674             if( !root || (skipsigs && ( pkt->pkttype == PKT_SIGNATURE
675                                       ||pkt->pkttype == PKT_COMMENT
676                                       ||pkt->pkttype == PKT_OLD_COMMENT )) ) {
677                 init_packet(pkt);
678                 break;
679             }
680             add_kbnode( root, new_kbnode( pkt ) );
681             pkt = m_alloc( sizeof *pkt );
682             init_packet(pkt);
683             break;
684         }
685     }
686   ready:
687     if( rc == -1 && root )
688         rc = 0;
689
690     if( rc )
691         release_kbnode( root );
692     else
693         *ret_root = root;
694     free_packet( pkt );
695     m_free( pkt );
696     return rc;
697 }
698
699
700
701 /****************
702  * Perform insert/delete/update operation.
703  * mode 1 = insert
704  *      2 = delete
705  *      3 = update
706  */
707 static int
708 keyring_copy( KBPOS *kbpos, int mode, KBNODE root )
709 {
710     RESTBL *rentry;
711     IOBUF fp, newfp;
712     int rc=0;
713     char *bakfname = NULL;
714     char *tmpfname = NULL;
715
716     if( !(rentry = check_pos( kbpos )) )
717         return G10ERR_GENERAL;
718     if( kbpos->fp )
719         BUG(); /* not allowed with such a handle */
720
721     /* open the source file */
722     fp = iobuf_open( rentry->fname );
723     if( mode == 1 && !fp && errno == ENOENT ) { /* no file yet */
724         KBNODE kbctx, node;
725
726         /* insert: create a new file */
727         newfp = iobuf_create( rentry->fname );
728         if( !newfp ) {
729             log_error("%s: can't create: %s\n", rentry->fname, strerror(errno));
730             return G10ERR_OPEN_FILE;
731         }
732
733         kbctx=NULL;
734         while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
735             if( (rc = build_packet( newfp, node->pkt )) ) {
736                 log_error("build_packet(%d) failed: %s\n",
737                             node->pkt->pkttype, g10_errstr(rc) );
738                 iobuf_cancel(newfp);
739                 return G10ERR_WRITE_FILE;
740             }
741         }
742         if( iobuf_close(newfp) ) {
743             log_error("%s: close failed: %s\n", rentry->fname, strerror(errno));
744             return G10ERR_CLOSE_FILE;
745         }
746         if( chmod( rentry->fname, S_IRUSR | S_IWUSR ) ) {
747             log_error("%s: chmod failed: %s\n",
748                                     rentry->fname, strerror(errno) );
749             return G10ERR_WRITE_FILE;
750         }
751         return 0;
752     }
753     if( !fp ) {
754         log_error("%s: can't open: %s\n", rentry->fname, strerror(errno) );
755         rc = G10ERR_OPEN_FILE;
756         goto leave;
757     }
758
759     /* create the new file */
760     bakfname = m_alloc( strlen( rentry->fname ) + 2 );
761     strcpy(stpcpy(bakfname,rentry->fname),"~");
762     tmpfname = m_alloc( strlen( rentry->fname ) + 5 );
763     strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
764     newfp = iobuf_create( tmpfname );
765     if( !newfp ) {
766         log_error("%s: can't create: %s\n", tmpfname, strerror(errno) );
767         iobuf_close(fp);
768         rc = G10ERR_OPEN_FILE;
769         goto leave;
770     }
771
772     if( mode == 1 ) { /* insert */
773         /* copy everything to the new file */
774         rc = copy_all_packets( fp, newfp );
775         if( rc != -1 ) {
776             log_error("%s: copy to %s failed: %s\n",
777                       rentry->fname, tmpfname, g10_errstr(rc) );
778             iobuf_close(fp);
779             iobuf_cancel(newfp);
780             goto leave;
781         }
782         rc = 0;
783     }
784
785     if( mode == 2 || mode == 3 ) { /* delete or update */
786         /* copy first part to the new file */
787         rc = copy_some_packets( fp, newfp, kbpos->offset );
788         if( rc ) { /* should never get EOF here */
789             log_error("%s: copy to %s failed: %s\n",
790                       rentry->fname, tmpfname, g10_errstr(rc) );
791             iobuf_close(fp);
792             iobuf_cancel(newfp);
793             goto leave;
794         }
795         /* skip this keyblock */
796         assert( kbpos->count );
797         rc = skip_some_packets( fp, kbpos->count );
798         if( rc ) {
799             log_error("%s: skipping %u packets failed: %s\n",
800                             rentry->fname, kbpos->count, g10_errstr(rc));
801             iobuf_close(fp);
802             iobuf_cancel(newfp);
803             goto leave;
804         }
805     }
806
807     if( mode == 1 || mode == 3 ) { /* insert or update */
808         KBNODE kbctx, node;
809
810         /* append the new data */
811         kbctx=NULL;
812         while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
813             if( (rc = build_packet( newfp, node->pkt )) ) {
814                 log_error("build_packet(%d) failed: %s\n",
815                             node->pkt->pkttype, g10_errstr(rc) );
816                 iobuf_close(fp);
817                 iobuf_cancel(newfp);
818                 rc = G10ERR_WRITE_FILE;
819                 goto leave;
820             }
821         }
822     }
823
824     if( mode == 2 || mode == 3 ) { /* delete or update */
825         /* copy the rest */
826         rc = copy_all_packets( fp, newfp );
827         if( rc != -1 ) {
828             log_error("%s: copy to %s failed: %s\n",
829                       rentry->fname, tmpfname, g10_errstr(rc) );
830             iobuf_close(fp);
831             iobuf_cancel(newfp);
832             goto leave;
833         }
834         rc = 0;
835     }
836
837     /* close both files */
838     if( iobuf_close(fp) ) {
839         log_error("%s: close failed: %s\n", rentry->fname, strerror(errno) );
840         rc = G10ERR_CLOSE_FILE;
841         goto leave;
842     }
843     if( iobuf_close(newfp) ) {
844         log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
845         rc = G10ERR_CLOSE_FILE;
846         goto leave;
847     }
848     /* if the new file is a secring, restrict the permissions */
849     if( rentry->secret ) {
850         if( chmod( tmpfname, S_IRUSR | S_IWUSR ) ) {
851             log_error("%s: chmod failed: %s\n",
852                                     tmpfname, strerror(errno) );
853             rc = G10ERR_WRITE_FILE;
854             goto leave;
855         }
856     }
857     /* rename and make backup file */
858   #if __MINGW32__
859     remove( bakfname );
860   #endif
861     if( rename( rentry->fname, bakfname ) ) {
862         log_error("%s: rename to %s failed: %s\n",
863                                 rentry->fname, bakfname, strerror(errno) );
864         rc = G10ERR_RENAME_FILE;
865         goto leave;
866     }
867   #if __MINGW32__
868     remove( rentry->fname );
869   #endif
870     if( rename( tmpfname, rentry->fname ) ) {
871         log_error("%s: rename to %s failed: %s\n",
872                             tmpfname, rentry->fname,strerror(errno) );
873         rc = G10ERR_RENAME_FILE;
874         goto leave;
875     }
876
877   leave:
878     m_free(bakfname);
879     m_free(tmpfname);
880     return rc;
881 }
882
883
884 /****************************************************************
885  ********** Functions which operates on databases ***************
886  ****************************************************************/
887