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