partly added creation of OP partial length headers
[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_UNKNOWN_PACKET ) {
579                 log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
580                 rc = G10ERR_INV_KEYRING;
581                 goto ready;
582             }
583             kbpos->count++;
584             free_packet( pkt );
585             init_packet( pkt );
586             continue;
587         }
588         /* make a linked list of all packets */
589         switch( pkt->pkttype ) {
590           case PKT_PUBLIC_KEY:
591           case PKT_SECRET_KEY:
592             if( in_cert )
593                 goto ready;
594             in_cert = 1;
595           default:
596             kbpos->count++;
597             if( !root )
598                 root = new_kbnode( pkt );
599             else
600                 add_kbnode( root, new_kbnode( pkt ) );
601             pkt = m_alloc( sizeof *pkt );
602             init_packet(pkt);
603             break;
604         }
605     }
606   ready:
607     if( rc == -1 && root )
608         rc = 0;
609
610     if( rc )
611         release_kbnode( root );
612     else
613         *ret_root = root;
614     free_packet( pkt );
615     m_free( pkt );
616     iobuf_close(a);
617     return rc;
618 }
619
620
621 static int
622 keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs )
623 {
624     PACKET *pkt;
625     int rc;
626     RESTBL *rentry;
627     KBNODE root = NULL;
628
629     if( !(rentry=check_pos(kbpos)) )
630         return G10ERR_GENERAL;
631
632     if( kbpos->pkt ) {
633         root = new_kbnode( kbpos->pkt );
634         kbpos->pkt = NULL;
635     }
636
637     pkt = m_alloc( sizeof *pkt );
638     init_packet(pkt);
639     while( (rc=parse_packet(kbpos->fp, pkt)) != -1 ) {
640         if( rc ) {  /* ignore errors */
641             if( rc != G10ERR_UNKNOWN_PACKET ) {
642                 log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
643                 rc = G10ERR_INV_KEYRING;
644                 goto ready;
645             }
646             free_packet( pkt );
647             init_packet( pkt );
648             continue;
649         }
650         /* make a linked list of all packets */
651         switch( pkt->pkttype ) {
652           case PKT_PUBLIC_KEY:
653           case PKT_SECRET_KEY:
654             if( root ) { /* store this packet */
655                 kbpos->pkt = pkt;
656                 pkt = NULL;
657                 goto ready;
658             }
659             root = new_kbnode( pkt );
660             pkt = m_alloc( sizeof *pkt );
661             init_packet(pkt);
662             break;
663
664           default:
665             /* skip pakets at the beginning of a keyring, until we find
666              * a start packet; issue a warning if it is not a comment */
667             if( !root && pkt->pkttype != PKT_COMMENT
668                       && pkt->pkttype != PKT_OLD_COMMENT )
669                 log_info("keyring_enum: skipped packet of type %d\n",
670                             pkt->pkttype );
671             if( !root || (skipsigs && ( pkt->pkttype == PKT_SIGNATURE
672                                       ||pkt->pkttype == PKT_COMMENT
673                                       ||pkt->pkttype == PKT_OLD_COMMENT )) ) {
674                 init_packet(pkt);
675                 break;
676             }
677             add_kbnode( root, new_kbnode( pkt ) );
678             pkt = m_alloc( sizeof *pkt );
679             init_packet(pkt);
680             break;
681         }
682     }
683   ready:
684     if( rc == -1 && root )
685         rc = 0;
686
687     if( rc )
688         release_kbnode( root );
689     else
690         *ret_root = root;
691     free_packet( pkt );
692     m_free( pkt );
693     return rc;
694 }
695
696
697
698 /****************
699  * Perform insert/delete/update operation.
700  * mode 1 = insert
701  *      2 = delete
702  *      3 = update
703  */
704 static int
705 keyring_copy( KBPOS *kbpos, int mode, KBNODE root )
706 {
707     RESTBL *rentry;
708     IOBUF fp, newfp;
709     int rc=0;
710     char *bakfname = NULL;
711     char *tmpfname = NULL;
712
713     if( !(rentry = check_pos( kbpos )) )
714         return G10ERR_GENERAL;
715     if( kbpos->fp )
716         BUG(); /* not allowed with such a handle */
717
718     /* open the source file */
719     fp = iobuf_open( rentry->fname );
720     if( mode == 1 && !fp && errno == ENOENT ) { /* no file yet */
721         KBNODE kbctx, node;
722
723         /* insert: create a new file */
724         newfp = iobuf_create( rentry->fname );
725         if( !newfp ) {
726             log_error("%s: can't create: %s\n", rentry->fname, strerror(errno));
727             return G10ERR_OPEN_FILE;
728         }
729
730         kbctx=NULL;
731         while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
732             if( (rc = build_packet( newfp, node->pkt )) ) {
733                 log_error("build_packet(%d) failed: %s\n",
734                             node->pkt->pkttype, g10_errstr(rc) );
735                 iobuf_cancel(newfp);
736                 return G10ERR_WRITE_FILE;
737             }
738         }
739         if( iobuf_close(newfp) ) {
740             log_error("%s: close failed: %s\n", rentry->fname, strerror(errno));
741             return G10ERR_CLOSE_FILE;
742         }
743         if( chmod( rentry->fname, S_IRUSR | S_IWUSR ) ) {
744             log_error("%s: chmod failed: %s\n",
745                                     rentry->fname, strerror(errno) );
746             return G10ERR_WRITE_FILE;
747         }
748         return 0;
749     }
750     if( !fp ) {
751         log_error("%s: can't open: %s\n", rentry->fname, strerror(errno) );
752         rc = G10ERR_OPEN_FILE;
753         goto leave;
754     }
755
756     /* create the new file */
757     bakfname = m_alloc( strlen( rentry->fname ) + 2 );
758     strcpy(stpcpy(bakfname,rentry->fname),"~");
759     tmpfname = m_alloc( strlen( rentry->fname ) + 5 );
760     strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
761     newfp = iobuf_create( tmpfname );
762     if( !newfp ) {
763         log_error("%s: can't create: %s\n", tmpfname, strerror(errno) );
764         iobuf_close(fp);
765         rc = G10ERR_OPEN_FILE;
766         goto leave;
767     }
768
769     if( mode == 1 ) { /* insert */
770         /* copy everything to the new file */
771         rc = copy_all_packets( fp, newfp );
772         if( rc != -1 ) {
773             log_error("%s: copy to %s failed: %s\n",
774                       rentry->fname, tmpfname, g10_errstr(rc) );
775             iobuf_close(fp);
776             iobuf_cancel(newfp);
777             goto leave;
778         }
779         rc = 0;
780     }
781
782     if( mode == 2 || mode == 3 ) { /* delete or update */
783         /* copy first part to the new file */
784         rc = copy_some_packets( fp, newfp, kbpos->offset );
785         if( rc ) { /* should never get EOF here */
786             log_error("%s: copy to %s failed: %s\n",
787                       rentry->fname, tmpfname, g10_errstr(rc) );
788             iobuf_close(fp);
789             iobuf_cancel(newfp);
790             goto leave;
791         }
792         /* skip this keyblock */
793         assert( kbpos->count );
794         rc = skip_some_packets( fp, kbpos->count );
795         if( rc ) {
796             log_error("%s: skipping %u packets failed: %s\n",
797                             rentry->fname, kbpos->count, g10_errstr(rc));
798             iobuf_close(fp);
799             iobuf_cancel(newfp);
800             goto leave;
801         }
802     }
803
804     if( mode == 1 || mode == 3 ) { /* insert or update */
805         KBNODE kbctx, node;
806
807         /* append the new data */
808         kbctx=NULL;
809         while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
810             if( (rc = build_packet( newfp, node->pkt )) ) {
811                 log_error("build_packet(%d) failed: %s\n",
812                             node->pkt->pkttype, g10_errstr(rc) );
813                 iobuf_close(fp);
814                 iobuf_cancel(newfp);
815                 rc = G10ERR_WRITE_FILE;
816                 goto leave;
817             }
818         }
819     }
820
821     if( mode == 2 || mode == 3 ) { /* delete or update */
822         /* copy the rest */
823         rc = copy_all_packets( fp, newfp );
824         if( rc != -1 ) {
825             log_error("%s: copy to %s failed: %s\n",
826                       rentry->fname, tmpfname, g10_errstr(rc) );
827             iobuf_close(fp);
828             iobuf_cancel(newfp);
829             goto leave;
830         }
831         rc = 0;
832     }
833
834     /* close both files */
835     if( iobuf_close(fp) ) {
836         log_error("%s: close failed: %s\n", rentry->fname, strerror(errno) );
837         rc = G10ERR_CLOSE_FILE;
838         goto leave;
839     }
840     if( iobuf_close(newfp) ) {
841         log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
842         rc = G10ERR_CLOSE_FILE;
843         goto leave;
844     }
845     /* if the new file is a secring, restrict the permissions */
846     if( rentry->secret ) {
847         if( chmod( tmpfname, S_IRUSR | S_IWUSR ) ) {
848             log_error("%s: chmod failed: %s\n",
849                                     tmpfname, strerror(errno) );
850             rc = G10ERR_WRITE_FILE;
851             goto leave;
852         }
853     }
854     /* rename and make backup file */
855   #if __MINGW32__
856     remove( bakfname );
857   #endif
858     if( rename( rentry->fname, bakfname ) ) {
859         log_error("%s: rename to %s failed: %s\n",
860                                 rentry->fname, bakfname, strerror(errno) );
861         rc = G10ERR_RENAME_FILE;
862         goto leave;
863     }
864   #if __MINGW32__
865     remove( rentry->fname );
866   #endif
867     if( rename( tmpfname, rentry->fname ) ) {
868         log_error("%s: rename to %s failed: %s\n",
869                             tmpfname, rentry->fname,strerror(errno) );
870         rc = G10ERR_RENAME_FILE;
871         goto leave;
872     }
873
874   leave:
875     m_free(bakfname);
876     m_free(tmpfname);
877     return rc;
878 }
879
880
881 /****************************************************************
882  ********** Functions which operates on databases ***************
883  ****************************************************************/
884