* configure.ac: --enable-ftp is on by default, --with-libcurl is off by
[gnupg.git] / kbx / keybox-search.c
index 1c78cae..231a32d 100644 (file)
@@ -1,5 +1,5 @@
 /* keybox-search.c - Search operations
- *     Copyright (C) 2001 Free Software Foundation, Inc.
+ *     Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -23,7 +23,9 @@
 #include <stdio.h>
 #include <string.h>
 #include <assert.h>
+#include <errno.h>
 
+#include "../jnlib/stringhelp.h" /* ascii_xxxx() */
 #include "keybox-defs.h"
 
 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
@@ -72,6 +74,19 @@ blob_get_type (KEYBOXBLOB blob)
   return buffer[4];
 }
 
+static unsigned int
+blob_get_blob_flags (KEYBOXBLOB blob)
+{
+  const unsigned char *buffer;
+  size_t length;
+
+  buffer = _keybox_get_blob_image (blob, &length);
+  if (length < 8)
+    return 0; /* oops */
+
+  return get16 (buffer + 6);
+}
+
 
 static int
 blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
@@ -106,7 +121,72 @@ blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
 
 
 static int
-blob_cmp_name (KEYBOXBLOB blob, int idx, const char *name, size_t namelen)
+blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr)
+{
+  const unsigned char *buffer;
+  size_t length;
+  size_t pos, off;
+  size_t nkeys, keyinfolen;
+  int idx;
+
+  buffer = _keybox_get_blob_image (blob, &length);
+  if (length < 40)
+    return 0; /* blob too short */
+
+  /*keys*/
+  nkeys = get16 (buffer + 16);
+  keyinfolen = get16 (buffer + 18 );
+  if (keyinfolen < 28)
+    return 0; /* invalid blob */
+  pos = 20;
+  if (pos + keyinfolen*nkeys > length)
+    return 0; /* out of bounds */
+
+  for (idx=0; idx < nkeys; idx++)
+    {
+      off = pos + idx*keyinfolen;
+      if (!memcmp (buffer + off, fpr, 20))
+        return 1; /* found */
+    }
+  return 0; /* not found */
+}
+
+static int
+blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr,
+                   int fproff, int fprlen)
+{
+  const unsigned char *buffer;
+  size_t length;
+  size_t pos, off;
+  size_t nkeys, keyinfolen;
+  int idx;
+
+  buffer = _keybox_get_blob_image (blob, &length);
+  if (length < 40)
+    return 0; /* blob too short */
+
+  /*keys*/
+  nkeys = get16 (buffer + 16);
+  keyinfolen = get16 (buffer + 18 );
+  if (keyinfolen < 28)
+    return 0; /* invalid blob */
+  pos = 20;
+  if (pos + keyinfolen*nkeys > length)
+    return 0; /* out of bounds */
+
+  for (idx=0; idx < nkeys; idx++)
+    {
+      off = pos + idx*keyinfolen;
+      if (!memcmp (buffer + off + fproff, fpr, fprlen))
+        return 1; /* found */
+    }
+  return 0; /* not found */
+}
+
+
+static int
+blob_cmp_name (KEYBOXBLOB blob, int idx,
+               const char *name, size_t namelen, int substr)
 {
   const unsigned char *buffer;
   size_t length;
@@ -155,11 +235,18 @@ blob_cmp_name (KEYBOXBLOB blob, int idx, const char *name, size_t namelen)
           len = get32 (buffer+mypos+4);
           if (off+len > length)
             return 0; /* error: better stop here out of bounds */
-          if (len < 2)
-            continue; /* empty name or 0 not stored */
-          len--;
-          if (len == namelen && !memcmp (buffer+off, name, len))
-            return 1; /* found */
+          if (len < 1)
+            continue; /* empty name */
+          if (substr)
+            {
+              if (ascii_memcasemem (buffer+off, len, name, namelen))
+                return 1; /* found */
+            }
+          else
+            {
+              if (len == namelen && !memcmp (buffer+off, name, len))
+                return 1; /* found */
+            }
         }
       return 0; /* not found */
     }
@@ -174,15 +261,23 @@ blob_cmp_name (KEYBOXBLOB blob, int idx, const char *name, size_t namelen)
         return 0; /* out of bounds */
       if (len < 1)
         return 0; /* empty name */
-      
-      return len == namelen && !memcmp (buffer+off, name, len);
+
+      if (substr)
+        {
+          return !!ascii_memcasemem (buffer+off, len, name, namelen);
+        }
+      else
+        {
+          return len == namelen && !memcmp (buffer+off, name, len);
+        }
     }
 }
 
 
-/* compare all email addresses of the subject */
+/* compare all email addresses of the subject.  With SUBSTR given as
+   True a substring search is done in the mail address */
 static int
-blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen)
+blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
 {
   const unsigned char *buffer;
   size_t length;
@@ -236,10 +331,18 @@ blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen)
         continue; /* empty name or trailing 0 not stored */
       len--; /* one back */
       if ( len < 3 || buffer[off+len] != '>')
-        continue; /* not a prober email address */
+        continue; /* not a proper email address */
       len--; 
-      if (len == namelen && !memcmp (buffer+off+1, name, len))
-        return 1; /* found */
+      if (substr)
+        {
+          if (ascii_memcasemem (buffer+off+1, len, name, namelen))
+            return 1; /* found */
+        }
+      else
+        {
+          if (len == namelen && !ascii_memcasecmp (buffer+off+1, name, len))
+            return 1; /* found */
+        }
     }
   return 0; /* not found */
 }
@@ -250,24 +353,22 @@ blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen)
 /*
   The has_foo functions are used as helpers for search 
 */
-#if 0
 static int
-has_short_kid (KEYBOXBLOB blob, u32 kid)
+has_short_kid (KEYBOXBLOB blob, const unsigned char *kid)
 {
-  return 0;
+  return blob_cmp_fpr_part (blob, kid+4, 16, 4);
 }
 
 static int
-has_long_kid (KEYBOXBLOB blob, u32 *kid)
+has_long_kid (KEYBOXBLOB blob, const unsigned char *kid)
 {
-  return 0;
+  return blob_cmp_fpr_part (blob, kid, 12, 8);
 }
-#endif
 
 static int
 has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr)
 {
-  return 0;
+  return blob_cmp_fpr (blob, fpr);
 }
 
 
@@ -282,7 +383,7 @@ has_issuer (KEYBOXBLOB blob, const char *name)
     return 0;
 
   namelen = strlen (name);
-  return blob_cmp_name (blob, 0 /* issuer */, name, namelen);
+  return blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0);
 }
 
 static int
@@ -300,7 +401,7 @@ has_issuer_sn (KEYBOXBLOB blob, const char *name,
   namelen = strlen (name);
   
   return (blob_cmp_sn (blob, sn, snlen)
-          && blob_cmp_name (blob, 0 /* issuer */, name, namelen));
+          && blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0));
 }
 
 static int
@@ -324,11 +425,11 @@ has_subject (KEYBOXBLOB blob, const char *name)
     return 0;
 
   namelen = strlen (name);
-  return blob_cmp_name (blob, 1 /* subject */, name, namelen);
+  return blob_cmp_name (blob, 1 /* subject */, name, namelen, 0);
 }
 
 static int
-has_subject_or_alt (KEYBOXBLOB blob, const char *name)
+has_subject_or_alt (KEYBOXBLOB blob, const char *name, int substr)
 {
   size_t namelen;
 
@@ -338,12 +439,13 @@ has_subject_or_alt (KEYBOXBLOB blob, const char *name)
     return 0;
 
   namelen = strlen (name);
-  return blob_cmp_name (blob, -1 /* all subject names*/, name, namelen);
+  return blob_cmp_name (blob, -1 /* all subject names*/, name,
+                        namelen, substr);
 }
 
 
 static int
-has_mail (KEYBOXBLOB blob, const char *name)
+has_mail (KEYBOXBLOB blob, const char *name, int substr)
 {
   size_t namelen;
 
@@ -355,7 +457,7 @@ has_mail (KEYBOXBLOB blob, const char *name)
   namelen = strlen (name);
   if (namelen && name[namelen-1] == '>')
     namelen--;
-  return blob_cmp_mail (blob, name, namelen);
+  return blob_cmp_mail (blob, name, namelen, substr);
 }
 
 
@@ -380,7 +482,7 @@ int
 keybox_search_reset (KEYBOX_HANDLE hd)
 {
   if (!hd)
-    return KEYBOX_Invalid_Value;
+    return gpg_error (GPG_ERR_INV_VALUE);
 
   if (hd->found.blob)
     {
@@ -398,6 +500,9 @@ keybox_search_reset (KEYBOX_HANDLE hd)
   return 0;   
 }
 
+
+/* Note: When in ephemeral mode the search function does visit all
+   blobs but in standard mode, blobs flagged as ephemeral are ignored.  */
 int 
 keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
 {
@@ -408,7 +513,7 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
   struct sn_array_s *sn_array = NULL;
 
   if (!hd)
-    return KEYBOX_Invalid_Value;
+    return gpg_error (GPG_ERR_INV_VALUE);
 
   /* clear last found result */
   if (hd->found.blob)
@@ -444,7 +549,7 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
         {
           sn_array = xtrycalloc (ndesc, sizeof *sn_array);
           if (!sn_array)
-            return (hd->error = KEYBOX_Out_Of_Core);
+            return (hd->error = gpg_error (gpg_err_code_from_errno (errno)));
         }
     }
 
@@ -453,8 +558,9 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
       hd->fp = fopen (hd->kb->fname, "rb");
       if (!hd->fp)
         {
+          hd->error = gpg_error (gpg_err_code_from_errno (errno));
           xfree (sn_array);
-          return (hd->error = KEYBOX_File_Open_Error);
+          return hd->error;
         }
     }
 
@@ -484,8 +590,9 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
               sn_array[n].sn = xtrymalloc (snlen);
               if (!sn_array[n].sn)
                 {
+                  hd->error = gpg_error (gpg_err_code_from_errno (errno));
                   release_sn_array (sn_array, n);
-                  return (hd->error = KEYBOX_Out_Of_Core);
+                  return hd->error;
                 }
               sn_array[n].snlen = snlen;
               sn = sn_array[n].sn;
@@ -507,8 +614,9 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
               sn_array[n].sn = xtrymalloc (snlen);
               if (!sn_array[n].sn)
                 {
+                  hd->error = gpg_error (gpg_err_code_from_errno (errno));
                   release_sn_array (sn_array, n);
-                  return (hd->error = KEYBOX_Out_Of_Core);
+                  return hd->error;
                 }
               sn_array[n].snlen = snlen;
               memcpy (sn_array[n].sn, sn, snlen);
@@ -519,11 +627,17 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
 
   for (;;)
     {
+      unsigned int blobflags;
+
       _keybox_release_blob (blob); blob = NULL;
       rc = _keybox_read_blob (&blob, hd->fp);
       if (rc)
         break;
 
+      blobflags = blob_get_blob_flags (blob);
+      if (!hd->ephemeral && (blobflags & 2))
+        continue; /* not in ephemeral mode but blob is flagged ephemeral */
+
       for (n=0; n < ndesc; n++) 
         {
           switch (desc[n].mode)
@@ -532,15 +646,21 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
               never_reached ();
               break;
             case KEYDB_SEARCH_MODE_EXACT: 
-              if (has_subject_or_alt (blob, desc[n].u.name))
+              if (has_subject_or_alt (blob, desc[n].u.name, 0))
                 goto found;
               break;
             case KEYDB_SEARCH_MODE_MAIL:
-              if (has_mail (blob, desc[n].u.name))
+              if (has_mail (blob, desc[n].u.name, 0))
                 goto found;
               break;
-            case KEYDB_SEARCH_MODE_SUBSTR:
             case KEYDB_SEARCH_MODE_MAILSUB:
+              if (has_mail (blob, desc[n].u.name, 1))
+                goto found;
+              break;
+            case KEYDB_SEARCH_MODE_SUBSTR:
+              if (has_subject_or_alt (blob, desc[n].u.name, 1))
+                goto found;
+              break;
             case KEYDB_SEARCH_MODE_MAILEND:
             case KEYDB_SEARCH_MODE_WORDS: 
               never_reached (); /* not yet implemented */
@@ -565,14 +685,15 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
                 goto found;
               break;
             case KEYDB_SEARCH_MODE_SHORT_KID: 
-/*                if (has_short_kid (blob, desc[n].u.kid[1])) */
-/*                  goto found; */
+              if (has_short_kid (blob, desc[n].u.kid))
+                goto found;
               break;
             case KEYDB_SEARCH_MODE_LONG_KID:
-/*                if (has_long_kid (blob, desc[n].u.kid)) */
-/*                  goto found; */
+              if (has_long_kid (blob, desc[n].u.kid))
+                goto found;
               break;
             case KEYDB_SEARCH_MODE_FPR:
+            case KEYDB_SEARCH_MODE_FPR20:
               if (has_fingerprint (blob, desc[n].u.fpr))
                 goto found;
               break;
@@ -583,7 +704,7 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
               goto found;
               break;
             default: 
-              rc = KEYBOX_Invalid_Value;
+              rc = gpg_error (GPG_ERR_INV_VALUE);
               goto found;
             }
        }
@@ -642,37 +763,37 @@ keybox_get_cert (KEYBOX_HANDLE hd, KsbaCert *r_cert)
   int rc;
 
   if (!hd)
-    return KEYBOX_Invalid_Value;
+    return gpg_error (GPG_ERR_INV_VALUE);
   if (!hd->found.blob)
-    return KEYBOX_Nothing_Found;
+    return gpg_error (GPG_ERR_NOTHING_FOUND);
 
   if (blob_get_type (hd->found.blob) != BLOBTYPE_X509)
-    return KEYBOX_Wrong_Blob_Type;
+    return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
 
   buffer = _keybox_get_blob_image (hd->found.blob, &length);
   if (length < 40)
-    return KEYBOX_Blob_Too_Short;
+    return gpg_error (GPG_ERR_TOO_SHORT);
   cert_off = get32 (buffer+8);
   cert_len = get32 (buffer+12);
   if (cert_off+cert_len > length)
-    return KEYBOX_Blob_Too_Short;
+    return gpg_error (GPG_ERR_TOO_SHORT);
 
   reader = ksba_reader_new ();
   if (!reader)
-    return KEYBOX_Out_Of_Core;
+    return gpg_error (GPG_ERR_ENOMEM);
   rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len);
   if (rc)
     {
       ksba_reader_release (reader);
       /* fixme: need to map the error codes */
-      return KEYBOX_General_Error;
+      return gpg_error (GPG_ERR_GENERAL);
     }
 
   cert = ksba_cert_new ();
   if (!cert)
     {
       ksba_reader_release (reader);
-      return KEYBOX_Out_Of_Core;
+      return gpg_error (GPG_ERR_ENOMEM);
     }
 
   rc = ksba_cert_read_der (cert, reader);
@@ -681,7 +802,7 @@ keybox_get_cert (KEYBOX_HANDLE hd, KsbaCert *r_cert)
       ksba_cert_release (cert);
       ksba_reader_release (reader);
       /* fixme: need to map the error codes */
-      return KEYBOX_General_Error;
+      return gpg_error (GPG_ERR_GENERAL);
     }
 
   *r_cert = cert;