See ChangeLog: Thu Jan 21 06:22:10 CET 1999 Werner Koch
[gnupg.git] / g10 / ringedit.c
1 /* ringedit.c -  Function for key ring editing
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21
22 /****************
23  * This module supplies function for:
24  *
25  *  - Search for a key block (pubkey and all other stuff) and return a
26  *    handle for it.
27  *
28  *  - Lock/Unlock a key block
29  *
30  *  - Read a key block into a tree
31  *
32  *  - Update a key block
33  *
34  *  - Insert a new key block
35  *
36  *  - Delete a key block
37  *
38  */
39
40
41
42 #include <config.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <errno.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <unistd.h> /* for truncate */
50 #include <assert.h>
51 #ifdef HAVE_LIBGDBM
52   #include <gdbm.h>
53 #endif
54 #include "util.h"
55 #include "packet.h"
56 #include "memory.h"
57 #include "mpi.h"
58 #include "iobuf.h"
59 #include "keydb.h"
60 #include "host2net.h"
61 #include "options.h"
62 #include "main.h"
63 #include "i18n.h"
64
65
66 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  * Combined function to search for a key and get the position
485  * of the keyblock.
486  */
487 int
488 find_keyblock_bysk( KBPOS *kbpos, PKT_secret_key *sk )
489 {
490     PACKET pkt;
491     int rc;
492
493     init_packet( &pkt );
494     pkt.pkttype = PKT_SECRET_KEY;
495     pkt.pkt.secret_key = sk;
496     rc = search( &pkt, kbpos, 0 );
497     return rc;
498 }
499
500
501 /****************
502  * Combined function to search for a username and get the position
503  * of the keyblock. This function does not unprotect the secret key.
504  */
505 int
506 find_secret_keyblock_byname( KBPOS *kbpos, const char *username )
507 {
508     PACKET pkt;
509     PKT_secret_key *sk = m_alloc_clear( sizeof *sk );
510     int rc;
511
512     rc = get_seckey_byname( sk, username, 0 );
513     if( rc ) {
514         free_secret_key(sk);
515         return rc;
516     }
517
518     init_packet( &pkt );
519     pkt.pkttype = PKT_SECRET_KEY;
520     pkt.pkt.secret_key = sk;
521     rc = search( &pkt, kbpos, 1 );
522     free_secret_key(sk);
523     return rc;
524 }
525
526
527 /****************
528  * Locate a keyblock in a database which is capable of direct access
529  * Put all information into KBPOS, which can be later be to access this
530  * key block.
531  * This function looks into all registered keyblock sources.
532  *
533  * Returns: 0 if found,
534  *          -1 if not found
535  *          G10ERR_UNSUPPORTED if no resource is able to handle this
536  *          or another errorcode.
537  */
538 int
539 locate_keyblock_by_fpr( KBPOS *kbpos, const byte *fpr, int fprlen, int secret )
540 {
541     RESTBL *rentry;
542     int i, rc, any=0, last_rc=-1;
543
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              #ifdef HAVE_LIBGDBM
550               case rt_GDBM:
551                 any = 1;
552                 rc = do_gdbm_locate( rentry->dbf, kbpos, fpr, fprlen );
553                 break;
554              #endif
555               default:
556                 rc = G10ERR_UNSUPPORTED;
557                 break;
558             }
559
560             if( !rc ) {
561                 kbpos->resno = i;
562                 kbpos->fp = NULL;
563                 return 0;
564             }
565             else if( rc != -1 && rc != G10ERR_UNSUPPORTED ) {
566                 log_error("error searching resource %d: %s\n",
567                                                   i, g10_errstr(rc));
568                 last_rc = rc;
569             }
570         }
571     }
572
573     return (last_rc == -1 && !any)? G10ERR_UNSUPPORTED : last_rc;
574 }
575
576
577 int
578 locate_keyblock_by_keyid( KBPOS *kbpos, u32 *keyid, int shortkid, int secret )
579 {
580     RESTBL *rentry;
581     int i, rc, any=0, last_rc=-1;
582
583     if( shortkid )
584         return G10ERR_UNSUPPORTED;
585
586     for(i=0, rentry = resource_table; i < MAX_RESOURCES; i++, rentry++ ) {
587         if( rentry->used && !rentry->secret == !secret ) {
588             kbpos->rt = rentry->rt;
589             switch( rentry->rt ) {
590              #ifdef HAVE_LIBGDBM
591               case rt_GDBM:
592                 any = 1;
593                 rc = do_gdbm_locate_by_keyid( rentry->dbf, kbpos, keyid );
594                 break;
595              #endif
596               default:
597                 rc = G10ERR_UNSUPPORTED;
598                 break;
599             }
600
601             if( !rc ) {
602                 kbpos->resno = i;
603                 kbpos->fp = NULL;
604                 return 0;
605             }
606             else if( rc != -1 && rc != G10ERR_UNSUPPORTED ) {
607                 log_error("error searching resource %d: %s\n",
608                                                   i, g10_errstr(rc));
609                 last_rc = rc;
610             }
611         }
612     }
613
614     return (last_rc == -1 && !any)? G10ERR_UNSUPPORTED : last_rc;
615 }
616
617
618
619
620 /****************
621  * Lock the keyblock; wait until it's available
622  * This function may change the internal data in kbpos, in cases
623  * when the keyblock to be locked has been modified.
624  * fixme: remove this function and add an option to search()?
625  */
626 int
627 lock_keyblock( KBPOS *kbpos )
628 {
629     if( !check_pos(kbpos) )
630         return G10ERR_GENERAL;
631     return 0;
632 }
633
634 /****************
635  * Release a lock on a keyblock
636  */
637 void
638 unlock_keyblock( KBPOS *kbpos )
639 {
640     if( !check_pos(kbpos) )
641         BUG();
642 }
643
644 /****************
645  * Read a complete keyblock and return the root in ret_root.
646  */
647 int
648 read_keyblock( KBPOS *kbpos, KBNODE *ret_root )
649 {
650     if( !check_pos(kbpos) )
651         return G10ERR_GENERAL;
652
653     switch( kbpos->rt ) {
654       case rt_RING:
655         return keyring_read( kbpos, ret_root );
656      #ifdef HAVE_LIBGDBM
657       case rt_GDBM:
658         return do_gdbm_read( kbpos, ret_root );
659      #endif
660       default: BUG();
661     }
662 }
663
664
665 /****************
666  * This functions can be used to read through a complete keyring.
667  * Mode is: 0 = open
668  *          1 = read
669  *          2 = close
670  *          5 = open secret keyrings
671  *          11 = read but skip signature and comment packets.
672  *          all others are reserved!
673  * Note that you do not need a search prior to this function,
674  * only a handle is needed.
675  * NOTE: It is not allowed to do an insert/update/delete with this
676  *       keyblock, if you want to do this, use search/read!
677  */
678 int
679 enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root )
680 {
681     int rc = 0;
682     RESTBL *rentry;
683
684     if( !mode || mode == 5 || mode == 100 ) {
685         int i;
686         kbpos->fp = NULL;
687         if( !mode ) {
688             kbpos->secret = 0;
689             i = 0;
690         }
691         else if( mode == 5 ) {
692             kbpos->secret = 1;
693             mode = 0;
694             i = 0;
695         }
696         else
697             i = kbpos->resno+1;
698         for(; i < MAX_RESOURCES; i++ )
699             if( resource_table[i].used
700                 && !resource_table[i].secret == !kbpos->secret )
701                 break;
702         if( i == MAX_RESOURCES )
703             return -1; /* no resources */
704         kbpos->resno = i;
705         rentry = check_pos( kbpos );
706         kbpos->rt = resource_table[i].rt;
707         kbpos->valid = 0;
708         switch( kbpos->rt ) {
709           case rt_RING:
710             kbpos->fp = iobuf_open( rentry->fname );
711             if( !kbpos->fp ) {
712                 log_error("can't open `%s'\n", rentry->fname );
713                 return G10ERR_OPEN_FILE;
714             }
715             break;
716          #ifdef HAVE_LIBGDBM
717           case rt_GDBM:
718             /* FIXME: make sure that there is only one enum at a time */
719             kbpos->offset = 0;
720             break;
721          #endif
722           default: BUG();
723         }
724         kbpos->pkt = NULL;
725     }
726     else if( mode == 1 || mode == 11 ) {
727         int cont;
728         do {
729             cont = 0;
730             switch( kbpos->rt ) {
731               case rt_RING:
732                 if( !kbpos->fp )
733                     return G10ERR_GENERAL;
734                 rc = keyring_enum( kbpos, ret_root, mode == 11 );
735                 break;
736              #ifdef HAVE_LIBGDBM
737               case rt_GDBM:
738                 rc = do_gdbm_enum( kbpos, ret_root );
739                 break;
740              #endif
741               default: BUG();
742             }
743
744             if( rc == -1 ) {
745                 assert( !kbpos->pkt );
746                 rentry = check_pos( kbpos );
747                 assert(rentry);
748                 /* close */
749                 enum_keyblocks(2, kbpos, ret_root );
750                 /* and open the next one */
751                 rc = enum_keyblocks(100, kbpos, ret_root );
752                 if( !rc )
753                     cont = 1;
754             }
755         } while(cont);
756     }
757     else {
758         switch( kbpos->rt ) {
759           case rt_RING:
760             if( kbpos->fp ) {
761                 iobuf_close( kbpos->fp );
762                 kbpos->fp = NULL;
763             }
764             break;
765           case rt_GDBM:
766             break;
767           default:
768             log_error("OOPS in close enum_keyblocks - ignored\n");
769             return rc;
770             break;
771         }
772         /* release pending packet */
773         free_packet( kbpos->pkt );
774         m_free( kbpos->pkt );
775     }
776     return rc;
777 }
778
779
780
781
782 /****************
783  * Insert the keyblock described by ROOT into the keyring described
784  * by KBPOS.  This actually appends the data to the keyfile.
785  */
786 int
787 insert_keyblock( KBPOS *kbpos, KBNODE root )
788 {
789     int rc;
790
791     if( !check_pos(kbpos) )
792         return G10ERR_GENERAL;
793
794     switch( kbpos->rt ) {
795       case rt_RING:
796         rc = keyring_copy( kbpos, 1, root );
797         break;
798      #ifdef HAVE_LIBGDBM
799       case rt_GDBM:
800         rc = do_gdbm_store( kbpos, root, 0 );
801         break;
802      #endif
803       default: BUG();
804     }
805
806     return rc;
807 }
808
809 /****************
810  * Delete the keyblock described by KBPOS.
811  * The current code simply changes the keyblock in the keyring
812  * to packet of type 0 with the correct length.  To help detect errors,
813  * zero bytes are written.
814  */
815 int
816 delete_keyblock( KBPOS *kbpos )
817 {
818     int rc;
819
820     if( !check_pos(kbpos) )
821         return G10ERR_GENERAL;
822
823     switch( kbpos->rt ) {
824       case rt_RING:
825         rc = keyring_copy( kbpos, 2, NULL );
826         break;
827      #ifdef HAVE_LIBGDBM
828       case rt_GDBM:
829         log_debug("deleting gdbm keyblock is not yet implemented\n");
830         rc = 0;
831         break;
832      #endif
833       default: BUG();
834     }
835
836     return rc;
837 }
838
839
840 /****************
841  * Update the keyblock at KBPOS with the one in ROOT.
842  */
843 int
844 update_keyblock( KBPOS *kbpos, KBNODE root )
845 {
846     int rc;
847
848     if( !check_pos(kbpos) )
849         return G10ERR_GENERAL;
850
851     switch( kbpos->rt ) {
852       case rt_RING:
853         rc = keyring_copy( kbpos, 3, root );
854         break;
855      #ifdef HAVE_LIBGDBM
856       case rt_GDBM:
857         rc = do_gdbm_store( kbpos, root, 1 );
858         break;
859      #endif
860       default: BUG();
861     }
862
863     return rc;
864 }
865
866
867 \f
868 /****************************************************************
869  ********** Implemenation of a user ID database    **************
870  ****************************************************************/
871 #if 0
872 /****************
873  * Layout of the user ID db
874  *
875  * This user ID DB provides fast lookup of user ID, but the user ids are
876  * not in any specific order.
877  *
878  * A string "GnuPG user db", a \n.
879  * user ids of one key, delimited by \t,
880  * a # or ^ followed by a 20 byte fingerprint, followed by an \n
881  * The literal characters %, \n, \t, #, ^ must be replaced by a percent sign
882  * and their hex value.
883  *
884  * (We use Boyer/Moore pattern matching)
885  */
886
887 /****************
888  * This compiles pattern to the distance table, the table will be allocate
889  * here and must be freed by using free().
890  * Returns: Ptr to new allocated Table
891  *          Caller must free the table.
892  */
893
894 static size_t *
895 compile_bm_table( const byte *pattern, size_t len )
896 {
897     ushort *dist;
898     int i;
899
900     dist = m_alloc_clear( 256 * sizeof *dist );
901     for(i=0; i < 256; i++ )
902         dist[i] = len;
903     for(i=0; i < len-1; i++ )
904         dTbl[p[i]] = len-i-1;
905     return dist;
906 }
907
908
909
910
911 /****************
912  * Search BUF of BUFLEN for pattern P of length PATLEN.
913  * dist is the Boyer/Moore distance table of 256 Elements,
914  * case insensitive search is done if IGNCASE is true (In this case
915  * the distance table has to compiled from uppercase chacaters and
916  * PAT must also be uppercase.
917  * Returns: Prt to maching string in BUF, or NULL if not found.
918  */
919
920 static const *
921 do_bm_search( const byte *buf, size_t buflen,
922               const byte *pat, size_t patlen, size_t *dist, int igncase )
923 {
924     int i, j, k;
925
926     if( igncase ) {
927         int c, c1;
928
929         for( i = --patlen; i < buflen; i += dist[c1] )
930             for( j=patlen, k=i, c1=c=toupper(buf[k]); c == pat[j];
931                                           j--, k--, c=toupper(buf[k]) ) {
932                 if( !j )
933                     return buf+k;
934             }
935     }
936     else {
937         for( i = --patlen; i < buflen; i += dist[buf[i]] )
938             for( j=patlen, k=i; buf[k] == pat[j]; j--, k-- ) {
939                 if( !j )
940                     return buf+k;
941             }
942     }
943     return NULL;
944 }
945
946
947 typedef struct {
948     size_t dist[256];
949 } *SCAN_USER_HANDLE;
950
951 static SCAN_USER_HANDLE
952 scan_user_file_open( const byte *name )
953 {
954     SCAN_USER_HANDLE hd;
955     size_t *dist;
956     int i;
957
958     hd = m_alloc_clear( sizeof *hd );
959     dist = hd->dist;
960     /* compile the distance table */
961     for(i=0; i < 256; i++ )
962         dist[i] = len;
963     for(i=0; i < len-1; i++ )
964         dTbl[p[i]] = len-i-1;
965     /* setup other things */
966
967     return hd;
968 }
969
970 static int
971 scan_user_file_close( SCAN_USER_HANDLE hd )
972 {
973     m_free( hd );
974 }
975
976 static int
977 scan_user_file_read( SCAN_USER_HANDLE hd, byte *fpr )
978 {
979     char record[1000];
980
981     /* read a record */
982
983
984 }
985 #endif
986
987
988 \f
989 /****************************************************************
990  ********** Functions which operates on regular keyrings ********
991  ****************************************************************/
992
993 static int
994 cmp_seckey( PKT_secret_key *req_sk, PKT_secret_key *sk )
995 {
996     int n,i;
997
998     assert( req_sk->pubkey_algo == sk->pubkey_algo );
999
1000     n = pubkey_get_nskey( req_sk->pubkey_algo );
1001     for(i=0; i < n; i++ ) {
1002         if( mpi_cmp( req_sk->skey[i], sk->skey[i] ) )
1003             return -1;
1004     }
1005     return 0;
1006 }
1007
1008 static int
1009 cmp_pubkey( PKT_public_key *req_pk, PKT_public_key *pk )
1010 {
1011     int n, i;
1012
1013     assert( req_pk->pubkey_algo == pk->pubkey_algo );
1014
1015     n = pubkey_get_npkey( req_pk->pubkey_algo );
1016     for(i=0; i < n; i++ ) {
1017         if( mpi_cmp( req_pk->pkey[i], pk->pkey[i] )  )
1018             return -1;
1019     }
1020     return 0;
1021 }
1022
1023 /****************
1024  * search one keyring, return 0 if found, -1 if not found or an errorcode.
1025  */
1026 static int
1027 keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname )
1028 {
1029     int rc;
1030     PACKET pkt;
1031     int save_mode;
1032     ulong offset;
1033     int pkttype = req->pkttype;
1034     PKT_public_key *req_pk = req->pkt.public_key;
1035     PKT_secret_key *req_sk = req->pkt.secret_key;
1036
1037     init_packet(&pkt);
1038     save_mode = set_packet_list_mode(0);
1039     kbpos->rt = rt_RING;
1040     kbpos->valid = 0;
1041
1042   #if __MINGW32__  || 1
1043     assert(!iobuf);
1044     iobuf = iobuf_open( fname );
1045     if( !iobuf ) {
1046         log_error("%s: can't open keyring file\n", fname);
1047         rc = G10ERR_KEYRING_OPEN;
1048         goto leave;
1049     }
1050   #else
1051     if( iobuf_seek( iobuf, 0 ) ) {
1052         log_error("can't rewind keyring file\n");
1053         rc = G10ERR_KEYRING_OPEN;
1054         goto leave;
1055     }
1056   #endif
1057
1058     while( !(rc=search_packet(iobuf, &pkt, pkttype, &offset)) ) {
1059         if( pkt.pkttype == PKT_SECRET_KEY ) {
1060             PKT_secret_key *sk = pkt.pkt.secret_key;
1061
1062             if(   req_sk->timestamp == sk->timestamp
1063                && req_sk->pubkey_algo == sk->pubkey_algo
1064                && !cmp_seckey( req_sk, sk) )
1065                 break; /* found */
1066         }
1067         else if( pkt.pkttype == PKT_PUBLIC_KEY ) {
1068             PKT_public_key *pk = pkt.pkt.public_key;
1069
1070             if(   req_pk->timestamp == pk->timestamp
1071                && req_pk->pubkey_algo == pk->pubkey_algo
1072                && !cmp_pubkey( req_pk, pk ) )
1073                 break; /* found */
1074         }
1075         else
1076             BUG();
1077         free_packet(&pkt);
1078     }
1079     if( !rc ) {
1080         kbpos->offset = offset;
1081         kbpos->valid = 1;
1082     }
1083
1084   leave:
1085     free_packet(&pkt);
1086     set_packet_list_mode(save_mode);
1087   #if __MINGW32__ || 1
1088     iobuf_close(iobuf);
1089   #endif
1090     return rc;
1091 }
1092
1093
1094 static int
1095 keyring_read( KBPOS *kbpos, KBNODE *ret_root )
1096 {
1097     PACKET *pkt;
1098     int rc;
1099     RESTBL *rentry;
1100     KBNODE root = NULL;
1101     IOBUF a;
1102     int in_cert = 0;
1103
1104     if( !(rentry=check_pos(kbpos)) )
1105         return G10ERR_GENERAL;
1106
1107     a = iobuf_open( rentry->fname );
1108     if( !a ) {
1109         log_error("can't open `%s'\n", rentry->fname );
1110         return G10ERR_OPEN_FILE;
1111     }
1112
1113     if( !kbpos->valid )
1114         log_debug("kbpos not valid in keyring_read, want %d\n", (int)kbpos->offset );
1115     if( iobuf_seek( a, kbpos->offset ) ) {
1116         log_error("can't seek to %lu\n", kbpos->offset);
1117         iobuf_close(a);
1118         return G10ERR_KEYRING_OPEN;
1119     }
1120
1121     pkt = m_alloc( sizeof *pkt );
1122     init_packet(pkt);
1123     kbpos->count=0;
1124     while( (rc=parse_packet(a, pkt)) != -1 ) {
1125         if( rc ) {  /* ignore errors */
1126             if( rc != G10ERR_UNKNOWN_PACKET ) {
1127                 log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
1128                 rc = G10ERR_INV_KEYRING;
1129                 goto ready;
1130             }
1131             kbpos->count++;
1132             free_packet( pkt );
1133             init_packet( pkt );
1134             continue;
1135         }
1136         /* make a linked list of all packets */
1137         switch( pkt->pkttype ) {
1138           case PKT_COMPRESSED:
1139             log_error("skipped compressed packet in keyring\n" );
1140             free_packet(pkt);
1141             init_packet(pkt);
1142             break;
1143
1144           case PKT_PUBLIC_KEY:
1145           case PKT_SECRET_KEY:
1146             if( in_cert )
1147                 goto ready;
1148             in_cert = 1;
1149           default:
1150             kbpos->count++;
1151             if( !root )
1152                 root = new_kbnode( pkt );
1153             else
1154                 add_kbnode( root, new_kbnode( pkt ) );
1155             pkt = m_alloc( sizeof *pkt );
1156             init_packet(pkt);
1157             break;
1158         }
1159     }
1160   ready:
1161     kbpos->valid = 0;
1162     if( rc == -1 && root )
1163         rc = 0;
1164
1165     if( rc )
1166         release_kbnode( root );
1167     else
1168         *ret_root = root;
1169     free_packet( pkt );
1170     m_free( pkt );
1171     iobuf_close(a);
1172     return rc;
1173 }
1174
1175
1176 static int
1177 keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs )
1178 {
1179     PACKET *pkt;
1180     int rc;
1181     RESTBL *rentry;
1182     KBNODE root = NULL;
1183
1184     if( !(rentry=check_pos(kbpos)) )
1185         return G10ERR_GENERAL;
1186
1187     if( kbpos->pkt ) {
1188         root = new_kbnode( kbpos->pkt );
1189         kbpos->pkt = NULL;
1190     }
1191
1192     pkt = m_alloc( sizeof *pkt );
1193     init_packet(pkt);
1194     while( (rc=parse_packet(kbpos->fp, pkt)) != -1 ) {
1195         if( rc ) {  /* ignore errors */
1196             if( rc != G10ERR_UNKNOWN_PACKET ) {
1197                 log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
1198                 rc = G10ERR_INV_KEYRING;
1199                 goto ready;
1200             }
1201             free_packet( pkt );
1202             init_packet( pkt );
1203             continue;
1204         }
1205         /* make a linked list of all packets */
1206         switch( pkt->pkttype ) {
1207           case PKT_COMPRESSED:
1208             log_error("skipped compressed packet in keyring\n" );
1209             free_packet(pkt);
1210             init_packet(pkt);
1211             break;
1212
1213           case PKT_PUBLIC_KEY:
1214           case PKT_SECRET_KEY:
1215             if( root ) { /* store this packet */
1216                 kbpos->pkt = pkt;
1217                 pkt = NULL;
1218                 goto ready;
1219             }
1220             root = new_kbnode( pkt );
1221             pkt = m_alloc( sizeof *pkt );
1222             init_packet(pkt);
1223             break;
1224
1225           default:
1226             /* skip pakets at the beginning of a keyring, until we find
1227              * a start packet; issue a warning if it is not a comment */
1228             if( !root && pkt->pkttype != PKT_COMMENT
1229                       && pkt->pkttype != PKT_OLD_COMMENT ) {
1230                 break;
1231             }
1232             if( !root || (skipsigs && ( pkt->pkttype == PKT_SIGNATURE
1233                                       ||pkt->pkttype == PKT_COMMENT
1234                                       ||pkt->pkttype == PKT_OLD_COMMENT )) ) {
1235                 init_packet(pkt);
1236                 break;
1237             }
1238             add_kbnode( root, new_kbnode( pkt ) );
1239             pkt = m_alloc( sizeof *pkt );
1240             init_packet(pkt);
1241             break;
1242         }
1243     }
1244   ready:
1245     if( rc == -1 && root )
1246         rc = 0;
1247
1248     if( rc )
1249         release_kbnode( root );
1250     else
1251         *ret_root = root;
1252     free_packet( pkt );
1253     m_free( pkt );
1254
1255     return rc;
1256 }
1257
1258
1259 /****************
1260  * Perform insert/delete/update operation.
1261  * mode 1 = insert
1262  *      2 = delete
1263  *      3 = update
1264  */
1265 static int
1266 keyring_copy( KBPOS *kbpos, int mode, KBNODE root )
1267 {
1268     RESTBL *rentry;
1269     IOBUF fp, newfp;
1270     int rc=0;
1271     char *bakfname = NULL;
1272     char *tmpfname = NULL;
1273
1274     if( !(rentry = check_pos( kbpos )) )
1275         return G10ERR_GENERAL;
1276     if( kbpos->fp )
1277         BUG(); /* not allowed with such a handle */
1278
1279     if( !keyring_lock );
1280         keyring_lock = make_dotlock( rentry->fname, -1 );
1281     if( !keyring_lock )
1282         log_fatal("can't lock `%s'\n", rentry->fname );
1283
1284     /* open the source file */
1285     fp = iobuf_open( rentry->fname );
1286     if( mode == 1 && !fp && errno == ENOENT ) { /* no file yet */
1287         KBNODE kbctx, node;
1288
1289         /* insert: create a new file */
1290         newfp = iobuf_create( rentry->fname );
1291         if( !newfp ) {
1292             log_error(_("%s: can't create: %s\n"), rentry->fname, strerror(errno));
1293             if( !opt.lock_once ) {
1294                 release_dotlock( keyring_lock );
1295                 keyring_lock = NULL;
1296             }
1297             return G10ERR_OPEN_FILE;
1298         }
1299         else
1300             log_info(_("%s: keyring created\n"), rentry->fname );
1301
1302         kbctx=NULL;
1303         while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
1304             if( (rc = build_packet( newfp, node->pkt )) ) {
1305                 log_error("build_packet(%d) failed: %s\n",
1306                             node->pkt->pkttype, g10_errstr(rc) );
1307                 iobuf_cancel(newfp);
1308                 if( !opt.lock_once ) {
1309                     release_dotlock( keyring_lock );
1310                     keyring_lock = NULL;
1311                 }
1312                 return G10ERR_WRITE_FILE;
1313             }
1314         }
1315         if( iobuf_close(newfp) ) {
1316             log_error("%s: close failed: %s\n", rentry->fname, strerror(errno));
1317             if( !opt.lock_once ) {
1318                 release_dotlock( keyring_lock );
1319                 keyring_lock = NULL;
1320             }
1321             return G10ERR_CLOSE_FILE;
1322         }
1323         if( chmod( rentry->fname, S_IRUSR | S_IWUSR ) ) {
1324             log_error("%s: chmod failed: %s\n",
1325                                     rentry->fname, strerror(errno) );
1326             if( !opt.lock_once ) {
1327                 release_dotlock( keyring_lock );
1328                 keyring_lock = NULL;
1329             }
1330             return G10ERR_WRITE_FILE;
1331         }
1332         return 0;
1333     }
1334     if( !fp ) {
1335         log_error("%s: can't open: %s\n", rentry->fname, strerror(errno) );
1336         rc = G10ERR_OPEN_FILE;
1337         goto leave;
1338     }
1339
1340     /* create the new file */
1341   #ifdef __MINGW32__
1342     /* Here is another Windoze bug?:
1343      * you cant rename("pubring.gpg.tmp", "pubring.gpg");
1344      * but      rename("pubring.gpg.tmp", "pubring.aaa");
1345      * works.  So we replace .gpg by .bak or .tmp
1346      */
1347     if( strlen(rentry->fname) > 4
1348         && !strcmp(rentry->fname+strlen(rentry->fname)-4, ".gpg") ) {
1349         bakfname = m_alloc( strlen( rentry->fname ) + 1 );
1350         strcpy(bakfname,rentry->fname);
1351         strcpy(bakfname+strlen(rentry->fname)-4, ".bak");
1352         tmpfname = m_alloc( strlen( rentry->fname ) + 1 );
1353         strcpy(tmpfname,rentry->fname);
1354         strcpy(tmpfname+strlen(rentry->fname)-4, ".tmp");
1355     }
1356     else { /* file does not end with gpg; hmmm */
1357         bakfname = m_alloc( strlen( rentry->fname ) + 5 );
1358         strcpy(stpcpy(bakfname,rentry->fname),".bak");
1359         tmpfname = m_alloc( strlen( rentry->fname ) + 5 );
1360         strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
1361     }
1362   #else
1363     bakfname = m_alloc( strlen( rentry->fname ) + 2 );
1364     strcpy(stpcpy(bakfname,rentry->fname),"~");
1365     tmpfname = m_alloc( strlen( rentry->fname ) + 5 );
1366     strcpy(stpcpy(tmpfname,rentry->fname),".tmp");
1367   #endif
1368     newfp = iobuf_create( tmpfname );
1369     if( !newfp ) {
1370         log_error("%s: can't create: %s\n", tmpfname, strerror(errno) );
1371         iobuf_close(fp);
1372         rc = G10ERR_OPEN_FILE;
1373         goto leave;
1374     }
1375
1376     if( mode == 1 ) { /* insert */
1377         /* copy everything to the new file */
1378         rc = copy_all_packets( fp, newfp );
1379         if( rc != -1 ) {
1380             log_error("%s: copy to %s failed: %s\n",
1381                       rentry->fname, tmpfname, g10_errstr(rc) );
1382             iobuf_close(fp);
1383             iobuf_cancel(newfp);
1384             goto leave;
1385         }
1386         rc = 0;
1387     }
1388
1389     if( mode == 2 || mode == 3 ) { /* delete or update */
1390         /* copy first part to the new file */
1391         rc = copy_some_packets( fp, newfp, kbpos->offset );
1392         if( rc ) { /* should never get EOF here */
1393             log_error("%s: copy to %s failed: %s\n",
1394                       rentry->fname, tmpfname, g10_errstr(rc) );
1395             iobuf_close(fp);
1396             iobuf_cancel(newfp);
1397             goto leave;
1398         }
1399         /* skip this keyblock */
1400         assert( kbpos->count );
1401         rc = skip_some_packets( fp, kbpos->count );
1402         if( rc ) {
1403             log_error("%s: skipping %u packets failed: %s\n",
1404                             rentry->fname, kbpos->count, g10_errstr(rc));
1405             iobuf_close(fp);
1406             iobuf_cancel(newfp);
1407             goto leave;
1408         }
1409     }
1410
1411     if( mode == 1 || mode == 3 ) { /* insert or update */
1412         KBNODE kbctx, node;
1413
1414         /* append the new data */
1415         kbctx=NULL;
1416         while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
1417             if( (rc = build_packet( newfp, node->pkt )) ) {
1418                 log_error("build_packet(%d) failed: %s\n",
1419                             node->pkt->pkttype, g10_errstr(rc) );
1420                 iobuf_close(fp);
1421                 iobuf_cancel(newfp);
1422                 rc = G10ERR_WRITE_FILE;
1423                 goto leave;
1424             }
1425         }
1426         kbpos->valid = 0;
1427     }
1428
1429     if( mode == 2 || mode == 3 ) { /* delete or update */
1430         /* copy the rest */
1431         rc = copy_all_packets( fp, newfp );
1432         if( rc != -1 ) {
1433             log_error("%s: copy to %s failed: %s\n",
1434                       rentry->fname, tmpfname, g10_errstr(rc) );
1435             iobuf_close(fp);
1436             iobuf_cancel(newfp);
1437             goto leave;
1438         }
1439         rc = 0;
1440     }
1441
1442     /* close both files */
1443     if( iobuf_close(fp) ) {
1444         log_error("%s: close failed: %s\n", rentry->fname, strerror(errno) );
1445         rc = G10ERR_CLOSE_FILE;
1446         goto leave;
1447     }
1448     if( iobuf_close(newfp) ) {
1449         log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
1450         rc = G10ERR_CLOSE_FILE;
1451         goto leave;
1452     }
1453     /* if the new file is a secring, restrict the permissions */
1454   #ifndef __MINGW32__
1455     if( rentry->secret ) {
1456         if( chmod( tmpfname, S_IRUSR | S_IWUSR ) ) {
1457             log_error("%s: chmod failed: %s\n",
1458                                     tmpfname, strerror(errno) );
1459             rc = G10ERR_WRITE_FILE;
1460             goto leave;
1461         }
1462     }
1463   #endif
1464
1465     /* rename and make backup file */
1466     if( !rentry->secret ) {  /* but not for secret keyrings */
1467       #ifdef __MINGW32__
1468         remove( bakfname );
1469       #endif
1470         if( rename( rentry->fname, bakfname ) ) {
1471             log_error("%s: rename to %s failed: %s\n",
1472                                     rentry->fname, bakfname, strerror(errno) );
1473             rc = G10ERR_RENAME_FILE;
1474             goto leave;
1475         }
1476     }
1477   #ifdef __MINGW32__
1478     remove( rentry->fname );
1479   #endif
1480     if( rename( tmpfname, rentry->fname ) ) {
1481         log_error("%s: rename to %s failed: %s\n",
1482                             tmpfname, rentry->fname,strerror(errno) );
1483         rc = G10ERR_RENAME_FILE;
1484         if( rentry->secret ) {
1485             log_info(_(
1486                 "WARNING: 2 files with confidential information exists.\n"));
1487             log_info(_("%s is the unchanged one\n"), rentry->fname );
1488             log_info(_("%s is the new one\n"), tmpfname );
1489             log_info(_("Please fix this possible security flaw\n"));
1490         }
1491         goto leave;
1492     }
1493
1494   leave:
1495     if( !opt.lock_once ) {
1496         release_dotlock( keyring_lock );
1497         keyring_lock = NULL;
1498     }
1499     m_free(bakfname);
1500     m_free(tmpfname);
1501     return rc;
1502 }
1503
1504 \f
1505 #ifdef HAVE_LIBGDBM
1506 /****************************************************************
1507  ********** Functions which operates on GDM files ***************
1508  ****************************************************************/
1509
1510 #if MAX_FINGERPRINT_LEN > 20
1511   #error A GDBM keyring assumes that fingerprints are less than 21
1512 #endif
1513
1514 /****************
1515  * Insert the keyblock into the GDBM database
1516  */
1517
1518 static int
1519 do_gdbm_store( KBPOS *kbpos, KBNODE root, int update )
1520 {
1521     RESTBL *rentry;
1522     PKT_public_key *pk;
1523     KBNODE kbctx, node;
1524     IOBUF fp = NULL;
1525     byte fpr[20];
1526     byte contbuf[21];
1527     byte keybuf[21];
1528     size_t fprlen;
1529     datum key, content;
1530     int i, rc;
1531
1532     if( !(rentry = check_pos( kbpos )) )
1533         return G10ERR_GENERAL;
1534
1535     /* construct the fingerprint which is used as the primary key */
1536     node = find_kbnode( root, PKT_PUBLIC_KEY );
1537     if( !node )
1538         log_bug("a gdbm database can't store secret keys\n");
1539     pk = node->pkt->pkt.public_key;
1540
1541     fingerprint_from_pk( pk, fpr, &fprlen );
1542     for(i=fprlen; i < DIM(fpr); i++ )
1543         fpr[i] = 0;
1544
1545     /* build the keyblock */
1546     kbctx=NULL;
1547     fp = iobuf_temp();
1548     iobuf_put( fp, 1 ); /* data is a keyblock */
1549     while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
1550         if( (rc = build_packet( fp, node->pkt )) ) {
1551             log_error("build_packet(%d) failed: %s\n",
1552                         node->pkt->pkttype, g10_errstr(rc) );
1553             rc = G10ERR_WRITE_FILE;
1554             goto leave;
1555         }
1556     }
1557     /* store data and key */
1558     *keybuf = 1;   /* key is a padded fingerprint */
1559     memcpy(keybuf+1, fpr, 20 );
1560     key.dptr  = keybuf;
1561     key.dsize = 21;
1562     content.dptr  = iobuf_get_temp_buffer( fp );
1563     content.dsize = iobuf_get_temp_length( fp );
1564     rc = gdbm_store( rentry->dbf, key, content,
1565                                   update? GDBM_REPLACE : GDBM_INSERT );
1566     if( rc == 1 && !update )
1567         rc = gdbm_store( rentry->dbf, key, content, GDBM_REPLACE );
1568
1569     if( rc ) {
1570         log_error("%s: gdbm_store failed: %s\n", rentry->fname,
1571                             rc == 1 ? "already stored"
1572                                     : gdbm_strerror(gdbm_errno) );
1573         rc = G10ERR_WRITE_FILE;
1574         goto leave;
1575     }
1576     /* now store all keyids */
1577     *contbuf = 2;  /* data is a list of fingerprints */
1578     memcpy(contbuf+1, fpr, 20 );
1579     content.dptr = contbuf;
1580     content.dsize= 21;
1581     kbctx=NULL;
1582     while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
1583         if(    node->pkt->pkttype == PKT_PUBLIC_KEY
1584             || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
1585             u32 aki[2];
1586
1587             keyid_from_pk( node->pkt->pkt.public_key, aki );
1588             *keybuf = 2; /* key is a 8 byte keyid */
1589             u32tobuf( keybuf+1  , aki[0] );
1590             u32tobuf( keybuf+5, aki[1] );
1591             key.dptr = keybuf;
1592             key.dsize= 9;
1593             /* fixme: must be more clever when a insert failed:
1594              *        build a list of fingerprints in this case */
1595             rc = gdbm_store( rentry->dbf, key, content,
1596                                           update? GDBM_REPLACE : GDBM_INSERT );
1597             if( rc ) {
1598                 log_info("%s: gdbm_store keyid failed: %s\n", rentry->fname,
1599                                     rc == 1 ? "already stored"
1600                                             : gdbm_strerror(gdbm_errno) );
1601                 rc = 0;
1602             }
1603         }
1604     }
1605
1606   leave:
1607     iobuf_close(fp); /* don't need a cancel because it is a temp iobuf */
1608     return rc;
1609 }
1610
1611
1612
1613 /****************
1614  * search one keybox, return 0 if found, -1 if not found or an errorcode.
1615  */
1616 static int
1617 do_gdbm_locate( GDBM_FILE dbf, KBPOS *kbpos, const byte *fpr, int fprlen )
1618 {
1619     byte *keybuf = kbpos->keybuf;
1620     datum key;
1621     int i;
1622
1623     *keybuf = 1;
1624     for(i=0; i < fprlen; i++ )
1625         keybuf[i+1] = fpr[i];
1626     for(; i < 20; i++ )
1627         keybuf[i+1] = 0;
1628
1629     /* fetch the data */
1630     key.dptr  = keybuf;
1631     key.dsize = 21;
1632     if( !gdbm_exists( dbf, key ) )
1633         return -1; /* not found */
1634     return 0;
1635 }
1636
1637 /****************
1638  * locate by keyid.
1639  * FIXME: we must have a way to enumerate thru the list opf fingerprints
1640  */
1641 static int
1642 do_gdbm_locate_by_keyid( GDBM_FILE dbf, KBPOS *kbpos, u32 *keyid )
1643 {
1644     byte keybuf[9];
1645     datum key, content;
1646     int rc;
1647
1648     /* construct the fingerprint which is used as the primary key */
1649     *keybuf = 2;
1650     u32tobuf( keybuf+1, keyid[0] );
1651     u32tobuf( keybuf+5, keyid[1] );
1652
1653     /* fetch the data */
1654     key.dptr  = keybuf;
1655     key.dsize = 9;
1656     content = gdbm_fetch( dbf, key );
1657     if( !content.dptr )
1658         return -1;
1659
1660     if( content.dsize < 2 ) {
1661         log_error("gdbm_fetch did not return enough data\n" );
1662         free( content.dptr ); /* can't use m_free() here */
1663         return G10ERR_INV_KEYRING;
1664     }
1665     if( *content.dptr != 2 ) {
1666         log_error("gdbm_fetch returned unexpected type %d\n",
1667                     *(byte*)content.dptr );
1668         free( content.dptr ); /* can't use m_free() here */
1669         return G10ERR_INV_KEYRING;
1670     }
1671     if( content.dsize < 21 ) {
1672         log_error("gdbm_fetch did not return a complete fingerprint\n" );
1673         free( content.dptr ); /* can't use m_free() here */
1674         return G10ERR_INV_KEYRING;
1675     }
1676     if( content.dsize > 21 )
1677         log_info("gdbm_fetch: WARNING: more than one fingerprint\n" );
1678
1679     rc = do_gdbm_locate( dbf, kbpos, content.dptr+1, 20 );
1680     free( content.dptr ); /* can't use m_free() here */
1681     return rc;
1682 }
1683
1684
1685
1686 static int
1687 do_gdbm_read( KBPOS *kbpos, KBNODE *ret_root )
1688 {
1689     PACKET *pkt;
1690     int rc;
1691     RESTBL *rentry;
1692     KBNODE root = NULL;
1693     IOBUF a;
1694     datum key, content;
1695
1696     if( !(rentry=check_pos(kbpos)) )
1697         return G10ERR_GENERAL;
1698
1699     key.dptr  = kbpos->keybuf;
1700     key.dsize = 21;
1701     content = gdbm_fetch( rentry->dbf, key );
1702     if( !content.dptr ) {
1703         log_error("gdbm_fetch failed: %s\n", gdbm_strerror(gdbm_errno) );
1704         return G10ERR_INV_KEYRING;
1705     }
1706     if( content.dsize < 2 ) {
1707         log_error("gdbm_fetch did not return enough data\n" );
1708         free( content.dptr ); /* can't use m_free() here */
1709         return G10ERR_INV_KEYRING;
1710     }
1711     if( *content.dptr != 1 ) {
1712         log_error("gdbm_fetch returned unexpected type %d\n",
1713                     *(byte*)content.dptr );
1714         free( content.dptr ); /* can't use m_free() here */
1715         return G10ERR_INV_KEYRING;
1716     }
1717
1718     a = iobuf_temp_with_content( content.dptr+1, content.dsize-1 );
1719     free( content.dptr ); /* can't use m_free() here */
1720
1721     pkt = m_alloc( sizeof *pkt );
1722     init_packet(pkt);
1723     kbpos->count=0;
1724     while( (rc=parse_packet(a, pkt)) != -1 ) {
1725         if( rc ) {  /* ignore errors */
1726             if( rc != G10ERR_UNKNOWN_PACKET ) {
1727                 log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
1728                 rc = G10ERR_INV_KEYRING;
1729                 break;
1730             }
1731             kbpos->count++;
1732             free_packet( pkt );
1733             init_packet( pkt );
1734             continue;
1735         }
1736         /* make a linked list of all packets */
1737         kbpos->count++;
1738         if( !root )
1739             root = new_kbnode( pkt );
1740         else
1741             add_kbnode( root, new_kbnode( pkt ) );
1742         pkt = m_alloc( sizeof *pkt );
1743         init_packet(pkt);
1744     }
1745     if( rc == -1 && root )
1746         rc = 0;
1747     if( rc )
1748         release_kbnode( root );
1749     else
1750         *ret_root = root;
1751     free_packet( pkt );
1752     m_free( pkt );
1753     iobuf_close(a);
1754     return rc;
1755 }
1756
1757
1758 /****************
1759  * Enum over keyblok data
1760  */
1761 static int
1762 do_gdbm_enum( KBPOS *kbpos, KBNODE *ret_root )
1763 {
1764     RESTBL *rentry;
1765     datum key, helpkey;
1766
1767     if( !(rentry=check_pos(kbpos)) )
1768         return G10ERR_GENERAL;
1769
1770     if( !kbpos->offset ) {
1771         kbpos->offset = 1;
1772         key = gdbm_firstkey( rentry->dbf );
1773     }
1774     else {
1775         helpkey.dptr = kbpos->keybuf;
1776         helpkey.dsize= 21;
1777         key = gdbm_nextkey( rentry->dbf, helpkey );
1778     }
1779     while( key.dptr && (!key.dsize || *key.dptr != 1) ) {
1780         helpkey = key;
1781         key = gdbm_nextkey( rentry->dbf, helpkey );
1782         free( helpkey.dptr ); /* free and not m_free() ! */
1783     }
1784     if( !key.dptr )
1785         return -1; /* eof */
1786
1787     if( key.dsize < 21 ) {
1788         free( key.dptr ); /* free and not m_free() ! */
1789         log_error("do_gdm_enum: key is too short\n" );
1790         return G10ERR_INV_KEYRING;
1791     }
1792     memcpy( kbpos->keybuf, key.dptr, 21 );
1793     free( key.dptr ); /* free and not m_free() ! */
1794     return do_gdbm_read( kbpos, ret_root );
1795 }
1796
1797 #endif /*HAVE_LIBGDBM*/