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