Solved cvs conflict
[gnupg.git] / sm / keydb.c
index 50c9e54..fe65565 100644 (file)
@@ -1,5 +1,5 @@
 /* keydb.c - key database dispatcher
- * Copyright (C) 2001 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2003 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -50,6 +50,7 @@ struct resource_item {
   } u;
   void *token;
   int secret;
+  DOTLOCK lockhandle;
 };
 
 static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
@@ -59,7 +60,7 @@ struct keydb_handle {
   int locked;
   int found;
   int current;
-  int ephemeral;
+  int is_ephemeral;
   int used; /* items in active */
   struct resource_item active[MAX_KEYDB_RESOURCES];
 };
@@ -102,7 +103,7 @@ keydb_add_resource (const char *url, int force, int secret)
       else if (strchr (resname, ':'))
         {
           log_error ("invalid key resource URL `%s'\n", url );
-          rc = GNUPG_General_Error;
+          rc = gpg_error (GPG_ERR_GENERAL);
           goto leave;
        }
 #endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
@@ -149,14 +150,14 @@ keydb_add_resource (const char *url, int force, int secret)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
       log_error ("unknown type of key resource `%s'\n", url );
-      rc = GNUPG_General_Error;
+      rc = gpg_error (GPG_ERR_GENERAL);
       goto leave;
       
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       fp = fopen (filename, "rb");
       if (!fp && !force)
         {
-          rc = GNUPG_File_Open_Error;
+          rc = gpg_error (gpg_err_code_from_errno (errno));
           goto leave;
         }
       
@@ -174,7 +175,7 @@ keydb_add_resource (const char *url, int force, int secret)
                    terminated, so that on the next invocation can
                    read the options file in on startup */
                 try_make_homedir (filename);
-                rc = GNUPG_File_Open_Error;
+                rc = gpg_error (GPG_ERR_FILE_OPEN_ERROR);
                 *last_slash_in_filename = DIRSEP_C;
                 goto leave;
               }
@@ -184,9 +185,9 @@ keydb_add_resource (const char *url, int force, int secret)
           fp = fopen (filename, "w");
           if (!fp)
             {
+              rc = gpg_error (gpg_err_code_from_errno (errno));
               log_error (_("error creating keybox `%s': %s\n"),
                          filename, strerror(errno));
-              rc = GNUPG_File_Create_Error;
               goto leave;
            }
 
@@ -196,26 +197,33 @@ keydb_add_resource (const char *url, int force, int secret)
        }
        fclose (fp);
        fp = NULL;
-        /* now regsiter the file */
+        /* now register the file */
         {
+          
           void *token = keybox_register_file (filename, secret);
           if (!token)
             ; /* already registered - ignore it */
           else if (used_resources >= MAX_KEYDB_RESOURCES)
-            rc = GNUPG_Resource_Limit;
+            rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
           else 
             {
               all_resources[used_resources].type = rt;
               all_resources[used_resources].u.kr = NULL; /* Not used here */
               all_resources[used_resources].token = token;
               all_resources[used_resources].secret = secret;
+
+              all_resources[used_resources].lockhandle
+                = create_dotlock (filename);
+              if (!all_resources[used_resources].lockhandle)
+                log_fatal ( _("can't create lock for `%s'\n"), filename);
+                  
               used_resources++;
             }
         }
        break;
     default:
       log_error ("resource type of `%s' not supported\n", url);
-      rc = GNUPG_Not_Supported;
+      rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
       goto leave;
     }
 
@@ -223,7 +231,7 @@ keydb_add_resource (const char *url, int force, int secret)
 
  leave:
   if (rc)
-    log_error ("keyblock resource `%s': %s\n", filename, gnupg_strerror(rc));
+    log_error ("keyblock resource `%s': %s\n", filename, gpg_strerror(rc));
   else if (secret)
     any_secret = 1;
   else
@@ -255,11 +263,13 @@ keydb_new (int secret)
           hd->active[j].type   = all_resources[i].type;
           hd->active[j].token  = all_resources[i].token;
           hd->active[j].secret = all_resources[i].secret;
+          hd->active[j].lockhandle = all_resources[i].lockhandle;
           hd->active[j].u.kr = keybox_new (all_resources[i].token, secret);
-          if (!hd->active[j].u.kr) {
-            xfree (hd);
-            return NULL; /* fixme: release all previously allocated handles*/
-          }
+          if (!hd->active[j].u.kr) 
+            {
+              xfree (hd);
+              return NULL; /* fixme: release all previously allocated handles*/
+            }
           j++;
           break;
         }
@@ -332,27 +342,34 @@ keydb_get_resource_name (KEYDB_HANDLE hd)
   return s? s: "";
 }
 
+/* Switch the handle into ephemeral mode and return the orginal value. */
 int
 keydb_set_ephemeral (KEYDB_HANDLE hd, int yes)
 {
   int i;
 
   if (!hd)
-    return GNUPG_Invalid_Value;
+    return 0;
 
-  for (i=0; i < hd->used; i++)
+  yes = !!yes;
+  if (hd->is_ephemeral != yes)
     {
-      switch (hd->active[i].type) 
+      for (i=0; i < hd->used; i++)
         {
-        case KEYDB_RESOURCE_TYPE_NONE:
-          break;
-        case KEYDB_RESOURCE_TYPE_KEYBOX:
-          keybox_set_ephemeral (hd->active[i].u.kr, yes);
-          break;
+          switch (hd->active[i].type) 
+            {
+            case KEYDB_RESOURCE_TYPE_NONE:
+              break;
+            case KEYDB_RESOURCE_TYPE_KEYBOX:
+              keybox_set_ephemeral (hd->active[i].u.kr, yes);
+              break;
+            }
         }
     }
-
-  return 0;
+      
+  i = hd->is_ephemeral;
+  hd->is_ephemeral = yes;
+  return i;
 }
 
 
@@ -362,16 +379,22 @@ lock_all (KEYDB_HANDLE hd)
 {
   int i, rc = 0;
 
-  for (i=0; !rc && i < hd->used; i++) 
+  /* Fixme: This locking scheme may lead to deadlock if the resources
+     are not added in the same sequence by all processes.  We are
+     cuurently only allowing one resource so it is not a problem. */
+  for (i=0; i < hd->used; i++) 
     {
       switch (hd->active[i].type) 
         {
         case KEYDB_RESOURCE_TYPE_NONE:
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
-          /* FIXME  rc = keybox_lock (hd->active[i].u.kr, 1);*/
+          if (hd->active[i].lockhandle)
+            rc = make_dotlock (hd->active[i].lockhandle, -1);
           break;
         }
+      if (rc)
+        break;
     }
 
     if (rc) 
@@ -384,7 +407,8 @@ lock_all (KEYDB_HANDLE hd)
               case KEYDB_RESOURCE_TYPE_NONE:
                 break;
               case KEYDB_RESOURCE_TYPE_KEYBOX:
-                /* Fixme: keybox_lock (hd->active[i].u.kr, 0);*/
+                if (hd->active[i].lockhandle)
+                  release_dotlock (hd->active[i].lockhandle);
                 break;
               }
           }
@@ -410,7 +434,8 @@ unlock_all (KEYDB_HANDLE hd)
         case KEYDB_RESOURCE_TYPE_NONE:
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
-          /* fixme: keybox_lock (hd->active[i].u.kr, 0);*/
+          if (hd->active[i].lockhandle)
+            release_dotlock (hd->active[i].lockhandle);
           break;
         }
     }
@@ -537,7 +562,7 @@ keydb_get_cert (KEYDB_HANDLE hd, KsbaCert *r_cert)
   int rc = 0;
 
   if (!hd)
-    return GNUPG_Invalid_Value;
+    return gpg_error (GPG_ERR_INV_VALUE);
   
   if ( hd->found < 0 || hd->found >= hd->used) 
     return -1; /* nothing found */
@@ -545,7 +570,7 @@ keydb_get_cert (KEYDB_HANDLE hd, KsbaCert *r_cert)
   switch (hd->active[hd->found].type) 
     {
     case KEYDB_RESOURCE_TYPE_NONE:
-      rc = GNUPG_General_Error; /* oops */
+      rc = gpg_error (GPG_ERR_GENERAL); /* oops */
       break;
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       rc = keybox_get_cert (hd->active[hd->found].u.kr, r_cert);
@@ -566,7 +591,7 @@ keydb_insert_cert (KEYDB_HANDLE hd, KsbaCert cert)
   char digest[20];
   
   if (!hd) 
-    return GNUPG_Invalid_Value;
+    return gpg_error (GPG_ERR_INV_VALUE);
 
   if (opt.dry_run)
     return 0;
@@ -576,7 +601,7 @@ keydb_insert_cert (KEYDB_HANDLE hd, KsbaCert cert)
   else if ( hd->current >= 0 && hd->current < hd->used) 
     idx = hd->current;
   else
-    return GNUPG_General_Error;
+    return gpg_error (GPG_ERR_GENERAL);
 
   rc = lock_all (hd);
   if (rc)
@@ -587,7 +612,7 @@ keydb_insert_cert (KEYDB_HANDLE hd, KsbaCert cert)
   switch (hd->active[idx].type) 
     {
     case KEYDB_RESOURCE_TYPE_NONE:
-      rc = GNUPG_General_Error;
+      rc = gpg_error (GPG_ERR_GENERAL);
       break;
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       rc = keybox_insert_cert (hd->active[idx].u.kr, cert, digest);
@@ -608,7 +633,7 @@ keydb_update_cert (KEYDB_HANDLE hd, KsbaCert cert)
   char digest[20];
   
   if (!hd)
-    return GNUPG_Invalid_Value;
+    return gpg_error (GPG_ERR_INV_VALUE);
 
   if ( hd->found < 0 || hd->found >= hd->used) 
     return -1; /* nothing found */
@@ -625,7 +650,7 @@ keydb_update_cert (KEYDB_HANDLE hd, KsbaCert cert)
   switch (hd->active[hd->found].type) 
     {
     case KEYDB_RESOURCE_TYPE_NONE:
-      rc = GNUPG_General_Error; /* oops */
+      rc = gpg_error (GPG_ERR_GENERAL); /* oops */
       break;
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       rc = keybox_update_cert (hd->active[hd->found].u.kr, cert, digest);
@@ -646,7 +671,7 @@ keydb_delete (KEYDB_HANDLE hd)
   int rc = -1;
   
   if (!hd)
-    return GNUPG_Invalid_Value;
+    return gpg_error (GPG_ERR_INV_VALUE);
 
   if ( hd->found < 0 || hd->found >= hd->used) 
     return -1; /* nothing found */
@@ -661,7 +686,7 @@ keydb_delete (KEYDB_HANDLE hd)
   switch (hd->active[hd->found].type)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
-      rc = GNUPG_General_Error;
+      rc = gpg_error (GPG_ERR_GENERAL);
       break;
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       rc = keybox_delete (hd->active[hd->found].u.kr);
@@ -685,7 +710,7 @@ keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
   int rc;
   
   if (!hd)
-    return GNUPG_Invalid_Value;
+    return gpg_error (GPG_ERR_INV_VALUE);
   
   rc = keydb_search_reset (hd); /* this does reset hd->current */
   if (rc)
@@ -745,7 +770,7 @@ keydb_search_reset (KEYDB_HANDLE hd)
   int i, rc = 0;
   
   if (!hd)
-    return GNUPG_Invalid_Value;
+    return gpg_error (GPG_ERR_INV_VALUE);
 
   hd->current = 0; 
   hd->found = -1;
@@ -775,7 +800,7 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
   int rc = -1;
   
   if (!hd)
-    return GNUPG_Invalid_Value;
+    return gpg_error (GPG_ERR_INV_VALUE);
 
   while (rc == -1 && hd->current >= 0 && hd->current < hd->used) 
     {
@@ -866,12 +891,12 @@ keydb_search_issuer_sn (KEYDB_HANDLE hd,
   desc.mode = KEYDB_SEARCH_MODE_ISSUER_SN;
   s = serial;
   if (*s !='(')
-    return GNUPG_Invalid_Value;
+    return gpg_error (GPG_ERR_INV_VALUE);
   s++;
   for (desc.snlen = 0; digitp (s); s++)
     desc.snlen = 10*desc.snlen + atoi_1 (s);
   if (*s !=':')
-    return GNUPG_Invalid_Value;
+    return gpg_error (GPG_ERR_INV_VALUE);
   desc.sn = s+1;
   desc.u.name = issuer;
   rc = keydb_search (hd, &desc, 1);
@@ -1137,10 +1162,31 @@ classify_user_id (const char *name,
           mode = KEYDB_SEARCH_MODE_FPR20;
         }
       else if (!hexprefix)
-        { /* default is substring search */
-          *force_exact = 0;
-          desc->u.name = s;
-          mode = KEYDB_SEARCH_MODE_SUBSTR; 
+        { 
+          /* The fingerprint in an X.509 listing is often delimited by
+             colons, so we try to single this case out. */
+          mode = 0;
+          hexlength = strspn (s, ":0123456789abcdefABCDEF");
+          if (hexlength == 59 && (!s[hexlength] || spacep (s+hexlength))) 
+            {
+              int i;
+
+              for (i=0; i < 20; i++, s += 3) 
+                {
+                  int c = hextobyte(s);
+                  if (c == -1 || (i < 19 && s[2] != ':'))
+                    break;
+                  desc->u.fpr[i] = c;
+                }
+              if (i == 20)
+                mode = KEYDB_SEARCH_MODE_FPR20;
+            }
+          if (!mode) /* default is substring search */
+            { 
+              *force_exact = 0;
+              desc->u.name = s;
+              mode = KEYDB_SEARCH_MODE_SUBSTR; 
+            }
         }
       else
        { /* hex number with a prefix but a wrong length */
@@ -1163,31 +1209,36 @@ keydb_classify_name (const char *name, KEYDB_SEARCH_DESC *desc)
     desc = &dummy_desc;
 
   if (!classify_user_id (name, desc, &dummy))
-    return GNUPG_Invalid_Name;
+    return gpg_error (GPG_ERR_INV_NAME);
   return 0;
 }
 
 \f
-/* Store the certificate in the key Db but make sure that it does not
-   already exists.  We do this simply by comparing the fingerprint */
+/* Store the certificate in the key DB but make sure that it does not
+   already exists.  We do this simply by comparing the fingerprint.
+   If EXISTED is not NULL it will be set to true if the certificate
+   was already in the DB. */
 int
-keydb_store_cert (KsbaCert cert, int ephemeral)
+keydb_store_cert (KsbaCert cert, int ephemeral, int *existed)
 {
   KEYDB_HANDLE kh;
   int rc;
   unsigned char fpr[20];
 
+  if (existed)
+    *existed = 0;
+
   if (!gpgsm_get_fingerprint (cert, 0, fpr, NULL))
     {
       log_error (_("failed to get the fingerprint\n"));
-      return GNUPG_General_Error;
+      return gpg_error (GPG_ERR_GENERAL);
     }
 
   kh = keydb_new (0);
   if (!kh)
     {
       log_error (_("failed to allocate keyDB handle\n"));
-      return GNUPG_Out_Of_Core;
+      return gpg_error (GPG_ERR_ENOMEM);;
     }
 
   if (ephemeral)
@@ -1198,16 +1249,20 @@ keydb_store_cert (KsbaCert cert, int ephemeral)
     {
       keydb_release (kh);
       if (!rc)
-        return 0; /* okay */
+        {
+          if (existed)
+            *existed = 1;
+          return 0; /* okay */
+        }
       log_error (_("problem looking for existing certificate: %s\n"),
-                 gnupg_strerror (rc));
+                 gpg_strerror (rc));
       return rc;
     }
 
   rc = keydb_locate_writable (kh, 0);
   if (rc)
     {
-      log_error (_("error finding writable keyDB: %s\n"), gnupg_strerror (rc));
+      log_error (_("error finding writable keyDB: %s\n"), gpg_strerror (rc));
       keydb_release (kh);
       return rc;
     }
@@ -1215,7 +1270,7 @@ keydb_store_cert (KsbaCert cert, int ephemeral)
   rc = keydb_insert_cert (kh, cert);
   if (rc)
     {
-      log_error (_("error storing certificate: %s\n"), gnupg_strerror (rc));
+      log_error (_("error storing certificate: %s\n"), gpg_strerror (rc));
       keydb_release (kh);
       return rc;
     }
@@ -1224,3 +1279,4 @@ keydb_store_cert (KsbaCert cert, int ephemeral)
 }
 
 
+