3160b1c37532b033bdc4fd07414834e5b76b9409
[gnupg.git] / g10 / keyring.c
1 /* keyring.c - keyring file handling
2  * Copyright (C) 2001 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 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <unistd.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30
31 #include "util.h"
32 #include "keyring.h"
33 #include "packet.h"
34 #include "keydb.h" 
35 #include "options.h"
36 #include "main.h" /*for check_key_signature()*/
37 #include "i18n.h"
38
39 /* off_item is a funny named for an object used to keep track of known
40  * keys.  The idea was to use the offset to seek to the known keyblock, but
41  * this is not possible if more than one process is using the keyring.
42  */
43 struct off_item {
44   struct off_item *next;
45   u32 kid[2];
46   /*off_t off;*/
47 };
48
49 typedef struct off_item **OffsetHashTable; 
50
51
52 typedef struct keyring_name *KR_NAME;
53 struct keyring_name {
54   struct keyring_name *next;
55   int secret;
56   DOTLOCK lockhd;
57   int is_locked;
58   int did_full_scan;
59   char fname[1];
60 };
61 typedef struct keyring_name const * CONST_KR_NAME;
62
63 static KR_NAME kr_names;
64 static int active_handles;
65
66 static OffsetHashTable kr_offtbl;
67 static int kr_offtbl_ready;
68
69
70 struct keyring_handle {
71   CONST_KR_NAME resource;
72   int secret;             /* this is for a secret keyring */
73   struct {
74     CONST_KR_NAME kr;
75     IOBUF iobuf;
76     int eof;
77     int error;
78   } current;
79   struct {
80     CONST_KR_NAME kr; 
81     off_t offset;
82     size_t pk_no;
83     size_t uid_no;
84     unsigned int n_packets; /*used for delete and update*/
85   } found;
86   struct {
87     char *name;
88     char *pattern;
89   } word_match;
90 };
91
92
93
94 static int do_copy (int mode, const char *fname, KBNODE root, int secret,
95                     off_t start_offset, unsigned int n_packets );
96
97
98 \f
99 static struct off_item *
100 new_offset_item (void)
101 {
102   struct off_item *k;
103   
104   k = m_alloc_clear (sizeof *k);
105   return k;
106 }
107
108 #if 0
109 static void
110 release_offset_items (struct off_item *k)
111 {
112   struct off_item *k2;
113
114   for (; k; k = k2)
115     {
116       k2 = k->next;
117       m_free (k);
118     }
119 }
120 #endif
121
122 static OffsetHashTable 
123 new_offset_hash_table (void)
124 {
125   struct off_item **tbl;
126
127   tbl = m_alloc_clear (2048 * sizeof *tbl);
128   return tbl;
129 }
130
131 #if 0
132 static void
133 release_offset_hash_table (OffsetHashTable tbl)
134 {
135   int i;
136
137   if (!tbl)
138     return;
139   for (i=0; i < 2048; i++)
140     release_offset_items (tbl[i]);
141   m_free (tbl);
142 }
143 #endif
144
145 static struct off_item *
146 lookup_offset_hash_table (OffsetHashTable tbl, u32 *kid)
147 {
148   struct off_item *k;
149
150   for (k = tbl[(kid[1] & 0x07ff)]; k; k = k->next)
151     if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
152       return k;
153   return NULL;
154 }
155
156 static void
157 update_offset_hash_table (OffsetHashTable tbl, u32 *kid, off_t off)
158 {
159   struct off_item *k;
160
161   for (k = tbl[(kid[1] & 0x07ff)]; k; k = k->next)
162     {
163       if (k->kid[0] == kid[0] && k->kid[1] == kid[1]) 
164         {
165           /*k->off = off;*/
166           return;
167         }
168     }
169
170   k = new_offset_item ();
171   k->kid[0] = kid[0];
172   k->kid[1] = kid[1];
173   /*k->off = off;*/
174   k->next = tbl[(kid[1] & 0x07ff)];
175   tbl[(kid[1] & 0x07ff)] = k;
176 }
177
178 static void
179 update_offset_hash_table_from_kb (OffsetHashTable tbl, KBNODE node, off_t off)
180 {
181   for (; node; node = node->next)
182     {
183       if (node->pkt->pkttype == PKT_PUBLIC_KEY
184           || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
185         {
186           u32 aki[2];
187           keyid_from_pk (node->pkt->pkt.public_key, aki);
188           update_offset_hash_table (tbl, aki, off);
189         }
190     }
191 }
192
193
194
195 \f
196 /* 
197  * Register a filename for plain keyring files.  Returns a pointer to
198  * be used to create a handles etc or NULL to indicate that it has
199  * already been registered */
200 void *
201 keyring_register_filename (const char *fname, int secret)
202 {
203     KR_NAME kr;
204
205     if (active_handles)
206         BUG (); /* We don't allow that */
207
208     for (kr=kr_names; kr; kr = kr->next) {
209         if ( !compare_filenames (kr->fname, fname) )
210             return NULL; /* already registered */
211     }
212
213     kr = m_alloc (sizeof *kr + strlen (fname));
214     strcpy (kr->fname, fname);
215     kr->secret = !!secret;
216     kr->lockhd = NULL;
217     kr->is_locked = 0;
218     kr->did_full_scan = 0;
219     /* keep a list of all issued pointers */
220     kr->next = kr_names;
221     kr_names = kr;
222
223     /* create the offset table the first time a function here is used */
224     if (!kr_offtbl)
225       kr_offtbl = new_offset_hash_table ();
226
227     return kr;
228 }
229
230 int
231 keyring_is_writable (void *token)
232 {
233   KR_NAME r = token;
234
235   return r? !access (r->fname, W_OK) : 0;
236 }
237     
238
239 \f
240 /* Create a new handle for the resource associated with TOKEN.  SECRET
241    is just just as a cross-check.
242    
243    The returned handle must be released using keyring_release (). */
244 KEYRING_HANDLE
245 keyring_new (void *token, int secret)
246 {
247   KEYRING_HANDLE hd;
248   KR_NAME resource = token;
249
250   assert (resource && !resource->secret == !secret);
251   
252   hd = m_alloc_clear (sizeof *hd);
253   hd->resource = resource;
254   hd->secret = !!secret;
255   active_handles++;
256   return hd;
257 }
258
259 void 
260 keyring_release (KEYRING_HANDLE hd)
261 {
262     if (!hd)
263         return;
264     assert (active_handles > 0);
265     active_handles--;
266     m_free (hd->word_match.name);
267     m_free (hd->word_match.pattern);
268     iobuf_close (hd->current.iobuf);
269     m_free (hd);
270 }
271
272
273 const char *
274 keyring_get_resource_name (KEYRING_HANDLE hd)
275 {
276     if (!hd || !hd->resource)
277       return NULL;
278     return hd->resource->fname;
279 }
280
281
282 /*
283  * Lock the keyring with the given handle, or unlok if yes is false.
284  * We ignore the handle and lock all registered files.
285  */
286 int 
287 keyring_lock (KEYRING_HANDLE hd, int yes)
288 {
289     KR_NAME kr;
290     int rc = 0;
291
292     if (yes) {
293         /* first make sure the lock handles are created */
294         for (kr=kr_names; kr; kr = kr->next) {
295             if (!keyring_is_writable(kr))
296                 continue;
297             if (!kr->lockhd) {
298                 kr->lockhd = create_dotlock( kr->fname );
299                 if (!kr->lockhd) {
300                     log_info ("can't allocate lock for `%s'\n", kr->fname );
301                     rc = G10ERR_GENERAL;
302                 }
303             }
304         }
305         if (rc)
306             return rc;
307         
308         /* and now set the locks */
309         for (kr=kr_names; kr; kr = kr->next) {
310             if (!keyring_is_writable(kr))
311                 continue;
312             if (kr->is_locked)
313                 ;
314             else if (make_dotlock (kr->lockhd, -1) ) {
315                 log_info ("can't lock `%s'\n", kr->fname );
316                 rc = G10ERR_GENERAL;
317             }
318             else 
319                 kr->is_locked = 1;
320         }
321     }
322
323     if (rc || !yes) {
324         for (kr=kr_names; kr; kr = kr->next) {
325             if (!keyring_is_writable(kr))
326                 continue;
327             if (!kr->is_locked)
328                 ;
329             else if (release_dotlock (kr->lockhd))
330                 log_info ("can't unlock `%s'\n", kr->fname );
331             else 
332                 kr->is_locked = 0;
333         }
334     } 
335
336     return rc;
337 }
338
339
340 \f
341 /*
342  * Return the last found keyring.  Caller must free it.
343  * The returned keyblock has the kbode flag bit 0 set for the node with
344  * the public key used to locate the keyblock or flag bit 1 set for 
345  * the user ID node.
346  */
347 int
348 keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
349 {
350     PACKET *pkt;
351     int rc;
352     KBNODE keyblock = NULL, node, lastnode;
353     IOBUF a;
354     int in_cert = 0;
355     int pk_no = 0;
356     int uid_no = 0;
357     int save_mode;
358
359     if (ret_kb)
360         *ret_kb = NULL;
361
362     if (!hd->found.kr)
363         return -1; /* no successful search */
364
365     a = iobuf_open (hd->found.kr->fname);
366     if (!a) {
367         log_error ("can't open `%s'\n", hd->found.kr->fname);
368         return G10ERR_KEYRING_OPEN;
369     }
370
371     if (iobuf_seek (a, hd->found.offset) ) {
372         log_error ("can't seek `%s'\n", hd->found.kr->fname);
373         iobuf_close(a);
374         return G10ERR_KEYRING_OPEN;
375     }
376
377     pkt = m_alloc (sizeof *pkt);
378     init_packet (pkt);
379     hd->found.n_packets = 0;;
380     lastnode = NULL;
381     save_mode = set_packet_list_mode(0);
382     while ((rc=parse_packet (a, pkt)) != -1) {
383         hd->found.n_packets++;
384         if (rc == G10ERR_UNKNOWN_PACKET) {
385             free_packet (pkt);
386             init_packet (pkt);
387             continue;
388         }
389         if (rc) {  
390             log_error ("keyring_get_keyblock: read error: %s\n",
391                        g10_errstr(rc) );
392             rc = G10ERR_INV_KEYRING;
393             break;
394         }
395         if (pkt->pkttype == PKT_COMPRESSED) {
396             log_error ("skipped compressed packet in keyring\n");
397             free_packet(pkt);
398             init_packet(pkt);
399             continue;
400         }
401
402         if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY
403                         || pkt->pkttype == PKT_SECRET_KEY)) {
404             hd->found.n_packets--; /* fix counter */
405             break; /* ready */
406         }
407
408         in_cert = 1;
409         if (pkt->pkttype == PKT_RING_TRUST) {
410             /*(this code is duplicated after the loop)*/
411             if ( lastnode 
412                  && lastnode->pkt->pkttype == PKT_SIGNATURE
413                  && (pkt->pkt.ring_trust->sigcache & 1) ) {
414                 /* this is a ring trust packet with a checked signature 
415                  * status cache following directly a signature paket.
416                  * Set the cache status into that signature packet */
417                 PKT_signature *sig = lastnode->pkt->pkt.signature;
418                 
419                 sig->flags.checked = 1;
420                 sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
421             }
422             /* reset lastnode, so that we set the cache status only from
423              * the ring trust packet immediately folling a signature */
424             lastnode = NULL;
425         }
426         else {
427             node = lastnode = new_kbnode (pkt);
428             if (!keyblock)
429                 keyblock = node;
430             else
431                 add_kbnode (keyblock, node);
432
433             if ( pkt->pkttype == PKT_PUBLIC_KEY
434                  || pkt->pkttype == PKT_PUBLIC_SUBKEY
435                  || pkt->pkttype == PKT_SECRET_KEY
436                  || pkt->pkttype == PKT_SECRET_SUBKEY) {
437                 if (++pk_no == hd->found.pk_no)
438                     node->flag |= 1;
439             }
440             else if ( pkt->pkttype == PKT_USER_ID) {
441                 if (++uid_no == hd->found.uid_no)
442                     node->flag |= 2;
443             }
444         }
445
446         pkt = m_alloc (sizeof *pkt);
447         init_packet(pkt);
448     }
449     set_packet_list_mode(save_mode);
450
451     if (rc == -1 && keyblock) 
452         rc = 0; /* got the entire keyblock */
453
454     if (rc || !ret_kb)
455         release_kbnode (keyblock);
456     else {
457         /*(duplicated form the loop body)*/
458         if ( pkt && pkt->pkttype == PKT_RING_TRUST
459              && lastnode 
460              && lastnode->pkt->pkttype == PKT_SIGNATURE
461              && (pkt->pkt.ring_trust->sigcache & 1) ) {
462             PKT_signature *sig = lastnode->pkt->pkt.signature;
463             sig->flags.checked = 1;
464             sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
465         }
466         *ret_kb = keyblock;
467     }
468     free_packet (pkt);
469     m_free (pkt);
470     iobuf_close(a);
471
472     /* Make sure that future search operations fail immediately when
473      * we know that we are working on a invalid keyring 
474      */
475     if (rc == G10ERR_INV_KEYRING)
476         hd->current.error = rc;
477
478     return rc;
479 }
480
481 int
482 keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb)
483 {
484     int rc;
485
486     if (!hd->found.kr)
487         return -1; /* no successful prior search */
488
489     if (!hd->found.n_packets) {
490         /* need to know the number of packets - do a dummy get_keyblock*/
491         rc = keyring_get_keyblock (hd, NULL);
492         if (rc) {
493             log_error ("re-reading keyblock failed: %s\n", g10_errstr (rc));
494             return rc;
495         }
496         if (!hd->found.n_packets)
497             BUG ();
498     }
499
500     /* The open iobuf isn't needed anymore and in fact is a problem when
501        it comes to renaming the keyring files on some operating systems,
502        so close it here */
503     iobuf_close(hd->current.iobuf);
504     hd->current.iobuf = NULL;
505
506     /* do the update */
507     rc = do_copy (3, hd->found.kr->fname, kb, hd->secret,
508                   hd->found.offset, hd->found.n_packets );
509     if (!rc) {
510       if (!hd->secret && kr_offtbl)
511         {
512           update_offset_hash_table_from_kb (kr_offtbl, kb, 0);
513         }
514       /* better reset the found info */
515       hd->found.kr = NULL;
516       hd->found.offset = 0;
517     }
518     return rc;
519 }
520
521 int
522 keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb)
523 {
524     int rc;
525     const char *fname;
526
527     if (!hd)
528         fname = NULL;
529     else if (hd->found.kr)
530         fname = hd->found.kr->fname;
531     else if (hd->current.kr)
532         fname = hd->current.kr->fname;
533     else 
534         fname = hd->resource? hd->resource->fname:NULL;
535
536     if (!fname)
537         return G10ERR_GENERAL; 
538
539     /* close this one otherwise we will lose the position for
540      * a next search.  Fixme: it would be better to adjust the position
541      * after the write opertions.
542      */
543     iobuf_close (hd->current.iobuf);
544     hd->current.iobuf = NULL;
545
546     /* do the insert */
547     rc = do_copy (1, fname, kb, hd->secret, 0, 0 );
548     if (!rc && !hd->secret && kr_offtbl)
549       {
550         update_offset_hash_table_from_kb (kr_offtbl, kb, 0);
551       }
552       
553     return rc;
554 }
555
556
557 int
558 keyring_delete_keyblock (KEYRING_HANDLE hd)
559 {
560     int rc;
561
562     if (!hd->found.kr)
563         return -1; /* no successful prior search */
564
565     if (!hd->found.n_packets) {
566         /* need to know the number of packets - do a dummy get_keyblock*/
567         rc = keyring_get_keyblock (hd, NULL);
568         if (rc) {
569             log_error ("re-reading keyblock failed: %s\n", g10_errstr (rc));
570             return rc;
571         }
572         if (!hd->found.n_packets)
573             BUG ();
574     }
575
576     /* close this one otherwise we will lose the position for
577      * a next search.  Fixme: it would be better to adjust the position
578      * after the write opertions.
579      */
580     iobuf_close (hd->current.iobuf);
581     hd->current.iobuf = NULL;
582
583     /* do the delete */
584     rc = do_copy (2, hd->found.kr->fname, NULL, hd->secret,
585                   hd->found.offset, hd->found.n_packets );
586     if (!rc) {
587         /* better reset the found info */
588         hd->found.kr = NULL;
589         hd->found.offset = 0;
590         /* Delete is a rare operations, so we don't remove the keys
591          * from the offset table */
592     }
593     return rc;
594 }
595
596
597 \f
598 /* 
599  * Start the next search on this handle right at the beginning
600  */
601 int 
602 keyring_search_reset (KEYRING_HANDLE hd)
603 {
604     assert (hd);
605
606     hd->current.kr = NULL;
607     iobuf_close (hd->current.iobuf);
608     hd->current.iobuf = NULL;
609     hd->current.eof = 0;
610     hd->current.error = 0;
611     
612     hd->found.kr = NULL;
613     hd->found.offset = 0;
614     return 0; 
615 }
616
617
618 static int
619 prepare_search (KEYRING_HANDLE hd)
620 {
621     if (hd->current.error)  
622         return hd->current.error; /* still in error state */
623
624     if (hd->current.kr && !hd->current.eof) {
625         if ( !hd->current.iobuf )
626             return G10ERR_GENERAL; /* position invalid after a modify */
627         return 0; /* okay */
628     }
629
630     if (!hd->current.kr && hd->current.eof)  
631         return -1; /* still EOF */
632
633     if (!hd->current.kr) { /* start search with first keyring */
634         hd->current.kr = hd->resource;
635         if (!hd->current.kr) {
636             hd->current.eof = 1;
637             return -1; /* keyring not available */
638         }
639         assert (!hd->current.iobuf);
640     }
641     else { /* EOF */
642         iobuf_close (hd->current.iobuf); 
643         hd->current.iobuf = NULL;
644         hd->current.kr = NULL;
645         hd->current.eof = 1;
646         return -1;
647     }
648
649     hd->current.eof = 0;
650     hd->current.iobuf = iobuf_open (hd->current.kr->fname);
651     if (!hd->current.iobuf) {
652         log_error ("can't open `%s'\n", hd->current.kr->fname );
653         return (hd->current.error = G10ERR_OPEN_FILE);
654     }
655
656     return 0;
657 }
658
659 \f
660 /* A map of the all characters valid used for word_match()
661  * Valid characters are in in this table converted to uppercase.
662  * because the upper 128 bytes have special meaning, we assume
663  * that they are all valid.
664  * Note: We must use numerical values here in case that this program
665  * will be converted to those little blue HAL9000s with their strange
666  * EBCDIC character set (user ids are UTF-8).
667  * wk 2000-04-13: Hmmm, does this really make sense, given the fact that
668  * we can run gpg now on a S/390 running GNU/Linux, where the code
669  * translation is done by the device drivers?
670  */
671 static const byte word_match_chars[256] = {
672   /* 00 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
673   /* 08 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
674   /* 10 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
675   /* 18 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
676   /* 20 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
677   /* 28 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
678   /* 30 */  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
679   /* 38 */  0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680   /* 40 */  0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
681   /* 48 */  0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
682   /* 50 */  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
683   /* 58 */  0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
684   /* 60 */  0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
685   /* 68 */  0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
686   /* 70 */  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
687   /* 78 */  0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00,
688   /* 80 */  0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
689   /* 88 */  0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
690   /* 90 */  0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
691   /* 98 */  0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
692   /* a0 */  0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
693   /* a8 */  0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
694   /* b0 */  0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
695   /* b8 */  0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
696   /* c0 */  0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
697   /* c8 */  0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
698   /* d0 */  0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
699   /* d8 */  0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
700   /* e0 */  0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
701   /* e8 */  0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
702   /* f0 */  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
703   /* f8 */  0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
704 };
705
706 /****************
707  * Do a word match (original user id starts with a '+').
708  * The pattern is already tokenized to a more suitable format:
709  * There are only the real words in it delimited by one space
710  * and all converted to uppercase.
711  *
712  * Returns: 0 if all words match.
713  *
714  * Note: This algorithm is a straightforward one and not very
715  *       fast.  It works for UTF-8 strings.  The uidlen should
716  *       be removed but due to the fact that old versions of
717  *       pgp don't use UTF-8 we still use the length; this should
718  *       be fixed in parse-packet (and replace \0 by some special
719  *       UTF-8 encoding)
720  */
721 static int
722 word_match( const byte *uid, size_t uidlen, const byte *pattern )
723 {
724     size_t wlen, n;
725     const byte *p;
726     const byte *s;
727
728     for( s=pattern; *s; ) {
729         do {
730             /* skip leading delimiters */
731             while( uidlen && !word_match_chars[*uid] )
732                 uid++, uidlen--;
733             /* get length of the word */
734             n = uidlen; p = uid;
735             while( n && word_match_chars[*p] )
736                 p++, n--;
737             wlen = p - uid;
738             /* and compare against the current word from pattern */
739             for(n=0, p=uid; n < wlen && s[n] != ' ' && s[n] ; n++, p++ ) {
740                 if( word_match_chars[*p] != s[n] )
741                     break;
742             }
743             if( n == wlen && (s[n] == ' ' || !s[n]) )
744                 break; /* found */
745             uid += wlen;
746             uidlen -= wlen;
747         } while( uidlen );
748         if( !uidlen )
749             return -1; /* not found */
750
751         /* advance to next word in pattern */
752         for(; *s != ' ' && *s ; s++ )
753             ;
754         if( *s )
755             s++ ;
756     }
757     return 0; /* found */
758 }
759
760 /****************
761  * prepare word word_match; that is parse the name and
762  * build the pattern.
763  * caller has to free the returned pattern
764  */
765 static char*
766 prepare_word_match (const byte *name)
767 {
768     byte *pattern, *p;
769     int c;
770
771     /* the original length is always enough for the pattern */
772     p = pattern = m_alloc(strlen(name)+1);
773     do {
774         /* skip leading delimiters */
775         while( *name && !word_match_chars[*name] )
776             name++;
777         /* copy as long as we don't have a delimiter and convert
778          * to uppercase.
779          * fixme: how can we handle utf8 uppercasing */
780         for( ; *name &&  (c=word_match_chars[*name]); name++ )
781             *p++ = c;
782         *p++ = ' '; /* append pattern delimiter */
783     } while( *name );
784     p[-1] = 0; /* replace last pattern delimiter by EOS */
785
786     return pattern;
787 }
788
789
790
791
792 static int
793 compare_name (int mode, const char *name, const char *uid, size_t uidlen)
794 {
795     int i;
796     const char *s, *se;
797
798     if (mode == KEYDB_SEARCH_MODE_EXACT) { 
799         for (i=0; name[i] && uidlen; i++, uidlen--)
800             if (uid[i] != name[i])
801                 break;
802         if (!uidlen && !name[i])
803             return 0; /* found */
804     }
805     else if (mode == KEYDB_SEARCH_MODE_SUBSTR) {
806         if (ascii_memistr( uid, uidlen, name ))
807             return 0;
808     }
809     else if (   mode == KEYDB_SEARCH_MODE_MAIL 
810              || mode == KEYDB_SEARCH_MODE_MAILSUB
811              || mode == KEYDB_SEARCH_MODE_MAILEND) {
812         for (i=0, s= uid; i < uidlen && *s != '<'; s++, i++)
813             ;
814         if (i < uidlen)  {
815             /* skip opening delim and one char and look for the closing one*/
816             s++; i++;
817             for (se=s+1, i++; i < uidlen && *se != '>'; se++, i++)
818                 ;
819             if (i < uidlen) {
820                 i = se - s;
821                 if (mode == KEYDB_SEARCH_MODE_MAIL) { 
822                     if( strlen(name)-2 == i
823                         && !ascii_memcasecmp( s, name+1, i) )
824                         return 0;
825                 }
826                 else if (mode == KEYDB_SEARCH_MODE_MAILSUB) {
827                     if( ascii_memistr( s, i, name ) )
828                         return 0;
829                 }
830                 else { /* email from end */
831                     /* nyi */
832                 }
833             }
834         }
835     }
836     else if (mode == KEYDB_SEARCH_MODE_WORDS)
837         return word_match (uid, uidlen, name);
838     else
839         BUG();
840
841     return -1; /* not found */
842 }
843
844 \f
845 /* 
846  * Search through the keyring(s), starting at the current position,
847  * for a keyblock which contains one of the keys described in the DESC array.
848  */
849 int 
850 keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
851 {
852   int rc;
853   PACKET pkt;
854   int save_mode;
855   off_t offset, main_offset;
856   size_t n;
857   int need_uid, need_words, need_keyid, need_fpr, any_skip;
858   int pk_no, uid_no;
859   int initial_skip;
860   int use_offtbl;
861   PKT_user_id *uid = NULL;
862   PKT_public_key *pk = NULL;
863   PKT_secret_key *sk = NULL;
864
865   /* figure out what information we need */
866   need_uid = need_words = need_keyid = need_fpr = any_skip = 0;
867   for (n=0; n < ndesc; n++) 
868     {
869       switch (desc[n].mode) 
870         {
871         case KEYDB_SEARCH_MODE_EXACT: 
872         case KEYDB_SEARCH_MODE_SUBSTR:
873         case KEYDB_SEARCH_MODE_MAIL:
874         case KEYDB_SEARCH_MODE_MAILSUB:
875         case KEYDB_SEARCH_MODE_MAILEND:
876           need_uid = 1;
877           break;
878         case KEYDB_SEARCH_MODE_WORDS: 
879           need_uid = 1;
880           need_words = 1;
881           break;
882         case KEYDB_SEARCH_MODE_SHORT_KID: 
883         case KEYDB_SEARCH_MODE_LONG_KID:
884           need_keyid = 1;
885           break;
886         case KEYDB_SEARCH_MODE_FPR16: 
887         case KEYDB_SEARCH_MODE_FPR20:
888         case KEYDB_SEARCH_MODE_FPR: 
889           need_fpr = 1;
890           break;
891         case KEYDB_SEARCH_MODE_FIRST:
892           /* always restart the search in this mode */
893           keyring_search_reset (hd);
894           break;
895         default: break;
896         }
897       if (desc[n].skipfnc) 
898         {
899           any_skip = 1;
900           need_keyid = 1;
901         }
902     }
903
904   rc = prepare_search (hd);
905   if (rc)
906     return rc;
907
908   use_offtbl = !hd->secret && kr_offtbl;
909   if (!use_offtbl)
910     ;
911   else if (!kr_offtbl_ready)
912     need_keyid = 1;
913   else if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID)
914     {
915       struct off_item *oi;
916             
917       oi = lookup_offset_hash_table (kr_offtbl, desc[0].u.kid);
918       if (!oi)
919         { /* We know that we don't have this key */
920           hd->found.kr = NULL;
921           hd->current.eof = 1;
922           return -1;
923         }
924       /* We could now create a positive search status and return.
925        * However the problem is that another instance of gpg may 
926        * have changed the keyring so that the offsets are not valid
927        * anymore - therefore we don't do it 
928        */
929     }
930
931   if (need_words)
932     {
933       const char *name = NULL;
934
935       log_debug ("word search mode does not yet work\n");
936       /* FIXME: here is a long standing bug in our function and in addition we
937          just use the first search description */
938       for (n=0; n < ndesc && !name; n++) 
939         {
940           if (desc[n].mode == KEYDB_SEARCH_MODE_WORDS) 
941             name = desc[n].u.name;
942         }
943       assert (name);
944       if ( !hd->word_match.name || strcmp (hd->word_match.name, name) ) 
945         {
946           /* name changed */
947           m_free (hd->word_match.name);
948           m_free (hd->word_match.pattern);
949           hd->word_match.name = m_strdup (name);
950           hd->word_match.pattern = prepare_word_match (name);
951         }
952       name = hd->word_match.pattern;
953     }
954
955   init_packet(&pkt);
956   save_mode = set_packet_list_mode(0);
957
958   hd->found.kr = NULL;
959   main_offset = 0;
960   pk_no = uid_no = 0;
961   initial_skip = 1; /* skip until we see the start of a keyblock */
962   while (!(rc=search_packet (hd->current.iobuf, &pkt, &offset, need_uid))) 
963     {
964       byte afp[MAX_FINGERPRINT_LEN];
965       size_t an;
966       u32 aki[2];
967
968       if (pkt.pkttype == PKT_PUBLIC_KEY  || pkt.pkttype == PKT_SECRET_KEY) 
969         {
970           main_offset = offset;
971           pk_no = uid_no = 0;
972           initial_skip = 0;
973         }
974       if (initial_skip) 
975         {
976           free_packet (&pkt);
977           continue;
978         }
979         
980       pk = NULL;
981       sk = NULL;
982       uid = NULL;
983       if (   pkt.pkttype == PKT_PUBLIC_KEY
984              || pkt.pkttype == PKT_PUBLIC_SUBKEY)
985         {
986           pk = pkt.pkt.public_key;
987           ++pk_no;
988
989           if (need_fpr) {
990             fingerprint_from_pk (pk, afp, &an);
991             while (an < 20) /* fill up to 20 bytes */
992               afp[an++] = 0;
993           }
994           if (need_keyid)
995             keyid_from_pk (pk, aki);
996
997           if (use_offtbl && !kr_offtbl_ready)
998             update_offset_hash_table (kr_offtbl, aki, main_offset);
999         }
1000       else if (pkt.pkttype == PKT_USER_ID) 
1001         {
1002           uid = pkt.pkt.user_id;
1003           ++uid_no;
1004         }
1005       else if (    pkt.pkttype == PKT_SECRET_KEY
1006                    || pkt.pkttype == PKT_SECRET_SUBKEY) 
1007         {
1008           sk = pkt.pkt.secret_key;
1009           ++pk_no;
1010
1011           if (need_fpr) {
1012             fingerprint_from_sk (sk, afp, &an);
1013             while (an < 20) /* fill up to 20 bytes */
1014               afp[an++] = 0;
1015           }
1016           if (need_keyid)
1017             keyid_from_sk (sk, aki);
1018             
1019         }
1020
1021       for (n=0; n < ndesc; n++) 
1022         {
1023           switch (desc[n].mode) {
1024           case KEYDB_SEARCH_MODE_NONE: 
1025             BUG ();
1026             break;
1027           case KEYDB_SEARCH_MODE_EXACT: 
1028           case KEYDB_SEARCH_MODE_SUBSTR:
1029           case KEYDB_SEARCH_MODE_MAIL:
1030           case KEYDB_SEARCH_MODE_MAILSUB:
1031           case KEYDB_SEARCH_MODE_MAILEND:
1032           case KEYDB_SEARCH_MODE_WORDS: 
1033             if ( uid && !compare_name (desc[n].mode,
1034                                        desc[n].u.name,
1035                                        uid->name, uid->len)) 
1036               goto found;
1037             break;
1038                 
1039           case KEYDB_SEARCH_MODE_SHORT_KID: 
1040             if ((pk||sk) && desc[n].u.kid[1] == aki[1])
1041               goto found;
1042             break;
1043           case KEYDB_SEARCH_MODE_LONG_KID:
1044             if ((pk||sk) && desc[n].u.kid[0] == aki[0]
1045                 && desc[n].u.kid[1] == aki[1])
1046               goto found;
1047             break;
1048           case KEYDB_SEARCH_MODE_FPR16:
1049             if ((pk||sk) && !memcmp (desc[n].u.fpr, afp, 16))
1050               goto found;
1051             break;
1052           case KEYDB_SEARCH_MODE_FPR20:
1053           case KEYDB_SEARCH_MODE_FPR: 
1054             if ((pk||sk) && !memcmp (desc[n].u.fpr, afp, 20))
1055               goto found;
1056             break;
1057           case KEYDB_SEARCH_MODE_FIRST: 
1058             if (pk||sk)
1059               goto found;
1060             break;
1061           case KEYDB_SEARCH_MODE_NEXT: 
1062             if (pk||sk)
1063               goto found;
1064             break;
1065           default: 
1066             rc = G10ERR_INV_ARG;
1067             goto found;
1068           }
1069         }
1070       free_packet (&pkt);
1071       continue;
1072     found:  
1073       for (n=any_skip?0:ndesc; n < ndesc; n++) 
1074         {
1075           if (desc[n].skipfnc
1076               && desc[n].skipfnc (desc[n].skipfncvalue, aki))
1077             break;
1078         }
1079       if (n == ndesc)
1080         goto real_found;
1081       free_packet (&pkt);
1082     }
1083  real_found:
1084   if (!rc)
1085     {
1086       hd->found.offset = main_offset;
1087       hd->found.kr = hd->current.kr;
1088       hd->found.pk_no = (pk||sk)? pk_no : 0;
1089       hd->found.uid_no = uid? uid_no : 0;
1090     }
1091   else if (rc == -1)
1092     {
1093       hd->current.eof = 1;
1094       /* if we scanned all keyrings, we are sure that
1095        * all known key IDs are in our offtbl, mark that. */
1096       if (use_offtbl && !kr_offtbl_ready)
1097         {
1098           KR_NAME kr;
1099           
1100           /* First set the did_full_scan flag for this keyring (ignore
1101              secret keyrings) */
1102           for (kr=kr_names; kr; kr = kr->next)
1103             {
1104               if (!kr->secret && hd->resource == kr) 
1105                 {
1106                   kr->did_full_scan = 1;
1107                   break;
1108                 }
1109             }
1110           /* Then check whether all flags are set and if so, mark the
1111              offtbl ready */
1112           for (kr=kr_names; kr; kr = kr->next)
1113             {
1114               if (!kr->secret && !kr->did_full_scan) 
1115                 break;
1116             }
1117           if (!kr)
1118             kr_offtbl_ready = 1;
1119         }
1120     }
1121   else 
1122     hd->current.error = rc;
1123
1124   free_packet(&pkt);
1125   set_packet_list_mode(save_mode);
1126   return rc;
1127 }
1128
1129
1130 static int
1131 create_tmp_file (const char *template,
1132                  char **r_bakfname, char **r_tmpfname, IOBUF *r_fp)
1133 {  
1134   char *bakfname, *tmpfname;
1135   mode_t oldmask;
1136
1137   *r_bakfname = NULL;
1138   *r_tmpfname = NULL;
1139
1140 # ifdef USE_ONLY_8DOT3
1141   /* Here is another Windoze bug?:
1142    * you cant rename("pubring.gpg.tmp", "pubring.gpg");
1143    * but        rename("pubring.gpg.tmp", "pubring.aaa");
1144    * works.  So we replace .gpg by .bak or .tmp
1145    */
1146   if (strlen (template) > 4
1147       && !strcmp (template+strlen(template)-4, EXTSEP_S "gpg") )
1148     {
1149       bakfname = m_alloc (strlen (template) + 1);
1150       strcpy (bakfname, template);
1151       strcpy (bakfname+strlen(template)-4, EXTSEP_S "bak");
1152
1153       tmpfname = m_alloc (strlen( template ) + 1 );
1154       strcpy (tmpfname,template);
1155       strcpy (tmpfname+strlen(template)-4, EXTSEP_S "tmp");
1156     }
1157     else 
1158       { /* file does not end with gpg; hmmm */
1159         bakfname = m_alloc (strlen( template ) + 5);
1160         strcpy (stpcpy(bakfname, template), EXTSEP_S "bak");
1161
1162         tmpfname = m_alloc (strlen( template ) + 5);
1163         strcpy (stpcpy(tmpfname, template), EXTSEP_S "tmp");
1164     }
1165 # else /* Posix file names */
1166     bakfname = m_alloc (strlen( template ) + 2);
1167     strcpy (stpcpy (bakfname,template),"~");
1168
1169     tmpfname = m_alloc (strlen( template ) + 5);
1170     strcpy (stpcpy(tmpfname,template), EXTSEP_S "tmp");
1171 # endif /* Posix filename */
1172
1173     /* Create the temp file with limited access */
1174     oldmask=umask(077);
1175     *r_fp = iobuf_create (tmpfname);
1176     umask(oldmask);
1177     if (!*r_fp) {
1178         log_error ("can't create `%s': %s\n", tmpfname, strerror(errno) );
1179         m_free (tmpfname);
1180         m_free (bakfname);
1181         return G10ERR_OPEN_FILE;
1182     }
1183     
1184     *r_bakfname = bakfname;
1185     *r_tmpfname = tmpfname;
1186     return 0;
1187 }
1188
1189
1190 static int
1191 rename_tmp_file (const char *bakfname, const char *tmpfname,
1192                  const char *fname, int secret )
1193 {
1194   int rc=0;
1195
1196   /* invalidate close caches*/
1197   iobuf_ioctl (NULL, 2, 0, (char*)tmpfname );
1198   iobuf_ioctl (NULL, 2, 0, (char*)bakfname );
1199   iobuf_ioctl (NULL, 2, 0, (char*)fname );
1200
1201   /* first make a backup file except for secret keyrings */
1202   if (!secret)
1203     { 
1204 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
1205       remove (bakfname);
1206 #endif
1207       if (rename (fname, bakfname) )
1208         {
1209           log_error ("renaming `%s' to `%s' failed: %s\n",
1210                      fname, bakfname, strerror(errno) );
1211           return G10ERR_RENAME_FILE;
1212         }
1213     }
1214   
1215   /* then rename the file */
1216 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
1217   remove( fname );
1218 #endif
1219   if (rename (tmpfname, fname) )
1220     {
1221       log_error ("renaming `%s' to `%s' failed: %s\n",
1222                  tmpfname, fname, strerror(errno) );
1223       rc = G10ERR_RENAME_FILE;
1224       if (secret)
1225         {
1226           log_info(_("WARNING: 2 files with confidential"
1227                      " information exists.\n"));
1228           log_info(_("%s is the unchanged one\n"), fname );
1229           log_info(_("%s is the new one\n"), tmpfname );
1230           log_info(_("Please fix this possible security flaw\n"));
1231         }
1232       return rc;
1233     }
1234
1235   /* Now make sure the file has the same permissions as the original */
1236
1237 #ifndef HAVE_DOSISH_SYSTEM
1238   {
1239     struct stat statbuf;
1240
1241     statbuf.st_mode=S_IRUSR | S_IWUSR;
1242
1243     if(((secret && !opt.preserve_permissions) ||
1244         (stat(bakfname,&statbuf)==0)) &&
1245        (chmod(fname,statbuf.st_mode)==0))
1246       ;
1247     else
1248       log_error("WARNING: unable to restore permissions to `%s': %s",
1249                 fname,strerror(errno));
1250   }
1251 #endif
1252
1253   return 0;
1254 }
1255
1256
1257 static int
1258 write_keyblock (IOBUF fp, KBNODE keyblock)
1259 {
1260   KBNODE kbctx = NULL, node;
1261   int rc;
1262   
1263   while ( (node = walk_kbnode (keyblock, &kbctx, 0)) ) 
1264     {
1265       if (node->pkt->pkttype == PKT_RING_TRUST) 
1266         continue; /* we write it later on our own */
1267
1268       if ( (rc = build_packet (fp, node->pkt) ))
1269         {
1270           log_error ("build_packet(%d) failed: %s\n",
1271                      node->pkt->pkttype, g10_errstr(rc) );
1272           return rc;
1273         }
1274       if (node->pkt->pkttype == PKT_SIGNATURE) 
1275         { /* always write a signature cache packet */
1276           PKT_signature *sig = node->pkt->pkt.signature;
1277           unsigned int cacheval = 0;
1278           
1279           if (sig->flags.checked) 
1280             {
1281               cacheval |= 1;
1282               if (sig->flags.valid)
1283                 cacheval |= 2;
1284             }
1285           iobuf_put (fp, 0xb0); /* old style packet 12, 1 byte len*/
1286           iobuf_put (fp, 2);    /* 2 bytes */
1287           iobuf_put (fp, 0);    /* unused */
1288           if (iobuf_put (fp, cacheval)) {
1289             log_error ("writing sigcache packet failed\n");
1290             return G10ERR_WRITE_FILE;
1291           }
1292         }
1293     }
1294   return 0;
1295 }
1296
1297 /* 
1298  * Walk over all public keyrings, check the signatures and replace the
1299  * keyring with a new one where the signature cache is then updated.
1300  * This is only done for the public keyrings.
1301  */
1302 int
1303 keyring_rebuild_cache (void *token)
1304 {
1305   KEYRING_HANDLE hd;
1306   KEYDB_SEARCH_DESC desc;
1307   KBNODE keyblock = NULL, node;
1308   const char *lastresname = NULL, *resname;
1309   IOBUF tmpfp = NULL;
1310   char *tmpfilename = NULL;
1311   char *bakfilename = NULL;
1312   int rc;
1313   ulong count = 0, sigcount = 0;
1314
1315   hd = keyring_new (token, 0);
1316   memset (&desc, 0, sizeof desc);
1317   desc.mode = KEYDB_SEARCH_MODE_FIRST;
1318
1319   while ( !(rc = keyring_search (hd, &desc, 1)) )
1320     {
1321       desc.mode = KEYDB_SEARCH_MODE_NEXT;
1322       resname = keyring_get_resource_name (hd);
1323       if (lastresname != resname )
1324         { /* we have switched to a new keyring - commit changes */
1325           if (tmpfp)
1326             {
1327               if (iobuf_close (tmpfp))
1328                 {
1329                   log_error ("error closing `%s': %s\n",
1330                              tmpfilename, strerror (errno));
1331                   rc = G10ERR_CLOSE_FILE;
1332                   goto leave;
1333                 }
1334               /* because we have switched resources, we can be sure that
1335                * the original file is closed */
1336               tmpfp = NULL;
1337             }
1338           rc = lastresname? rename_tmp_file (bakfilename, tmpfilename, 
1339                                              lastresname, 0) : 0;
1340           m_free (tmpfilename);  tmpfilename = NULL;
1341           m_free (bakfilename);  bakfilename = NULL;
1342           if (rc)
1343             goto leave;
1344           lastresname = resname;
1345           if (!opt.quiet)
1346             log_info (_("checking keyring `%s'\n"), resname);
1347           rc = create_tmp_file (resname, &bakfilename, &tmpfilename, &tmpfp);
1348           if (rc)
1349             goto leave;
1350         }
1351       
1352       release_kbnode (keyblock);
1353       rc = keyring_get_keyblock (hd, &keyblock);
1354       if (rc) 
1355         {
1356           log_error ("keyring_get_keyblock failed: %s\n", g10_errstr(rc));
1357           goto leave;
1358         }
1359       assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
1360
1361       /* check all signature to set the signature's cache flags */
1362       for (node=keyblock; node; node=node->next)
1363         {
1364           if (node->pkt->pkttype == PKT_SIGNATURE)
1365             {
1366               check_key_signature (keyblock, node, NULL);
1367               sigcount++;
1368             }
1369         }
1370       
1371       /* write the keyblock to the temporary file */
1372       rc = write_keyblock (tmpfp, keyblock);
1373       if (rc)
1374         goto leave;
1375
1376       if ( !(++count % 50) && !opt.quiet)
1377         log_info(_("%lu keys checked so far (%lu signatures)\n"),
1378                  count, sigcount );
1379
1380     } /* end main loop */ 
1381   if (rc == -1)
1382     rc = 0;
1383   if (rc) 
1384     {
1385       log_error ("keyring_search failed: %s\n", g10_errstr(rc));
1386       goto leave;
1387     }
1388   log_info(_("%lu keys checked (%lu signatures)\n"), count, sigcount );
1389   if (tmpfp)
1390     {
1391       if (iobuf_close (tmpfp))
1392         {
1393           log_error ("error closing `%s': %s\n",
1394                      tmpfilename, strerror (errno));
1395           rc = G10ERR_CLOSE_FILE;
1396           goto leave;
1397         }
1398       /* because we have switched resources, we can be sure that
1399        * the original file is closed */
1400       tmpfp = NULL;
1401     }
1402   rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
1403                                      lastresname, 0) : 0;
1404   m_free (tmpfilename);  tmpfilename = NULL;
1405   m_free (bakfilename);  bakfilename = NULL;
1406
1407  leave:
1408   if (tmpfp)
1409     iobuf_cancel (tmpfp);
1410   m_free (tmpfilename);  
1411   m_free (bakfilename);  
1412   release_kbnode (keyblock);
1413   keyring_release (hd);
1414   return rc;
1415 }
1416
1417 \f
1418 /****************
1419  * Perform insert/delete/update operation.
1420  * mode 1 = insert
1421  *      2 = delete
1422  *      3 = update
1423  */
1424 static int
1425 do_copy (int mode, const char *fname, KBNODE root, int secret,
1426          off_t start_offset, unsigned int n_packets )
1427 {
1428     IOBUF fp, newfp;
1429     int rc=0;
1430     char *bakfname = NULL;
1431     char *tmpfname = NULL;
1432
1433     /* Open the source file. Because we do a rname, we have to check the 
1434        permissions of the file */
1435     if (access (fname, W_OK))
1436       return G10ERR_WRITE_FILE;
1437
1438     fp = iobuf_open (fname);
1439     if (mode == 1 && !fp && errno == ENOENT) { 
1440         /* insert mode but file does not exist: create a new file */
1441         KBNODE kbctx, node;
1442         mode_t oldmask;
1443
1444         oldmask=umask(077);
1445         newfp = iobuf_create (fname);
1446         umask(oldmask);
1447         if( !newfp ) {
1448             log_error (_("%s: can't create: %s\n"),
1449                        fname, strerror(errno));
1450             return G10ERR_OPEN_FILE;
1451         }
1452         if( !opt.quiet )
1453             log_info(_("%s: keyring created\n"), fname );
1454
1455         kbctx=NULL;
1456         while ( (node = walk_kbnode( root, &kbctx, 0 )) ) {
1457             if( (rc = build_packet( newfp, node->pkt )) ) {
1458                 log_error("build_packet(%d) failed: %s\n",
1459                             node->pkt->pkttype, g10_errstr(rc) );
1460                 iobuf_cancel(newfp);
1461                 return G10ERR_WRITE_FILE;
1462             }
1463         }
1464         if( iobuf_close(newfp) ) {
1465             log_error ("%s: close failed: %s\n", fname, strerror(errno));
1466             return G10ERR_CLOSE_FILE;
1467         }
1468         return 0; /* ready */
1469     }
1470
1471     if( !fp ) {
1472         log_error ("%s: can't open: %s\n", fname, strerror(errno) );
1473         rc = G10ERR_OPEN_FILE;
1474         goto leave;
1475     }
1476
1477     /* create the new file */
1478     rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
1479     if (rc) {
1480         iobuf_close(fp);
1481         goto leave;
1482     }
1483     if( mode == 1 ) { /* insert */
1484         /* copy everything to the new file */
1485         rc = copy_all_packets (fp, newfp);
1486         if( rc != -1 ) {
1487             log_error("%s: copy to `%s' failed: %s\n",
1488                       fname, tmpfname, g10_errstr(rc) );
1489             iobuf_close(fp);
1490             iobuf_cancel(newfp);
1491             goto leave;
1492         }
1493         rc = 0;
1494     }
1495
1496     if( mode == 2 || mode == 3 ) { /* delete or update */
1497         /* copy first part to the new file */
1498         rc = copy_some_packets( fp, newfp, start_offset );
1499         if( rc ) { /* should never get EOF here */
1500             log_error ("%s: copy to `%s' failed: %s\n",
1501                        fname, tmpfname, g10_errstr(rc) );
1502             iobuf_close(fp);
1503             iobuf_cancel(newfp);
1504             goto leave;
1505         }
1506         /* skip this keyblock */
1507         assert( n_packets );
1508         rc = skip_some_packets( fp, n_packets );
1509         if( rc ) {
1510             log_error("%s: skipping %u packets failed: %s\n",
1511                             fname, n_packets, g10_errstr(rc));
1512             iobuf_close(fp);
1513             iobuf_cancel(newfp);
1514             goto leave;
1515         }
1516     }
1517
1518     if( mode == 1 || mode == 3 ) { /* insert or update */
1519         rc = write_keyblock (newfp, root);
1520         if (rc) {
1521           iobuf_close(fp);
1522           iobuf_cancel(newfp);
1523           goto leave;
1524         }
1525     }
1526
1527     if( mode == 2 || mode == 3 ) { /* delete or update */
1528         /* copy the rest */
1529         rc = copy_all_packets( fp, newfp );
1530         if( rc != -1 ) {
1531             log_error("%s: copy to `%s' failed: %s\n",
1532                       fname, tmpfname, g10_errstr(rc) );
1533             iobuf_close(fp);
1534             iobuf_cancel(newfp);
1535             goto leave;
1536         }
1537         rc = 0;
1538     }
1539
1540     /* close both files */
1541     if( iobuf_close(fp) ) {
1542         log_error("%s: close failed: %s\n", fname, strerror(errno) );
1543         rc = G10ERR_CLOSE_FILE;
1544         goto leave;
1545     }
1546     if( iobuf_close(newfp) ) {
1547         log_error("%s: close failed: %s\n", tmpfname, strerror(errno) );
1548         rc = G10ERR_CLOSE_FILE;
1549         goto leave;
1550     }
1551
1552     rc = rename_tmp_file (bakfname, tmpfname, fname, secret);
1553
1554   leave:
1555     m_free(bakfname);
1556     m_free(tmpfname);
1557     return rc;
1558 }