~ubuntu-branches/ubuntu/karmic/gnupg2/karmic-security

« back to all changes in this revision

Viewing changes to g10/ringedit.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Viehmann
  • Date: 2008-10-04 10:25:53 UTC
  • mfrom: (5.1.15 intrepid)
  • Revision ID: james.westby@ubuntu.com-20081004102553-fv62pp8dsitxli47
Tags: 2.0.9-3.1
* Non-maintainer upload.
* agent/gpg-agent.c: Deinit the threading library before exec'ing
  the command to run in --daemon mode. And because that still doesn't
  restore the sigprocmask, do that manually. Closes: #499569

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