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