~ubuntu-branches/ubuntu/precise/gnupg2/precise-proposed

« back to all changes in this revision

Viewing changes to g10/ringedit.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Urlichs
  • Date: 2006-01-24 04:31:42 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060124043142-pbg192or6qxv3yk2
Tags: 1.9.20-1
* New Upstream version. Closes:#306890,#344530
  * Closes:#320490: gpg-protect-tool fails to decrypt PKCS-12 files 
* Depend on libopensc2-dev, not -1-. Closes:#348106

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
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
 
 
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