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