gpg: Remove option --no-sig-create-check.
[gnupg.git] / sm / keydb.c
index da2ec4a..b3363c4 100644 (file)
@@ -1,11 +1,12 @@
 /* keydb.c - key database dispatcher
  * Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2014 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -14,9 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -31,7 +30,7 @@
 
 #include "gpgsm.h"
 #include "../kbx/keybox.h"
-#include "keydb.h" 
+#include "keydb.h"
 #include "i18n.h"
 
 static int active_handles;
@@ -49,7 +48,7 @@ struct resource_item {
   } u;
   void *token;
   int secret;
-  DOTLOCK lockhandle;
+  dotlock_t lockhandle;
 };
 
 static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
@@ -58,6 +57,7 @@ static int used_resources;
 struct keydb_handle {
   int locked;
   int found;
+  int saved_found;
   int current;
   int is_ephemeral;
   int used; /* items in active */
@@ -69,11 +69,173 @@ static int lock_all (KEYDB_HANDLE hd);
 static void unlock_all (KEYDB_HANDLE hd);
 
 
+static void
+try_make_homedir (const char *fname)
+{
+  const char *defhome = standard_homedir ();
+
+  /* Create the directory only if the supplied directory name is the
+     same as the default one.  This way we avoid to create arbitrary
+     directories when a non-default home directory is used.  To cope
+     with HOME, we do compare only the suffix if we see that the
+     default homedir does start with a tilde.  */
+  if ( opt.dry_run || opt.no_homedir_creation )
+    return;
+
+  if (
+#ifdef HAVE_W32_SYSTEM
+      ( !compare_filenames (fname, defhome) )
+#else
+      ( *defhome == '~'
+        && (strlen(fname) >= strlen (defhome+1)
+            && !strcmp(fname+strlen(fname)-strlen(defhome+1), defhome+1 ) ))
+      || (*defhome != '~'  && !compare_filenames( fname, defhome ) )
+#endif
+      )
+    {
+      if (gnupg_mkdir (fname, "-rwx"))
+        log_info (_("can't create directory '%s': %s\n"),
+                  fname, strerror(errno) );
+      else if (!opt.quiet )
+        log_info (_("directory '%s' created\n"), fname);
+    }
+}
+
+
+/* Handle the creation of a keybox if it does not yet exist.  Take
+   into acount that other processes might have the keybox already
+   locked.  This lock check does not work if the directory itself is
+   not yet available.  If R_CREATED is not NULL it will be set to true
+   if the function created a new keybox.  */
+static int
+maybe_create_keybox (char *filename, int force, int *r_created)
+{
+  dotlock_t lockhd = NULL;
+  FILE *fp;
+  int rc;
+  mode_t oldmask;
+  char *last_slash_in_filename;
+  int save_slash;
+
+  if (r_created)
+    *r_created = 0;
+
+  /* A quick test whether the filename already exists. */
+  if (!access (filename, F_OK))
+    return 0;
+
+  /* If we don't want to create a new file at all, there is no need to
+     go any further - bail out right here.  */
+  if (!force)
+    return gpg_error (GPG_ERR_ENOENT);
+
+  /* First of all we try to create the home directory.  Note, that we
+     don't do any locking here because any sane application of gpg
+     would create the home directory by itself and not rely on gpg's
+     tricky auto-creation which is anyway only done for some home
+     directory name patterns. */
+  last_slash_in_filename = strrchr (filename, DIRSEP_C);
+#if HAVE_W32_SYSTEM
+  {
+    /* Windows may either have a slash or a backslash.  Take care of it.  */
+    char *p = strrchr (filename, '/');
+    if (!last_slash_in_filename || p > last_slash_in_filename)
+      last_slash_in_filename = p;
+  }
+#endif /*HAVE_W32_SYSTEM*/
+  if (!last_slash_in_filename)
+    return gpg_error (GPG_ERR_ENOENT);  /* No slash at all - should
+                                           not happen though.  */
+  save_slash = *last_slash_in_filename;
+  *last_slash_in_filename = 0;
+  if (access(filename, F_OK))
+    {
+      static int tried;
+
+      if (!tried)
+        {
+          tried = 1;
+          try_make_homedir (filename);
+        }
+      if (access (filename, F_OK))
+        {
+          rc = gpg_error_from_syserror ();
+          *last_slash_in_filename = save_slash;
+          goto leave;
+        }
+    }
+  *last_slash_in_filename = save_slash;
+
+  /* To avoid races with other instances of gpg trying to create or
+     update the keybox (it is removed during an update for a short
+     time), we do the next stuff in a locked state. */
+  lockhd = dotlock_create (filename, 0);
+  if (!lockhd)
+    {
+      /* A reason for this to fail is that the directory is not
+         writable. However, this whole locking stuff does not make
+         sense if this is the case. An empty non-writable directory
+         with no keyring is not really useful at all. */
+      if (opt.verbose)
+        log_info ("can't allocate lock for '%s'\n", filename );
+
+      if (!force)
+        return gpg_error (GPG_ERR_ENOENT);
+      else
+        return gpg_error (GPG_ERR_GENERAL);
+    }
+
+  if ( dotlock_take (lockhd, -1) )
+    {
+      /* This is something bad.  Probably a stale lockfile.  */
+      log_info ("can't lock '%s'\n", filename);
+      rc = gpg_error (GPG_ERR_GENERAL);
+      goto leave;
+    }
+
+  /* Now the real test while we are locked. */
+  if (!access(filename, F_OK))
+    {
+      rc = 0;  /* Okay, we may access the file now.  */
+      goto leave;
+    }
+
+  /* The file does not yet exist, create it now. */
+  oldmask = umask (077);
+  fp = fopen (filename, "w");
+  if (!fp)
+    {
+      rc = gpg_error_from_syserror ();
+      umask (oldmask);
+      log_error (_("error creating keybox '%s': %s\n"),
+                 filename, gpg_strerror (rc));
+      goto leave;
+    }
+  umask (oldmask);
+
+  if (!opt.quiet)
+    log_info (_("keybox '%s' created\n"), filename);
+  if (r_created)
+    *r_created = 1;
+
+  fclose (fp);
+  rc = 0;
+
+ leave:
+  if (lockhd)
+    {
+      dotlock_release (lockhd);
+      dotlock_destroy (lockhd);
+    }
+  return rc;
+}
+
+
 /*
  * Register a resource (which currently may only be a keybox file).
  * The first keybox which is added by this function is created if it
  * does not exist.  If AUTO_CREATED is not NULL it will be set to true
- * if the function has created a a new keybox. 
+ * if the function has created a new keybox.
  */
 int
 keydb_add_resource (const char *url, int force, int secret, int *auto_created)
@@ -81,10 +243,8 @@ keydb_add_resource (const char *url, int force, int secret, int *auto_created)
   static int any_secret, any_public;
   const char *resname = url;
   char *filename = NULL;
-  int rc = 0; 
-  FILE *fp;
+  int rc = 0;
   KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
-  const char *created_fname = NULL;
 
   if (auto_created)
     *auto_created = 0;
@@ -93,7 +253,7 @@ keydb_add_resource (const char *url, int force, int secret, int *auto_created)
      gnupg-kbx:filename := this is a plain keybox
      filename := See what is is, but create as plain keybox.
   */
-  if (strlen (resname) > 10) 
+  if (strlen (resname) > 10)
     {
       if (!strncmp (resname, "gnupg-kbx:", 10) )
         {
@@ -103,7 +263,7 @@ keydb_add_resource (const char *url, int force, int secret, int *auto_created)
 #if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
       else if (strchr (resname, ':'))
         {
-          log_error ("invalid key resource URL `%s'\n", url );
+          log_error ("invalid key resource URL '%s'\n", url );
           rc = gpg_error (GPG_ERR_GENERAL);
           goto leave;
        }
@@ -119,130 +279,85 @@ keydb_add_resource (const char *url, int force, int secret, int *auto_created)
     }
   else
     filename = xstrdup (resname);
-  
+
   if (!force)
     force = secret? !any_secret : !any_public;
-  
+
   /* see whether we can determine the filetype */
   if (rt == KEYDB_RESOURCE_TYPE_NONE)
     {
-      FILE *fp2 = fopen( filename, "rb" );
-      
-      if (fp2) {
-        u32 magic;
-        
-        /* FIXME: check for the keybox magic */
-        if (fread( &magic, 4, 1, fp2) == 1 ) 
-          {
-            if (magic == 0x13579ace || magic == 0xce9a5713)
-              ; /* GDBM magic - no more support */
-            else
-              rt = KEYDB_RESOURCE_TYPE_KEYBOX;
-          }
-        else /* maybe empty: assume ring */
-          rt = KEYDB_RESOURCE_TYPE_KEYBOX;
-        fclose (fp2);
-      }
-      else /* no file yet: create ring */
+      FILE *fp = fopen( filename, "rb" );
+
+      if (fp)
+        {
+          u32 magic;
+
+          /* FIXME: check for the keybox magic */
+          if (fread (&magic, 4, 1, fp) == 1 )
+            {
+              if (magic == 0x13579ace || magic == 0xce9a5713)
+                ; /* GDBM magic - no more support */
+              else
+                rt = KEYDB_RESOURCE_TYPE_KEYBOX;
+            }
+          else /* maybe empty: assume keybox */
+            rt = KEYDB_RESOURCE_TYPE_KEYBOX;
+          fclose (fp);
+        }
+      else /* no file yet: create keybox */
         rt = KEYDB_RESOURCE_TYPE_KEYBOX;
     }
-    
+
   switch (rt)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
-      log_error ("unknown type of key resource `%s'\n", url );
+      log_error ("unknown type of key resource '%s'\n", url );
       rc = gpg_error (GPG_ERR_GENERAL);
       goto leave;
-      
+
     case KEYDB_RESOURCE_TYPE_KEYBOX:
-      fp = fopen (filename, "rb");
-      if (!fp && !force)
-        {
-          rc = gpg_error (gpg_err_code_from_errno (errno));
-          goto leave;
-        }
-      
-      if (!fp)
-        { /* no file */
-#if 0 /* no autocreate of the homedirectory yet */
+      rc = maybe_create_keybox (filename, force, auto_created);
+      if (rc)
+        goto leave;
+      /* 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 = gpg_error (GPG_ERR_RESOURCE_LIMIT);
+        else
           {
-            char *last_slash_in_filename;
-            
-            last_slash_in_filename = strrchr (filename, DIRSEP_C);
-            *last_slash_in_filename = 0;
-            if (access (filename, F_OK))
-              { /* on the first time we try to create the default
-                   homedir and in this case the process will be
-                   terminated, so that on the next invocation can
-                   read the options file in on startup */
-                try_make_homedir (filename);
-                rc = gpg_error (GPG_ERR_FILE_OPEN_ERROR);
-                *last_slash_in_filename = DIRSEP_C;
-                goto leave;
+            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
+              = dotlock_create (filename, 0);
+            if (!all_resources[used_resources].lockhandle)
+              log_fatal ( _("can't create lock for '%s'\n"), filename);
+
+            /* Do a compress run if needed and the file is not locked. */
+            if (!dotlock_take (all_resources[used_resources].lockhandle, 0))
+              {
+                KEYBOX_HANDLE kbxhd = keybox_new_x509 (token, secret);
+
+                if (kbxhd)
+                  {
+                    keybox_compress (kbxhd);
+                    keybox_release (kbxhd);
+                  }
+                dotlock_release (all_resources[used_resources].lockhandle);
               }
-            *last_slash_in_filename = DIRSEP_C;
-          }
-#endif
-          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));
-              if (errno == ENOENT)
-                log_info (_("you may want to start the gpg-agent first\n"));
-              goto leave;
-           }
-
-          if (!opt.quiet)
-            log_info (_("keybox `%s' created\n"), filename);
-          created_fname = filename;
-          if (auto_created)
-            *auto_created = 1;
-       }
-       fclose (fp);
-       fp = NULL;
-        /* 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 = 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);
-
-              /* Do a compress run if needed and the file is not locked. */
-              if (!make_dotlock (all_resources[used_resources].lockhandle, 0))
-                {
-                  KEYBOX_HANDLE kbxhd = keybox_new (token, secret);
-                  
-                  if (kbxhd)
-                    {
-                      keybox_compress (kbxhd);
-                      keybox_release (kbxhd);
-                    }
-                  release_dotlock (all_resources[used_resources].lockhandle);
-                }
-                  
-              used_resources++;
-            }
-        }
 
+            used_resources++;
+          }
+      }
+      break;
 
-       break;
     default:
-      log_error ("resource type of `%s' not supported\n", url);
+      log_error ("resource type of '%s' not supported\n", url);
       rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
       goto leave;
     }
@@ -251,7 +366,7 @@ keydb_add_resource (const char *url, int force, int secret, int *auto_created)
 
  leave:
   if (rc)
-    log_error ("keyblock resource `%s': %s\n", filename, gpg_strerror(rc));
+    log_error ("keyblock resource '%s': %s\n", filename, gpg_strerror(rc));
   else if (secret)
     any_secret = 1;
   else
@@ -266,10 +381,11 @@ keydb_new (int secret)
 {
   KEYDB_HANDLE hd;
   int i, j;
-  
+
   hd = xcalloc (1, sizeof *hd);
   hd->found = -1;
-  
+  hd->saved_found = -1;
+
   assert (used_resources <= MAX_KEYDB_RESOURCES);
   for (i=j=0; i < used_resources; i++)
     {
@@ -284,8 +400,8 @@ keydb_new (int secret)
           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) 
+          hd->active[j].u.kr = keybox_new_x509 (all_resources[i].token, secret);
+          if (!hd->active[j].u.kr)
             {
               xfree (hd);
               return NULL; /* fixme: release all previously allocated handles*/
@@ -295,16 +411,16 @@ keydb_new (int secret)
         }
     }
   hd->used = j;
-  
+
   active_handles++;
   return hd;
 }
 
-void 
+void
 keydb_release (KEYDB_HANDLE hd)
 {
   int i;
-  
+
   if (!hd)
     return;
   assert (active_handles > 0);
@@ -313,7 +429,7 @@ keydb_release (KEYDB_HANDLE hd)
   unlock_all (hd);
   for (i=0; i < hd->used; i++)
     {
-      switch (hd->active[i].type) 
+      switch (hd->active[i].type)
         {
         case KEYDB_RESOURCE_TYPE_NONE:
           break;
@@ -338,27 +454,27 @@ keydb_get_resource_name (KEYDB_HANDLE hd)
 {
   int idx;
   const char *s = NULL;
-  
-  if (!hd) 
+
+  if (!hd)
     return NULL;
 
-  if ( hd->found >= 0 && hd->found < hd->used) 
+  if ( hd->found >= 0 && hd->found < hd->used)
     idx = hd->found;
-  else if ( hd->current >= 0 && hd->current < hd->used) 
+  else if ( hd->current >= 0 && hd->current < hd->used)
     idx = hd->current;
   else
     idx = 0;
 
-  switch (hd->active[idx].type) 
+  switch (hd->active[idx].type)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
-      s = NULL; 
+      s = NULL;
       break;
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       s = keybox_get_resource_name (hd->active[idx].u.kr);
       break;
     }
-  
+
   return s? s: "";
 }
 
@@ -376,7 +492,7 @@ keydb_set_ephemeral (KEYDB_HANDLE hd, int yes)
     {
       for (i=0; i < hd->used; i++)
         {
-          switch (hd->active[i].type) 
+          switch (hd->active[i].type)
             {
             case KEYDB_RESOURCE_TYPE_NONE:
               break;
@@ -386,7 +502,7 @@ keydb_set_ephemeral (KEYDB_HANDLE hd, int yes)
             }
         }
     }
-      
+
   i = hd->is_ephemeral;
   hd->is_ephemeral = yes;
   return i;
@@ -394,7 +510,7 @@ keydb_set_ephemeral (KEYDB_HANDLE hd, int yes)
 
 
 /* If the keyring has not yet been locked, lock it now.  This
-   operation is required before any update opeations; it is optionaly
+   operation is required before any update operation; it is optional
    for an insert operation.  The lock is released with
    keydb_released. */
 gpg_error_t
@@ -409,7 +525,7 @@ keydb_lock (KEYDB_HANDLE hd)
 
 
 \f
-static int 
+static int
 lock_all (KEYDB_HANDLE hd)
 {
   int i, rc = 0;
@@ -417,33 +533,33 @@ lock_all (KEYDB_HANDLE hd)
   /* Fixme: This locking scheme may lead to deadlock if the resources
      are not added in the same order by all processes.  We are
      currently only allowing one resource so it is not a problem. */
-  for (i=0; i < hd->used; i++) 
+  for (i=0; i < hd->used; i++)
     {
-      switch (hd->active[i].type) 
+      switch (hd->active[i].type)
         {
         case KEYDB_RESOURCE_TYPE_NONE:
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
           if (hd->active[i].lockhandle)
-            rc = make_dotlock (hd->active[i].lockhandle, -1);
+            rc = dotlock_take (hd->active[i].lockhandle, -1);
           break;
         }
       if (rc)
         break;
     }
 
-    if (rc) 
+    if (rc)
       {
         /* revert the already set locks */
-        for (i--; i >= 0; i--) 
+        for (i--; i >= 0; i--)
           {
-            switch (hd->active[i].type) 
+            switch (hd->active[i].type)
               {
               case KEYDB_RESOURCE_TYPE_NONE:
                 break;
               case KEYDB_RESOURCE_TYPE_KEYBOX:
                 if (hd->active[i].lockhandle)
-                  release_dotlock (hd->active[i].lockhandle);
+                  dotlock_release (hd->active[i].lockhandle);
                 break;
               }
           }
@@ -461,131 +577,76 @@ static void
 unlock_all (KEYDB_HANDLE hd)
 {
   int i;
-  
+
   if (!hd->locked)
     return;
 
-  for (i=hd->used-1; i >= 0; i--) 
+  for (i=hd->used-1; i >= 0; i--)
     {
-      switch (hd->active[i].type) 
+      switch (hd->active[i].type)
         {
         case KEYDB_RESOURCE_TYPE_NONE:
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
           if (hd->active[i].lockhandle)
-            release_dotlock (hd->active[i].lockhandle);
+            dotlock_release (hd->active[i].lockhandle);
           break;
         }
     }
   hd->locked = 0;
 }
 
+
 \f
-#if 0
-/*
- * Return the last found keybox.  Caller must free it.
- * The returned keyblock has the kbode flag bit 0 set for the node with
- * the public key used to locate the keyblock or flag bit 1 set for 
- * the user ID node.
- */
-int
-keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
+/* Push the last found state if any.  */
+void
+keydb_push_found_state (KEYDB_HANDLE hd)
 {
-    int rc = 0;
-
-    if (!hd)
-        return G10ERR_INV_ARG;
-
-    if ( hd->found < 0 || hd->found >= hd->used) 
-        return -1; /* nothing found */
+  if (!hd)
+    return;
 
-    switch (hd->active[hd->found].type) {
-      case KEYDB_RESOURCE_TYPE_NONE:
-        rc = G10ERR_GENERAL; /* oops */
-        break;
-      case KEYDB_RESOURCE_TYPE_KEYBOX:
-        rc = keybox_get_keyblock (hd->active[hd->found].u.kr, ret_kb);
-        break;
+  if (hd->found < 0 || hd->found >= hd->used)
+    {
+      hd->saved_found = -1;
+      return;
     }
 
-    return rc;
-}
-
-/* 
- * update the current keyblock with KB
- */
-int
-keydb_update_keyblock (KEYDB_HANDLE hd, KBNODE kb)
-{
-    int rc = 0;
-
-    if (!hd)
-        return G10ERR_INV_ARG;
-
-    if ( hd->found < 0 || hd->found >= hd->used) 
-        return -1; /* nothing found */
-
-    if( opt.dry_run )
-       return 0;
-
-    if (!hd->locked)
-      return gpg_error (GPG_ERR_NOT_LOCKED);
-
-    switch (hd->active[hd->found].type) {
-      case KEYDB_RESOURCE_TYPE_NONE:
-        rc = G10ERR_GENERAL; /* oops */
-        break;
-      case KEYDB_RESOURCE_TYPE_KEYBOX:
-        rc = keybox_update_keyblock (hd->active[hd->found].u.kr, kb);
-        break;
+  switch (hd->active[hd->found].type)
+    {
+    case KEYDB_RESOURCE_TYPE_NONE:
+      break;
+    case KEYDB_RESOURCE_TYPE_KEYBOX:
+      keybox_push_found_state (hd->active[hd->found].u.kr);
+      break;
     }
 
-    unlock_all (hd);
-    return rc;
+  hd->saved_found = hd->found;
+  hd->found = -1;
 }
 
 
-/* 
- * Insert a new KB into one of the resources. 
- */
-int
-keydb_insert_keyblock (KEYDB_HANDLE hd, KBNODE kb)
+/* Pop the last found state.  */
+void
+keydb_pop_found_state (KEYDB_HANDLE hd)
 {
-    int rc = -1;
-    int idx;
-
-    if (!hd) 
-        return G10ERR_INV_ARG;
-
-    if( opt.dry_run )
-       return 0;
-
-    if ( hd->found >= 0 && hd->found < hd->used) 
-        idx = hd->found;
-    else if ( hd->current >= 0 && hd->current < hd->used) 
-        idx = hd->current;
-    else
-        return G10ERR_GENERAL;
+  if (!hd)
+    return;
 
-    rc = lock_all (hd);
-    if (rc)
-        return rc;
+  hd->found = hd->saved_found;
+  hd->saved_found = -1;
+  if (hd->found < 0 || hd->found >= hd->used)
+    return;
 
-    switch (hd->active[idx].type) {
-      case KEYDB_RESOURCE_TYPE_NONE:
-        rc = G10ERR_GENERAL; /* oops */
-        break;
-      case KEYDB_RESOURCE_TYPE_KEYBOX:
-        rc = keybox_insert_keyblock (hd->active[idx].u.kr, kb);
-        break;
+  switch (hd->active[hd->found].type)
+    {
+    case KEYDB_RESOURCE_TYPE_NONE:
+      break;
+    case KEYDB_RESOURCE_TYPE_KEYBOX:
+      keybox_pop_found_state (hd->active[hd->found].u.kr);
+      break;
     }
-
-    unlock_all (hd);
-    return rc;
 }
 
-#endif /*disabled code*/
-
 
 \f
 /*
@@ -600,11 +661,11 @@ keydb_get_cert (KEYDB_HANDLE hd, ksba_cert_t *r_cert)
 
   if (!hd)
     return gpg_error (GPG_ERR_INV_VALUE);
-  
-  if ( hd->found < 0 || hd->found >= hd->used) 
+
+  if ( hd->found < 0 || hd->found >= hd->used)
     return -1; /* nothing found */
-  
-  switch (hd->active[hd->found].type) 
+
+  switch (hd->active[hd->found].type)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
       rc = gpg_error (GPG_ERR_GENERAL); /* oops */
@@ -613,7 +674,7 @@ keydb_get_cert (KEYDB_HANDLE hd, ksba_cert_t *r_cert)
       rc = keybox_get_cert (hd->active[hd->found].u.kr, r_cert);
       break;
     }
-  
+
   return rc;
 }
 
@@ -628,11 +689,11 @@ keydb_get_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int *value)
 
   if (!hd)
     return gpg_error (GPG_ERR_INV_VALUE);
-  
-  if ( hd->found < 0 || hd->found >= hd->used) 
+
+  if ( hd->found < 0 || hd->found >= hd->used)
     return gpg_error (GPG_ERR_NOTHING_FOUND);
-  
-  switch (hd->active[hd->found].type) 
+
+  switch (hd->active[hd->found].type)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
       err = gpg_error (GPG_ERR_GENERAL); /* oops */
@@ -641,7 +702,7 @@ keydb_get_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int *value)
       err = keybox_get_flags (hd->active[hd->found].u.kr, which, idx, value);
       break;
     }
-  
+
   return err;
 }
 
@@ -658,14 +719,14 @@ keydb_set_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int value)
 
   if (!hd)
     return gpg_error (GPG_ERR_INV_VALUE);
-  
-  if ( hd->found < 0 || hd->found >= hd->used) 
+
+  if ( hd->found < 0 || hd->found >= hd->used)
     return gpg_error (GPG_ERR_NOTHING_FOUND);
-  
+
   if (!hd->locked)
     return gpg_error (GPG_ERR_NOT_LOCKED);
 
-  switch (hd->active[hd->found].type) 
+  switch (hd->active[hd->found].type)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
       err = gpg_error (GPG_ERR_GENERAL); /* oops */
@@ -674,12 +735,12 @@ keydb_set_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int value)
       err = keybox_set_flags (hd->active[hd->found].u.kr, which, idx, value);
       break;
     }
-  
+
   return err;
 }
 
-/* 
- * Insert a new Certificate into one of the resources. 
+/*
+ * Insert a new Certificate into one of the resources.
  */
 int
 keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert)
@@ -687,16 +748,16 @@ keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert)
   int rc = -1;
   int idx;
   unsigned char digest[20];
-  
-  if (!hd) 
+
+  if (!hd)
     return gpg_error (GPG_ERR_INV_VALUE);
 
   if (opt.dry_run)
     return 0;
-  
-  if ( hd->found >= 0 && hd->found < hd->used) 
+
+  if ( hd->found >= 0 && hd->found < hd->used)
     idx = hd->found;
-  else if ( hd->current >= 0 && hd->current < hd->used) 
+  else if ( hd->current >= 0 && hd->current < hd->used)
     idx = hd->current;
   else
     return gpg_error (GPG_ERR_GENERAL);
@@ -706,7 +767,7 @@ keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert)
 
   gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL); /* kludge*/
 
-  switch (hd->active[idx].type) 
+  switch (hd->active[idx].type)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
       rc = gpg_error (GPG_ERR_GENERAL);
@@ -715,24 +776,24 @@ keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert)
       rc = keybox_insert_cert (hd->active[idx].u.kr, cert, digest);
       break;
     }
-  
+
   unlock_all (hd);
   return rc;
 }
 
 
 
-/* update the current keyblock with KB */
+/* Update the current keyblock with KB.  */
 int
 keydb_update_cert (KEYDB_HANDLE hd, ksba_cert_t cert)
 {
   int rc = 0;
   unsigned char digest[20];
-  
+
   if (!hd)
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  if ( hd->found < 0 || hd->found >= hd->used) 
+  if ( hd->found < 0 || hd->found >= hd->used)
     return -1; /* nothing found */
 
   if (opt.dry_run)
@@ -744,7 +805,7 @@ keydb_update_cert (KEYDB_HANDLE hd, ksba_cert_t cert)
 
   gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL); /* kludge*/
 
-  switch (hd->active[hd->found].type) 
+  switch (hd->active[hd->found].type)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
       rc = gpg_error (GPG_ERR_GENERAL); /* oops */
@@ -759,25 +820,25 @@ keydb_update_cert (KEYDB_HANDLE hd, ksba_cert_t cert)
 }
 
 
-/* 
+/*
  * The current keyblock or cert will be deleted.
  */
 int
 keydb_delete (KEYDB_HANDLE hd, int unlock)
 {
   int rc = -1;
-  
+
   if (!hd)
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  if ( hd->found < 0 || hd->found >= hd->used) 
+  if ( hd->found < 0 || hd->found >= hd->used)
     return -1; /* nothing found */
 
   if( opt.dry_run )
     return 0;
 
   if (!hd->locked)
-    return gpg_error (GPG_ERR_NOT_LOCKED); 
+    return gpg_error (GPG_ERR_NOT_LOCKED);
 
   switch (hd->active[hd->found].type)
     {
@@ -799,23 +860,25 @@ keydb_delete (KEYDB_HANDLE hd, int unlock)
 /*
  * Locate the default writable key resource, so that the next
  * operation (which is only relevant for inserts) will be done on this
- * resource.  
+ * resource.
  */
 int
 keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
 {
   int rc;
-  
+
+  (void)reserved;
+
   if (!hd)
     return gpg_error (GPG_ERR_INV_VALUE);
-  
+
   rc = keydb_search_reset (hd); /* this does reset hd->current */
   if (rc)
     return rc;
-  
-  for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++) 
+
+  for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
     {
-      switch (hd->active[hd->current].type) 
+      switch (hd->active[hd->current].type)
         {
         case KEYDB_RESOURCE_TYPE_NONE:
           BUG();
@@ -826,7 +889,7 @@ keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
           break;
         }
     }
-  
+
   return -1;
 }
 
@@ -837,7 +900,7 @@ void
 keydb_rebuild_caches (void)
 {
   int i;
-  
+
   for (i=0; i < used_resources; i++)
     {
       if (all_resources[i].secret)
@@ -858,23 +921,23 @@ keydb_rebuild_caches (void)
 
 
 
-/* 
+/*
  * Start the next search on this handle right at the beginning
  */
-int 
+int
 keydb_search_reset (KEYDB_HANDLE hd)
 {
   int i, rc = 0;
-  
+
   if (!hd)
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  hd->current = 0; 
+  hd->current = 0;
   hd->found = -1;
   /* and reset all resources */
-  for (i=0; !rc && i < hd->used; i++) 
+  for (i=0; !rc && i < hd->used; i++)
     {
-      switch (hd->active[i].type) 
+      switch (hd->active[i].type)
         {
         case KEYDB_RESOURCE_TYPE_NONE:
           break;
@@ -887,36 +950,39 @@ keydb_search_reset (KEYDB_HANDLE hd)
                 all modules*/
 }
 
-/* 
+/*
  * Search through all keydb resources, starting at the current position,
  * for a keyblock which contains one of the keys described in the DESC array.
  */
-int 
+int
 keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
 {
   int rc = -1;
-  
+  unsigned long skipped;
+
   if (!hd)
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  while (rc == -1 && hd->current >= 0 && hd->current < hd->used) 
+  while (rc == -1 && hd->current >= 0 && hd->current < hd->used)
     {
-      switch (hd->active[hd->current].type) 
+      switch (hd->active[hd->current].type)
         {
         case KEYDB_RESOURCE_TYPE_NONE:
           BUG(); /* we should never see it here */
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
-          rc = keybox_search (hd->active[hd->current].u.kr, desc, ndesc);
+          rc = keybox_search (hd->active[hd->current].u.kr, desc, ndesc,
+                              KEYBOX_BLOBTYPE_X509,
+                              NULL, &skipped);
           break;
         }
       if (rc == -1) /* EOF -> switch to next resource */
-        hd->current++; 
+        hd->current++;
       else if (!rc)
         hd->found = hd->current;
     }
-  
-  return rc; 
+
+  return rc;
 }
 
 
@@ -924,7 +990,7 @@ int
 keydb_search_first (KEYDB_HANDLE hd)
 {
   KEYDB_SEARCH_DESC desc;
-  
+
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_FIRST;
   return keydb_search (hd, &desc, 1);
@@ -934,7 +1000,7 @@ int
 keydb_search_next (KEYDB_HANDLE hd)
 {
   KEYDB_SEARCH_DESC desc;
-  
+
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_NEXT;
   return keydb_search (hd, &desc, 1);
@@ -944,11 +1010,13 @@ int
 keydb_search_kid (KEYDB_HANDLE hd, u32 *kid)
 {
   KEYDB_SEARCH_DESC desc;
-  
+
+  (void)kid;
+
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
-/*    desc.u.kid[0] = kid[0]; */
-/*    desc.u.kid[1] = kid[1]; */
+  desc.u.kid[0] = kid[0];
+  desc.u.kid[1] = kid[1];
   return keydb_search (hd, &desc, 1);
 }
 
@@ -956,7 +1024,7 @@ int
 keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr)
 {
   KEYDB_SEARCH_DESC desc;
-  
+
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_FPR;
   memcpy (desc.u.fpr, fpr, 20);
@@ -968,7 +1036,7 @@ keydb_search_issuer (KEYDB_HANDLE hd, const char *issuer)
 {
   KEYDB_SEARCH_DESC desc;
   int rc;
-  
+
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_ISSUER;
   desc.u.name = issuer;
@@ -983,7 +1051,7 @@ keydb_search_issuer_sn (KEYDB_HANDLE hd,
   KEYDB_SEARCH_DESC desc;
   int rc;
   const unsigned char *s;
-  
+
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_ISSUER_SN;
   s = serial;
@@ -1005,7 +1073,7 @@ keydb_search_subject (KEYDB_HANDLE hd, const char *name)
 {
   KEYDB_SEARCH_DESC desc;
   int rc;
-  
+
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_SUBJECT;
   desc.u.name = name;
@@ -1014,276 +1082,6 @@ keydb_search_subject (KEYDB_HANDLE hd, const char *name)
 }
 
 
-static int
-classify_user_id (const char *name, 
-                  KEYDB_SEARCH_DESC *desc,
-                  int *force_exact )
-{
-  const char *s;
-  int hexprefix = 0;
-  int hexlength;
-  int mode = 0;   
-    
-  /* clear the structure so that the mode field is set to zero unless
-   * we set it to the correct value right at the end of this function */
-  memset (desc, 0, sizeof *desc);
-  *force_exact = 0;
-  /* Skip leading spaces.  Fixme: what about trailing white space? */
-  for(s = name; *s && spacep (s); s++ )
-    ;
-
-  switch (*s) 
-    {
-    case 0:  /* empty string is an error */
-      return 0;
-
-    case '.': /* an email address, compare from end */
-      mode = KEYDB_SEARCH_MODE_MAILEND;
-      s++;
-      desc->u.name = s;
-      break;
-
-    case '<': /* an email address */
-      mode = KEYDB_SEARCH_MODE_MAIL;
-      s++;
-      desc->u.name = s;
-      break;
-
-    case '@':  /* part of an email address */
-      mode = KEYDB_SEARCH_MODE_MAILSUB;
-      s++;
-      desc->u.name = s;
-      break;
-
-    case '=':  /* exact compare */
-      mode = KEYDB_SEARCH_MODE_EXACT;
-      s++;
-      desc->u.name = s;
-      break;
-
-    case '*':  /* case insensitive substring search */
-      mode = KEYDB_SEARCH_MODE_SUBSTR;
-      s++;
-      desc->u.name = s;
-      break;
-
-    case '+':  /* compare individual words */
-      mode = KEYDB_SEARCH_MODE_WORDS;
-      s++;
-      desc->u.name = s;
-      break;
-
-    case '/': /* subject's DN */
-      s++;
-      if (!*s || spacep (s))
-        return 0; /* no DN or prefixed with a space */
-      desc->u.name = s;
-      mode = KEYDB_SEARCH_MODE_SUBJECT;
-      break;
-
-    case '#':
-      { 
-        const char *si;
-        
-        s++;
-        if ( *s == '/')
-          { /* "#/" indicates an issuer's DN */
-            s++;
-            if (!*s || spacep (s))
-              return 0; /* no DN or prefixed with a space */
-            desc->u.name = s;
-            mode = KEYDB_SEARCH_MODE_ISSUER;
-          }
-        else 
-          { /* serialnumber + optional issuer ID */
-            for (si=s; *si && *si != '/'; si++)
-              {
-                if (!strchr("01234567890abcdefABCDEF", *si))
-                  return 0; /* invalid digit in serial number*/
-              }
-            desc->sn = (const unsigned char*)s;
-            desc->snlen = -1;
-            if (!*si)
-              mode = KEYDB_SEARCH_MODE_SN;
-            else
-              {
-                s = si+1;
-                if (!*s || spacep (s))
-                  return 0; /* no DN or prefixed with a space */
-                desc->u.name = s;
-                mode = KEYDB_SEARCH_MODE_ISSUER_SN;
-              }
-          }
-      }
-      break;
-
-    case ':': /*Unified fingerprint */
-      {  
-        const char *se, *si;
-        int i;
-        
-        se = strchr (++s,':');
-        if (!se)
-          return 0;
-        for (i=0,si=s; si < se; si++, i++ )
-          {
-            if (!strchr("01234567890abcdefABCDEF", *si))
-              return 0; /* invalid digit */
-          }
-        if (i != 32 && i != 40)
-          return 0; /* invalid length of fpr*/
-        for (i=0,si=s; si < se; i++, si +=2) 
-          desc->u.fpr[i] = hextobyte(si);
-        for (; i < 20; i++)
-          desc->u.fpr[i]= 0;
-        s = se + 1;
-        mode = KEYDB_SEARCH_MODE_FPR;
-      } 
-      break;
-           
-    default:
-      if (s[0] == '0' && s[1] == 'x')
-        {
-          hexprefix = 1;
-          s += 2;
-        }
-
-      hexlength = strspn(s, "0123456789abcdefABCDEF");
-      if (hexlength >= 8 && s[hexlength] =='!')
-        {
-          *force_exact = 1;
-          hexlength++; /* just for the following check */
-        }
-      
-      /* check if a hexadecimal number is terminated by EOS or blank */
-      if (hexlength && s[hexlength] && !spacep (s+hexlength)) 
-        {
-          if (hexprefix) /* a "0x" prefix without correct */
-            return 0;   /* termination is an error */
-          /* The first chars looked like a hex number, but really is
-             not */
-          hexlength = 0;  
-        }
-      
-      if (*force_exact)
-        hexlength--; /* remove the bang */
-
-      if (hexlength == 8
-          || (!hexprefix && hexlength == 9 && *s == '0'))
-        { /* short keyid */
-          unsigned long kid;
-          if (hexlength == 9)
-            s++;
-          kid = strtoul( s, NULL, 16 );
-          desc->u.kid[4] = kid >> 24; 
-          desc->u.kid[5] = kid >> 16; 
-          desc->u.kid[6] = kid >>  8; 
-          desc->u.kid[7] = kid; 
-          mode = KEYDB_SEARCH_MODE_SHORT_KID;
-        }
-      else if (hexlength == 16
-               || (!hexprefix && hexlength == 17 && *s == '0'))
-        { /* complete keyid */
-          unsigned long kid0, kid1;
-          char buf[9];
-          if (hexlength == 17)
-            s++;
-          mem2str(buf, s, 9 );
-          kid0 = strtoul (buf, NULL, 16);
-          kid1 = strtoul (s+8, NULL, 16);
-          desc->u.kid[0] = kid0 >> 24; 
-          desc->u.kid[1] = kid0 >> 16; 
-          desc->u.kid[2] = kid0 >>  8; 
-          desc->u.kid[3] = kid0; 
-          desc->u.kid[4] = kid1 >> 24; 
-          desc->u.kid[5] = kid1 >> 16; 
-          desc->u.kid[6] = kid1 >>  8; 
-          desc->u.kid[7] = kid1; 
-          mode = KEYDB_SEARCH_MODE_LONG_KID;
-        }
-      else if (hexlength == 32
-               || (!hexprefix && hexlength == 33 && *s == '0'))
-        { /* md5 fingerprint */
-          int i;
-          if (hexlength == 33)
-            s++;
-          memset(desc->u.fpr+16, 0, 4); 
-          for (i=0; i < 16; i++, s+=2) 
-            {
-              int c = hextobyte(s);
-              if (c == -1)
-                return 0;
-              desc->u.fpr[i] = c;
-            }
-          mode = KEYDB_SEARCH_MODE_FPR16;
-        }
-      else if (hexlength == 40
-               || (!hexprefix && hexlength == 41 && *s == '0'))
-        { /* sha1/rmd160 fingerprint */
-          int i;
-          if (hexlength == 41)
-            s++;
-          for (i=0; i < 20; i++, s+=2) 
-            {
-              int c = hextobyte(s);
-              if (c == -1)
-                return 0;
-              desc->u.fpr[i] = c;
-            }
-          mode = KEYDB_SEARCH_MODE_FPR20;
-        }
-      else if (!hexprefix)
-        { 
-          /* 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 */
-          return 0;
-        }
-    }
-  
-  desc->mode = mode;
-  return mode;
-}
-
-
-int
-keydb_classify_name (const char *name, KEYDB_SEARCH_DESC *desc)
-{
-  int dummy;
-  KEYDB_SEARCH_DESC dummy_desc;
-
-  if (!desc)
-    desc = &dummy_desc;
-
-  if (!classify_user_id (name, desc, &dummy))
-    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.
@@ -1312,9 +1110,10 @@ keydb_store_cert (ksba_cert_t cert, int ephemeral, int *existed)
       return gpg_error (GPG_ERR_ENOMEM);;
     }
 
-  if (ephemeral)
-    keydb_set_ephemeral (kh, 1);
-  
+  /* Set the ephemeral flag so that the search looks at all
+     records.  */
+  keydb_set_ephemeral (kh, 1);
+
   rc = lock_all (kh);
   if (rc)
     return rc;
@@ -1327,6 +1126,19 @@ keydb_store_cert (ksba_cert_t cert, int ephemeral, int *existed)
         {
           if (existed)
             *existed = 1;
+          if (!ephemeral)
+            {
+              /* Remove ephemeral flags from existing certificate to "store"
+                 it permanently. */
+              rc = keydb_set_cert_flags (cert, 1, KEYBOX_FLAG_BLOB, 0,
+                                         KEYBOX_FLAG_BLOB_EPHEMERAL, 0);
+              if (rc)
+                {
+                  log_error ("clearing ephemeral flag failed: %s\n",
+                             gpg_strerror (rc));
+                  return rc;
+                }
+            }
           return 0; /* okay */
         }
       log_error (_("problem looking for existing certificate: %s\n"),
@@ -1334,6 +1146,10 @@ keydb_store_cert (ksba_cert_t cert, int ephemeral, int *existed)
       return rc;
     }
 
+  /* Reset the ephemeral flag if not requested.  */
+  if (!ephemeral)
+    keydb_set_ephemeral (kh, 0);
+
   rc = keydb_locate_writable (kh, 0);
   if (rc)
     {
@@ -1349,7 +1165,7 @@ keydb_store_cert (ksba_cert_t cert, int ephemeral, int *existed)
       keydb_release (kh);
       return rc;
     }
-  keydb_release (kh);               
+  keydb_release (kh);
   return 0;
 }
 
@@ -1358,7 +1174,9 @@ keydb_store_cert (ksba_cert_t cert, int ephemeral, int *existed)
    transaction by locating the certificate in the DB and updating the
    flags. */
 gpg_error_t
-keydb_set_cert_flags (ksba_cert_t cert, int which, int idx, unsigned int value)
+keydb_set_cert_flags (ksba_cert_t cert, int ephemeral,
+                      int which, int idx,
+                      unsigned int mask, unsigned int value)
 {
   KEYDB_HANDLE kh;
   gpg_error_t err;
@@ -1378,6 +1196,9 @@ keydb_set_cert_flags (ksba_cert_t cert, int which, int idx, unsigned int value)
       return gpg_error (GPG_ERR_ENOMEM);;
     }
 
+  if (ephemeral)
+    keydb_set_ephemeral (kh, 1);
+
   err = keydb_lock (kh);
   if (err)
     {
@@ -1389,8 +1210,11 @@ keydb_set_cert_flags (ksba_cert_t cert, int which, int idx, unsigned int value)
   err = keydb_search_fpr (kh, fpr);
   if (err)
     {
-      log_error (_("problem re-searching certificate: %s\n"),
-                 gpg_strerror (err));
+      if (err == -1)
+        err = gpg_error (GPG_ERR_NOT_FOUND);
+      else
+        log_error (_("problem re-searching certificate: %s\n"),
+                   gpg_strerror (err));
       keydb_release (kh);
       return err;
     }
@@ -1402,6 +1226,9 @@ keydb_set_cert_flags (ksba_cert_t cert, int which, int idx, unsigned int value)
       keydb_release (kh);
       return err;
     }
+
+  value = ((old_value & ~mask) | (value & mask));
+
   if (value != old_value)
     {
       err = keydb_set_flags (kh, which, idx, value);
@@ -1412,7 +1239,8 @@ keydb_set_cert_flags (ksba_cert_t cert, int which, int idx, unsigned int value)
           return err;
         }
     }
-  keydb_release (kh);               
+
+  keydb_release (kh);
   return 0;
 }
 
@@ -1429,7 +1257,9 @@ keydb_clear_some_cert_flags (ctrl_t ctrl, strlist_t names)
   strlist_t sl;
   int rc=0;
   unsigned int old_value, value;
-  
+
+  (void)ctrl;
+
   hd = keydb_new (0);
   if (!hd)
     {
@@ -1441,7 +1271,7 @@ keydb_clear_some_cert_flags (ctrl_t ctrl, strlist_t names)
     ndesc = 1;
   else
     {
-      for (sl=names, ndesc=0; sl; sl = sl->next, ndesc++) 
+      for (sl=names, ndesc=0; sl; sl = sl->next, ndesc++)
         ;
     }
 
@@ -1455,14 +1285,14 @@ keydb_clear_some_cert_flags (ctrl_t ctrl, strlist_t names)
 
   if (!names)
     desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
-  else 
+  else
     {
-      for (ndesc=0, sl=names; sl; sl = sl->next) 
+      for (ndesc=0, sl=names; sl; sl = sl->next)
         {
-          rc = keydb_classify_name (sl->d, desc+ndesc);
+          rc = classify_user_id (sl->d, desc+ndesc, 0);
           if (rc)
             {
-              log_error ("key `%s' not found: %s\n",
+              log_error ("key '%s' not found: %s\n",
                          sl->d, gpg_strerror (rc));
               rc = 0;
             }
@@ -1480,7 +1310,7 @@ keydb_clear_some_cert_flags (ctrl_t ctrl, strlist_t names)
 
   while (!(rc = keydb_search (hd, desc, ndesc)))
     {
-      if (!names) 
+      if (!names)
         desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
 
       err = keydb_get_flags (hd, KEYBOX_FLAG_VALIDITY, 0, &old_value);
@@ -1490,7 +1320,7 @@ keydb_clear_some_cert_flags (ctrl_t ctrl, strlist_t names)
                      gpg_strerror (err));
           goto leave;
         }
+
       value = (old_value & ~VALIDITY_REVOKED);
       if (value != old_value)
         {
@@ -1504,10 +1334,8 @@ keydb_clear_some_cert_flags (ctrl_t ctrl, strlist_t names)
     }
   if (rc && rc != -1)
     log_error ("keydb_search failed: %s\n", gpg_strerror (rc));
-  
+
  leave:
   xfree (desc);
   keydb_release (hd);
 }
-
-