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