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