See ChangeLog: Tue Oct 26 14:10:21 CEST 1999 Werner Koch
[gnupg.git] / g10 / ringedit.c
1 /* ringedit.c -  Function for key ring editing
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21
22 /****************
23  * This module supplies function for:
24  *
25  *  - Search for a key block (pubkey and all other stuff) and return a
26  *    handle for it.
27  *
28  *  - Lock/Unlock a key block
29  *
30  *  - Read a key block into a tree
31  *
32  *  - Update a key block
33  *
34  *  - Insert a new key block
35  *
36  *  - Delete a key block
37  *
38  */
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 #ifdef HAVE_LIBGDBM
52   #include <gdbm.h>
53 #endif
54 #include "util.h"
55 #include "packet.h"
56 #include "memory.h"
57 #include "mpi.h"
58 #include "iobuf.h"
59 #include "keydb.h"
60 #include "host2net.h"
61 #include "options.h"
62 #include "main.h"
63 #include "i18n.h"
64
65
66 #ifdef MKDIR_TAKES_ONE_ARG
67 # undef mkdir
68 # define mkdir(a,b) mkdir(a)
69 #endif
70
71
72 struct resource_table_struct {
73     int used;
74     int secret; /* this is a secret keyring */
75     char *fname;
76     IOBUF iobuf;
77   #ifdef HAVE_LIBGDBM
78     GDBM_FILE dbf;
79   #endif
80     enum resource_type rt;
81     DOTLOCK lockhd;
82     int    is_locked;
83 };
84 typedef struct resource_table_struct RESTBL;
85
86 #define MAX_RESOURCES 10
87 static RESTBL resource_table[MAX_RESOURCES];
88 static int default_public_resource;
89 static int default_secret_resource;
90
91 static int search( PACKET *pkt, KBPOS *kbpos, int secret );
92
93
94 static int keyring_search( PACKET *pkt, KBPOS *kbpos, IOBUF iobuf,
95                                                 const char *fname );
96 static int keyring_read( KBPOS *kbpos, KBNODE *ret_root );
97 static int keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs );
98 static int keyring_copy( KBPOS *kbpos, int mode, KBNODE root );
99
100 #ifdef HAVE_LIBGDBM
101 static int do_gdbm_store( KBPOS *kbpos, KBNODE root, int update );
102 static int do_gdbm_locate( GDBM_FILE dbf, KBPOS *kbpos,
103                                           const byte *fpr, int fprlen );
104 static int do_gdbm_locate_by_keyid( GDBM_FILE dbf, KBPOS *kbpos, u32 *keyid );
105 static int do_gdbm_read( KBPOS *kbpos, KBNODE *ret_root );
106 static int do_gdbm_enum( KBPOS *kbpos, KBNODE *ret_root );
107 #endif
108
109
110 static RESTBL *
111 check_pos( KBPOS *kbpos )
112 {
113     if( kbpos->resno < 0 || kbpos->resno >= MAX_RESOURCES )
114         return NULL;
115     if( !resource_table[kbpos->resno].used )
116         return NULL;
117     return resource_table + kbpos->resno;
118 }
119
120 #ifdef HAVE_LIBGDBM
121 static void
122 fatal_gdbm_error( const char *string )
123 {
124     log_fatal("gdbm failed: %s\n", string);
125 }
126
127 #endif /* HAVE_LIBGDBM */
128
129
130 /****************
131  * Hmmm, how to avoid deadlock? They should not happen if everyone
132  * locks the key resources in the same order; but who knows.
133  * A solution is to use only one lock file in the gnupg homedir but
134  * what will happen with key resources which normally don't belong
135  * to the gpg homedir?
136  */
137 static void
138 lock_rentry( RESTBL *rentry )
139 {
140     if( !rentry->lockhd ) {
141         rentry->lockhd = create_dotlock( rentry->fname );
142         if( !rentry->lockhd )
143             log_fatal("can't allocate lock for `%s'\n", rentry->fname );
144         rentry->is_locked = 0;
145     }
146     if( !rentry->is_locked ) {
147         if( make_dotlock( rentry->lockhd, -1 ) )
148             log_fatal("can't lock `%s'\n", rentry->fname );
149         rentry->is_locked = 1;
150     }
151 }
152
153 static void
154 unlock_rentry( RESTBL *rentry )
155 {
156     if( opt.lock_once )
157         return;
158     if( !release_dotlock( rentry->lockhd ) )
159         rentry->is_locked = 0;
160 }
161
162
163 /****************************************************************
164  ****************** public functions ****************************
165  ****************************************************************/
166
167 /****************
168  * Get the name of the keyrings, start with a sequence number pointing to a 0.
169  */
170 const char *
171 enum_keyblock_resources( int *sequence, int secret )
172 {
173     int i = *sequence;
174     const char *name = NULL;
175
176     for(; i < MAX_RESOURCES; i++ )
177         if( resource_table[i].used && !resource_table[i].secret == !secret ) {
178             if( resource_table[i].fname ) {
179                 name = resource_table[i].fname;
180                 break;
181             }
182         }
183     *sequence = ++i;
184     return name;
185 }
186
187
188
189 /****************
190  * Register a resource (which currently may only be a keyring file).
191  * The first keyring which is added by this function is
192  * created if it does not exist.
193  * Note: this function may be called before secure memory is
194  * available.
195  */
196 int
197 add_keyblock_resource( const char *url, int force, int secret )
198 {
199     static int any_secret, any_public;
200     const char *resname = url;
201     IOBUF iobuf = NULL;
202     int i;
203     char *filename = NULL;
204     int rc = 0;
205     enum resource_type rt = rt_UNKNOWN;
206
207
208     /* Do we have an URL?
209      *  gnupg-gdbm:filename  := this is a GDBM resource
210      *  gnupg-ring:filename  := this is a plain keyring
211      *  filename := See what is is, but create as plain keyring.
212      */
213     if( strlen( resname ) > 11 ) {
214         if( !strncmp( resname, "gnupg-ring:", 11 ) ) {
215             rt = rt_RING;
216             resname += 11;
217         }
218         else if( !strncmp( resname, "gnupg-gdbm:", 11 ) ) {
219             rt = rt_GDBM;
220             resname += 11;
221         }
222       #ifndef HAVE_DRIVE_LETTERS
223         else if( strchr( resname, ':' ) ) {
224             log_error("%s: invalid URL\n", url );
225             rc = G10ERR_GENERAL;
226             goto leave;
227         }
228       #endif
229     }
230
231     if( *resname != '/' ) { /* do tilde expansion etc */
232         if( strchr(resname, '/') )
233             filename = make_filename(resname, NULL);
234         else
235             filename = make_filename(opt.homedir, resname, NULL);
236     }
237     else
238         filename = m_strdup( resname );
239
240     if( !force )
241         force = secret? !any_secret : !any_public;
242
243     for(i=0; i < MAX_RESOURCES; i++ )
244         if( !resource_table[i].used )
245             break;
246     if( i == MAX_RESOURCES ) {
247         rc = G10ERR_RESOURCE_LIMIT;
248         goto leave;
249     }
250
251     /* see whether we can determine the filetype */
252     if( rt == rt_UNKNOWN ) {
253         FILE *fp = fopen( filename, "rb" );
254
255         if( fp ) {
256             u32 magic;
257
258             if( fread( &magic, 4, 1, fp) == 1 ) {
259                 if( magic == 0x13579ace )
260                     rt = rt_GDBM;
261                 else if( magic == 0xce9a5713 )
262                     log_error("%s: endianess does not match\n", url );
263                 else
264                     rt = rt_RING;
265             }
266             else /* maybe empty: assume ring */
267                 rt = rt_RING;
268             fclose( fp );
269         }
270         else /* no file yet: create ring */
271             rt = rt_RING;
272     }
273
274     switch( rt ) {
275       case rt_UNKNOWN:
276         log_error("%s: unknown resource type\n", url );
277         rc = G10ERR_GENERAL;
278         goto leave;
279
280       case rt_RING:
281         iobuf = iobuf_open( filename );
282         if( !iobuf && !force ) {
283             rc = G10ERR_OPEN_FILE;
284             goto leave;
285         }
286
287         if( !iobuf ) {
288             char *last_slash_in_filename;
289
290             last_slash_in_filename = strrchr(filename, '/');
291             *last_slash_in_filename = 0;
292
293             if( access(filename, F_OK) ) {
294                 if( strlen(filename) >= 7
295                     && !strcmp(filename+strlen(filename)-7, "/.gnupg") ) {
296                     if( mkdir(filename, S_IRUSR|S_IWUSR|S_IXUSR) )
297                     {
298                         log_error( _("%s: can't create directory: %s\n"),
299                                   filename, strerror(errno));
300                         rc = G10ERR_OPEN_FILE;
301                         goto leave;
302                     }
303                     else if( !opt.quiet )
304                         log_info( _("%s: directory created\n"), filename );
305                     copy_options_file( filename );
306                 }
307                 else
308                 {
309                     rc = G10ERR_OPEN_FILE;
310                     goto leave;
311                 }
312             }
313
314             *last_slash_in_filename = '/';
315
316             iobuf = iobuf_create( filename );
317             if( !iobuf ) {
318                 log_error(_("%s: can't create keyring: %s\n"),
319                                             filename, strerror(errno));
320                 rc = G10ERR_OPEN_FILE;
321                 goto leave;
322             }
323             else {
324               #ifndef HAVE_DOSISH_SYSTEM
325                 if( secret ) {
326                     if( chmod( filename, S_IRUSR | S_IWUSR ) ) {
327                         log_error("%s: chmod failed: %s\n",
328                                                 filename, strerror(errno) );
329                         rc = G10ERR_WRITE_FILE;
330                         goto leave;
331                     }
332                 }
333               #endif
334                 if( !opt.quiet )
335                     log_info(_("%s: keyring created\n"), filename );
336             }
337         }
338       #if HAVE_DOSISH_SYSTEM || 1
339         iobuf_close( iobuf );
340         iobuf = NULL;
341         /* must close it again */
342       #endif
343         break;
344
345     #ifdef HAVE_LIBGDBM
346       case rt_GDBM:
347         resource_table[i].dbf = gdbm_open( filename, 0,
348                                            force? GDBM_WRCREAT : GDBM_WRITER,
349                                            S_IRUSR | S_IWUSR |
350                                            S_IRGRP | S_IWGRP | S_IROTH,
351                                            fatal_gdbm_error );
352         if( !resource_table[i].dbf ) {
353             log_error("%s: can't open gdbm file: %s\n",
354                             filename, gdbm_strerror(gdbm_errno));
355             rc = G10ERR_OPEN_FILE;
356             goto leave;
357         }
358         break;
359     #endif
360
361       default:
362         log_error("%s: unsupported resource type\n", url );
363         rc = G10ERR_GENERAL;
364         goto leave;
365     }
366
367   #ifndef HAVE_DOSISH_SYSTEM
368   #if 0 /* fixme: check directory permissions and print a warning */
369     if( secret ) {
370     }
371   #endif
372   #endif
373
374     /* fixme: avoid duplicate resources */
375     resource_table[i].used = 1;
376     resource_table[i].secret = !!secret;
377     resource_table[i].fname = m_strdup(filename);
378     resource_table[i].iobuf = iobuf;
379     resource_table[i].rt    = rt;
380     if( secret )
381         default_secret_resource = i;
382     else
383         default_public_resource = i;
384
385   leave:
386     if( rc )
387         log_error("keyblock resource `%s': %s\n", filename, g10_errstr(rc) );
388     else if( secret )
389         any_secret = 1;
390     else
391         any_public = 1;
392     m_free( filename );
393     return rc;
394 }
395
396 /****************
397  * Return the resource name of the keyblock associated with KBPOS.
398  */
399 const char *
400 keyblock_resource_name( KBPOS *kbpos )
401 {
402     RESTBL *rentry;
403
404     if( !(rentry = check_pos( kbpos )) || !rentry->fname )
405         log_bug("no name for keyblock resource %d\n", kbpos->resno );
406     return rentry->fname;
407 }
408
409
410 /****************
411  * Get a keyblock handle KBPOS from a filename. This can be used
412  * to get a handle for insert_keyblock for a new keyblock.
413  * Using a filename of NULL returns the default resource
414  */
415 int
416 get_keyblock_handle( const char *filename, int secret, KBPOS *kbpos )
417 {
418     int i = 0;
419
420     if( !filename )
421         i = secret? default_secret_resource : default_public_resource;
422
423     for(; i < MAX_RESOURCES; i++ ) {
424         if( resource_table[i].used && !resource_table[i].secret == !secret ) {
425             /* fixme: dos needs case insensitive file compare */
426             if( !filename || !strcmp( resource_table[i].fname, filename ) ) {
427                 memset( kbpos, 0, sizeof *kbpos );
428                 kbpos->resno = i;
429                 kbpos->rt = resource_table[i].rt;
430                 return 0;
431             }
432         }
433     }
434     return -1; /* not found */
435 }
436
437
438
439 /****************
440  * Search a keyblock which starts with the given packet and puts all
441  * information into KBPOS, which can be used later to access this key block.
442  * This function looks into all registered keyblock sources.
443  * PACKET must be a packet with either a secret_key or a public_key
444  *
445  * This function is intended to check whether a given certificate
446  * is already in a keyring or to prepare it for editing.
447  *
448  * Returns: 0 if found, -1 if not found or an errorcode.
449  */
450 static int
451 search( PACKET *pkt, KBPOS *kbpos, int secret )
452 {
453     int i, rc, last_rc=-1;
454
455     for(i=0; i < MAX_RESOURCES; i++ ) {
456         if( resource_table[i].used && !resource_table[i].secret == !secret ) {
457             switch( resource_table[i].rt ) {
458               case rt_RING:
459                 rc = keyring_search( pkt, kbpos, resource_table[i].iobuf,
460                                                  resource_table[i].fname );
461                 break;
462              #ifdef HAVE_LIBGDBM
463               case rt_GDBM: {
464                     PKT_public_key *req_pk = pkt->pkt.public_key;
465                     byte fpr[20];
466                     size_t fprlen;
467
468                     fingerprint_from_pk( req_pk, fpr, &fprlen );
469                     rc = do_gdbm_locate( resource_table[i].dbf,
470                                          kbpos, fpr, fprlen );
471                 }
472                 break;
473              #endif
474               default: BUG();
475             }
476
477             kbpos->rt = resource_table[i].rt;
478             if( !rc ) {
479                 kbpos->resno = i;
480                 kbpos->fp = NULL;
481                 return 0;
482             }
483             if( rc != -1 ) {
484                 log_error("error searching resource %d: %s\n",
485                                                   i, g10_errstr(rc));
486                 last_rc = rc;
487             }
488         }
489     }
490     return last_rc;
491 }
492
493
494 /****************
495  * Combined function to search for a username and get the position
496  * of the keyblock.
497  */
498 int
499 find_keyblock_byname( KBPOS *kbpos, const char *username )
500 {
501     PACKET pkt;
502     PKT_public_key *pk = m_alloc_clear( sizeof *pk );
503     int rc;
504
505     rc = get_pubkey_byname( NULL, pk, username, NULL );
506     if( rc ) {
507         free_public_key(pk);
508         return rc;
509     }
510
511     init_packet( &pkt );
512     pkt.pkttype = PKT_PUBLIC_KEY;
513     pkt.pkt.public_key = pk;
514     rc = search( &pkt, kbpos, 0 );
515     free_public_key(pk);
516     return rc;
517 }
518
519
520 /****************
521  * Combined function to search for a key and get the position
522  * of the keyblock.
523  */
524 int
525 find_keyblock_bypk( KBPOS *kbpos, PKT_public_key *pk )
526 {
527     PACKET pkt;
528     int rc;
529
530     init_packet( &pkt );
531     pkt.pkttype = PKT_PUBLIC_KEY;
532     pkt.pkt.public_key = pk;
533     rc = search( &pkt, kbpos, 0 );
534     return rc;
535 }
536
537 /****************
538  * Combined function to search for a key and get the position
539  * of the keyblock.
540  */
541 int
542 find_keyblock_bysk( KBPOS *kbpos, PKT_secret_key *sk )
543 {
544     PACKET pkt;
545     int rc;
546
547     init_packet( &pkt );
548     pkt.pkttype = PKT_SECRET_KEY;
549     pkt.pkt.secret_key = sk;
550     rc = search( &pkt, kbpos, 0 );
551     return rc;
552 }
553
554
555 /****************
556  * Combined function to search for a username and get the position
557  * of the keyblock. This function does not unprotect the secret key.
558  */
559 int
560 find_secret_keyblock_byname( KBPOS *kbpos, const char *username )
561 {
562     PACKET pkt;
563     PKT_secret_key *sk = m_alloc_clear( sizeof *sk );
564     int rc;
565
566     rc = get_seckey_byname( sk, username, 0 );
567     if( rc ) {
568         free_secret_key(sk);
569         return rc;
570     }
571
572     init_packet( &pkt );
573     pkt.pkttype = PKT_SECRET_KEY;
574     pkt.pkt.secret_key = sk;
575     rc = search( &pkt, kbpos, 1 );
576     free_secret_key(sk);
577     return rc;
578 }
579
580
581 /****************
582  * Locate a keyblock in a database which is capable of direct access
583  * Put all information into KBPOS, which can be later be to access this
584  * key block.
585  * This function looks into all registered keyblock sources.
586  *
587  * Returns: 0 if found,
588  *          -1 if not found
589  *          G10ERR_UNSUPPORTED if no resource is able to handle this
590  *          or another errorcode.
591  */
592 int
593 locate_keyblock_by_fpr( KBPOS *kbpos, const byte *fpr, int fprlen, int secret )
594 {
595     RESTBL *rentry;
596     int i, rc, any=0, last_rc=-1;
597
598
599     for(i=0, rentry = resource_table; i < MAX_RESOURCES; i++, rentry++ ) {
600         if( rentry->used && !rentry->secret == !secret ) {
601             kbpos->rt = rentry->rt;
602             switch( rentry->rt ) {
603              #ifdef HAVE_LIBGDBM
604               case rt_GDBM:
605                 any = 1;
606                 rc = do_gdbm_locate( rentry->dbf, kbpos, fpr, fprlen );
607                 break;
608              #endif
609               default:
610                 rc = G10ERR_UNSUPPORTED;
611                 break;
612             }
613
614             if( !rc ) {
615                 kbpos->resno = i;
616                 kbpos->fp = NULL;
617                 return 0;
618             }
619             else if( rc != -1 && rc != G10ERR_UNSUPPORTED ) {
620                 log_error("error searching resource %d: %s\n",
621                                                   i, g10_errstr(rc));
622                 last_rc = rc;
623             }
624         }
625     }
626
627     return (last_rc == -1 && !any)? G10ERR_UNSUPPORTED : last_rc;
628 }
629
630
631 int
632 locate_keyblock_by_keyid( KBPOS *kbpos, u32 *keyid, int shortkid, int secret )
633 {
634     RESTBL *rentry;
635     int i, rc, any=0, last_rc=-1;
636
637     if( shortkid )
638         return G10ERR_UNSUPPORTED;
639
640     for(i=0, rentry = resource_table; i < MAX_RESOURCES; i++, rentry++ ) {
641         if( rentry->used && !rentry->secret == !secret ) {
642             kbpos->rt = rentry->rt;
643             switch( rentry->rt ) {
644              #ifdef HAVE_LIBGDBM
645               case rt_GDBM:
646                 any = 1;
647                 rc = do_gdbm_locate_by_keyid( rentry->dbf, kbpos, keyid );
648                 break;
649              #endif
650               default:
651                 rc = G10ERR_UNSUPPORTED;
652                 break;
653             }
654
655             if( !rc ) {
656                 kbpos->resno = i;
657                 kbpos->fp = NULL;
658                 return 0;
659             }
660             else if( rc != -1 && rc != G10ERR_UNSUPPORTED ) {
661                 log_error("error searching resource %d: %s\n",
662                                                   i, g10_errstr(rc));
663                 last_rc = rc;
664             }
665         }
666     }
667
668     return (last_rc == -1 && !any)? G10ERR_UNSUPPORTED : last_rc;
669 }
670
671
672
673
674 /****************
675  * Lock the keyblock; wait until it's available
676  * This function may change the internal data in kbpos, in cases
677  * when the keyblock to be locked has been modified.
678  * fixme: remove this function and add an option to search()?
679  */
680 int
681 lock_keyblock( KBPOS *kbpos )
682 {
683     if( !check_pos(kbpos) )
684         return G10ERR_GENERAL;
685     return 0;
686 }
687
688 /****************
689  * Release a lock on a keyblock
690  */
691 void
692 unlock_keyblock( KBPOS *kbpos )
693 {
694     if( !check_pos(kbpos) )
695         BUG();
696 }
697
698 /****************
699  * Read a complete keyblock and return the root in ret_root.
700  */
701 int
702 read_keyblock( KBPOS *kbpos, KBNODE *ret_root )
703 {
704     if( !check_pos(kbpos) )
705         return G10ERR_GENERAL;
706
707     switch( kbpos->rt ) {
708       case rt_RING:
709         return keyring_read( kbpos, ret_root );
710      #ifdef HAVE_LIBGDBM
711       case rt_GDBM:
712         return do_gdbm_read( kbpos, ret_root );
713      #endif
714       default: BUG();
715     }
716 }
717
718
719 /****************
720  * This functions can be used to read through a complete keyring.
721  * Mode is: 0 = open
722  *          1 = read
723  *          2 = close
724  *          5 = open secret keyrings
725  *          11 = read but skip signature and comment packets.
726  *          all others are reserved!
727  * Note that you do not need a search prior to this function,
728  * only a handle is needed.
729  * NOTE: It is not allowed to do an insert/update/delete with this
730  *       keyblock, if you want to do this, use search/read!
731  */
732 int
733 enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root )
734 {
735     int rc = 0;
736     RESTBL *rentry;
737
738     if( !mode || mode == 5 || mode == 100 ) {
739         int i;
740
741         kbpos->fp = NULL;
742         kbpos->rt = rt_UNKNOWN;
743         if( !mode ) {
744             kbpos->secret = 0;
745             i = 0;
746         }
747         else if( mode == 5 ) {
748             kbpos->secret = 1;
749             mode = 0;
750             i = 0;
751         }
752         else
753             i = kbpos->resno+1;
754         for(; i < MAX_RESOURCES; i++ )
755             if( resource_table[i].used
756                 && !resource_table[i].secret == !kbpos->secret )
757                 break;
758         if( i == MAX_RESOURCES )
759             return -1; /* no resources */
760         kbpos->resno = i;
761         rentry = check_pos( kbpos );
762         kbpos->rt = resource_table[i].rt;
763         kbpos->valid = 0;
764         switch( kbpos->rt ) {
765           case rt_RING:
766             kbpos->fp = iobuf_open( rentry->fname );
767             if( !kbpos->fp ) {
768                 log_error("can't open `%s'\n", rentry->fname );
769                 return G10ERR_OPEN_FILE;
770             }
771             break;
772          #ifdef HAVE_LIBGDBM
773           case rt_GDBM:
774             /* FIXME: make sure that there is only one enum at a time */
775             kbpos->offset = 0;
776             break;
777          #endif
778           default: BUG();
779         }
780         kbpos->pkt = NULL;
781     }
782     else if( mode == 1 || mode == 11 ) {
783         int cont;
784         do {
785             cont = 0;
786             switch( kbpos->rt ) {
787               case rt_RING:
788                 if( !kbpos->fp )
789                     return G10ERR_GENERAL;
790                 rc = keyring_enum( kbpos, ret_root, mode == 11 );
791                 break;
792              #ifdef HAVE_LIBGDBM
793               case rt_GDBM:
794                 rc = do_gdbm_enum( kbpos, ret_root );
795                 break;
796              #endif
797               default: BUG();
798             }
799
800             if( rc == -1 ) {
801                 assert( !kbpos->pkt );
802                 rentry = check_pos( kbpos );
803                 assert(rentry);
804                 /* close */
805                 enum_keyblocks(2, kbpos, ret_root );
806                 /* and open the next one */
807                 rc = enum_keyblocks(100, kbpos, ret_root );
808                 if( !rc )
809                     cont = 1;
810             }
811         } while(cont);
812     }
813     else {
814         switch( kbpos->rt ) {
815           case rt_RING:
816             if( kbpos->fp ) {
817                 iobuf_close( kbpos->fp );
818                 kbpos->fp = NULL;
819             }
820             break;
821           case rt_GDBM:
822             break;
823           case rt_UNKNOWN:
824             /* this happens when we have no keyring at all */
825             return rc;
826
827           default:
828             BUG();
829         }
830         /* release pending packet */
831         free_packet( kbpos->pkt );
832         m_free( kbpos->pkt );
833     }
834     return rc;
835 }
836
837
838
839
840 /****************
841  * Insert the keyblock described by ROOT into the keyring described
842  * by KBPOS.  This actually appends the data to the keyfile.
843  */
844 int
845 insert_keyblock( KBPOS *kbpos, KBNODE root )
846 {
847     int rc;
848
849     if( !check_pos(kbpos) )
850         return G10ERR_GENERAL;
851
852     switch( kbpos->rt ) {
853       case rt_RING:
854         rc = keyring_copy( kbpos, 1, root );
855         break;
856      #ifdef HAVE_LIBGDBM
857       case rt_GDBM:
858         rc = do_gdbm_store( kbpos, root, 0 );
859         break;
860      #endif
861       default: BUG();
862     }
863
864     return rc;
865 }
866
867 /****************
868  * Delete the keyblock described by KBPOS.
869  * The current code simply changes the keyblock in the keyring
870  * to packet of type 0 with the correct length.  To help detect errors,
871  * zero bytes are written.
872  */
873 int
874 delete_keyblock( KBPOS *kbpos )
875 {
876     int rc;
877
878     if( !check_pos(kbpos) )
879         return G10ERR_GENERAL;
880
881     switch( kbpos->rt ) {
882       case rt_RING:
883         rc = keyring_copy( kbpos, 2, NULL );
884         break;
885      #ifdef HAVE_LIBGDBM
886       case rt_GDBM:
887         log_debug("deleting gdbm keyblock is not yet implemented\n");
888         rc = 0;
889         break;
890      #endif
891       default: BUG();
892     }
893
894     return rc;
895 }
896
897
898 /****************
899  * Update the keyblock at KBPOS with the one in ROOT.
900  */
901 int
902 update_keyblock( KBPOS *kbpos, KBNODE root )
903 {
904     int rc;
905
906     if( !check_pos(kbpos) )
907         return G10ERR_GENERAL;
908
909     switch( kbpos->rt ) {
910       case rt_RING:
911         rc = keyring_copy( kbpos, 3, root );
912         break;
913      #ifdef HAVE_LIBGDBM
914       case rt_GDBM:
915         rc = do_gdbm_store( kbpos, root, 1 );
916         break;
917      #endif
918       default: BUG();
919     }
920
921     return rc;
922 }
923
924
925 \f
926 /****************************************************************
927  ********** Implemenation of a user ID database    **************
928  ****************************************************************/
929 #if 0
930 /****************
931  * Layout of the user ID db
932  *
933  * This user ID DB provides fast lookup of user ID, but the user ids are
934  * not in any specific order.
935  *
936  * A string "GnuPG user db", a \n.
937  * user ids of one key, delimited by \t,
938  * a # or ^ followed by a 20 byte fingerprint, followed by an \n
939  * The literal characters %, \n, \t, #, ^ must be replaced by a percent sign
940  * and their hex value.
941  *
942  * (We use Boyer/Moore pattern matching)
943  */
944
945 /****************
946  * This compiles pattern to the distance table, the table will be allocate
947  * here and must be freed by using free().
948  * Returns: Ptr to new allocated Table
949  *          Caller must free the table.
950  */
951
952 static size_t *
953 compile_bm_table( const byte *pattern, size_t len )
954 {
955     ushort *dist;
956     int i;
957
958     dist = m_alloc_clear( 256 * sizeof *dist );
959     for(i=0; i < 256; i++ )
960         dist[i] = len;
961     for(i=0; i < len-1; i++ )
962         dTbl[p[i]] = len-i-1;
963     return dist;
964 }
965
966
967
968
969 /****************
970  * Search BUF of BUFLEN for pattern P of length PATLEN.
971  * dist is the Boyer/Moore distance table of 256 Elements,
972  * case insensitive search is done if IGNCASE is true (In this case
973  * the distance table has to compiled from uppercase chacaters and
974  * PAT must also be uppercase.
975  * Returns: Prt to maching string in BUF, or NULL if not found.
976  */
977
978 static const *
979 do_bm_search( const byte *buf, size_t buflen,
980               const byte *pat, size_t patlen, size_t *dist, int igncase )
981 {
982     int i, j, k;
983
984     if( igncase ) {
985         int c, c1;
986
987         for( i = --patlen; i < buflen; i += dist[c1] )
988             for( j=patlen, k=i, c1=c=toupper(buf[k]); c == pat[j];
989                                           j--, k--, c=toupper(buf[k]) ) {
990                 if( !j )
991                     return buf+k;
992             }
993     }
994     else {
995         for( i = --patlen; i < buflen; i += dist[buf[i]] )
996             for( j=patlen, k=i; buf[k] == pat[j]; j--, k-- ) {
997                 if( !j )
998                     return buf+k;
999             }
1000     }
1001     return NULL;
1002 }
1003
1004
1005 typedef struct {
1006     size_t dist[256];
1007 } *SCAN_USER_HANDLE;
1008
1009 static SCAN_USER_HANDLE
1010 scan_user_file_open( const byte *name )
1011 {
1012     SCAN_USER_HANDLE hd;
1013     size_t *dist;
1014     int i;
1015
1016     hd = m_alloc_clear( sizeof *hd );
1017     dist = hd->dist;
1018     /* compile the distance table */
1019     for(i=0; i < 256; i++ )
1020         dist[i] = len;
1021     for(i=0; i < len-1; i++ )
1022         dTbl[p[i]] = len-i-1;
1023     /* setup other things */
1024
1025     return hd;
1026 }
1027
1028 static int
1029 scan_user_file_close( SCAN_USER_HANDLE hd )
1030 {
1031     m_free( hd );
1032 }
1033
1034 static int
1035 scan_user_file_read( SCAN_USER_HANDLE hd, byte *fpr )
1036 {
1037     char record[1000];
1038
1039     /* read a record */
1040
1041
1042 }
1043 #endif
1044
1045
1046 \f
1047 /****************************************************************
1048  ********** Functions which operates on regular keyrings ********
1049  ****************************************************************/
1050
1051 static int
1052 cmp_seckey( PKT_secret_key *req_sk, PKT_secret_key *sk )
1053 {
1054     int n,i;
1055
1056     assert( req_sk->pubkey_algo == sk->pubkey_algo );
1057
1058     n = pubkey_get_nskey( req_sk->pubkey_algo );
1059     for(i=0; i < n; i++ ) {
1060         if( mpi_cmp( req_sk->skey[i], sk->skey[i] ) )
1061             return -1;
1062     }
1063     return 0;
1064 }
1065
1066 static int
1067 cmp_pubkey( PKT_public_key *req_pk, PKT_public_key *pk )
1068 {
1069     int n, i;
1070
1071     assert( req_pk->pubkey_algo == pk->pubkey_algo );
1072
1073     n = pubkey_get_npkey( req_pk->pubkey_algo );
1074     for(i=0; i < n; i++ ) {
1075         if( mpi_cmp( req_pk->pkey[i], pk->pkey[i] )  )
1076             return -1;
1077     }
1078     return 0;
1079 }
1080
1081 /****************
1082  * search one keyring, return 0 if found, -1 if not found or an errorcode.
1083  */
1084 static int
1085 keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname )
1086 {
1087     int rc;
1088     PACKET pkt;
1089     int save_mode;
1090     ulong offset;
1091     int pkttype = req->pkttype;
1092     PKT_public_key *req_pk = req->pkt.public_key;
1093     PKT_secret_key *req_sk = req->pkt.secret_key;
1094
1095     init_packet(&pkt);
1096     save_mode = set_packet_list_mode(0);
1097     kbpos->rt = rt_RING;
1098     kbpos->valid = 0;
1099
1100   #if HAVE_DOSISH_SYSTEM || 1
1101     assert(!iobuf);
1102     iobuf = iobuf_open( fname );
1103     if( !iobuf ) {
1104         log_error("%s: can't open keyring file\n", fname);
1105         rc = G10ERR_KEYRING_OPEN;
1106         goto leave;
1107     }
1108   #else
1109     if( iobuf_seek( iobuf, 0 ) ) {
1110         log_error("can't rewind keyring file\n");
1111         rc = G10ERR_KEYRING_OPEN;
1112         goto leave;
1113     }
1114   #endif
1115
1116     while( !(rc=search_packet(iobuf, &pkt, pkttype, &offset)) ) {
1117         if( pkt.pkttype == PKT_SECRET_KEY ) {
1118             PKT_secret_key *sk = pkt.pkt.secret_key;
1119
1120             if(   req_sk->timestamp == sk->timestamp
1121                && req_sk->pubkey_algo == sk->pubkey_algo
1122                && !cmp_seckey( req_sk, sk) )
1123                 break; /* found */
1124         }
1125         else if( pkt.pkttype == PKT_PUBLIC_KEY ) {
1126             PKT_public_key *pk = pkt.pkt.public_key;
1127
1128             if(   req_pk->timestamp == pk->timestamp
1129                && req_pk->pubkey_algo == pk->pubkey_algo
1130                && !cmp_pubkey( req_pk, pk ) )
1131                 break; /* found */
1132         }
1133         else
1134             BUG();
1135         free_packet(&pkt);
1136     }
1137     if( !rc ) {
1138         kbpos->offset = offset;
1139         kbpos->valid = 1;
1140     }
1141
1142   leave:
1143     free_packet(&pkt);
1144     set_packet_list_mode(save_mode);
1145   #if HAVE_DOSISH_SYSTEM || 1
1146     iobuf_close(iobuf);
1147   #endif
1148     return rc;
1149 }
1150
1151
1152 static int
1153 keyring_read( KBPOS *kbpos, KBNODE *ret_root )
1154 {
1155     PACKET *pkt;
1156     int rc;
1157     RESTBL *rentry;
1158     KBNODE root = NULL;
1159     IOBUF a;
1160     int in_cert = 0;
1161
1162     if( !(rentry=check_pos(kbpos)) )
1163         return G10ERR_GENERAL;
1164
1165     a = iobuf_open( rentry->fname );
1166     if( !a ) {
1167         log_error("can't open `%s'\n", rentry->fname );
1168         return G10ERR_OPEN_FILE;
1169     }
1170
1171     if( !kbpos->valid )
1172         log_debug("kbpos not valid in keyring_read, want %d\n", (int)kbpos->offset );
1173     if( iobuf_seek( a, kbpos->offset ) ) {
1174         log_error("can't seek to %lu\n", kbpos->offset);
1175         iobuf_close(a);
1176         return G10ERR_KEYRING_OPEN;
1177     }
1178
1179     pkt = m_alloc( sizeof *pkt );
1180     init_packet(pkt);
1181     kbpos->count=0;
1182     while( (rc=parse_packet(a, pkt)) != -1 ) {
1183         if( rc ) {  /* ignore errors */
1184             if( rc != G10ERR_UNKNOWN_PACKET ) {
1185                 log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
1186                 rc = G10ERR_INV_KEYRING;
1187                 goto ready;
1188             }
1189             kbpos->count++;
1190             free_packet( pkt );
1191             init_packet( pkt );
1192             continue;
1193         }
1194         /* make a linked list of all packets */
1195         switch( pkt->pkttype ) {
1196           case PKT_COMPRESSED:
1197             log_error("skipped compressed packet in keyring\n" );
1198             free_packet(pkt);
1199             init_packet(pkt);
1200             break;
1201
1202           case PKT_PUBLIC_KEY:
1203           case PKT_SECRET_KEY:
1204             if( in_cert )
1205                 goto ready;
1206             in_cert = 1;
1207           default:
1208             kbpos->count++;
1209             if( !root )
1210                 root = new_kbnode( pkt );
1211             else
1212                 add_kbnode( root, new_kbnode( pkt ) );
1213             pkt = m_alloc( sizeof *pkt );
1214             init_packet(pkt);
1215             break;
1216         }
1217     }
1218   ready:
1219     kbpos->valid = 0;
1220     if( rc == -1 && root )
1221         rc = 0;
1222
1223     if( rc )
1224         release_kbnode( root );
1225     else
1226         *ret_root = root;
1227     free_packet( pkt );
1228     m_free( pkt );
1229     iobuf_close(a);
1230     return rc;
1231 }
1232
1233
1234 static int
1235 keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs )
1236 {
1237     PACKET *pkt;
1238     int rc;
1239     RESTBL *rentry;
1240     KBNODE root = NULL;
1241
1242     if( !(rentry=check_pos(kbpos)) )
1243         return G10ERR_GENERAL;
1244
1245     if( kbpos->pkt ) {
1246         root = new_kbnode( kbpos->pkt );
1247         kbpos->pkt = NULL;
1248     }
1249
1250     pkt = m_alloc( sizeof *pkt );
1251     init_packet(pkt);
1252     while( (rc=parse_packet(kbpos->fp, pkt)) != -1 ) {
1253         if( rc ) {  /* ignore errors */
1254             if( rc != G10ERR_UNKNOWN_PACKET ) {
1255                 log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
1256                 rc = G10ERR_INV_KEYRING;
1257                 goto ready;
1258             }
1259             free_packet( pkt );
1260             init_packet( pkt );
1261             continue;
1262         }
1263         /* make a linked list of all packets */
1264         switch( pkt->pkttype ) {
1265           case PKT_COMPRESSED:
1266             log_error("skipped compressed packet in keyring\n" );
1267             free_packet(pkt);
1268             init_packet(pkt);
1269             break;
1270
1271           case PKT_PUBLIC_KEY:
1272           case PKT_SECRET_KEY:
1273             if( root ) { /* store this packet */
1274                 kbpos->pkt = pkt;
1275                 pkt = NULL;
1276                 goto ready;
1277             }
1278             root = new_kbnode( pkt );
1279             pkt = m_alloc( sizeof *pkt );
1280             init_packet(pkt);
1281             break;
1282
1283           default:
1284             /* skip pakets at the beginning of a keyring, until we find
1285              * a start packet; issue a warning if it is not a comment */
1286             if( !root && pkt->pkttype != PKT_COMMENT
1287                       && pkt->pkttype != PKT_OLD_COMMENT ) {
1288                 break;
1289             }
1290             if( !root || (skipsigs && ( pkt->pkttype == PKT_SIGNATURE
1291                                       ||pkt->pkttype == PKT_COMMENT
1292                                       ||pkt->pkttype == PKT_OLD_COMMENT )) ) {
1293                 init_packet(pkt);
1294                 break;
1295             }
1296             add_kbnode( root, new_kbnode( pkt ) );
1297             pkt = m_alloc( sizeof *pkt );
1298             init_packet(pkt);
1299             break;
1300         }
1301     }
1302   ready:
1303     if( rc == -1 && root )
1304         rc = 0;
1305
1306     if( rc )
1307         release_kbnode( root );
1308     else
1309         *ret_root = root;
1310     free_packet( pkt );
1311     m_free( pkt );
1312
1313     return rc;
1314 }
1315
1316
1317 /****************
1318  * Perform insert/delete/update operation.
1319  * mode 1 = insert
1320  *      2 = delete
1321  *      3 = update
1322  */
1323 static int
1324 keyring_copy( KBPOS *kbpos, int mode, KBNODE root )
1325 {
1326     RESTBL *rentry;
1327     IOBUF fp, newfp;
1328     int rc=0;
1329     char *bakfname = NULL;
1330     char *tmpfname = NULL;
1331
1332     if( !(rentry = check_pos( kbpos )) )
1333         return G10ERR_GENERAL;
1334     if( kbpos->fp )
1335         BUG(); /* not allowed with such a handle */
1336
1337     if( opt.dry_run )
1338         return 0;
1339
1340     lock_rentry( rentry );
1341
1342     /* open the source file */
1343     fp = iobuf_open( rentry->fname );
1344     if( mode == 1 && !fp && errno == ENOENT ) { /* no file yet */
1345         KBNODE kbctx, node;
1346
1347         /* insert: create a new file */
1348         newfp = iobuf_create( rentry->fname );
1349         if( !newfp ) {
1350             log_error(_("%s: can't create: %s\n"), rentry->fname, strerror(errno));
1351             unlock_rentry( rentry );
1352             return G10ERR_OPEN_FILE;
1353         }
1354         else if( !opt.quiet )
1355             log_info(_("%s: keyring created\n"), rentry->fname );
1356
1357         kbctx=NULL;
1358         while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
1359             if( (rc = build_packet( newfp, node->pkt )) ) {
1360                 log_error("build_packet(%d) failed: %s\n",
1361                             node->pkt->pkttype, g10_errstr(rc) );
1362                 iobuf_cancel(newfp);
1363                 unlock_rentry( rentry );
1364                 return G10ERR_WRITE_FILE;
1365             }
1366         }
1367         if( iobuf_close(newfp) ) {
1368             log_error("%s: close failed: %s\n", rentry->fname, strerror(errno));
1369             unlock_rentry( rentry );
1370             return G10ERR_CLOSE_FILE;
1371         }
1372         if( chmod( rentry->fname, S_IRUSR | S_IWUSR ) ) {
1373             log_error("%s: chmod failed: %s\n",
1374                                     rentry->fname, strerror(errno) );
1375             unlock_rentry( rentry );
1376             return G10ERR_WRITE_FILE;
1377         }
1378         return 0;
1379     }
1380     if( !fp ) {
1381         log_error("%s: can't open: %s\n", rentry->fname, strerror(errno) );
1382         rc = G10ERR_OPEN_FILE;
1383         goto leave;
1384     }
1385
1386     /* create the new file */
1387   #ifdef USE_ONLY_8DOT3
1388     /* Here is another Windoze bug?:
1389      * you cant rename("pubring.gpg.tmp", "pubring.gpg");
1390      * but      rename("pubring.gpg.tmp", "pubring.aaa");
1391      * works.  So we replace .gpg by .bak or .tmp
1392      */
1393     if( strlen(rentry->fname) > 4
1394         && !strcmp(rentry->fname+strlen(rentry->fname)-4, ".gpg") ) {
1395         bakfname = m_alloc( strlen( rentry->fname ) + 1 );
1396         strcpy(bakfname,rentry->fname);
1397         strcpy(bakfname+strlen(rentry->fname)-4, ".bak");
1398         tmpfname = m_alloc( strlen( rentry->fname ) + 1 );
1399         strcpy(tmpfname,rentry->fname);
1400         strcpy(tmpfname+strlen(rentry->fname)-4, ".tmp");
1401     }
1402     else { /* file does not end with gpg; hmmm */
1403         bakfname = m_alloc( strlen( rentry->fname ) + 5 );
1404         strcpy(stpcpy(bakfname,rentry->fname),".bak");
1405         tmpfname = m_alloc( strlen( rentry->fname ) + 5 );
1406         strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
1407     }
1408   #else
1409     bakfname = m_alloc( strlen( rentry->fname ) + 2 );
1410     strcpy(stpcpy(bakfname,rentry->fname),"~");
1411     tmpfname = m_alloc( strlen( rentry->fname ) + 5 );
1412     strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
1413   #endif
1414     newfp = iobuf_create( tmpfname );
1415     if( !newfp ) {
1416         log_error("%s: can't create: %s\n", tmpfname, strerror(errno) );
1417         iobuf_close(fp);
1418         rc = G10ERR_OPEN_FILE;
1419         goto leave;
1420     }
1421
1422     if( mode == 1 ) { /* insert */
1423         /* copy everything to the new file */
1424         rc = copy_all_packets( fp, newfp );
1425         if( rc != -1 ) {
1426             log_error("%s: copy to %s failed: %s\n",
1427                       rentry->fname, tmpfname, g10_errstr(rc) );
1428             iobuf_close(fp);
1429             iobuf_cancel(newfp);
1430             goto leave;
1431         }
1432         rc = 0;
1433     }
1434
1435     if( mode == 2 || mode == 3 ) { /* delete or update */
1436         /* copy first part to the new file */
1437         rc = copy_some_packets( fp, newfp, kbpos->offset );
1438         if( rc ) { /* should never get EOF here */
1439             log_error("%s: copy to %s failed: %s\n",
1440                       rentry->fname, tmpfname, g10_errstr(rc) );
1441             iobuf_close(fp);
1442             iobuf_cancel(newfp);
1443             goto leave;
1444         }
1445         /* skip this keyblock */
1446         assert( kbpos->count );
1447         rc = skip_some_packets( fp, kbpos->count );
1448         if( rc ) {
1449             log_error("%s: skipping %u packets failed: %s\n",
1450                             rentry->fname, kbpos->count, g10_errstr(rc));
1451             iobuf_close(fp);
1452             iobuf_cancel(newfp);
1453             goto leave;
1454         }
1455     }
1456
1457     if( mode == 1 || mode == 3 ) { /* insert or update */
1458         KBNODE kbctx, node;
1459
1460         /* append the new data */
1461         kbctx=NULL;
1462         while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
1463             if( (rc = build_packet( newfp, node->pkt )) ) {
1464                 log_error("build_packet(%d) failed: %s\n",
1465                             node->pkt->pkttype, g10_errstr(rc) );
1466                 iobuf_close(fp);
1467                 iobuf_cancel(newfp);
1468                 rc = G10ERR_WRITE_FILE;
1469                 goto leave;
1470             }
1471         }
1472         kbpos->valid = 0;
1473     }
1474
1475     if( mode == 2 || mode == 3 ) { /* delete or update */
1476         /* copy the rest */
1477         rc = copy_all_packets( fp, newfp );
1478         if( rc != -1 ) {
1479             log_error("%s: copy to %s failed: %s\n",
1480                       rentry->fname, tmpfname, g10_errstr(rc) );
1481             iobuf_close(fp);
1482             iobuf_cancel(newfp);
1483             goto leave;
1484         }
1485         rc = 0;
1486     }
1487
1488     /* close both files */
1489     if( iobuf_close(fp) ) {
1490         log_error("%s: close failed: %s\n", rentry->fname, strerror(errno) );
1491         rc = G10ERR_CLOSE_FILE;
1492         goto leave;
1493     }
1494     if( iobuf_close(newfp) ) {
1495         log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
1496         rc = G10ERR_CLOSE_FILE;
1497         goto leave;
1498     }
1499     /* if the new file is a secring, restrict the permissions */
1500   #ifndef HAVE_DOSISH_SYSTEM
1501     if( rentry->secret ) {
1502         if( chmod( tmpfname, S_IRUSR | S_IWUSR ) ) {
1503             log_error("%s: chmod failed: %s\n",
1504                                     tmpfname, strerror(errno) );
1505             rc = G10ERR_WRITE_FILE;
1506             goto leave;
1507         }
1508     }
1509   #endif
1510
1511     /* rename and make backup file */
1512     if( !rentry->secret ) {  /* but not for secret keyrings */
1513       #ifdef HAVE_DOSISH_SYSTEM
1514         remove( bakfname );
1515       #endif
1516         if( rename( rentry->fname, bakfname ) ) {
1517             log_error("%s: rename to %s failed: %s\n",
1518                                     rentry->fname, bakfname, strerror(errno) );
1519             rc = G10ERR_RENAME_FILE;
1520             goto leave;
1521         }
1522     }
1523   #ifdef HAVE_DOSISH_SYSTEM
1524     remove( rentry->fname );
1525   #endif
1526     if( rename( tmpfname, rentry->fname ) ) {
1527         log_error("%s: rename to %s failed: %s\n",
1528                             tmpfname, rentry->fname,strerror(errno) );
1529         rc = G10ERR_RENAME_FILE;
1530         if( rentry->secret ) {
1531             log_info(_(
1532                 "WARNING: 2 files with confidential information exists.\n"));
1533             log_info(_("%s is the unchanged one\n"), rentry->fname );
1534             log_info(_("%s is the new one\n"), tmpfname );
1535             log_info(_("Please fix this possible security flaw\n"));
1536         }
1537         goto leave;
1538     }
1539
1540   leave:
1541     unlock_rentry( rentry );
1542     m_free(bakfname);
1543     m_free(tmpfname);
1544     return rc;
1545 }
1546
1547 \f
1548 #ifdef HAVE_LIBGDBM
1549 /****************************************************************
1550  ********** Functions which operates on GDM files ***************
1551  ****************************************************************/
1552
1553 #if MAX_FINGERPRINT_LEN > 20
1554   #error A GDBM keyring assumes that fingerprints are less than 21
1555 #endif
1556
1557 /****************
1558  * Insert the keyblock into the GDBM database
1559  */
1560
1561 static int
1562 do_gdbm_store( KBPOS *kbpos, KBNODE root, int update )
1563 {
1564     RESTBL *rentry;
1565     PKT_public_key *pk;
1566     KBNODE kbctx, node;
1567     IOBUF fp = NULL;
1568     byte fpr[20];
1569     byte contbuf[21];
1570     byte keybuf[21];
1571     size_t fprlen;
1572     datum key, content;
1573     int i, rc;
1574
1575     if( !(rentry = check_pos( kbpos )) )
1576         return G10ERR_GENERAL;
1577
1578     if( opt.dry_run )
1579         return 0;
1580
1581     /* construct the fingerprint which is used as the primary key */
1582     node = find_kbnode( root, PKT_PUBLIC_KEY );
1583     if( !node )
1584         log_bug("a gdbm database can't store secret keys\n");
1585     pk = node->pkt->pkt.public_key;
1586
1587     fingerprint_from_pk( pk, fpr, &fprlen );
1588     for(i=fprlen; i < DIM(fpr); i++ )
1589         fpr[i] = 0;
1590
1591     /* build the keyblock */
1592     kbctx=NULL;
1593     fp = iobuf_temp();
1594     iobuf_put( fp, 1 ); /* data is a keyblock */
1595     while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
1596         if( (rc = build_packet( fp, node->pkt )) ) {
1597             log_error("build_packet(%d) failed: %s\n",
1598                         node->pkt->pkttype, g10_errstr(rc) );
1599             rc = G10ERR_WRITE_FILE;
1600             goto leave;
1601         }
1602     }
1603     /* store data and key */
1604     *keybuf = 1;   /* key is a padded fingerprint */
1605     memcpy(keybuf+1, fpr, 20 );
1606     key.dptr  = keybuf;
1607     key.dsize = 21;
1608     content.dptr  = iobuf_get_temp_buffer( fp );
1609     content.dsize = iobuf_get_temp_length( fp );
1610     rc = gdbm_store( rentry->dbf, key, content,
1611                                   update? GDBM_REPLACE : GDBM_INSERT );
1612     if( rc == 1 && !update )
1613         rc = gdbm_store( rentry->dbf, key, content, GDBM_REPLACE );
1614
1615     if( rc ) {
1616         log_error("%s: gdbm_store failed: %s\n", rentry->fname,
1617                             rc == 1 ? "already stored"
1618                                     : gdbm_strerror(gdbm_errno) );
1619         rc = G10ERR_WRITE_FILE;
1620         goto leave;
1621     }
1622     /* now store all keyids */
1623     *contbuf = 2;  /* data is a list of fingerprints */
1624     memcpy(contbuf+1, fpr, 20 );
1625     content.dptr = contbuf;
1626     content.dsize= 21;
1627     kbctx=NULL;
1628     while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
1629         if(    node->pkt->pkttype == PKT_PUBLIC_KEY
1630             || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
1631             u32 aki[2];
1632
1633             keyid_from_pk( node->pkt->pkt.public_key, aki );
1634             *keybuf = 2; /* key is a 8 byte keyid */
1635             u32tobuf( keybuf+1  , aki[0] );
1636             u32tobuf( keybuf+5, aki[1] );
1637             key.dptr = keybuf;
1638             key.dsize= 9;
1639             /* fixme: must be more clever when a insert failed:
1640              *        build a list of fingerprints in this case */
1641             rc = gdbm_store( rentry->dbf, key, content,
1642                                           update? GDBM_REPLACE : GDBM_INSERT );
1643             if( rc ) {
1644                 log_info("%s: gdbm_store keyid failed: %s\n", rentry->fname,
1645                                     rc == 1 ? "already stored"
1646                                             : gdbm_strerror(gdbm_errno) );
1647                 rc = 0;
1648             }
1649         }
1650     }
1651
1652   leave:
1653     iobuf_close(fp); /* don't need a cancel because it is a temp iobuf */
1654     return rc;
1655 }
1656
1657
1658
1659 /****************
1660  * search one keybox, return 0 if found, -1 if not found or an errorcode.
1661  */
1662 static int
1663 do_gdbm_locate( GDBM_FILE dbf, KBPOS *kbpos, const byte *fpr, int fprlen )
1664 {
1665     byte *keybuf = kbpos->keybuf;
1666     datum key;
1667     int i;
1668
1669     *keybuf = 1;
1670     for(i=0; i < fprlen; i++ )
1671         keybuf[i+1] = fpr[i];
1672     for(; i < 20; i++ )
1673         keybuf[i+1] = 0;
1674
1675     /* fetch the data */
1676     key.dptr  = keybuf;
1677     key.dsize = 21;
1678     if( !gdbm_exists( dbf, key ) )
1679         return -1; /* not found */
1680     return 0;
1681 }
1682
1683 /****************
1684  * locate by keyid.
1685  * FIXME: we must have a way to enumerate thru the list opf fingerprints
1686  */
1687 static int
1688 do_gdbm_locate_by_keyid( GDBM_FILE dbf, KBPOS *kbpos, u32 *keyid )
1689 {
1690     byte keybuf[9];
1691     datum key, content;
1692     int rc;
1693
1694     /* construct the fingerprint which is used as the primary key */
1695     *keybuf = 2;
1696     u32tobuf( keybuf+1, keyid[0] );
1697     u32tobuf( keybuf+5, keyid[1] );
1698
1699     /* fetch the data */
1700     key.dptr  = keybuf;
1701     key.dsize = 9;
1702     content = gdbm_fetch( dbf, key );
1703     if( !content.dptr )
1704         return -1;
1705
1706     if( content.dsize < 2 ) {
1707         log_error("gdbm_fetch did not return enough data\n" );
1708         free( content.dptr ); /* can't use m_free() here */
1709         return G10ERR_INV_KEYRING;
1710     }
1711     if( *content.dptr != 2 ) {
1712         log_error("gdbm_fetch returned unexpected type %d\n",
1713                     *(byte*)content.dptr );
1714         free( content.dptr ); /* can't use m_free() here */
1715         return G10ERR_INV_KEYRING;
1716     }
1717     if( content.dsize < 21 ) {
1718         log_error("gdbm_fetch did not return a complete fingerprint\n" );
1719         free( content.dptr ); /* can't use m_free() here */
1720         return G10ERR_INV_KEYRING;
1721     }
1722     if( content.dsize > 21 )
1723         log_info("gdbm_fetch: WARNING: more than one fingerprint\n" );
1724
1725     rc = do_gdbm_locate( dbf, kbpos, content.dptr+1, 20 );
1726     free( content.dptr ); /* can't use m_free() here */
1727     return rc;
1728 }
1729
1730
1731
1732 static int
1733 do_gdbm_read( KBPOS *kbpos, KBNODE *ret_root )
1734 {
1735     PACKET *pkt;
1736     int rc;
1737     RESTBL *rentry;
1738     KBNODE root = NULL;
1739     IOBUF a;
1740     datum key, content;
1741
1742     if( !(rentry=check_pos(kbpos)) )
1743         return G10ERR_GENERAL;
1744
1745     key.dptr  = kbpos->keybuf;
1746     key.dsize = 21;
1747     content = gdbm_fetch( rentry->dbf, key );
1748     if( !content.dptr ) {
1749         log_error("gdbm_fetch failed: %s\n", gdbm_strerror(gdbm_errno) );
1750         return G10ERR_INV_KEYRING;
1751     }
1752     if( content.dsize < 2 ) {
1753         log_error("gdbm_fetch did not return enough data\n" );
1754         free( content.dptr ); /* can't use m_free() here */
1755         return G10ERR_INV_KEYRING;
1756     }
1757     if( *content.dptr != 1 ) {
1758         log_error("gdbm_fetch returned unexpected type %d\n",
1759                     *(byte*)content.dptr );
1760         free( content.dptr ); /* can't use m_free() here */
1761         return G10ERR_INV_KEYRING;
1762     }
1763
1764     a = iobuf_temp_with_content( content.dptr+1, content.dsize-1 );
1765     free( content.dptr ); /* can't use m_free() here */
1766
1767     pkt = m_alloc( sizeof *pkt );
1768     init_packet(pkt);
1769     kbpos->count=0;
1770     while( (rc=parse_packet(a, pkt)) != -1 ) {
1771         if( rc ) {  /* ignore errors */
1772             if( rc != G10ERR_UNKNOWN_PACKET ) {
1773                 log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
1774                 rc = G10ERR_INV_KEYRING;
1775                 break;
1776             }
1777             kbpos->count++;
1778             free_packet( pkt );
1779             init_packet( pkt );
1780             continue;
1781         }
1782         /* make a linked list of all packets */
1783         kbpos->count++;
1784         if( !root )
1785             root = new_kbnode( pkt );
1786         else
1787             add_kbnode( root, new_kbnode( pkt ) );
1788         pkt = m_alloc( sizeof *pkt );
1789         init_packet(pkt);
1790     }
1791     if( rc == -1 && root )
1792         rc = 0;
1793     if( rc )
1794         release_kbnode( root );
1795     else
1796         *ret_root = root;
1797     free_packet( pkt );
1798     m_free( pkt );
1799     iobuf_close(a);
1800     return rc;
1801 }
1802
1803
1804 /****************
1805  * Enum over keyblok data
1806  */
1807 static int
1808 do_gdbm_enum( KBPOS *kbpos, KBNODE *ret_root )
1809 {
1810     RESTBL *rentry;
1811     datum key, helpkey;
1812
1813     if( !(rentry=check_pos(kbpos)) )
1814         return G10ERR_GENERAL;
1815
1816     if( !kbpos->offset ) {
1817         kbpos->offset = 1;
1818         key = gdbm_firstkey( rentry->dbf );
1819     }
1820     else {
1821         helpkey.dptr = kbpos->keybuf;
1822         helpkey.dsize= 21;
1823         key = gdbm_nextkey( rentry->dbf, helpkey );
1824     }
1825     while( key.dptr && (!key.dsize || *key.dptr != 1) ) {
1826         helpkey = key;
1827         key = gdbm_nextkey( rentry->dbf, helpkey );
1828         free( helpkey.dptr ); /* free and not m_free() ! */
1829     }
1830     if( !key.dptr )
1831         return -1; /* eof */
1832
1833     if( key.dsize < 21 ) {
1834         free( key.dptr ); /* free and not m_free() ! */
1835         log_error("do_gdm_enum: key is too short\n" );
1836         return G10ERR_INV_KEYRING;
1837     }
1838     memcpy( kbpos->keybuf, key.dptr, 21 );
1839     free( key.dptr ); /* free and not m_free() ! */
1840     return do_gdbm_read( kbpos, ret_root );
1841 }
1842
1843 #endif /*HAVE_LIBGDBM*/