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