* call-agent.c (start_agent): Make copies of old locales and check
[gnupg.git] / g10 / ringedit.c
1 /* ringedit.c -  Function for key ring editing
2  *      Copyright (C) 1998, 2000 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  */
39
40
41
42 #include <config.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <errno.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <unistd.h> /* for truncate */
50 #include <assert.h>
51
52 #include <gcrypt.h>
53 #include "util.h"
54 #include "packet.h"
55 #include "iobuf.h"
56 #include "keydb.h"
57 #include "host2net.h"
58 #include "options.h"
59 #include "main.h"
60 #include "i18n.h"
61 #include "kbx.h"
62
63
64
65
66 struct resource_table_struct {
67     int used;
68     int secret; /* this is a secret keyring */
69     char *fname;
70     IOBUF iobuf;
71     enum resource_type rt;
72     DOTLOCK lockhd;
73     int    is_locked;
74 };
75 typedef struct resource_table_struct RESTBL;
76
77
78 struct keyblock_pos_struct {
79     int   resno;     /* resource number */
80     enum resource_type rt;
81     ulong offset;    /* position information */
82     unsigned count;  /* length of the keyblock in packets */
83     IOBUF  fp;       /* used by enum_keyblocks */
84     int secret;      /* working on a secret keyring */
85     PACKET *pkt;     /* ditto */
86     int valid;
87     ulong save_offset;
88 };
89
90
91
92
93 #define MAX_RESOURCES 10
94 static RESTBL resource_table[MAX_RESOURCES];
95 static int default_public_resource;
96 static int default_secret_resource;
97
98 static int keyring_enum( KBPOS kbpos, KBNODE *ret_root, int skipsigs );
99 static int keyring_copy( KBPOS kbpos, int mode, KBNODE root );
100
101 static int do_kbxf_enum( KBPOS kbpos, KBNODE *ret_root, int skipsigs );
102 static int do_kbxf_copy( KBPOS kbpos, int mode, KBNODE root );
103
104
105 static RESTBL *
106 check_pos( KBPOS kbpos )
107 {
108     if( kbpos->resno < 0 || kbpos->resno >= MAX_RESOURCES )
109         return NULL;
110     if( !resource_table[kbpos->resno].used )
111         return NULL;
112     return resource_table + kbpos->resno;
113 }
114
115
116 /****************
117  * Hmmm, how to avoid deadlock? They should not happen if everyone
118  * locks the key resources in the same order; but who knows.
119  * A solution is to use only one lock file in the gnupg homedir but
120  * what will happen with key resources which normally don't belong
121  * to the gpg homedir?
122  */
123 static void
124 lock_rentry( RESTBL *rentry )
125 {
126     if( !rentry->lockhd ) {
127         rentry->lockhd = create_dotlock( rentry->fname );
128         if( !rentry->lockhd )
129             log_fatal("can't allocate lock for `%s'\n", rentry->fname );
130         rentry->is_locked = 0;
131     }
132     if( !rentry->is_locked ) {
133         if( make_dotlock( rentry->lockhd, -1 ) )
134             log_fatal("can't lock `%s'\n", rentry->fname );
135         rentry->is_locked = 1;
136     }
137 }
138
139 static void
140 unlock_rentry( RESTBL *rentry )
141 {
142     if( opt.lock_once )
143         return;
144     if( !release_dotlock( rentry->lockhd ) )
145         rentry->is_locked = 0;
146 }
147
148
149 /****************************************************************
150  ****************** public functions ****************************
151  ****************************************************************/
152
153 /****************
154  * Get the name of the keyrings, start with a sequence number pointing to a 0.
155  */
156 const char *
157 enum_keyblock_resources( int *sequence, int secret )
158 {
159     int i = *sequence;
160     const char *name = NULL;
161
162     for(; i < MAX_RESOURCES; i++ )
163         if( resource_table[i].used && !resource_table[i].secret == !secret ) {
164             if( resource_table[i].fname ) {
165                 name = resource_table[i].fname;
166                 break;
167             }
168         }
169     *sequence = ++i;
170     return name;
171 }
172
173
174 /****************
175  * Register a resource (which currently may only be a keyring file).
176  * The first keyring which is added by this function is
177  * created if it does not exist.
178  * Note: this function may be called before secure memory is
179  * available.
180  */
181 int
182 add_keyblock_resource( const char *url, int force, int secret )
183 {
184     static int any_secret, any_public;
185     const char *resname = url;
186     IOBUF iobuf = NULL;
187     int i;
188     char *filename = NULL;
189     int rc = 0;
190     enum resource_type rt = rt_UNKNOWN;
191
192
193     /* Do we have an URL?
194      *  gnupg-kbxf:filename  := this is a KBX file resource
195      *  gnupg-ring:filename  := this is a plain keyring
196      *  filename := See what is is, but create as plain keyring.
197      */
198     if( strlen( resname ) > 11 ) {
199         if( !strncmp( resname, "gnupg-ring:", 11 ) ) {
200             rt = rt_RING;
201             resname += 11;
202         }
203         else if( !strncmp( resname, "gnupg-kbxf:", 11 ) ) {
204             rt = rt_KBXF;
205             resname += 11;
206         }
207       #ifndef HAVE_DRIVE_LETTERS
208         else if( strchr( resname, ':' ) ) {
209             log_error("%s: invalid URL\n", url );
210             rc = GPGERR_GENERAL;
211             goto leave;
212         }
213       #endif
214     }
215
216     if( *resname != '/' ) { /* do tilde expansion etc */
217         if( strchr(resname, '/') )
218             filename = make_filename(resname, NULL);
219         else
220             filename = make_filename(opt.homedir, resname, NULL);
221     }
222     else
223         filename = gcry_xstrdup( resname );
224
225     if( !force )
226         force = secret? !any_secret : !any_public;
227
228     for(i=0; i < MAX_RESOURCES; i++ )
229         if( !resource_table[i].used )
230             break;
231     if( i == MAX_RESOURCES ) {
232         rc = GPGERR_RESOURCE_LIMIT;
233         goto leave;
234     }
235
236     /* see whether we can determine the filetype */
237     if( rt == rt_UNKNOWN ) {
238         FILE *fp = fopen( filename, "rb" );
239
240         if( fp ) {
241             u32 magic;
242
243             if( fread( &magic, 4, 1, fp) == 1 ) {
244                 char buf[8];
245
246                 rt = rt_RING;
247                 if( fread( buf, 8, 1, fp) == 1 ) {
248                     if( !memcmp( buf+4, "KBXf", 4 )
249                         && buf[0] == 1 && buf[1] == 1 ) {
250                         rt = rt_KBXF;
251                     }
252                 }
253                             }
254             else /* maybe empty: assume ring */
255                 rt = rt_RING;
256             fclose( fp );
257         }
258         else /* no file yet: create ring */
259             rt = rt_RING;
260     }
261
262     switch( rt ) {
263       case rt_UNKNOWN:
264         log_error("%s: unknown resource type\n", url );
265         rc = GPGERR_GENERAL;
266         goto leave;
267
268       case rt_RING:
269       case rt_KBXF:
270         iobuf = iobuf_open( filename );
271         if( !iobuf && !force ) {
272             rc = GPGERR_OPEN_FILE;
273             goto leave;
274         }
275
276         if( !iobuf ) {
277             char *last_slash_in_filename;
278
279             last_slash_in_filename = strrchr(filename, '/');
280             *last_slash_in_filename = 0;
281
282             if( access(filename, F_OK) ) {
283                 /* on the first time we try to create the default homedir and
284                  * in this case the process will be terminated, so that on the
285                  * next invocation it can read the options file in on startup
286                  */
287                 try_make_homedir( filename );
288                 rc = GPGERR_OPEN_FILE;
289                 goto leave;
290             }
291
292             *last_slash_in_filename = '/';
293
294             iobuf = iobuf_create( filename );
295             if( !iobuf ) {
296                 log_error(_("%s: can't create keyring: %s\n"),
297                                             filename, strerror(errno));
298                 rc = GPGERR_OPEN_FILE;
299                 goto leave;
300             }
301             else {
302               #ifndef HAVE_DOSISH_SYSTEM
303                 if( secret ) {
304                     if( chmod( filename, S_IRUSR | S_IWUSR ) ) {
305                         log_error("%s: chmod failed: %s\n",
306                                                 filename, strerror(errno) );
307                         rc = GPGERR_WRITE_FILE;
308                         goto leave;
309                     }
310                 }
311               #endif
312                 if( !opt.quiet )
313                     log_info(_("%s: keyring created\n"), filename );
314             }
315         }
316       #if HAVE_DOSISH_SYSTEM || 1
317         iobuf_close( iobuf );
318         iobuf = NULL;
319         /* must close it again */
320       #endif
321         break;
322
323
324       default:
325         log_error("%s: unsupported resource type\n", url );
326         rc = GPGERR_GENERAL;
327         goto leave;
328     }
329
330   #ifndef HAVE_DOSISH_SYSTEM
331   #if 0 /* fixme: check directory permissions and print a warning */
332     if( secret ) {
333     }
334   #endif
335   #endif
336
337     /* fixme: avoid duplicate resources */
338     resource_table[i].used = 1;
339     resource_table[i].secret = !!secret;
340     resource_table[i].fname = gcry_xstrdup(filename);
341     resource_table[i].iobuf = iobuf;
342     resource_table[i].rt    = rt;
343     if( secret )
344         default_secret_resource = i;
345     else
346         default_public_resource = i;
347
348   leave:
349     if( rc )
350         log_error("keyblock resource `%s': %s\n", filename, gpg_errstr(rc) );
351     else if( secret )
352         any_secret = 1;
353     else
354         any_public = 1;
355     gcry_free( filename );
356     return rc;
357 }
358
359 /****************
360  * Return the resource name of the keyblock associated with KBPOS.
361  */
362 const char *
363 keyblock_resource_name( KBPOS kbpos )
364 {
365     RESTBL *rentry;
366
367     if( !(rentry = check_pos( kbpos )) || !rentry->fname )
368         log_bug("no name for keyblock resource %d\n", kbpos->resno );
369     return rentry->fname;
370 }
371
372
373 /****************
374  * Get a keyblock handle KBPOS from a filename. This can be used
375  * to get a handle for insert_keyblock for a new keyblock.
376  * Using a filename of NULL returns the default resource
377  */
378 int
379 get_keyblock_handle( const char *filename, int secret, KBPOS kbpos )
380 {
381     int i = 0;
382
383     if( !filename )
384         i = secret? default_secret_resource : default_public_resource;
385
386     for(; i < MAX_RESOURCES; i++ ) {
387         if( resource_table[i].used && !resource_table[i].secret == !secret ) {
388             /* fixme: dos needs case insensitive file compare */
389             if( !filename || !strcmp( resource_table[i].fname, filename ) ) {
390                 memset( kbpos, 0, sizeof *kbpos );
391                 kbpos->resno = i;
392                 kbpos->rt = resource_table[i].rt;
393                 return 0;
394             }
395         }
396     }
397     return -1; /* not found */
398 }
399
400
401 /****************
402  * Return the filename of the firstkeyblock resource which is intended
403  * for write access. This will either be the default resource or in
404  * case this is not writable one of the others.  If no writable is found,
405  * the default filename in the homedirectory will be returned.
406  * Caller must free, will never return NULL.
407  */
408 char *
409 get_writable_keyblock_file( int secret )
410 {
411     int i = secret? default_secret_resource : default_public_resource;
412
413     if( resource_table[i].used && !resource_table[i].secret == !secret ) {
414         if( !access( resource_table[i].fname, R_OK|W_OK ) ) {
415             return gcry_xstrdup( resource_table[i].fname );
416         }
417     }
418     for(i=0; i < MAX_RESOURCES; i++ ) {
419         if( resource_table[i].used && !resource_table[i].secret == !secret ) {
420             if( !access( resource_table[i].fname, R_OK|W_OK ) ) {
421                 return gcry_xstrdup( resource_table[i].fname );
422             }
423         }
424     }
425     /* Assume the home dir is always writable */
426     return  make_filename(opt.homedir, secret? "secring.gpg"
427                                              : "pubring.gpg", NULL );
428 }
429
430
431 void
432 ringedit_copy_kbpos ( KBPOS d, KBPOS s )
433 {
434     *d = *s;
435 }
436
437
438 /****************
439  * Lock the keyblock; wait until it's available
440  * This function may change the internal data in kbpos, in cases
441  * when the keyblock to be locked has been modified.
442  * fixme: remove this function and add an option to search()?
443  */
444 static int
445 lock_keyblock( KBPOS kbpos )
446 {
447     if( !check_pos(kbpos) )
448         return GPGERR_GENERAL;
449     return 0;
450 }
451
452 /****************
453  * Release a lock on a keyblock
454  */
455 static void
456 unlock_keyblock( KBPOS kbpos )
457 {
458     if( !check_pos(kbpos) )
459         BUG();
460 }
461
462
463 static int
464 enum_keyrings_open_helper( KBPOS kbpos, int where )
465 {
466     int i = where;
467     RESTBL *rentry;
468
469     for(; i < MAX_RESOURCES; i++ )
470         if( resource_table[i].used
471             && !resource_table[i].secret == !kbpos->secret )
472             break;
473     if( i == MAX_RESOURCES ) 
474         return -1; /* no resources */
475     kbpos->resno = i;
476     rentry = check_pos( kbpos );
477     kbpos->rt = resource_table[i].rt;
478     kbpos->valid = 0;
479     switch( kbpos->rt ) {
480       case rt_RING:
481       case rt_KBXF:
482         kbpos->fp = iobuf_open( rentry->fname );
483         if ( !kbpos->fp ) {
484             log_error("can't open `%s'\n", rentry->fname );
485             return GPGERR_OPEN_FILE;
486         }
487         break;
488     
489        default: BUG();
490     }
491     kbpos->pkt = NULL;
492     return 0;
493 }
494
495
496 /****************
497  * This set of functions is used to scan over all keyrings.
498  * The mode in enum_keyblocks_next() is used liek this:
499  * Mode is: 1 = read
500  *          11 = read but skip signature and comment packets.
501  */
502 int
503 enum_keyblocks_begin( KBPOS *rkbpos, int use_secret )
504 {
505     int rc, i;
506     KBPOS kbpos;
507     
508     *rkbpos = NULL;
509
510     kbpos = gcry_xcalloc( 1, sizeof *kbpos );
511     kbpos->fp = NULL;
512     kbpos->rt = rt_UNKNOWN;
513     if( !use_secret ) {
514         kbpos->secret = 0;
515         i = 0;
516     }
517     else {
518         kbpos->secret = 1;
519         i = 0;
520     }
521     
522     rc = enum_keyrings_open_helper( kbpos, i );
523     if ( rc ) {
524         gcry_free( kbpos );
525         return rc;
526     }
527     /* return the handle */
528     *rkbpos = kbpos;
529     return 0;
530 }
531
532 void
533 enum_keyblocks_end( KBPOS kbpos )
534 {
535     if ( !kbpos )
536         return;
537     switch( kbpos->rt ) {
538      case rt_RING:
539      case rt_KBXF:
540        if( kbpos->fp ) {
541            iobuf_close( kbpos->fp );
542            kbpos->fp = NULL;
543        }
544        break;
545      case rt_UNKNOWN:
546        /* this happens when we have no keyring at all */
547        gcry_free( kbpos );
548        return;
549
550      default:
551        BUG();
552     }
553     /* release pending packet */
554     free_packet( kbpos->pkt );
555     gcry_free( kbpos->pkt );
556     gcry_free( kbpos );
557 }
558
559 int
560 enum_keyblocks_next( KBPOS kbpos, int mode, KBNODE *ret_root )
561 {
562     int cont, rc = 0;
563     RESTBL *rentry;
564
565     if( mode != 1 && mode != 11 ) 
566         return GPGERR_INV_ARG;
567
568     do {
569         cont = 0;
570         switch( kbpos->rt ) {
571           case rt_RING:
572             if( !kbpos->fp )
573                 return GPGERR_GENERAL;
574             rc = keyring_enum( kbpos, ret_root, mode == 11 );
575             break;
576           case rt_KBXF:
577             if( !kbpos->fp )
578                 return GPGERR_GENERAL;
579             rc = do_kbxf_enum( kbpos, ret_root, mode == 11 );
580             break;
581           default: BUG();
582         }
583
584         if( rc == -1 ) {
585             RESTBL *rentry;
586             int i;
587
588             assert( !kbpos->pkt );
589             rentry = check_pos( kbpos );
590             assert(rentry);
591             i = kbpos->resno+1;
592             /* first close */
593             if( kbpos->fp ) {
594                 iobuf_close( kbpos->fp );
595                 kbpos->fp = NULL;
596             }
597             free_packet( kbpos->pkt );
598             gcry_free( kbpos->pkt );
599             kbpos->pkt = NULL;
600             /* and then open the next one */
601             rc = enum_keyrings_open_helper( kbpos, i );
602             if ( !rc ) 
603                 cont = 1;
604             /* hmm, that is not really correct: if we got an error kbpos
605              * might be not well anymore */
606         }
607     } while(cont);
608
609     return rc;
610 }
611
612
613
614
615 /****************
616  * Insert the keyblock described by ROOT into the keyring described
617  * by KBPOS.  This actually appends the data to the keyfile.
618  */
619 int
620 insert_keyblock( KBNODE root )
621 {
622     int rc;
623 #if 0
624     if( !check_pos(kbpos) )
625         return GPGERR_GENERAL;
626
627     switch( kbpos->rt ) {
628       case rt_RING:
629         rc = keyring_copy( kbpos, 1, root );
630         break;
631       case rt_KBXF:
632         rc = do_kbxf_copy( kbpos, 1, root );
633         break;
634       default: BUG();
635     }
636 #endif
637     return rc;
638 }
639
640 /****************
641  * Delete the keyblock described by KBPOS.
642  * The current code simply changes the keyblock in the keyring
643  * to packet of type 0 with the correct length.  To help detect errors,
644  * zero bytes are written.
645  */
646 int
647 delete_keyblock( KBNODE keyblock )
648 {
649     int rc;
650   #if 0
651     if( !check_pos(kbpos) )
652         return GPGERR_GENERAL;
653
654     switch( kbpos->rt ) {
655       case rt_RING:
656         rc = keyring_copy( kbpos, 2, NULL );
657         break;
658       case rt_KBXF:
659         rc = do_kbxf_copy( kbpos, 2, NULL );
660         break;
661       default: BUG();
662     }
663   #endif
664     return rc;
665 }
666
667
668 /****************
669  * Update the keyblock in the ring (or whatever resource) one in ROOT.
670  */
671 int
672 update_keyblock( KBNODE root )
673 {
674     int rc;
675     struct keyblock_pos_struct kbpos;
676     
677     /* We need to get the file position of original keyblock first */
678     if ( root->pkt->pkttype == PKT_PUBLIC_KEY )
679         rc = find_kblocation_bypk( &kbpos, root->pkt->pkt.public_key );
680     else if ( root->pkt->pkttype == PKT_SECRET_KEY )
681         rc = find_kblocation_bysk( &kbpos, root->pkt->pkt.secret_key );
682     else
683         BUG();
684
685     if ( rc )
686         return rc;
687
688     if( !check_pos(&kbpos) )
689         return GPGERR_GENERAL;
690
691     switch( kbpos.rt ) {
692       case rt_RING:
693         rc = keyring_copy( &kbpos, 3, root );
694         break;
695       case rt_KBXF:
696         rc = do_kbxf_copy( &kbpos, 3, root );
697         break;
698       default: BUG();
699     }
700
701     return rc;
702 }
703
704
705 \f
706 /****************************************************************
707  ********** Functions which operates on regular keyrings ********
708  ****************************************************************/
709
710 static int
711 keyring_enum( KBPOS kbpos, KBNODE *ret_root, int skipsigs )
712 {
713     PACKET *pkt;
714     int rc;
715     RESTBL *rentry;
716     KBNODE root = NULL;
717     ulong offset, first_offset=0;
718
719     if( !(rentry=check_pos(kbpos)) )
720         return GPGERR_GENERAL;
721
722     if( kbpos->pkt ) {
723         root = new_kbnode( kbpos->pkt );
724         first_offset = kbpos->save_offset;
725         kbpos->pkt = NULL;
726     }
727     kbpos->valid = 0;
728
729     pkt = gcry_xmalloc( sizeof *pkt );
730     init_packet(pkt);
731     while( (rc=parse_packet(kbpos->fp, pkt, &offset )) != -1 ) {
732         if( rc ) {  /* ignore errors */
733             if( rc != GPGERR_UNKNOWN_PACKET ) {
734                 log_error("keyring_enum: read error: %s\n", gpg_errstr(rc) );
735                 rc = GPGERR_INV_KEYRING;
736                 goto ready;
737             }
738             free_packet( pkt );
739             init_packet( pkt );
740             continue;
741         }
742         /* make a linked list of all packets */
743         switch( pkt->pkttype ) {
744           case PKT_COMPRESSED:
745             log_error("skipped compressed packet in keyring\n" );
746             free_packet(pkt);
747             init_packet(pkt);
748             break;
749
750           case PKT_PUBLIC_KEY:
751           case PKT_SECRET_KEY:
752             if( root ) { /* save this packet */
753                 kbpos->pkt = pkt;
754                 kbpos->save_offset = offset;
755                 pkt = NULL;
756                 goto ready;
757             }
758             root = new_kbnode( pkt );
759             first_offset = offset;
760             pkt = gcry_xmalloc( sizeof *pkt );
761             init_packet(pkt);
762             break;
763
764           default:
765             /* skip pakets at the beginning of a keyring, until we find
766              * a start packet; issue a warning if it is not a comment */
767             if( !root && pkt->pkttype != PKT_COMMENT
768                       && pkt->pkttype != PKT_OLD_COMMENT ) {
769                 break;
770             }
771             if( !root || (skipsigs && ( pkt->pkttype == PKT_SIGNATURE
772                                       ||pkt->pkttype == PKT_COMMENT
773                                       ||pkt->pkttype == PKT_OLD_COMMENT )) ) {
774                 init_packet(pkt);
775                 break;
776             }
777             add_kbnode( root, new_kbnode( pkt ) );
778             pkt = gcry_xmalloc( sizeof *pkt );
779             init_packet(pkt);
780             break;
781         }
782     }
783   ready:
784     if( rc == -1 && root )
785         rc = 0;
786
787     if( rc )
788         release_kbnode( root );
789     else {
790         if ( root ) {
791             kbpos->offset = first_offset;
792             kbpos->valid = 1;
793         }
794         *ret_root = root;
795     }
796     free_packet( pkt );
797     gcry_free( pkt );
798
799     return rc;
800 }
801
802
803 /****************
804  * Perform insert/delete/update operation.
805  * mode 1 = insert
806  *      2 = delete
807  *      3 = update
808  */
809 static int
810 keyring_copy( KBPOS kbpos, int mode, KBNODE root )
811 {
812     RESTBL *rentry;
813     IOBUF fp, newfp;
814     int rc=0;
815     char *bakfname = NULL;
816     char *tmpfname = NULL;
817 #warning We need to lock the keyring while we are editing it.
818     /* rethink this whole module */
819
820     if( !(rentry = check_pos( kbpos )) )
821         return GPGERR_GENERAL;
822
823     if( opt.dry_run )
824         return 0;
825
826     lock_rentry( rentry );
827
828     /* open the source file */
829     if( kbpos->fp ) {
830         /* BUG(); not allowed with such a handle */
831         log_debug("keyring_copy: closing fp %p\n", kbpos->fp );
832         iobuf_close (kbpos->fp);
833         kbpos->fp = NULL;
834         kbpos->valid = 0;
835     }
836     fp = iobuf_open( rentry->fname );
837     if( mode == 1 && !fp && errno == ENOENT ) { /* no file yet */
838         KBNODE kbctx, node;
839
840         /* insert: create a new file */
841         newfp = iobuf_create( rentry->fname );
842         if( !newfp ) {
843             log_error(_("%s: can't create: %s\n"), rentry->fname, strerror(errno));
844             unlock_rentry( rentry );
845             return GPGERR_OPEN_FILE;
846         }
847         else if( !opt.quiet )
848             log_info(_("%s: keyring created\n"), rentry->fname );
849
850         kbctx=NULL;
851         while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
852             if( (rc = build_packet( newfp, node->pkt )) ) {
853                 log_error("build_packet(%d) failed: %s\n",
854                             node->pkt->pkttype, gpg_errstr(rc) );
855                 iobuf_cancel(newfp);
856                 unlock_rentry( rentry );
857                 return GPGERR_WRITE_FILE;
858             }
859         }
860         if( iobuf_close(newfp) ) {
861             log_error("%s: close failed: %s\n", rentry->fname, strerror(errno));
862             unlock_rentry( rentry );
863             return GPGERR_CLOSE_FILE;
864         }
865         if( chmod( rentry->fname, S_IRUSR | S_IWUSR ) ) {
866             log_error("%s: chmod failed: %s\n",
867                                     rentry->fname, strerror(errno) );
868             unlock_rentry( rentry );
869             return GPGERR_WRITE_FILE;
870         }
871         return 0;
872     }
873     if( !fp ) {
874         log_error("%s: can't open: %s\n", rentry->fname, strerror(errno) );
875         rc = GPGERR_OPEN_FILE;
876         goto leave;
877     }
878
879     /* create the new file */
880   #ifdef USE_ONLY_8DOT3
881     /* Here is another Windoze bug?:
882      * you cant rename("pubring.gpg.tmp", "pubring.gpg");
883      * but      rename("pubring.gpg.tmp", "pubring.aaa");
884      * works.  So we replace .gpg by .bak or .tmp
885      */
886     if( strlen(rentry->fname) > 4
887         && !strcmp(rentry->fname+strlen(rentry->fname)-4, ".gpg") ) {
888         bakfname = gcry_xmalloc( strlen( rentry->fname ) + 1 );
889         strcpy(bakfname,rentry->fname);
890         strcpy(bakfname+strlen(rentry->fname)-4, ".bak");
891         tmpfname = gcry_xmalloc( strlen( rentry->fname ) + 1 );
892         strcpy(tmpfname,rentry->fname);
893         strcpy(tmpfname+strlen(rentry->fname)-4, ".tmp");
894     }
895     else { /* file does not end with gpg; hmmm */
896         bakfname = gcry_xmalloc( strlen( rentry->fname ) + 5 );
897         strcpy(stpcpy(bakfname,rentry->fname),".bak");
898         tmpfname = gcry_xmalloc( strlen( rentry->fname ) + 5 );
899         strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
900     }
901   #else
902     bakfname = gcry_xmalloc( strlen( rentry->fname ) + 2 );
903     strcpy(stpcpy(bakfname,rentry->fname),"~");
904     tmpfname = gcry_xmalloc( strlen( rentry->fname ) + 5 );
905     strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
906   #endif
907     newfp = iobuf_create( tmpfname );
908     if( !newfp ) {
909         log_error("%s: can't create: %s\n", tmpfname, strerror(errno) );
910         iobuf_close(fp);
911         rc = GPGERR_OPEN_FILE;
912         goto leave;
913     }
914
915     if( mode == 1 ) { /* insert */
916         /* copy everything to the new file */
917         rc = copy_all_packets( fp, newfp );
918         if( rc != -1 ) {
919             log_error("%s: copy to %s failed: %s\n",
920                       rentry->fname, tmpfname, gpg_errstr(rc) );
921             iobuf_close(fp);
922             iobuf_cancel(newfp);
923             goto leave;
924         }
925         rc = 0;
926     }
927
928     if( mode == 2 || mode == 3 ) { /* delete or update */
929         /* copy first part to the new file */
930         rc = copy_some_packets( fp, newfp, kbpos->offset );
931         if( rc ) { /* should never get EOF here */
932             log_error("%s: copy to %s failed: %s\n",
933                       rentry->fname, tmpfname, gpg_errstr(rc) );
934             iobuf_close(fp);
935             iobuf_cancel(newfp);
936             goto leave;
937         }
938         /* skip this keyblock */
939         assert( kbpos->count );
940         rc = skip_some_packets( fp, kbpos->count );
941         if( rc ) {
942             log_error("%s: skipping %u packets failed: %s\n",
943                             rentry->fname, kbpos->count, gpg_errstr(rc));
944             iobuf_close(fp);
945             iobuf_cancel(newfp);
946             goto leave;
947         }
948     }
949
950     if( mode == 1 || mode == 3 ) { /* insert or update */
951         KBNODE kbctx, node;
952
953         /* append the new data */
954         kbctx=NULL;
955         while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
956             if( (rc = build_packet( newfp, node->pkt )) ) {
957                 log_error("build_packet(%d) failed: %s\n",
958                             node->pkt->pkttype, gpg_errstr(rc) );
959                 iobuf_close(fp);
960                 iobuf_cancel(newfp);
961                 rc = GPGERR_WRITE_FILE;
962                 goto leave;
963             }
964         }
965         kbpos->valid = 0;
966     }
967
968     if( mode == 2 || mode == 3 ) { /* delete or update */
969         /* copy the rest */
970         rc = copy_all_packets( fp, newfp );
971         if( rc != -1 ) {
972             log_error("%s: copy to %s failed: %s\n",
973                       rentry->fname, tmpfname, gpg_errstr(rc) );
974             iobuf_close(fp);
975             iobuf_cancel(newfp);
976             goto leave;
977         }
978         rc = 0;
979     }
980
981     /* close both files */
982     if( iobuf_close(fp) ) {
983         log_error("%s: close failed: %s\n", rentry->fname, strerror(errno) );
984         rc = GPGERR_CLOSE_FILE;
985         goto leave;
986     }
987     if( iobuf_close(newfp) ) {
988         log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
989         rc = GPGERR_CLOSE_FILE;
990         goto leave;
991     }
992     /* if the new file is a secring, restrict the permissions */
993   #ifndef HAVE_DOSISH_SYSTEM
994     if( rentry->secret ) {
995         if( chmod( tmpfname, S_IRUSR | S_IWUSR ) ) {
996             log_error("%s: chmod failed: %s\n",
997                                     tmpfname, strerror(errno) );
998             rc = GPGERR_WRITE_FILE;
999             goto leave;
1000         }
1001     }
1002   #endif
1003
1004     /* rename and make backup file */
1005     if( !rentry->secret ) {  /* but not for secret keyrings */
1006       #ifdef HAVE_DOSISH_SYSTEM
1007         remove( bakfname );
1008       #endif
1009         if( rename( rentry->fname, bakfname ) ) {
1010             log_error("%s: rename to %s failed: %s\n",
1011                                     rentry->fname, bakfname, strerror(errno) );
1012             rc = GPGERR_RENAME_FILE;
1013             goto leave;
1014         }
1015     }
1016   #ifdef HAVE_DOSISH_SYSTEM
1017     remove( rentry->fname );
1018   #endif
1019     if( rename( tmpfname, rentry->fname ) ) {
1020         log_error("%s: rename to %s failed: %s\n",
1021                             tmpfname, rentry->fname,strerror(errno) );
1022         rc = GPGERR_RENAME_FILE;
1023         if( rentry->secret ) {
1024             log_info(_(
1025                 "WARNING: 2 files with confidential information exists.\n"));
1026             log_info(_("%s is the unchanged one\n"), rentry->fname );
1027             log_info(_("%s is the new one\n"), tmpfname );
1028             log_info(_("Please fix this possible security flaw\n"));
1029         }
1030         goto leave;
1031     }
1032
1033   leave:
1034     unlock_rentry( rentry );
1035     gcry_free(bakfname);
1036     gcry_free(tmpfname);
1037     return rc;
1038 }
1039
1040 \f
1041 /****************************************************************
1042  ********** Functions which operate on KBX files ****************
1043  ****************************************************************/
1044
1045 static int
1046 do_kbxf_enum( KBPOS kbpos, KBNODE *ret_root, int skipsigs )
1047 {
1048     PACKET *pkt;
1049     int rc;
1050     RESTBL *rentry;
1051     KBNODE root = NULL;
1052
1053     if( !(rentry=check_pos(kbpos)) )
1054         return GPGERR_GENERAL;
1055
1056     if( kbpos->pkt ) {
1057         root = new_kbnode( kbpos->pkt );
1058         kbpos->pkt = NULL;
1059     }
1060
1061     pkt = gcry_xmalloc( sizeof *pkt );
1062     init_packet(pkt);
1063     while( (rc=parse_packet(kbpos->fp, pkt, NULL)) != -1 ) {
1064         if( rc ) {  /* ignore errors */
1065             if( rc != GPGERR_UNKNOWN_PACKET ) {
1066                 log_error("do_kbxf_enum: read error: %s\n", gpg_errstr(rc) );
1067                 rc = GPGERR_INV_KEYRING;
1068                 goto ready;
1069             }
1070             free_packet( pkt );
1071             init_packet( pkt );
1072             continue;
1073         }
1074         /* make a linked list of all packets */
1075         switch( pkt->pkttype ) {
1076           case PKT_COMPRESSED:
1077             log_error("skipped compressed packet in keyring\n" );
1078             free_packet(pkt);
1079             init_packet(pkt);
1080             break;
1081
1082           case PKT_PUBLIC_KEY:
1083           case PKT_SECRET_KEY:
1084             if( root ) { /* store this packet */
1085                 kbpos->pkt = pkt;
1086                 pkt = NULL;
1087                 goto ready;
1088             }
1089             root = new_kbnode( pkt );
1090             pkt = gcry_xmalloc( sizeof *pkt );
1091             init_packet(pkt);
1092             break;
1093
1094           default:
1095             /* skip pakets at the beginning of a keyring, until we find
1096              * a start packet; issue a warning if it is not a comment */
1097             if( !root && pkt->pkttype != PKT_COMMENT
1098                       && pkt->pkttype != PKT_OLD_COMMENT ) {
1099                 break;
1100             }
1101             if( !root || (skipsigs && ( pkt->pkttype == PKT_SIGNATURE
1102                                       ||pkt->pkttype == PKT_COMMENT
1103                                       ||pkt->pkttype == PKT_OLD_COMMENT )) ) {
1104                 init_packet(pkt);
1105                 break;
1106             }
1107             add_kbnode( root, new_kbnode( pkt ) );
1108             pkt = gcry_xmalloc( sizeof *pkt );
1109             init_packet(pkt);
1110             break;
1111         }
1112     }
1113   ready:
1114     if( rc == -1 && root )
1115         rc = 0;
1116
1117     if( rc )
1118         release_kbnode( root );
1119     else
1120         *ret_root = root;
1121     free_packet( pkt );
1122     gcry_free( pkt );
1123
1124     return rc;
1125 }
1126
1127
1128 /****************
1129  * Perform insert/delete/update operation.
1130  * mode 1 = insert
1131  *      2 = delete
1132  *      3 = update
1133  */
1134 static int
1135 do_kbxf_copy( KBPOS kbpos, int mode, KBNODE root )
1136 {
1137     RESTBL *rentry;
1138     IOBUF fp, newfp;
1139     int rc=0;
1140     char *bakfname = NULL;
1141     char *tmpfname = NULL;
1142
1143     if( !(rentry = check_pos( kbpos )) )
1144         return GPGERR_GENERAL;
1145     if( kbpos->fp )
1146         BUG(); /* not allowed with such a handle */
1147
1148     if( opt.dry_run )
1149         return 0;
1150
1151     lock_rentry( rentry );
1152
1153     /* open the source file */
1154     fp = iobuf_open( rentry->fname );
1155     if( mode == 1 && !fp && errno == ENOENT ) { /* no file yet */
1156         KBNODE kbctx, node;
1157
1158         /* insert: create a new file */
1159         newfp = iobuf_create( rentry->fname );
1160         if( !newfp ) {
1161             log_error(_("%s: can't create: %s\n"), rentry->fname, strerror(errno));
1162             unlock_rentry( rentry );
1163             return GPGERR_OPEN_FILE;
1164         }
1165         else if( !opt.quiet )
1166             log_info(_("%s: keyring created\n"), rentry->fname );
1167
1168         kbctx=NULL;
1169         while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
1170             if( (rc = build_packet( newfp, node->pkt )) ) {
1171                 log_error("build_packet(%d) failed: %s\n",
1172                             node->pkt->pkttype, gpg_errstr(rc) );
1173                 iobuf_cancel(newfp);
1174                 unlock_rentry( rentry );
1175                 return GPGERR_WRITE_FILE;
1176             }
1177         }
1178         if( iobuf_close(newfp) ) {
1179             log_error("%s: close failed: %s\n", rentry->fname, strerror(errno));
1180             unlock_rentry( rentry );
1181             return GPGERR_CLOSE_FILE;
1182         }
1183         if( chmod( rentry->fname, S_IRUSR | S_IWUSR ) ) {
1184             log_error("%s: chmod failed: %s\n",
1185                                     rentry->fname, strerror(errno) );
1186             unlock_rentry( rentry );
1187             return GPGERR_WRITE_FILE;
1188         }
1189         return 0;
1190     }
1191     if( !fp ) {
1192         log_error("%s: can't open: %s\n", rentry->fname, strerror(errno) );
1193         rc = GPGERR_OPEN_FILE;
1194         goto leave;
1195     }
1196
1197     /* create the new file */
1198   #ifdef USE_ONLY_8DOT3
1199     /* Here is another Windoze bug?:
1200      * you cant rename("pubring.gpg.tmp", "pubring.gpg");
1201      * but      rename("pubring.gpg.tmp", "pubring.aaa");
1202      * works.  So we replace .gpg by .bak or .tmp
1203      */
1204     if( strlen(rentry->fname) > 4
1205         && !strcmp(rentry->fname+strlen(rentry->fname)-4, ".gpg") ) {
1206         bakfname = gcry_xmalloc( strlen( rentry->fname ) + 1 );
1207         strcpy(bakfname,rentry->fname);
1208         strcpy(bakfname+strlen(rentry->fname)-4, ".bak");
1209         tmpfname = gcry_xmalloc( strlen( rentry->fname ) + 1 );
1210         strcpy(tmpfname,rentry->fname);
1211         strcpy(tmpfname+strlen(rentry->fname)-4, ".tmp");
1212     }
1213     else { /* file does not end with gpg; hmmm */
1214         bakfname = gcry_xmalloc( strlen( rentry->fname ) + 5 );
1215         strcpy(stpcpy(bakfname,rentry->fname),".bak");
1216         tmpfname = gcry_xmalloc( strlen( rentry->fname ) + 5 );
1217         strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
1218     }
1219   #else
1220     bakfname = gcry_xmalloc( strlen( rentry->fname ) + 2 );
1221     strcpy(stpcpy(bakfname,rentry->fname),"~");
1222     tmpfname = gcry_xmalloc( strlen( rentry->fname ) + 5 );
1223     strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
1224   #endif
1225     newfp = iobuf_create( tmpfname );
1226     if( !newfp ) {
1227         log_error("%s: can't create: %s\n", tmpfname, strerror(errno) );
1228         iobuf_close(fp);
1229         rc = GPGERR_OPEN_FILE;
1230         goto leave;
1231     }
1232
1233     if( mode == 1 ) { /* insert */
1234         /* copy everything to the new file */
1235         rc = copy_all_packets( fp, newfp );
1236         if( rc != -1 ) {
1237             log_error("%s: copy to %s failed: %s\n",
1238                       rentry->fname, tmpfname, gpg_errstr(rc) );
1239             iobuf_close(fp);
1240             iobuf_cancel(newfp);
1241             goto leave;
1242         }
1243         rc = 0;
1244     }
1245
1246     if( mode == 2 || mode == 3 ) { /* delete or update */
1247         /* copy first part to the new file */
1248         rc = copy_some_packets( fp, newfp, kbpos->offset );
1249         if( rc ) { /* should never get EOF here */
1250             log_error("%s: copy to %s failed: %s\n",
1251                       rentry->fname, tmpfname, gpg_errstr(rc) );
1252             iobuf_close(fp);
1253             iobuf_cancel(newfp);
1254             goto leave;
1255         }
1256         /* skip this keyblock */
1257         assert( kbpos->count );
1258         rc = skip_some_packets( fp, kbpos->count );
1259         if( rc ) {
1260             log_error("%s: skipping %u packets failed: %s\n",
1261                             rentry->fname, kbpos->count, gpg_errstr(rc));
1262             iobuf_close(fp);
1263             iobuf_cancel(newfp);
1264             goto leave;
1265         }
1266     }
1267
1268     if( mode == 1 || mode == 3 ) { /* insert or update */
1269         KBNODE kbctx, node;
1270
1271         /* append the new data */
1272         kbctx=NULL;
1273         while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
1274             if( (rc = build_packet( newfp, node->pkt )) ) {
1275                 log_error("build_packet(%d) failed: %s\n",
1276                             node->pkt->pkttype, gpg_errstr(rc) );
1277                 iobuf_close(fp);
1278                 iobuf_cancel(newfp);
1279                 rc = GPGERR_WRITE_FILE;
1280                 goto leave;
1281             }
1282         }
1283         kbpos->valid = 0;
1284     }
1285
1286     if( mode == 2 || mode == 3 ) { /* delete or update */
1287         /* copy the rest */
1288         rc = copy_all_packets( fp, newfp );
1289         if( rc != -1 ) {
1290             log_error("%s: copy to %s failed: %s\n",
1291                       rentry->fname, tmpfname, gpg_errstr(rc) );
1292             iobuf_close(fp);
1293             iobuf_cancel(newfp);
1294             goto leave;
1295         }
1296         rc = 0;
1297     }
1298
1299     /* close both files */
1300     if( iobuf_close(fp) ) {
1301         log_error("%s: close failed: %s\n", rentry->fname, strerror(errno) );
1302         rc = GPGERR_CLOSE_FILE;
1303         goto leave;
1304     }
1305     if( iobuf_close(newfp) ) {
1306         log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
1307         rc = GPGERR_CLOSE_FILE;
1308         goto leave;
1309     }
1310     /* if the new file is a secring, restrict the permissions */
1311   #ifndef HAVE_DOSISH_SYSTEM
1312     if( rentry->secret ) {
1313         if( chmod( tmpfname, S_IRUSR | S_IWUSR ) ) {
1314             log_error("%s: chmod failed: %s\n",
1315                                     tmpfname, strerror(errno) );
1316             rc = GPGERR_WRITE_FILE;
1317             goto leave;
1318         }
1319     }
1320   #endif
1321
1322     /* rename and make backup file */
1323     if( !rentry->secret ) {  /* but not for secret keyrings */
1324       #ifdef HAVE_DOSISH_SYSTEM
1325         remove( bakfname );
1326       #endif
1327         if( rename( rentry->fname, bakfname ) ) {
1328             log_error("%s: rename to %s failed: %s\n",
1329                                     rentry->fname, bakfname, strerror(errno) );
1330             rc = GPGERR_RENAME_FILE;
1331             goto leave;
1332         }
1333     }
1334   #ifdef HAVE_DOSISH_SYSTEM
1335     remove( rentry->fname );
1336   #endif
1337     if( rename( tmpfname, rentry->fname ) ) {
1338         log_error("%s: rename to %s failed: %s\n",
1339                             tmpfname, rentry->fname,strerror(errno) );
1340         rc = GPGERR_RENAME_FILE;
1341         if( rentry->secret ) {
1342             log_info(_(
1343                 "WARNING: 2 files with confidential information exists.\n"));
1344             log_info(_("%s is the unchanged one\n"), rentry->fname );
1345             log_info(_("%s is the new one\n"), tmpfname );
1346             log_info(_("Please fix this possible security flaw\n"));
1347         }
1348         goto leave;
1349     }
1350
1351   leave:
1352     unlock_rentry( rentry );
1353     gcry_free(bakfname);
1354     gcry_free(tmpfname);
1355     return rc;
1356 }
1357
1358
1359
1360