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