po: Update and enable Ukrainian (uk) translation.
[gnupg.git] / sm / keydb.c
1 /* keydb.c - key database dispatcher
2  * Copyright (C) 2001, 2003, 2004 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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <assert.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29
30 #include "gpgsm.h"
31 #include "../kbx/keybox.h"
32 #include "keydb.h"
33 #include "i18n.h"
34
35 static int active_handles;
36
37 typedef enum {
38     KEYDB_RESOURCE_TYPE_NONE = 0,
39     KEYDB_RESOURCE_TYPE_KEYBOX
40 } KeydbResourceType;
41 #define MAX_KEYDB_RESOURCES 20
42
43 struct resource_item {
44   KeydbResourceType type;
45   union {
46     KEYBOX_HANDLE kr;
47   } u;
48   void *token;
49   int secret;
50   dotlock_t lockhandle;
51 };
52
53 static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
54 static int used_resources;
55
56 struct keydb_handle {
57   int locked;
58   int found;
59   int saved_found;
60   int current;
61   int is_ephemeral;
62   int used; /* items in active */
63   struct resource_item active[MAX_KEYDB_RESOURCES];
64 };
65
66
67 static int lock_all (KEYDB_HANDLE hd);
68 static void unlock_all (KEYDB_HANDLE hd);
69
70
71 /*
72  * Register a resource (which currently may only be a keybox file).
73  * The first keybox which is added by this function is created if it
74  * does not exist.  If AUTO_CREATED is not NULL it will be set to true
75  * if the function has created a a new keybox.
76  */
77 int
78 keydb_add_resource (const char *url, int force, int secret, int *auto_created)
79 {
80   static int any_secret, any_public;
81   const char *resname = url;
82   char *filename = NULL;
83   int rc = 0;
84   FILE *fp;
85   KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
86
87   if (auto_created)
88     *auto_created = 0;
89
90   /* Do we have an URL?
91      gnupg-kbx:filename := this is a plain keybox
92      filename := See what is is, but create as plain keybox.
93   */
94   if (strlen (resname) > 10)
95     {
96       if (!strncmp (resname, "gnupg-kbx:", 10) )
97         {
98           rt = KEYDB_RESOURCE_TYPE_KEYBOX;
99           resname += 10;
100         }
101 #if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
102       else if (strchr (resname, ':'))
103         {
104           log_error ("invalid key resource URL '%s'\n", url );
105           rc = gpg_error (GPG_ERR_GENERAL);
106           goto leave;
107         }
108 #endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
109     }
110
111   if (*resname != DIRSEP_C )
112     { /* do tilde expansion etc */
113       if (strchr(resname, DIRSEP_C) )
114         filename = make_filename (resname, NULL);
115       else
116         filename = make_filename (opt.homedir, resname, NULL);
117     }
118   else
119     filename = xstrdup (resname);
120
121   if (!force)
122     force = secret? !any_secret : !any_public;
123
124   /* see whether we can determine the filetype */
125   if (rt == KEYDB_RESOURCE_TYPE_NONE)
126     {
127       FILE *fp2 = fopen( filename, "rb" );
128
129       if (fp2) {
130         u32 magic;
131
132         /* FIXME: check for the keybox magic */
133         if (fread( &magic, 4, 1, fp2) == 1 )
134           {
135             if (magic == 0x13579ace || magic == 0xce9a5713)
136               ; /* GDBM magic - no more support */
137             else
138               rt = KEYDB_RESOURCE_TYPE_KEYBOX;
139           }
140         else /* maybe empty: assume ring */
141           rt = KEYDB_RESOURCE_TYPE_KEYBOX;
142         fclose (fp2);
143       }
144       else /* no file yet: create ring */
145         rt = KEYDB_RESOURCE_TYPE_KEYBOX;
146     }
147
148   switch (rt)
149     {
150     case KEYDB_RESOURCE_TYPE_NONE:
151       log_error ("unknown type of key resource '%s'\n", url );
152       rc = gpg_error (GPG_ERR_GENERAL);
153       goto leave;
154
155     case KEYDB_RESOURCE_TYPE_KEYBOX:
156       fp = fopen (filename, "rb");
157       if (!fp && !force)
158         {
159           rc = gpg_error (gpg_err_code_from_errno (errno));
160           goto leave;
161         }
162
163       if (!fp)
164         { /* no file */
165 #if 0 /* no autocreate of the homedirectory yet */
166           {
167             char *last_slash_in_filename;
168
169             last_slash_in_filename = strrchr (filename, DIRSEP_C);
170             *last_slash_in_filename = 0;
171             if (access (filename, F_OK))
172               { /* on the first time we try to create the default
173                    homedir and in this case the process will be
174                    terminated, so that on the next invocation can
175                    read the options file in on startup */
176                 try_make_homedir (filename);
177                 rc = gpg_error (GPG_ERR_FILE_OPEN_ERROR);
178                 *last_slash_in_filename = DIRSEP_C;
179                 goto leave;
180               }
181             *last_slash_in_filename = DIRSEP_C;
182           }
183 #endif
184           fp = fopen (filename, "w");
185           if (!fp)
186             {
187               rc = gpg_error (gpg_err_code_from_errno (errno));
188               log_error (_("error creating keybox '%s': %s\n"),
189                          filename, strerror(errno));
190               if (errno == ENOENT)
191                 log_info (_("you may want to start the gpg-agent first\n"));
192               goto leave;
193             }
194
195           if (!opt.quiet)
196             log_info (_("keybox '%s' created\n"), filename);
197           if (auto_created)
198             *auto_created = 1;
199         }
200         fclose (fp);
201         fp = NULL;
202         /* now register the file */
203         {
204
205           void *token = keybox_register_file (filename, secret);
206           if (!token)
207             ; /* already registered - ignore it */
208           else if (used_resources >= MAX_KEYDB_RESOURCES)
209             rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
210           else
211             {
212               all_resources[used_resources].type = rt;
213               all_resources[used_resources].u.kr = NULL; /* Not used here */
214               all_resources[used_resources].token = token;
215               all_resources[used_resources].secret = secret;
216
217               all_resources[used_resources].lockhandle
218                 = dotlock_create (filename, 0);
219               if (!all_resources[used_resources].lockhandle)
220                 log_fatal ( _("can't create lock for '%s'\n"), filename);
221
222               /* Do a compress run if needed and the file is not locked. */
223               if (!dotlock_take (all_resources[used_resources].lockhandle, 0))
224                 {
225                   KEYBOX_HANDLE kbxhd = keybox_new (token, secret);
226
227                   if (kbxhd)
228                     {
229                       keybox_compress (kbxhd);
230                       keybox_release (kbxhd);
231                     }
232                   dotlock_release (all_resources[used_resources].lockhandle);
233                 }
234
235               used_resources++;
236             }
237         }
238
239
240         break;
241     default:
242       log_error ("resource type of '%s' not supported\n", url);
243       rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
244       goto leave;
245     }
246
247   /* fixme: check directory permissions and print a warning */
248
249  leave:
250   if (rc)
251     log_error ("keyblock resource '%s': %s\n", filename, gpg_strerror(rc));
252   else if (secret)
253     any_secret = 1;
254   else
255     any_public = 1;
256   xfree (filename);
257   return rc;
258 }
259
260
261 KEYDB_HANDLE
262 keydb_new (int secret)
263 {
264   KEYDB_HANDLE hd;
265   int i, j;
266
267   hd = xcalloc (1, sizeof *hd);
268   hd->found = -1;
269   hd->saved_found = -1;
270
271   assert (used_resources <= MAX_KEYDB_RESOURCES);
272   for (i=j=0; i < used_resources; i++)
273     {
274       if (!all_resources[i].secret != !secret)
275         continue;
276       switch (all_resources[i].type)
277         {
278         case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
279           break;
280         case KEYDB_RESOURCE_TYPE_KEYBOX:
281           hd->active[j].type   = all_resources[i].type;
282           hd->active[j].token  = all_resources[i].token;
283           hd->active[j].secret = all_resources[i].secret;
284           hd->active[j].lockhandle = all_resources[i].lockhandle;
285           hd->active[j].u.kr = keybox_new (all_resources[i].token, secret);
286           if (!hd->active[j].u.kr)
287             {
288               xfree (hd);
289               return NULL; /* fixme: release all previously allocated handles*/
290             }
291           j++;
292           break;
293         }
294     }
295   hd->used = j;
296
297   active_handles++;
298   return hd;
299 }
300
301 void
302 keydb_release (KEYDB_HANDLE hd)
303 {
304   int i;
305
306   if (!hd)
307     return;
308   assert (active_handles > 0);
309   active_handles--;
310
311   unlock_all (hd);
312   for (i=0; i < hd->used; i++)
313     {
314       switch (hd->active[i].type)
315         {
316         case KEYDB_RESOURCE_TYPE_NONE:
317           break;
318         case KEYDB_RESOURCE_TYPE_KEYBOX:
319           keybox_release (hd->active[i].u.kr);
320           break;
321         }
322     }
323
324     xfree (hd);
325 }
326
327
328 /* Return the name of the current resource.  This is function first
329    looks for the last found found, then for the current search
330    position, and last returns the first available resource.  The
331    returned string is only valid as long as the handle exists.  This
332    function does only return NULL if no handle is specified, in all
333    other error cases an empty string is returned.  */
334 const char *
335 keydb_get_resource_name (KEYDB_HANDLE hd)
336 {
337   int idx;
338   const char *s = NULL;
339
340   if (!hd)
341     return NULL;
342
343   if ( hd->found >= 0 && hd->found < hd->used)
344     idx = hd->found;
345   else if ( hd->current >= 0 && hd->current < hd->used)
346     idx = hd->current;
347   else
348     idx = 0;
349
350   switch (hd->active[idx].type)
351     {
352     case KEYDB_RESOURCE_TYPE_NONE:
353       s = NULL;
354       break;
355     case KEYDB_RESOURCE_TYPE_KEYBOX:
356       s = keybox_get_resource_name (hd->active[idx].u.kr);
357       break;
358     }
359
360   return s? s: "";
361 }
362
363 /* Switch the handle into ephemeral mode and return the orginal value. */
364 int
365 keydb_set_ephemeral (KEYDB_HANDLE hd, int yes)
366 {
367   int i;
368
369   if (!hd)
370     return 0;
371
372   yes = !!yes;
373   if (hd->is_ephemeral != yes)
374     {
375       for (i=0; i < hd->used; i++)
376         {
377           switch (hd->active[i].type)
378             {
379             case KEYDB_RESOURCE_TYPE_NONE:
380               break;
381             case KEYDB_RESOURCE_TYPE_KEYBOX:
382               keybox_set_ephemeral (hd->active[i].u.kr, yes);
383               break;
384             }
385         }
386     }
387
388   i = hd->is_ephemeral;
389   hd->is_ephemeral = yes;
390   return i;
391 }
392
393
394 /* If the keyring has not yet been locked, lock it now.  This
395    operation is required before any update operation; it is optional
396    for an insert operation.  The lock is released with
397    keydb_released. */
398 gpg_error_t
399 keydb_lock (KEYDB_HANDLE hd)
400 {
401   if (!hd)
402     return gpg_error (GPG_ERR_INV_HANDLE);
403   if (hd->locked)
404     return 0; /* Already locked. */
405   return lock_all (hd);
406 }
407
408
409 \f
410 static int
411 lock_all (KEYDB_HANDLE hd)
412 {
413   int i, rc = 0;
414
415   /* Fixme: This locking scheme may lead to deadlock if the resources
416      are not added in the same order by all processes.  We are
417      currently only allowing one resource so it is not a problem. */
418   for (i=0; i < hd->used; i++)
419     {
420       switch (hd->active[i].type)
421         {
422         case KEYDB_RESOURCE_TYPE_NONE:
423           break;
424         case KEYDB_RESOURCE_TYPE_KEYBOX:
425           if (hd->active[i].lockhandle)
426             rc = dotlock_take (hd->active[i].lockhandle, -1);
427           break;
428         }
429       if (rc)
430         break;
431     }
432
433     if (rc)
434       {
435         /* revert the already set locks */
436         for (i--; i >= 0; i--)
437           {
438             switch (hd->active[i].type)
439               {
440               case KEYDB_RESOURCE_TYPE_NONE:
441                 break;
442               case KEYDB_RESOURCE_TYPE_KEYBOX:
443                 if (hd->active[i].lockhandle)
444                   dotlock_release (hd->active[i].lockhandle);
445                 break;
446               }
447           }
448       }
449     else
450       hd->locked = 1;
451
452     /* make_dotlock () does not yet guarantee that errno is set, thus
453        we can't rely on the error reason and will simply use
454        EACCES. */
455     return rc? gpg_error (GPG_ERR_EACCES) : 0;
456 }
457
458 static void
459 unlock_all (KEYDB_HANDLE hd)
460 {
461   int i;
462
463   if (!hd->locked)
464     return;
465
466   for (i=hd->used-1; i >= 0; i--)
467     {
468       switch (hd->active[i].type)
469         {
470         case KEYDB_RESOURCE_TYPE_NONE:
471           break;
472         case KEYDB_RESOURCE_TYPE_KEYBOX:
473           if (hd->active[i].lockhandle)
474             dotlock_release (hd->active[i].lockhandle);
475           break;
476         }
477     }
478   hd->locked = 0;
479 }
480
481
482 \f
483 /* Push the last found state if any.  */
484 void
485 keydb_push_found_state (KEYDB_HANDLE hd)
486 {
487   if (!hd)
488     return;
489
490   if (hd->found < 0 || hd->found >= hd->used)
491     {
492       hd->saved_found = -1;
493       return;
494     }
495
496   switch (hd->active[hd->found].type)
497     {
498     case KEYDB_RESOURCE_TYPE_NONE:
499       break;
500     case KEYDB_RESOURCE_TYPE_KEYBOX:
501       keybox_push_found_state (hd->active[hd->found].u.kr);
502       break;
503     }
504
505   hd->saved_found = hd->found;
506   hd->found = -1;
507 }
508
509
510 /* Pop the last found state.  */
511 void
512 keydb_pop_found_state (KEYDB_HANDLE hd)
513 {
514   if (!hd)
515     return;
516
517   hd->found = hd->saved_found;
518   hd->saved_found = -1;
519   if (hd->found < 0 || hd->found >= hd->used)
520     return;
521
522   switch (hd->active[hd->found].type)
523     {
524     case KEYDB_RESOURCE_TYPE_NONE:
525       break;
526     case KEYDB_RESOURCE_TYPE_KEYBOX:
527       keybox_pop_found_state (hd->active[hd->found].u.kr);
528       break;
529     }
530 }
531
532
533 \f
534 /*
535   Return the last found object.  Caller must free it.  The returned
536   keyblock has the kbode flag bit 0 set for the node with the public
537   key used to locate the keyblock or flag bit 1 set for the user ID
538   node.  */
539 int
540 keydb_get_cert (KEYDB_HANDLE hd, ksba_cert_t *r_cert)
541 {
542   int rc = 0;
543
544   if (!hd)
545     return gpg_error (GPG_ERR_INV_VALUE);
546
547   if ( hd->found < 0 || hd->found >= hd->used)
548     return -1; /* nothing found */
549
550   switch (hd->active[hd->found].type)
551     {
552     case KEYDB_RESOURCE_TYPE_NONE:
553       rc = gpg_error (GPG_ERR_GENERAL); /* oops */
554       break;
555     case KEYDB_RESOURCE_TYPE_KEYBOX:
556       rc = keybox_get_cert (hd->active[hd->found].u.kr, r_cert);
557       break;
558     }
559
560   return rc;
561 }
562
563 /* Return a flag of the last found object. WHICH is the flag requested;
564    it should be one of the KEYBOX_FLAG_ values.  If the operation is
565    successful, the flag value will be stored at the address given by
566    VALUE.  Return 0 on success or an error code. */
567 gpg_error_t
568 keydb_get_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int *value)
569 {
570   int err = 0;
571
572   if (!hd)
573     return gpg_error (GPG_ERR_INV_VALUE);
574
575   if ( hd->found < 0 || hd->found >= hd->used)
576     return gpg_error (GPG_ERR_NOTHING_FOUND);
577
578   switch (hd->active[hd->found].type)
579     {
580     case KEYDB_RESOURCE_TYPE_NONE:
581       err = gpg_error (GPG_ERR_GENERAL); /* oops */
582       break;
583     case KEYDB_RESOURCE_TYPE_KEYBOX:
584       err = keybox_get_flags (hd->active[hd->found].u.kr, which, idx, value);
585       break;
586     }
587
588   return err;
589 }
590
591 /* Set a flag of the last found object. WHICH is the flag to be set; it
592    should be one of the KEYBOX_FLAG_ values.  If the operation is
593    successful, the flag value will be stored in the keybox.  Note,
594    that some flag values can't be updated and thus may return an
595    error, some other flag values may be masked out before an update.
596    Returns 0 on success or an error code. */
597 gpg_error_t
598 keydb_set_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int value)
599 {
600   int err = 0;
601
602   if (!hd)
603     return gpg_error (GPG_ERR_INV_VALUE);
604
605   if ( hd->found < 0 || hd->found >= hd->used)
606     return gpg_error (GPG_ERR_NOTHING_FOUND);
607
608   if (!hd->locked)
609     return gpg_error (GPG_ERR_NOT_LOCKED);
610
611   switch (hd->active[hd->found].type)
612     {
613     case KEYDB_RESOURCE_TYPE_NONE:
614       err = gpg_error (GPG_ERR_GENERAL); /* oops */
615       break;
616     case KEYDB_RESOURCE_TYPE_KEYBOX:
617       err = keybox_set_flags (hd->active[hd->found].u.kr, which, idx, value);
618       break;
619     }
620
621   return err;
622 }
623
624 /*
625  * Insert a new Certificate into one of the resources.
626  */
627 int
628 keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert)
629 {
630   int rc = -1;
631   int idx;
632   unsigned char digest[20];
633
634   if (!hd)
635     return gpg_error (GPG_ERR_INV_VALUE);
636
637   if (opt.dry_run)
638     return 0;
639
640   if ( hd->found >= 0 && hd->found < hd->used)
641     idx = hd->found;
642   else if ( hd->current >= 0 && hd->current < hd->used)
643     idx = hd->current;
644   else
645     return gpg_error (GPG_ERR_GENERAL);
646
647   if (!hd->locked)
648     return gpg_error (GPG_ERR_NOT_LOCKED);
649
650   gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL); /* kludge*/
651
652   switch (hd->active[idx].type)
653     {
654     case KEYDB_RESOURCE_TYPE_NONE:
655       rc = gpg_error (GPG_ERR_GENERAL);
656       break;
657     case KEYDB_RESOURCE_TYPE_KEYBOX:
658       rc = keybox_insert_cert (hd->active[idx].u.kr, cert, digest);
659       break;
660     }
661
662   unlock_all (hd);
663   return rc;
664 }
665
666
667
668 /* Update the current keyblock with KB.  */
669 int
670 keydb_update_cert (KEYDB_HANDLE hd, ksba_cert_t cert)
671 {
672   int rc = 0;
673   unsigned char digest[20];
674
675   if (!hd)
676     return gpg_error (GPG_ERR_INV_VALUE);
677
678   if ( hd->found < 0 || hd->found >= hd->used)
679     return -1; /* nothing found */
680
681   if (opt.dry_run)
682     return 0;
683
684   rc = lock_all (hd);
685   if (rc)
686     return rc;
687
688   gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL); /* kludge*/
689
690   switch (hd->active[hd->found].type)
691     {
692     case KEYDB_RESOURCE_TYPE_NONE:
693       rc = gpg_error (GPG_ERR_GENERAL); /* oops */
694       break;
695     case KEYDB_RESOURCE_TYPE_KEYBOX:
696       rc = keybox_update_cert (hd->active[hd->found].u.kr, cert, digest);
697       break;
698     }
699
700   unlock_all (hd);
701   return rc;
702 }
703
704
705 /*
706  * The current keyblock or cert will be deleted.
707  */
708 int
709 keydb_delete (KEYDB_HANDLE hd, int unlock)
710 {
711   int rc = -1;
712
713   if (!hd)
714     return gpg_error (GPG_ERR_INV_VALUE);
715
716   if ( hd->found < 0 || hd->found >= hd->used)
717     return -1; /* nothing found */
718
719   if( opt.dry_run )
720     return 0;
721
722   if (!hd->locked)
723     return gpg_error (GPG_ERR_NOT_LOCKED);
724
725   switch (hd->active[hd->found].type)
726     {
727     case KEYDB_RESOURCE_TYPE_NONE:
728       rc = gpg_error (GPG_ERR_GENERAL);
729       break;
730     case KEYDB_RESOURCE_TYPE_KEYBOX:
731       rc = keybox_delete (hd->active[hd->found].u.kr);
732       break;
733     }
734
735   if (unlock)
736     unlock_all (hd);
737   return rc;
738 }
739
740
741 \f
742 /*
743  * Locate the default writable key resource, so that the next
744  * operation (which is only relevant for inserts) will be done on this
745  * resource.
746  */
747 int
748 keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
749 {
750   int rc;
751
752   (void)reserved;
753
754   if (!hd)
755     return gpg_error (GPG_ERR_INV_VALUE);
756
757   rc = keydb_search_reset (hd); /* this does reset hd->current */
758   if (rc)
759     return rc;
760
761   for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
762     {
763       switch (hd->active[hd->current].type)
764         {
765         case KEYDB_RESOURCE_TYPE_NONE:
766           BUG();
767           break;
768         case KEYDB_RESOURCE_TYPE_KEYBOX:
769           if (keybox_is_writable (hd->active[hd->current].token))
770             return 0; /* found (hd->current is set to it) */
771           break;
772         }
773     }
774
775   return -1;
776 }
777
778 /*
779  * Rebuild the caches of all key resources.
780  */
781 void
782 keydb_rebuild_caches (void)
783 {
784   int i;
785
786   for (i=0; i < used_resources; i++)
787     {
788       if (all_resources[i].secret)
789         continue;
790       switch (all_resources[i].type)
791         {
792         case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
793           break;
794         case KEYDB_RESOURCE_TYPE_KEYBOX:
795 /*            rc = keybox_rebuild_cache (all_resources[i].token); */
796 /*            if (rc) */
797 /*              log_error (_("failed to rebuild keybox cache: %s\n"), */
798 /*                         g10_errstr (rc)); */
799           break;
800         }
801     }
802 }
803
804
805
806 /*
807  * Start the next search on this handle right at the beginning
808  */
809 int
810 keydb_search_reset (KEYDB_HANDLE hd)
811 {
812   int i, rc = 0;
813
814   if (!hd)
815     return gpg_error (GPG_ERR_INV_VALUE);
816
817   hd->current = 0;
818   hd->found = -1;
819   /* and reset all resources */
820   for (i=0; !rc && i < hd->used; i++)
821     {
822       switch (hd->active[i].type)
823         {
824         case KEYDB_RESOURCE_TYPE_NONE:
825           break;
826         case KEYDB_RESOURCE_TYPE_KEYBOX:
827           rc = keybox_search_reset (hd->active[i].u.kr);
828           break;
829         }
830     }
831   return rc; /* fixme: we need to map error codes or share them with
832                 all modules*/
833 }
834
835 /*
836  * Search through all keydb resources, starting at the current position,
837  * for a keyblock which contains one of the keys described in the DESC array.
838  */
839 int
840 keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
841 {
842   int rc = -1;
843
844   if (!hd)
845     return gpg_error (GPG_ERR_INV_VALUE);
846
847   while (rc == -1 && hd->current >= 0 && hd->current < hd->used)
848     {
849       switch (hd->active[hd->current].type)
850         {
851         case KEYDB_RESOURCE_TYPE_NONE:
852           BUG(); /* we should never see it here */
853           break;
854         case KEYDB_RESOURCE_TYPE_KEYBOX:
855           rc = keybox_search (hd->active[hd->current].u.kr, desc, ndesc, NULL);
856           break;
857         }
858       if (rc == -1) /* EOF -> switch to next resource */
859         hd->current++;
860       else if (!rc)
861         hd->found = hd->current;
862     }
863
864   return rc;
865 }
866
867
868 int
869 keydb_search_first (KEYDB_HANDLE hd)
870 {
871   KEYDB_SEARCH_DESC desc;
872
873   memset (&desc, 0, sizeof desc);
874   desc.mode = KEYDB_SEARCH_MODE_FIRST;
875   return keydb_search (hd, &desc, 1);
876 }
877
878 int
879 keydb_search_next (KEYDB_HANDLE hd)
880 {
881   KEYDB_SEARCH_DESC desc;
882
883   memset (&desc, 0, sizeof desc);
884   desc.mode = KEYDB_SEARCH_MODE_NEXT;
885   return keydb_search (hd, &desc, 1);
886 }
887
888 int
889 keydb_search_kid (KEYDB_HANDLE hd, u32 *kid)
890 {
891   KEYDB_SEARCH_DESC desc;
892
893   (void)kid;
894
895   memset (&desc, 0, sizeof desc);
896   desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
897   desc.u.kid[0] = kid[0];
898   desc.u.kid[1] = kid[1];
899   return keydb_search (hd, &desc, 1);
900 }
901
902 int
903 keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr)
904 {
905   KEYDB_SEARCH_DESC desc;
906
907   memset (&desc, 0, sizeof desc);
908   desc.mode = KEYDB_SEARCH_MODE_FPR;
909   memcpy (desc.u.fpr, fpr, 20);
910   return keydb_search (hd, &desc, 1);
911 }
912
913 int
914 keydb_search_issuer (KEYDB_HANDLE hd, const char *issuer)
915 {
916   KEYDB_SEARCH_DESC desc;
917   int rc;
918
919   memset (&desc, 0, sizeof desc);
920   desc.mode = KEYDB_SEARCH_MODE_ISSUER;
921   desc.u.name = issuer;
922   rc = keydb_search (hd, &desc, 1);
923   return rc;
924 }
925
926 int
927 keydb_search_issuer_sn (KEYDB_HANDLE hd,
928                         const char *issuer, ksba_const_sexp_t serial)
929 {
930   KEYDB_SEARCH_DESC desc;
931   int rc;
932   const unsigned char *s;
933
934   memset (&desc, 0, sizeof desc);
935   desc.mode = KEYDB_SEARCH_MODE_ISSUER_SN;
936   s = serial;
937   if (*s !='(')
938     return gpg_error (GPG_ERR_INV_VALUE);
939   s++;
940   for (desc.snlen = 0; digitp (s); s++)
941     desc.snlen = 10*desc.snlen + atoi_1 (s);
942   if (*s !=':')
943     return gpg_error (GPG_ERR_INV_VALUE);
944   desc.sn = s+1;
945   desc.u.name = issuer;
946   rc = keydb_search (hd, &desc, 1);
947   return rc;
948 }
949
950 int
951 keydb_search_subject (KEYDB_HANDLE hd, const char *name)
952 {
953   KEYDB_SEARCH_DESC desc;
954   int rc;
955
956   memset (&desc, 0, sizeof desc);
957   desc.mode = KEYDB_SEARCH_MODE_SUBJECT;
958   desc.u.name = name;
959   rc = keydb_search (hd, &desc, 1);
960   return rc;
961 }
962
963
964 \f
965 /* Store the certificate in the key DB but make sure that it does not
966    already exists.  We do this simply by comparing the fingerprint.
967    If EXISTED is not NULL it will be set to true if the certificate
968    was already in the DB. */
969 int
970 keydb_store_cert (ksba_cert_t cert, int ephemeral, int *existed)
971 {
972   KEYDB_HANDLE kh;
973   int rc;
974   unsigned char fpr[20];
975
976   if (existed)
977     *existed = 0;
978
979   if (!gpgsm_get_fingerprint (cert, 0, fpr, NULL))
980     {
981       log_error (_("failed to get the fingerprint\n"));
982       return gpg_error (GPG_ERR_GENERAL);
983     }
984
985   kh = keydb_new (0);
986   if (!kh)
987     {
988       log_error (_("failed to allocate keyDB handle\n"));
989       return gpg_error (GPG_ERR_ENOMEM);;
990     }
991
992   if (ephemeral)
993     keydb_set_ephemeral (kh, 1);
994
995   rc = lock_all (kh);
996   if (rc)
997     return rc;
998
999   rc = keydb_search_fpr (kh, fpr);
1000   if (rc != -1)
1001     {
1002       keydb_release (kh);
1003       if (!rc)
1004         {
1005           if (existed)
1006             *existed = 1;
1007           return 0; /* okay */
1008         }
1009       log_error (_("problem looking for existing certificate: %s\n"),
1010                  gpg_strerror (rc));
1011       return rc;
1012     }
1013
1014   rc = keydb_locate_writable (kh, 0);
1015   if (rc)
1016     {
1017       log_error (_("error finding writable keyDB: %s\n"), gpg_strerror (rc));
1018       keydb_release (kh);
1019       return rc;
1020     }
1021
1022   rc = keydb_insert_cert (kh, cert);
1023   if (rc)
1024     {
1025       log_error (_("error storing certificate: %s\n"), gpg_strerror (rc));
1026       keydb_release (kh);
1027       return rc;
1028     }
1029   keydb_release (kh);
1030   return 0;
1031 }
1032
1033
1034 /* This is basically keydb_set_flags but it implements a complete
1035    transaction by locating the certificate in the DB and updating the
1036    flags. */
1037 gpg_error_t
1038 keydb_set_cert_flags (ksba_cert_t cert, int ephemeral,
1039                       int which, int idx,
1040                       unsigned int mask, unsigned int value)
1041 {
1042   KEYDB_HANDLE kh;
1043   gpg_error_t err;
1044   unsigned char fpr[20];
1045   unsigned int old_value;
1046
1047   if (!gpgsm_get_fingerprint (cert, 0, fpr, NULL))
1048     {
1049       log_error (_("failed to get the fingerprint\n"));
1050       return gpg_error (GPG_ERR_GENERAL);
1051     }
1052
1053   kh = keydb_new (0);
1054   if (!kh)
1055     {
1056       log_error (_("failed to allocate keyDB handle\n"));
1057       return gpg_error (GPG_ERR_ENOMEM);;
1058     }
1059
1060   if (ephemeral)
1061     keydb_set_ephemeral (kh, 1);
1062
1063   err = keydb_lock (kh);
1064   if (err)
1065     {
1066       log_error (_("error locking keybox: %s\n"), gpg_strerror (err));
1067       keydb_release (kh);
1068       return err;
1069     }
1070
1071   err = keydb_search_fpr (kh, fpr);
1072   if (err)
1073     {
1074       if (err == -1)
1075         err = gpg_error (GPG_ERR_NOT_FOUND);
1076       else
1077         log_error (_("problem re-searching certificate: %s\n"),
1078                    gpg_strerror (err));
1079       keydb_release (kh);
1080       return err;
1081     }
1082
1083   err = keydb_get_flags (kh, which, idx, &old_value);
1084   if (err)
1085     {
1086       log_error (_("error getting stored flags: %s\n"), gpg_strerror (err));
1087       keydb_release (kh);
1088       return err;
1089     }
1090
1091   value = ((old_value & ~mask) | (value & mask));
1092
1093   if (value != old_value)
1094     {
1095       err = keydb_set_flags (kh, which, idx, value);
1096       if (err)
1097         {
1098           log_error (_("error storing flags: %s\n"), gpg_strerror (err));
1099           keydb_release (kh);
1100           return err;
1101         }
1102     }
1103
1104   keydb_release (kh);
1105   return 0;
1106 }
1107
1108
1109 /* Reset all the certificate flags we have stored with the certificates
1110    for performance reasons. */
1111 void
1112 keydb_clear_some_cert_flags (ctrl_t ctrl, strlist_t names)
1113 {
1114   gpg_error_t err;
1115   KEYDB_HANDLE hd = NULL;
1116   KEYDB_SEARCH_DESC *desc = NULL;
1117   int ndesc;
1118   strlist_t sl;
1119   int rc=0;
1120   unsigned int old_value, value;
1121
1122   (void)ctrl;
1123
1124   hd = keydb_new (0);
1125   if (!hd)
1126     {
1127       log_error ("keydb_new failed\n");
1128       goto leave;
1129     }
1130
1131   if (!names)
1132     ndesc = 1;
1133   else
1134     {
1135       for (sl=names, ndesc=0; sl; sl = sl->next, ndesc++)
1136         ;
1137     }
1138
1139   desc = xtrycalloc (ndesc, sizeof *desc);
1140   if (!ndesc)
1141     {
1142       log_error ("allocating memory failed: %s\n",
1143                  gpg_strerror (out_of_core ()));
1144       goto leave;
1145     }
1146
1147   if (!names)
1148     desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
1149   else
1150     {
1151       for (ndesc=0, sl=names; sl; sl = sl->next)
1152         {
1153           rc = classify_user_id (sl->d, desc+ndesc, 0);
1154           if (rc)
1155             {
1156               log_error ("key '%s' not found: %s\n",
1157                          sl->d, gpg_strerror (rc));
1158               rc = 0;
1159             }
1160           else
1161             ndesc++;
1162         }
1163     }
1164
1165   err = keydb_lock (hd);
1166   if (err)
1167     {
1168       log_error (_("error locking keybox: %s\n"), gpg_strerror (err));
1169       goto leave;
1170     }
1171
1172   while (!(rc = keydb_search (hd, desc, ndesc)))
1173     {
1174       if (!names)
1175         desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
1176
1177       err = keydb_get_flags (hd, KEYBOX_FLAG_VALIDITY, 0, &old_value);
1178       if (err)
1179         {
1180           log_error (_("error getting stored flags: %s\n"),
1181                      gpg_strerror (err));
1182           goto leave;
1183         }
1184
1185       value = (old_value & ~VALIDITY_REVOKED);
1186       if (value != old_value)
1187         {
1188           err = keydb_set_flags (hd, KEYBOX_FLAG_VALIDITY, 0, value);
1189           if (err)
1190             {
1191               log_error (_("error storing flags: %s\n"), gpg_strerror (err));
1192               goto leave;
1193             }
1194         }
1195     }
1196   if (rc && rc != -1)
1197     log_error ("keydb_search failed: %s\n", gpg_strerror (rc));
1198
1199  leave:
1200   xfree (desc);
1201   keydb_release (hd);
1202 }