See ChangeLog: Tue Dec 29 14:41:47 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_open( filename );
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       #if __MINGW32__ || 1
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         kbpos->valid = 0;
691         switch( kbpos->rt ) {
692           case rt_RING:
693             kbpos->fp = iobuf_open( rentry->fname );
694             if( !kbpos->fp ) {
695                 log_error("can't open `%s'\n", rentry->fname );
696                 return G10ERR_OPEN_FILE;
697             }
698             break;
699          #ifdef HAVE_LIBGDBM
700           case rt_GDBM:
701             /* FIXME: make sure that there is only one enum at a time */
702             kbpos->offset = 0;
703             break;
704          #endif
705           default: BUG();
706         }
707         kbpos->pkt = NULL;
708     }
709     else if( mode == 1 || mode == 11 ) {
710         int cont;
711         do {
712             cont = 0;
713             switch( kbpos->rt ) {
714               case rt_RING:
715                 if( !kbpos->fp )
716                     return G10ERR_GENERAL;
717                 rc = keyring_enum( kbpos, ret_root, mode == 11 );
718                 break;
719              #ifdef HAVE_LIBGDBM
720               case rt_GDBM:
721                 rc = do_gdbm_enum( kbpos, ret_root );
722                 break;
723              #endif
724               default: BUG();
725             }
726
727             if( rc == -1 ) {
728                 assert( !kbpos->pkt );
729                 rentry = check_pos( kbpos );
730                 assert(rentry);
731                 /* close */
732                 enum_keyblocks(2, kbpos, ret_root );
733                 /* and open the next one */
734                 rc = enum_keyblocks(100, kbpos, ret_root );
735                 if( !rc )
736                     cont = 1;
737             }
738         } while(cont);
739     }
740     else {
741         switch( kbpos->rt ) {
742           case rt_RING:
743             if( kbpos->fp ) {
744                 iobuf_close( kbpos->fp );
745                 kbpos->fp = NULL;
746             }
747             break;
748           case rt_GDBM:
749             break;
750           default:
751             log_error("OOPS in close enum_keyblocks - ignored\n");
752             return rc;
753             break;
754         }
755         /* release pending packet */
756         free_packet( kbpos->pkt );
757         m_free( kbpos->pkt );
758     }
759     return rc;
760 }
761
762
763
764
765 /****************
766  * Insert the keyblock described by ROOT into the keyring described
767  * by KBPOS.  This actually appends the data to the keyfile.
768  */
769 int
770 insert_keyblock( KBPOS *kbpos, KBNODE root )
771 {
772     int rc;
773
774     if( !check_pos(kbpos) )
775         return G10ERR_GENERAL;
776
777     switch( kbpos->rt ) {
778       case rt_RING:
779         rc = keyring_copy( kbpos, 1, root );
780         break;
781      #ifdef HAVE_LIBGDBM
782       case rt_GDBM:
783         rc = do_gdbm_store( kbpos, root, 0 );
784         break;
785      #endif
786       default: BUG();
787     }
788
789     return rc;
790 }
791
792 /****************
793  * Delete the keyblock described by KBPOS.
794  * The current code simply changes the keyblock in the keyring
795  * to packet of type 0 with the correct length.  To help detect errors,
796  * zero bytes are written.
797  */
798 int
799 delete_keyblock( KBPOS *kbpos )
800 {
801     int rc;
802
803     if( !check_pos(kbpos) )
804         return G10ERR_GENERAL;
805
806     switch( kbpos->rt ) {
807       case rt_RING:
808         rc = keyring_copy( kbpos, 2, NULL );
809         break;
810      #ifdef HAVE_LIBGDBM
811       case rt_GDBM:
812         log_debug("deleting gdbm keyblock is not yet implemented\n");
813         rc = 0;
814         break;
815      #endif
816       default: BUG();
817     }
818
819     return rc;
820 }
821
822
823 /****************
824  * Update the keyblock at KBPOS with the one in ROOT.
825  */
826 int
827 update_keyblock( KBPOS *kbpos, KBNODE root )
828 {
829     int rc;
830
831     if( !check_pos(kbpos) )
832         return G10ERR_GENERAL;
833
834     switch( kbpos->rt ) {
835       case rt_RING:
836         rc = keyring_copy( kbpos, 3, root );
837         break;
838      #ifdef HAVE_LIBGDBM
839       case rt_GDBM:
840         rc = do_gdbm_store( kbpos, root, 1 );
841         break;
842      #endif
843       default: BUG();
844     }
845
846     return rc;
847 }
848
849
850 \f
851 /****************************************************************
852  ********** Implemenation of a user ID database    **************
853  ****************************************************************/
854 #if 0
855 /****************
856  * Layout of the user ID db
857  *
858  * This user ID DB provides fast lookup of user ID, but the user ids are
859  * not in any specific order.
860  *
861  * A string "GnuPG user db", a \n.
862  * user ids of one key, delimited by \t,
863  * a # or ^ followed by a 20 byte fingerprint, followed by an \n
864  * The literal characters %, \n, \t, #, ^ must be replaced by a percent sign
865  * and their hex value.
866  *
867  * (We use Boyer/Moore pattern matching)
868  */
869
870 /****************
871  * This compiles pattern to the distance table, the table will be allocate
872  * here and must be freed by using free().
873  * Returns: Ptr to new allocated Table
874  *          Caller must free the table.
875  */
876
877 static size_t *
878 compile_bm_table( const byte *pattern, size_t len )
879 {
880     ushort *dist;
881     int i;
882
883     dist = m_alloc_clear( 256 * sizeof *dist );
884     for(i=0; i < 256; i++ )
885         dist[i] = len;
886     for(i=0; i < len-1; i++ )
887         dTbl[p[i]] = len-i-1;
888     return dist;
889 }
890
891
892
893
894 /****************
895  * Search BUF of BUFLEN for pattern P of length PATLEN.
896  * dist is the Boyer/Moore distance table of 256 Elements,
897  * case insensitive search is done if IGNCASE is true (In this case
898  * the distance table has to compiled from uppercase chacaters and
899  * PAT must also be uppercase.
900  * Returns: Prt to maching string in BUF, or NULL if not found.
901  */
902
903 static const *
904 do_bm_search( const byte *buf, size_t buflen,
905               const byte *pat, size_t patlen, size_t *dist, int igncase )
906 {
907     int i, j, k;
908
909     if( igncase ) {
910         int c, c1;
911
912         for( i = --patlen; i < buflen; i += dist[c1] )
913             for( j=patlen, k=i, c1=c=toupper(buf[k]); c == pat[j];
914                                           j--, k--, c=toupper(buf[k]) ) {
915                 if( !j )
916                     return buf+k;
917             }
918     }
919     else {
920         for( i = --patlen; i < buflen; i += dist[buf[i]] )
921             for( j=patlen, k=i; buf[k] == pat[j]; j--, k-- ) {
922                 if( !j )
923                     return buf+k;
924             }
925     }
926     return NULL;
927 }
928
929
930 typedef struct {
931     size_t dist[256];
932 } *SCAN_USER_HANDLE;
933
934 static SCAN_USER_HANDLE
935 scan_user_file_open( const byte *name )
936 {
937     SCAN_USER_HANDLE hd;
938     size_t *dist;
939     int i;
940
941     hd = m_alloc_clear( sizeof *hd );
942     dist = hd->dist;
943     /* compile the distance table */
944     for(i=0; i < 256; i++ )
945         dist[i] = len;
946     for(i=0; i < len-1; i++ )
947         dTbl[p[i]] = len-i-1;
948     /* setup other things */
949
950     return hd;
951 }
952
953 static int
954 scan_user_file_close( SCAN_USER_HANDLE hd )
955 {
956     m_free( hd );
957 }
958
959 static int
960 scan_user_file_read( SCAN_USER_HANDLE hd, byte *fpr )
961 {
962     char record[1000];
963
964     /* read a record */
965
966
967 }
968 #endif
969
970
971 \f
972 /****************************************************************
973  ********** Functions which operates on regular keyrings ********
974  ****************************************************************/
975
976 static int
977 cmp_seckey( PKT_secret_key *req_sk, PKT_secret_key *sk )
978 {
979     int n,i;
980
981     assert( req_sk->pubkey_algo == sk->pubkey_algo );
982
983     n = pubkey_get_nskey( req_sk->pubkey_algo );
984     for(i=0; i < n; i++ ) {
985         if( mpi_cmp( req_sk->skey[i], sk->skey[i] ) )
986             return -1;
987     }
988     return 0;
989 }
990
991 static int
992 cmp_pubkey( PKT_public_key *req_pk, PKT_public_key *pk )
993 {
994     int n, i;
995
996     assert( req_pk->pubkey_algo == pk->pubkey_algo );
997
998     n = pubkey_get_npkey( req_pk->pubkey_algo );
999     for(i=0; i < n; i++ ) {
1000         if( mpi_cmp( req_pk->pkey[i], pk->pkey[i] )  )
1001             return -1;
1002     }
1003     return 0;
1004 }
1005
1006 /****************
1007  * search one keyring, return 0 if found, -1 if not found or an errorcode.
1008  */
1009 static int
1010 keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname )
1011 {
1012     int rc;
1013     PACKET pkt;
1014     int save_mode;
1015     ulong offset;
1016     int pkttype = req->pkttype;
1017     PKT_public_key *req_pk = req->pkt.public_key;
1018     PKT_secret_key *req_sk = req->pkt.secret_key;
1019
1020     init_packet(&pkt);
1021     save_mode = set_packet_list_mode(0);
1022     kbpos->rt = rt_RING;
1023     kbpos->valid = 0;
1024
1025   #if __MINGW32__  || 1
1026     assert(!iobuf);
1027     iobuf = iobuf_open( fname );
1028     if( !iobuf ) {
1029         log_error("%s: can't open keyring file\n", fname);
1030         rc = G10ERR_KEYRING_OPEN;
1031         goto leave;
1032     }
1033   #else
1034     if( iobuf_seek( iobuf, 0 ) ) {
1035         log_error("can't rewind keyring file\n");
1036         rc = G10ERR_KEYRING_OPEN;
1037         goto leave;
1038     }
1039   #endif
1040
1041     while( !(rc=search_packet(iobuf, &pkt, pkttype, &offset)) ) {
1042         if( pkt.pkttype == PKT_SECRET_KEY ) {
1043             PKT_secret_key *sk = pkt.pkt.secret_key;
1044
1045             if(   req_sk->timestamp == sk->timestamp
1046                && req_sk->pubkey_algo == sk->pubkey_algo
1047                && !cmp_seckey( req_sk, sk) )
1048                 break; /* found */
1049         }
1050         else if( pkt.pkttype == PKT_PUBLIC_KEY ) {
1051             PKT_public_key *pk = pkt.pkt.public_key;
1052
1053             if(   req_pk->timestamp == pk->timestamp
1054                && req_pk->pubkey_algo == pk->pubkey_algo
1055                && !cmp_pubkey( req_pk, pk ) )
1056                 break; /* found */
1057         }
1058         else
1059             BUG();
1060         free_packet(&pkt);
1061     }
1062     if( !rc ) {
1063         kbpos->offset = offset;
1064         kbpos->valid = 1;
1065     }
1066
1067   leave:
1068     free_packet(&pkt);
1069     set_packet_list_mode(save_mode);
1070   #if __MINGW32__ || 1
1071     iobuf_close(iobuf);
1072   #endif
1073     return rc;
1074 }
1075
1076
1077 static int
1078 keyring_read( KBPOS *kbpos, KBNODE *ret_root )
1079 {
1080     PACKET *pkt;
1081     int rc;
1082     RESTBL *rentry;
1083     KBNODE root = NULL;
1084     IOBUF a;
1085     int in_cert = 0;
1086
1087     if( !(rentry=check_pos(kbpos)) )
1088         return G10ERR_GENERAL;
1089
1090     a = iobuf_open( rentry->fname );
1091     if( !a ) {
1092         log_error("can't open `%s'\n", rentry->fname );
1093         return G10ERR_OPEN_FILE;
1094     }
1095
1096     if( !kbpos->valid )
1097         log_debug("kbpos not valid in keyring_read, want %d\n", (int)kbpos->offset );
1098     if( iobuf_seek( a, kbpos->offset ) ) {
1099         log_error("can't seek to %lu\n", kbpos->offset);
1100         iobuf_close(a);
1101         return G10ERR_KEYRING_OPEN;
1102     }
1103
1104     pkt = m_alloc( sizeof *pkt );
1105     init_packet(pkt);
1106     kbpos->count=0;
1107     while( (rc=parse_packet(a, pkt)) != -1 ) {
1108         if( rc ) {  /* ignore errors */
1109             if( rc != G10ERR_UNKNOWN_PACKET ) {
1110                 log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
1111                 rc = G10ERR_INV_KEYRING;
1112                 goto ready;
1113             }
1114             kbpos->count++;
1115             free_packet( pkt );
1116             init_packet( pkt );
1117             continue;
1118         }
1119         /* make a linked list of all packets */
1120         switch( pkt->pkttype ) {
1121           case PKT_COMPRESSED:
1122             log_error("skipped compressed packet in keyring\n" );
1123             free_packet(pkt);
1124             init_packet(pkt);
1125             break;
1126
1127           case PKT_PUBLIC_KEY:
1128           case PKT_SECRET_KEY:
1129             if( in_cert )
1130                 goto ready;
1131             in_cert = 1;
1132           default:
1133             kbpos->count++;
1134             if( !root )
1135                 root = new_kbnode( pkt );
1136             else
1137                 add_kbnode( root, new_kbnode( pkt ) );
1138             pkt = m_alloc( sizeof *pkt );
1139             init_packet(pkt);
1140             break;
1141         }
1142     }
1143   ready:
1144     kbpos->valid = 0;
1145     if( rc == -1 && root )
1146         rc = 0;
1147
1148     if( rc )
1149         release_kbnode( root );
1150     else
1151         *ret_root = root;
1152     free_packet( pkt );
1153     m_free( pkt );
1154     iobuf_close(a);
1155     return rc;
1156 }
1157
1158
1159 static int
1160 keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs )
1161 {
1162     PACKET *pkt;
1163     int rc;
1164     RESTBL *rentry;
1165     KBNODE root = NULL;
1166
1167     if( !(rentry=check_pos(kbpos)) )
1168         return G10ERR_GENERAL;
1169
1170     if( kbpos->pkt ) {
1171         root = new_kbnode( kbpos->pkt );
1172         kbpos->pkt = NULL;
1173     }
1174
1175     pkt = m_alloc( sizeof *pkt );
1176     init_packet(pkt);
1177     while( (rc=parse_packet(kbpos->fp, pkt)) != -1 ) {
1178         if( rc ) {  /* ignore errors */
1179             if( rc != G10ERR_UNKNOWN_PACKET ) {
1180                 log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
1181                 rc = G10ERR_INV_KEYRING;
1182                 goto ready;
1183             }
1184             free_packet( pkt );
1185             init_packet( pkt );
1186             continue;
1187         }
1188         /* make a linked list of all packets */
1189         switch( pkt->pkttype ) {
1190           case PKT_COMPRESSED:
1191             log_error("skipped compressed packet in keyring\n" );
1192             free_packet(pkt);
1193             init_packet(pkt);
1194             break;
1195
1196           case PKT_PUBLIC_KEY:
1197           case PKT_SECRET_KEY:
1198             if( root ) { /* store this packet */
1199                 kbpos->pkt = pkt;
1200                 pkt = NULL;
1201                 goto ready;
1202             }
1203             root = new_kbnode( pkt );
1204             pkt = m_alloc( sizeof *pkt );
1205             init_packet(pkt);
1206             break;
1207
1208           default:
1209             /* skip pakets at the beginning of a keyring, until we find
1210              * a start packet; issue a warning if it is not a comment */
1211             if( !root && pkt->pkttype != PKT_COMMENT
1212                       && pkt->pkttype != PKT_OLD_COMMENT ) {
1213                 break;
1214             }
1215             if( !root || (skipsigs && ( pkt->pkttype == PKT_SIGNATURE
1216                                       ||pkt->pkttype == PKT_COMMENT
1217                                       ||pkt->pkttype == PKT_OLD_COMMENT )) ) {
1218                 init_packet(pkt);
1219                 break;
1220             }
1221             add_kbnode( root, new_kbnode( pkt ) );
1222             pkt = m_alloc( sizeof *pkt );
1223             init_packet(pkt);
1224             break;
1225         }
1226     }
1227   ready:
1228     if( rc == -1 && root )
1229         rc = 0;
1230
1231     if( rc )
1232         release_kbnode( root );
1233     else
1234         *ret_root = root;
1235     free_packet( pkt );
1236     m_free( pkt );
1237
1238     return rc;
1239 }
1240
1241
1242 /****************
1243  * Perform insert/delete/update operation.
1244  * mode 1 = insert
1245  *      2 = delete
1246  *      3 = update
1247  */
1248 static int
1249 keyring_copy( KBPOS *kbpos, int mode, KBNODE root )
1250 {
1251     RESTBL *rentry;
1252     IOBUF fp, newfp;
1253     int rc=0;
1254     char *bakfname = NULL;
1255     char *tmpfname = NULL;
1256
1257     if( !(rentry = check_pos( kbpos )) )
1258         return G10ERR_GENERAL;
1259     if( kbpos->fp )
1260         BUG(); /* not allowed with such a handle */
1261
1262     if( !keyring_lock );
1263         keyring_lock = make_dotlock( rentry->fname, -1 );
1264     if( !keyring_lock )
1265         log_fatal("can't lock `%s'\n", rentry->fname );
1266
1267     /* open the source file */
1268     fp = iobuf_open( rentry->fname );
1269     if( mode == 1 && !fp && errno == ENOENT ) { /* no file yet */
1270         KBNODE kbctx, node;
1271
1272         /* insert: create a new file */
1273         newfp = iobuf_create( rentry->fname );
1274         if( !newfp ) {
1275             log_error(_("%s: can't create: %s\n"), rentry->fname, strerror(errno));
1276             if( !opt.lock_once ) {
1277                 release_dotlock( keyring_lock );
1278                 keyring_lock = NULL;
1279             }
1280             return G10ERR_OPEN_FILE;
1281         }
1282         else
1283             log_info(_("%s: keyring created\n"), rentry->fname );
1284
1285         kbctx=NULL;
1286         while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
1287             if( (rc = build_packet( newfp, node->pkt )) ) {
1288                 log_error("build_packet(%d) failed: %s\n",
1289                             node->pkt->pkttype, g10_errstr(rc) );
1290                 iobuf_cancel(newfp);
1291                 if( !opt.lock_once ) {
1292                     release_dotlock( keyring_lock );
1293                     keyring_lock = NULL;
1294                 }
1295                 return G10ERR_WRITE_FILE;
1296             }
1297         }
1298         if( iobuf_close(newfp) ) {
1299             log_error("%s: close failed: %s\n", rentry->fname, strerror(errno));
1300             if( !opt.lock_once ) {
1301                 release_dotlock( keyring_lock );
1302                 keyring_lock = NULL;
1303             }
1304             return G10ERR_CLOSE_FILE;
1305         }
1306         if( chmod( rentry->fname, S_IRUSR | S_IWUSR ) ) {
1307             log_error("%s: chmod failed: %s\n",
1308                                     rentry->fname, strerror(errno) );
1309             if( !opt.lock_once ) {
1310                 release_dotlock( keyring_lock );
1311                 keyring_lock = NULL;
1312             }
1313             return G10ERR_WRITE_FILE;
1314         }
1315         return 0;
1316     }
1317     if( !fp ) {
1318         log_error("%s: can't open: %s\n", rentry->fname, strerror(errno) );
1319         rc = G10ERR_OPEN_FILE;
1320         goto leave;
1321     }
1322
1323     /* create the new file */
1324   #ifdef __MINGW32__
1325     /* Here is another Windoze bug?:
1326      * you cant rename("pubring.gpg.tmp", "pubring.gpg");
1327      * but      rename("pubring.gpg.tmp", "pubring.aaa");
1328      * works.  So we replace .gpg by .bak or .tmp
1329      */
1330     if( strlen(rentry->fname) > 4
1331         && !strcmp(rentry->fname+strlen(rentry->fname)-4, ".gpg") ) {
1332         bakfname = m_alloc( strlen( rentry->fname ) + 1 );
1333         strcpy(bakfname,rentry->fname);
1334         strcpy(bakfname+strlen(rentry->fname)-4, ".bak");
1335         tmpfname = m_alloc( strlen( rentry->fname ) + 1 );
1336         strcpy(tmpfname,rentry->fname);
1337         strcpy(tmpfname+strlen(rentry->fname)-4, ".tmp");
1338     }
1339     else { /* file does not end with gpg; hmmm */
1340         bakfname = m_alloc( strlen( rentry->fname ) + 5 );
1341         strcpy(stpcpy(bakfname,rentry->fname),".bak");
1342         tmpfname = m_alloc( strlen( rentry->fname ) + 5 );
1343         strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
1344     }
1345   #else
1346     bakfname = m_alloc( strlen( rentry->fname ) + 2 );
1347     strcpy(stpcpy(bakfname,rentry->fname),"~");
1348     tmpfname = m_alloc( strlen( rentry->fname ) + 5 );
1349     strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
1350   #endif
1351     newfp = iobuf_create( tmpfname );
1352     if( !newfp ) {
1353         log_error("%s: can't create: %s\n", tmpfname, strerror(errno) );
1354         iobuf_close(fp);
1355         rc = G10ERR_OPEN_FILE;
1356         goto leave;
1357     }
1358
1359     if( mode == 1 ) { /* insert */
1360         /* copy everything to the new file */
1361         rc = copy_all_packets( fp, newfp );
1362         if( rc != -1 ) {
1363             log_error("%s: copy to %s failed: %s\n",
1364                       rentry->fname, tmpfname, g10_errstr(rc) );
1365             iobuf_close(fp);
1366             iobuf_cancel(newfp);
1367             goto leave;
1368         }
1369         rc = 0;
1370     }
1371
1372     if( mode == 2 || mode == 3 ) { /* delete or update */
1373         /* copy first part to the new file */
1374         rc = copy_some_packets( fp, newfp, kbpos->offset );
1375         if( rc ) { /* should never get EOF here */
1376             log_error("%s: copy to %s failed: %s\n",
1377                       rentry->fname, tmpfname, g10_errstr(rc) );
1378             iobuf_close(fp);
1379             iobuf_cancel(newfp);
1380             goto leave;
1381         }
1382         /* skip this keyblock */
1383         assert( kbpos->count );
1384         rc = skip_some_packets( fp, kbpos->count );
1385         if( rc ) {
1386             log_error("%s: skipping %u packets failed: %s\n",
1387                             rentry->fname, kbpos->count, g10_errstr(rc));
1388             iobuf_close(fp);
1389             iobuf_cancel(newfp);
1390             goto leave;
1391         }
1392     }
1393
1394     if( mode == 1 || mode == 3 ) { /* insert or update */
1395         KBNODE kbctx, node;
1396
1397         /* append the new data */
1398         kbctx=NULL;
1399         while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
1400             if( (rc = build_packet( newfp, node->pkt )) ) {
1401                 log_error("build_packet(%d) failed: %s\n",
1402                             node->pkt->pkttype, g10_errstr(rc) );
1403                 iobuf_close(fp);
1404                 iobuf_cancel(newfp);
1405                 rc = G10ERR_WRITE_FILE;
1406                 goto leave;
1407             }
1408         }
1409         kbpos->valid = 0;
1410     }
1411
1412     if( mode == 2 || mode == 3 ) { /* delete or update */
1413         /* copy the rest */
1414         rc = copy_all_packets( fp, newfp );
1415         if( rc != -1 ) {
1416             log_error("%s: copy to %s failed: %s\n",
1417                       rentry->fname, tmpfname, g10_errstr(rc) );
1418             iobuf_close(fp);
1419             iobuf_cancel(newfp);
1420             goto leave;
1421         }
1422         rc = 0;
1423     }
1424
1425     /* close both files */
1426     if( iobuf_close(fp) ) {
1427         log_error("%s: close failed: %s\n", rentry->fname, strerror(errno) );
1428         rc = G10ERR_CLOSE_FILE;
1429         goto leave;
1430     }
1431     if( iobuf_close(newfp) ) {
1432         log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
1433         rc = G10ERR_CLOSE_FILE;
1434         goto leave;
1435     }
1436     /* if the new file is a secring, restrict the permissions */
1437   #ifndef __MINGW32__
1438     if( rentry->secret ) {
1439         if( chmod( tmpfname, S_IRUSR | S_IWUSR ) ) {
1440             log_error("%s: chmod failed: %s\n",
1441                                     tmpfname, strerror(errno) );
1442             rc = G10ERR_WRITE_FILE;
1443             goto leave;
1444         }
1445     }
1446   #endif
1447
1448     /* rename and make backup file */
1449     if( !rentry->secret ) {  /* but not for secret keyrings */
1450       #ifdef __MINGW32__
1451         remove( bakfname );
1452       #endif
1453         if( rename( rentry->fname, bakfname ) ) {
1454             log_error("%s: rename to %s failed: %s\n",
1455                                     rentry->fname, bakfname, strerror(errno) );
1456             rc = G10ERR_RENAME_FILE;
1457             goto leave;
1458         }
1459     }
1460   #ifdef __MINGW32__
1461     remove( rentry->fname );
1462   #endif
1463     if( rename( tmpfname, rentry->fname ) ) {
1464         log_error("%s: rename to %s failed: %s\n",
1465                             tmpfname, rentry->fname,strerror(errno) );
1466         rc = G10ERR_RENAME_FILE;
1467         if( rentry->secret ) {
1468             log_info(_(
1469                 "WARNING: 2 files with confidential information exists.\n"));
1470             log_info(_("%s is the unchanged one\n"), rentry->fname );
1471             log_info(_("%s is the new one\n"), tmpfname );
1472             log_info(_("Please fix this possible security flaw\n"));
1473         }
1474         goto leave;
1475     }
1476
1477   leave:
1478     if( !opt.lock_once ) {
1479         release_dotlock( keyring_lock );
1480         keyring_lock = NULL;
1481     }
1482     m_free(bakfname);
1483     m_free(tmpfname);
1484     return rc;
1485 }
1486
1487 \f
1488 #ifdef HAVE_LIBGDBM
1489 /****************************************************************
1490  ********** Functions which operates on GDM files ***************
1491  ****************************************************************/
1492
1493 #if MAX_FINGERPRINT_LEN > 20
1494   #error A GDBM keyring assumes that fingerprints are less than 21
1495 #endif
1496
1497 /****************
1498  * Insert the keyblock into the GDBM database
1499  */
1500
1501 static int
1502 do_gdbm_store( KBPOS *kbpos, KBNODE root, int update )
1503 {
1504     RESTBL *rentry;
1505     PKT_public_key *pk;
1506     KBNODE kbctx, node;
1507     IOBUF fp = NULL;
1508     byte fpr[20];
1509     byte contbuf[21];
1510     byte keybuf[21];
1511     size_t fprlen;
1512     datum key, content;
1513     int i, rc;
1514
1515     if( !(rentry = check_pos( kbpos )) )
1516         return G10ERR_GENERAL;
1517
1518     /* construct the fingerprint which is used as the primary key */
1519     node = find_kbnode( root, PKT_PUBLIC_KEY );
1520     if( !node )
1521         log_bug("a gdbm database can't store secret keys\n");
1522     pk = node->pkt->pkt.public_key;
1523
1524     fingerprint_from_pk( pk, fpr, &fprlen );
1525     for(i=fprlen; i < DIM(fpr); i++ )
1526         fpr[i] = 0;
1527
1528     /* build the keyblock */
1529     kbctx=NULL;
1530     fp = iobuf_temp();
1531     iobuf_put( fp, 1 ); /* data is a keyblock */
1532     while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
1533         if( (rc = build_packet( fp, node->pkt )) ) {
1534             log_error("build_packet(%d) failed: %s\n",
1535                         node->pkt->pkttype, g10_errstr(rc) );
1536             rc = G10ERR_WRITE_FILE;
1537             goto leave;
1538         }
1539     }
1540     /* store data and key */
1541     *keybuf = 1;   /* key is a padded fingerprint */
1542     memcpy(keybuf+1, fpr, 20 );
1543     key.dptr  = keybuf;
1544     key.dsize = 21;
1545     content.dptr  = iobuf_get_temp_buffer( fp );
1546     content.dsize = iobuf_get_temp_length( fp );
1547     rc = gdbm_store( rentry->dbf, key, content,
1548                                   update? GDBM_REPLACE : GDBM_INSERT );
1549     if( rc == 1 && !update )
1550         rc = gdbm_store( rentry->dbf, key, content, GDBM_REPLACE );
1551
1552     if( rc ) {
1553         log_error("%s: gdbm_store failed: %s\n", rentry->fname,
1554                             rc == 1 ? "already stored"
1555                                     : gdbm_strerror(gdbm_errno) );
1556         rc = G10ERR_WRITE_FILE;
1557         goto leave;
1558     }
1559     /* now store all keyids */
1560     *contbuf = 2;  /* data is a list of fingerprints */
1561     memcpy(contbuf+1, fpr, 20 );
1562     content.dptr = contbuf;
1563     content.dsize= 21;
1564     kbctx=NULL;
1565     while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
1566         if(    node->pkt->pkttype == PKT_PUBLIC_KEY
1567             || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
1568             u32 aki[2];
1569
1570             keyid_from_pk( node->pkt->pkt.public_key, aki );
1571             *keybuf = 2; /* key is a 8 byte keyid */
1572             u32tobuf( keybuf+1  , aki[0] );
1573             u32tobuf( keybuf+5, aki[1] );
1574             key.dptr = keybuf;
1575             key.dsize= 9;
1576             /* fixme: must be more clever when a insert failed:
1577              *        build a list of fingerprints in this case */
1578             rc = gdbm_store( rentry->dbf, key, content,
1579                                           update? GDBM_REPLACE : GDBM_INSERT );
1580             if( rc ) {
1581                 log_info("%s: gdbm_store keyid failed: %s\n", rentry->fname,
1582                                     rc == 1 ? "already stored"
1583                                             : gdbm_strerror(gdbm_errno) );
1584                 rc = 0;
1585             }
1586         }
1587     }
1588
1589   leave:
1590     iobuf_close(fp); /* don't need a cancel because it is a temp iobuf */
1591     return rc;
1592 }
1593
1594
1595
1596 /****************
1597  * search one keybox, return 0 if found, -1 if not found or an errorcode.
1598  */
1599 static int
1600 do_gdbm_locate( GDBM_FILE dbf, KBPOS *kbpos, const byte *fpr, int fprlen )
1601 {
1602     byte *keybuf = kbpos->keybuf;
1603     datum key;
1604     int i;
1605
1606     *keybuf = 1;
1607     for(i=0; i < fprlen; i++ )
1608         keybuf[i+1] = fpr[i];
1609     for(; i < 20; i++ )
1610         keybuf[i+1] = 0;
1611
1612     /* fetch the data */
1613     key.dptr  = keybuf;
1614     key.dsize = 21;
1615     if( !gdbm_exists( dbf, key ) )
1616         return -1; /* not found */
1617     return 0;
1618 }
1619
1620 /****************
1621  * locate by keyid.
1622  * FIXME: we must have a way to enumerate thru the list opf fingerprints
1623  */
1624 static int
1625 do_gdbm_locate_by_keyid( GDBM_FILE dbf, KBPOS *kbpos, u32 *keyid )
1626 {
1627     byte keybuf[9];
1628     datum key, content;
1629     int rc;
1630
1631     /* construct the fingerprint which is used as the primary key */
1632     *keybuf = 2;
1633     u32tobuf( keybuf+1, keyid[0] );
1634     u32tobuf( keybuf+5, keyid[1] );
1635
1636     /* fetch the data */
1637     key.dptr  = keybuf;
1638     key.dsize = 9;
1639     content = gdbm_fetch( dbf, key );
1640     if( !content.dptr )
1641         return -1;
1642
1643     if( content.dsize < 2 ) {
1644         log_error("gdbm_fetch did not return enough data\n" );
1645         free( content.dptr ); /* can't use m_free() here */
1646         return G10ERR_INV_KEYRING;
1647     }
1648     if( *content.dptr != 2 ) {
1649         log_error("gdbm_fetch returned unexpected type %d\n",
1650                     *(byte*)content.dptr );
1651         free( content.dptr ); /* can't use m_free() here */
1652         return G10ERR_INV_KEYRING;
1653     }
1654     if( content.dsize < 21 ) {
1655         log_error("gdbm_fetch did not return a complete fingerprint\n" );
1656         free( content.dptr ); /* can't use m_free() here */
1657         return G10ERR_INV_KEYRING;
1658     }
1659     if( content.dsize > 21 )
1660         log_info("gdbm_fetch: WARNING: more than one fingerprint\n" );
1661
1662     rc = do_gdbm_locate( dbf, kbpos, content.dptr+1, 20 );
1663     free( content.dptr ); /* can't use m_free() here */
1664     return rc;
1665 }
1666
1667
1668
1669 static int
1670 do_gdbm_read( KBPOS *kbpos, KBNODE *ret_root )
1671 {
1672     PACKET *pkt;
1673     int rc;
1674     RESTBL *rentry;
1675     KBNODE root = NULL;
1676     IOBUF a;
1677     datum key, content;
1678
1679     if( !(rentry=check_pos(kbpos)) )
1680         return G10ERR_GENERAL;
1681
1682     key.dptr  = kbpos->keybuf;
1683     key.dsize = 21;
1684     content = gdbm_fetch( rentry->dbf, key );
1685     if( !content.dptr ) {
1686         log_error("gdbm_fetch failed: %s\n", gdbm_strerror(gdbm_errno) );
1687         return G10ERR_INV_KEYRING;
1688     }
1689     if( content.dsize < 2 ) {
1690         log_error("gdbm_fetch did not return enough data\n" );
1691         free( content.dptr ); /* can't use m_free() here */
1692         return G10ERR_INV_KEYRING;
1693     }
1694     if( *content.dptr != 1 ) {
1695         log_error("gdbm_fetch returned unexpected type %d\n",
1696                     *(byte*)content.dptr );
1697         free( content.dptr ); /* can't use m_free() here */
1698         return G10ERR_INV_KEYRING;
1699     }
1700
1701     a = iobuf_temp_with_content( content.dptr+1, content.dsize-1 );
1702     free( content.dptr ); /* can't use m_free() here */
1703
1704     pkt = m_alloc( sizeof *pkt );
1705     init_packet(pkt);
1706     kbpos->count=0;
1707     while( (rc=parse_packet(a, pkt)) != -1 ) {
1708         if( rc ) {  /* ignore errors */
1709             if( rc != G10ERR_UNKNOWN_PACKET ) {
1710                 log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
1711                 rc = G10ERR_INV_KEYRING;
1712                 break;
1713             }
1714             kbpos->count++;
1715             free_packet( pkt );
1716             init_packet( pkt );
1717             continue;
1718         }
1719         /* make a linked list of all packets */
1720         kbpos->count++;
1721         if( !root )
1722             root = new_kbnode( pkt );
1723         else
1724             add_kbnode( root, new_kbnode( pkt ) );
1725         pkt = m_alloc( sizeof *pkt );
1726         init_packet(pkt);
1727     }
1728     if( rc == -1 && root )
1729         rc = 0;
1730     if( rc )
1731         release_kbnode( root );
1732     else
1733         *ret_root = root;
1734     free_packet( pkt );
1735     m_free( pkt );
1736     iobuf_close(a);
1737     return rc;
1738 }
1739
1740
1741 /****************
1742  * Enum over keyblok data
1743  */
1744 static int
1745 do_gdbm_enum( KBPOS *kbpos, KBNODE *ret_root )
1746 {
1747     RESTBL *rentry;
1748     datum key, helpkey;
1749
1750     if( !(rentry=check_pos(kbpos)) )
1751         return G10ERR_GENERAL;
1752
1753     if( !kbpos->offset ) {
1754         kbpos->offset = 1;
1755         key = gdbm_firstkey( rentry->dbf );
1756     }
1757     else {
1758         helpkey.dptr = kbpos->keybuf;
1759         helpkey.dsize= 21;
1760         key = gdbm_nextkey( rentry->dbf, helpkey );
1761     }
1762     while( key.dptr && (!key.dsize || *key.dptr != 1) ) {
1763         helpkey = key;
1764         key = gdbm_nextkey( rentry->dbf, helpkey );
1765         free( helpkey.dptr ); /* free and not m_free() ! */
1766     }
1767     if( !key.dptr )
1768         return -1; /* eof */
1769
1770     if( key.dsize < 21 ) {
1771         free( key.dptr ); /* free and not m_free() ! */
1772         log_error("do_gdm_enum: key is too short\n" );
1773         return G10ERR_INV_KEYRING;
1774     }
1775     memcpy( kbpos->keybuf, key.dptr, 21 );
1776     free( key.dptr ); /* free and not m_free() ! */
1777     return do_gdbm_read( kbpos, ret_root );
1778 }
1779
1780 #endif /*HAVE_LIBGDBM*/