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