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