Ask for the keysize when generating a new card key.
[gnupg.git] / g10 / getkey.c
index 8594ad9..54843cf 100644 (file)
@@ -1,12 +1,12 @@
 /* getkey.c -  Get a key from the database
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- *               2006 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ *               2007, 2008 Free Software Foundation, Inc.
  *
  * 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,
@@ -15,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>
 #include <string.h>
 #include <assert.h>
 #include <ctype.h>
+
+#include "gpg.h"
 #include "util.h"
 #include "packet.h"
-#include "memory.h"
 #include "iobuf.h"
 #include "keydb.h"
 #include "options.h"
@@ -48,7 +47,8 @@ struct getkey_ctx_s {
     int exact;
     KBNODE keyblock;
     KBPOS  kbpos;
-    KBNODE found_key; /* pointer into some keyblock */
+    KBNODE found_key; /* Pointer into some keyblock. */
+    strlist_t extra_list;  /* Will be freed when releasing the context.  */
     int last_rc;
     int req_usage;
     int req_algo;
@@ -163,6 +163,21 @@ cache_public_key( PKT_public_key *pk )
 }
 
 
+/* Return a const utf-8 string with the text "[User ID not found]".
+   This fucntion is required so that we don't need to switch gettext's
+   encoding temporary. */
+static const char *
+user_id_not_found_utf8 (void)
+{
+  static char *text;
+
+  if (!text)
+    text = native_to_utf8 (_("[User ID not found]"));
+  return text;
+}
+
+
+
 /*
  * Return the user ID from the given keyblock.
  * We use the primary uid flag which has been set by the merge_selfsigs
@@ -183,9 +198,7 @@ get_primary_uid ( KBNODE keyblock, size_t *uidlen )
             return k->pkt->pkt.user_id->name;
         }
     } 
-    /* fixme: returning translatable constants instead of a user ID is 
-     * not good because they are probably not utf-8 encoded. */
-    s = _("[User ID not found]");
+    s = user_id_not_found_utf8 ();
     *uidlen = strlen (s);
     return s;
 }
@@ -564,6 +577,7 @@ seckey_available( u32 *keyid )
  *   Words are delimited by white space or "()<>[]{}.@-+_,;/&!"
  *   (note that you can't search for these characters). Compare
  *   is not case sensitive.
+ * - If the userid starts with a '&' a 40 hex digits keygrip is expected.
  */
 
 int
@@ -630,7 +644,7 @@ classify_user_id( const char *name, KEYDB_SEARCH_DESC *desc )
 #endif
 
        case '#':  /* local user id */
-            return 0; /* This is now obsolete and van't not be used anymore*/
+            return 0; /* This is now obsolete and can't not be used anymore*/
         
         case ':': /*Unified fingerprint */
             {  
@@ -655,6 +669,9 @@ classify_user_id( const char *name, KEYDB_SEARCH_DESC *desc )
             } 
             break;
            
+       case '&':  /* keygrip */
+          return 0; /* Not yet implememted. */
+
        default:
            if (s[0] == '0' && s[1] == 'x') {
                hexprefix = 1;
@@ -743,10 +760,12 @@ classify_user_id( const char *name, KEYDB_SEARCH_DESC *desc )
 
 
 static int
-skip_unusable(void *dummy,u32 *keyid,PKT_user_id *uid)
+skip_unusable (void *dummy, u32 *keyid, PKT_user_id *uid)
 {
   int unusable=0;
   KBNODE keyblock;
+  
+  (void)dummy;
 
   keyblock=get_pubkeyblock(keyid);
   if(!keyblock)
@@ -794,14 +813,14 @@ skip_unusable(void *dummy,u32 *keyid,PKT_user_id *uid)
  */
 
 static int
-key_byname( GETKEY_CTX *retctx, STRLIST namelist,
+key_byname( GETKEY_CTX *retctx, strlist_t namelist,
            PKT_public_key *pk, PKT_secret_key *sk,
            int secmode, int include_unusable,
             KBNODE *ret_kb, KEYDB_HANDLE *ret_kdbhd )
 {
     int rc = 0;
     int n;
-    STRLIST r;
+    strlist_t r;
     GETKEY_CTX ctx;
     KBNODE help_kb = NULL;
     
@@ -896,64 +915,122 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
 /* Find a public key from NAME and return the keyblock or the key.  If
    ret_kdb is not NULL, the KEYDB handle used to locate this keyblock
    is returned and the caller is responsible for closing it.  If a key
-   was not found and NAME is a valid RFC822 mailbox and PKA retrieval
-   has been enabled, we try to import the pkea via the PKA
-   mechanism. */
+   was not found (or if local search has been disabled) and NAME is a
+   valid RFC822 mailbox and --auto-key-locate has been enabled, we try
+   to import the key via the online mechanisms defined by
+   --auto-key-locate.  */
 int
-get_pubkey_byname (PKT_public_key *pk,
+get_pubkey_byname (GETKEY_CTX *retctx, PKT_public_key *pk,
                   const char *name, KBNODE *ret_keyblock,
-                   KEYDB_HANDLE *ret_kdbhd, int include_unusable )
+                   KEYDB_HANDLE *ret_kdbhd, int include_unusable, 
+                   int no_akl)
 {
   int rc;
-  STRLIST namelist = NULL;
+  strlist_t namelist = NULL;
+  struct akl *akl;
+  int is_mbox;
+  int nodefault = 0;
+  int anylocalfirst = 0;
+
+  if (retctx)
+    *retctx = NULL;
+
+  is_mbox = is_valid_mailbox (name);
+
+  /* Check whether we the default local search has been disabled.
+     This is the case if either the "nodefault" or the "local" keyword
+     are in the list of auto key locate mechanisms. 
+
+     ANYLOCALFIRST is set if the search order has the local method
+     before any other or if "local" is used first by default.  This
+     makes sure that if a RETCTX is used it gets only set if a local
+     search has precedence over the other search methods and only then
+     a followup call to get_pubkey_next shall succeed.  */
+  if (!no_akl)
+    {
+      for (akl=opt.auto_key_locate; akl; akl=akl->next)
+        if (akl->type == AKL_NODEFAULT || akl->type == AKL_LOCAL)
+          {
+            nodefault = 1;
+            break;
+          }
+      for (akl=opt.auto_key_locate; akl; akl=akl->next)
+        if (akl->type != AKL_NODEFAULT)
+          {
+            if (akl->type == AKL_LOCAL)
+              anylocalfirst = 1;
+            break;
+          }
+    }
 
-  add_to_strlist( &namelist, name );
+  if (!nodefault)
+    anylocalfirst = 1;
 
-  rc = key_byname( NULL, namelist, pk, NULL, 0,
-                   include_unusable, ret_keyblock, ret_kdbhd);
+  if (nodefault && is_mbox)
+    {
+      /* Nodefault but a mailbox - let the AKL locate the key.  */
+      rc = G10ERR_NO_PUBKEY;
+    }
+  else
+    {
+      add_to_strlist (&namelist, name);
+      rc = key_byname (retctx, namelist, pk, NULL, 0,
+                       include_unusable, ret_keyblock, ret_kdbhd);
+    }
 
   /* If the requested name resembles a valid mailbox and automatic
      retrieval has been enabled, we try to import the key. */
-
-  if (rc == G10ERR_NO_PUBKEY && is_valid_mailbox(name))
+  if (gpg_err_code (rc) == G10ERR_NO_PUBKEY && !no_akl && is_mbox)
     {
-      int res;
-      struct akl *akl;
-
-      for(akl=opt.auto_key_locate;akl;akl=akl->next)
+      for (akl=opt.auto_key_locate; akl; akl=akl->next)
        {
-         unsigned char *fpr;
+         unsigned char *fpr = NULL;
          size_t fpr_len;
-
-         switch(akl->type)
+          int did_key_byname = 0;
+          int no_fingerprint = 0;
+          const char *mechanism = "?";
+          
+          switch(akl->type)
            {
+            case AKL_NODEFAULT:
+              /* This is a dummy mechanism.  */
+              mechanism = "None";
+              rc = G10ERR_NO_PUBKEY;
+              break;
+
+            case AKL_LOCAL:
+              mechanism = "Local";
+              did_key_byname = 1;
+              if (retctx)
+                {
+                  get_pubkey_end (*retctx);
+                  *retctx = NULL;
+                }
+              add_to_strlist (&namelist, name);
+              rc = key_byname (anylocalfirst? retctx:NULL,
+                               namelist, pk, NULL, 0,
+                               include_unusable, ret_keyblock, ret_kdbhd);
+              break;
+
            case AKL_CERT:
+              mechanism = "DNS CERT";
              glo_ctrl.in_auto_key_retrieve++;
-             res=keyserver_import_cert(name,&fpr,&fpr_len);
+             rc=keyserver_import_cert(name,&fpr,&fpr_len);
              glo_ctrl.in_auto_key_retrieve--;
-
-             if(res==0)
-               log_info(_("Automatically retrieved `%s' via %s\n"),
-                        name,"DNS CERT");
              break;
 
            case AKL_PKA:
+              mechanism = "PKA";
              glo_ctrl.in_auto_key_retrieve++;
-             res=keyserver_import_pka(name,&fpr,&fpr_len);
-
-             if(res==0)
-               log_info(_("Automatically retrieved `%s' via %s\n"),
-                        name,"PKA");
+             rc=keyserver_import_pka(name,&fpr,&fpr_len);
+             glo_ctrl.in_auto_key_retrieve--;
              break;
 
            case AKL_LDAP:
+              mechanism = "LDAP";
              glo_ctrl.in_auto_key_retrieve++;
-             res=keyserver_import_ldap(name,&fpr,&fpr_len);
+             rc=keyserver_import_ldap(name,&fpr,&fpr_len);
              glo_ctrl.in_auto_key_retrieve--;
-
-             if(res==0)
-               log_info(_("Automatically retrieved `%s' via %s\n"),
-                        name,"LDAP");
              break;
 
            case AKL_KEYSERVER:
@@ -963,32 +1040,31 @@ get_pubkey_byname (PKT_public_key *pk,
                 and getting a whole lot of keys back. */
              if(opt.keyserver)
                {
+                  mechanism = opt.keyserver->uri;
                  glo_ctrl.in_auto_key_retrieve++;
-                 res=keyserver_import_name(name,&fpr,&fpr_len,opt.keyserver);
+                 rc=keyserver_import_name(name,&fpr,&fpr_len,opt.keyserver);
                  glo_ctrl.in_auto_key_retrieve--;
-
-                 if(res==0)
-                   log_info(_("Automatically retrieved `%s' via %s\n"),
-                            name,opt.keyserver->uri);
                }
+              else
+                {
+                  mechanism = "Unconfigured keyserver";
+                  rc = G10ERR_NO_PUBKEY;
+                }
              break;
 
            case AKL_SPEC:
              {
                struct keyserver_spec *keyserver;
 
+                mechanism = akl->spec->uri;
                keyserver=keyserver_match(akl->spec);
                glo_ctrl.in_auto_key_retrieve++;
-               res=keyserver_import_name(name,&fpr,&fpr_len,keyserver);
+               rc=keyserver_import_name(name,&fpr,&fpr_len,keyserver);
                glo_ctrl.in_auto_key_retrieve--;
-
-               if(res==0)
-                 log_info(_("Automatically retrieved `%s' via %s\n"),
-                          name,akl->spec->uri);
              }
              break;
            }
-
+          
          /* Use the fingerprint of the key that we actually fetched.
             This helps prevent problems where the key that we fetched
             doesn't have the same name that we used to fetch it.  In
@@ -996,9 +1072,8 @@ get_pubkey_byname (PKT_public_key *pk,
             requirement as the URL might point to a key put in by an
             attacker.  By forcing the use of the fingerprint, we
             won't use the attacker's key here. */
-         if(res==0 && fpr)
+         if (!rc && fpr)
            {
-             int i;
              char fpr_string[MAX_FINGERPRINT_LEN*2+1];
 
              assert(fpr_len<=MAX_FINGERPRINT_LEN);
@@ -1006,31 +1081,67 @@ get_pubkey_byname (PKT_public_key *pk,
              free_strlist(namelist);
              namelist=NULL;
 
-             for(i=0;i<fpr_len;i++)
-               sprintf(fpr_string+2*i,"%02X",fpr[i]);
-
+              bin2hex (fpr, fpr_len, fpr_string);
+              
              if(opt.verbose)
                log_info("auto-key-locate found fingerprint %s\n",fpr_string);
 
              add_to_strlist( &namelist, fpr_string );
-
-             xfree(fpr);
            }
-
-         rc = key_byname( NULL, namelist, pk, NULL, 0,
-                          include_unusable, ret_keyblock, ret_kdbhd);
-         if(rc!=G10ERR_NO_PUBKEY)
-           break;
+          else if (!rc && !fpr && !did_key_byname)
+            {
+              no_fingerprint = 1;
+              rc = G10ERR_NO_PUBKEY;
+            }
+          xfree (fpr);
+          fpr = NULL;
+
+          if (!rc && !did_key_byname)
+            {
+              if (retctx)
+                {
+                  get_pubkey_end (*retctx);
+                  *retctx = NULL;
+                }
+              rc = key_byname (anylocalfirst?retctx:NULL,
+                               namelist, pk, NULL, 0,
+                               include_unusable, ret_keyblock, ret_kdbhd);
+            }
+         if (!rc)
+            {
+              /* Key found.  */
+              log_info (_("automatically retrieved `%s' via %s\n"),
+                        name, mechanism);
+              break;  
+            }
+          if (rc != G10ERR_NO_PUBKEY || opt.verbose || no_fingerprint)
+            log_info (_("error retrieving `%s' via %s: %s\n"),
+                      name, mechanism, 
+                      no_fingerprint? _("No fingerprint"):g10_errstr(rc));
        }
     }
 
-  free_strlist( namelist );
+  
+  if (rc && retctx)
+    {
+      get_pubkey_end (*retctx);
+      *retctx = NULL;
+    }
+
+  if (retctx && *retctx)
+    {
+      assert (!(*retctx)->extra_list);
+      (*retctx)->extra_list = namelist;
+    }
+  else
+    free_strlist (namelist);
   return rc;
 }
 
+
 int
 get_pubkey_bynames( GETKEY_CTX *retctx, PKT_public_key *pk,
-                   STRLIST names, KBNODE *ret_keyblock )
+                   strlist_t names, KBNODE *ret_keyblock )
 {
     return key_byname( retctx, names, pk, NULL, 0, 1, ret_keyblock, NULL);
 }
@@ -1053,6 +1164,7 @@ get_pubkey_end( GETKEY_CTX ctx )
     if( ctx ) {
         memset (&ctx->kbpos, 0, sizeof ctx->kbpos);
         keydb_release (ctx->kr_handle);
+        free_strlist (ctx->extra_list);
        if( !ctx->not_allocated )
            xfree( ctx );
     }
@@ -1181,7 +1293,7 @@ get_seckey_byname2( GETKEY_CTX *retctx,
                    PKT_secret_key *sk, const char *name, int unprotect,
                    KBNODE *retblock )
 {
-  STRLIST namelist = NULL;
+  strlist_t namelist = NULL;
   int rc,include_unusable=1;
 
   /* If we have no name, try to use the default secret key.  If we
@@ -1214,7 +1326,7 @@ get_seckey_byname( PKT_secret_key *sk, const char *name, int unlock )
 
 int
 get_seckey_bynames( GETKEY_CTX *retctx, PKT_secret_key *sk,
-                   STRLIST names, KBNODE *ret_keyblock )
+                   strlist_t names, KBNODE *ret_keyblock )
 {
     return key_byname( retctx, names, NULL, sk, 1, 1, ret_keyblock, NULL );
 }
@@ -1472,18 +1584,23 @@ fixup_uidnode ( KBNODE uidnode, KBNODE signode, u32 keycreated )
 
     sig->flags.chosen_selfsig = 1; /* we chose this one */
     uid->created = 0; /* not created == invalid */
-    if ( IS_UID_REV ( sig ) ) {
+    if ( IS_UID_REV ( sig ) ) 
+      {
         uid->is_revoked = 1;
         return; /* has been revoked */
-    }
+      }
+    else
+      uid->is_revoked = 0;
 
     uid->expiredate = sig->expiredate;
 
-    if(sig->flags.expired)
+    if (sig->flags.expired)
       {
        uid->is_expired = 1;
        return; /* has expired */
       }
+    else
+      uid->is_expired = 0;
 
     uid->created = sig->timestamp; /* this one is okay */
     uid->selfsigversion = sig->version;
@@ -1493,12 +1610,12 @@ fixup_uidnode ( KBNODE uidnode, KBNODE signode, u32 keycreated )
     /* store the key flags in the helper variable for later processing */
     uid->help_key_usage=parse_key_usage(sig);
 
-    /* ditto or the key expiration */
-    uid->help_key_expire = 0;
+    /* ditto for the key expiration */
     p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
-    if ( p ) { 
-        uid->help_key_expire = keycreated + buffer_to_u32(p);
-    }
+    if( p && buffer_to_u32(p) )
+      uid->help_key_expire = keycreated + buffer_to_u32(p);
+    else
+      uid->help_key_expire = 0;
 
     /* Set the primary user ID flag - we will later wipe out some
      * of them to only have one in our keyblock */
@@ -1710,7 +1827,7 @@ merge_selfsigs_main(KBNODE keyblock, int *r_revoked, struct revoke_info *rinfo)
        key_usage=parse_key_usage(sig);
 
        p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
-       if ( p )
+       if( p && buffer_to_u32(p) )
          {
            key_expire = keytimestamp + buffer_to_u32(p);
            key_expire_seen = 1;
@@ -2021,6 +2138,26 @@ merge_selfsigs_main(KBNODE keyblock, int *r_revoked, struct revoke_info *rinfo)
       }
 }
 
+/* Convert a buffer to a signature.  Useful for 0x19 embedded sigs.
+   Caller must free the signature when they are done. */
+static PKT_signature *
+buf_to_sig(const byte *buf,size_t len)
+{
+  PKT_signature *sig=xmalloc_clear(sizeof(PKT_signature));
+  IOBUF iobuf=iobuf_temp_with_content(buf,len);
+  int save_mode=set_packet_list_mode(0);
+
+  if(parse_signature(iobuf,PKT_SIGNATURE,len,sig)!=0)
+    {
+      xfree(sig);
+      sig=NULL;
+    }
+
+  set_packet_list_mode(save_mode);
+  iobuf_close(iobuf);
+
+  return sig;
+}
 
 static void
 merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
@@ -2114,7 +2251,7 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
     subpk->pubkey_usage = key_usage;
     
     p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
-    if ( p 
+    if ( p && buffer_to_u32(p) )
         key_expire = keytimestamp + buffer_to_u32(p);
     else
         key_expire = 0;
@@ -2122,50 +2259,79 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
     subpk->expiredate = key_expire;
 
     /* algo doesn't exist */
-    if(check_pubkey_algo(subpk->pubkey_algo))
+    if(openpgp_pk_test_algo(subpk->pubkey_algo))
       return;
 
     subpk->is_valid = 1;
 
-    /* Find the first 0x19 embedded signature on our self-sig. */
+    /* Find the most recent 0x19 embedded signature on our self-sig. */
     if(subpk->backsig==0)
       {
        int seq=0;
        size_t n;
+       PKT_signature *backsig=NULL;
+
+       sigdate=0;
 
        /* We do this while() since there may be other embedded
           signatures in the future.  We only want 0x19 here. */
+
        while((p=enum_sig_subpkt(sig->hashed,
                                 SIGSUBPKT_SIGNATURE,&n,&seq,NULL)))
          if(n>3 && ((p[0]==3 && p[2]==0x19) || (p[0]==4 && p[1]==0x19)))
-           break;
+           {
+             PKT_signature *tempsig=buf_to_sig(p,n);
+             if(tempsig)
+               {
+                 if(tempsig->timestamp>sigdate)
+                   {
+                     if(backsig)
+                       free_seckey_enc(backsig);
 
-       if(p==NULL)
-         {
-           seq=0;
-           /* It is safe to have this in the unhashed area since the
-              0x19 is located on the selfsig for convenience, not
-              security. */
-           while((p=enum_sig_subpkt(sig->unhashed,SIGSUBPKT_SIGNATURE,
-                                    &n,&seq,NULL)))
-             if(n>3 && ((p[0]==3 && p[2]==0x19) || (p[0]==4 && p[1]==0x19)))
-               break;
-         }
+                     backsig=tempsig;
+                     sigdate=backsig->timestamp;
+                   }
+                 else
+                   free_seckey_enc(tempsig);
+               }
+           }
 
-       if(p)
+       seq=0;
+
+       /* It is safe to have this in the unhashed area since the 0x19
+          is located on the selfsig for convenience, not security. */
+
+       while((p=enum_sig_subpkt(sig->unhashed,SIGSUBPKT_SIGNATURE,
+                                &n,&seq,NULL)))
+         if(n>3 && ((p[0]==3 && p[2]==0x19) || (p[0]==4 && p[1]==0x19)))
+           {
+             PKT_signature *tempsig=buf_to_sig(p,n);
+             if(tempsig)
+               {
+                 if(tempsig->timestamp>sigdate)
+                   {
+                     if(backsig)
+                       free_seckey_enc(backsig);
+
+                     backsig=tempsig;
+                     sigdate=backsig->timestamp;
+                   }
+                 else
+                   free_seckey_enc(tempsig);
+               }
+           }
+
+       if(backsig)
          {
-           PKT_signature *backsig=xmalloc_clear(sizeof(PKT_signature));
-           IOBUF backsig_buf=iobuf_temp_with_content(p,n);
+           /* At ths point, backsig contains the most recent 0x19 sig.
+              Let's see if it is good. */
 
-           if(parse_signature(backsig_buf,PKT_SIGNATURE,n,backsig)==0)
-             {
-               if(check_backsig(mainpk,subpk,backsig)==0)
-                 subpk->backsig=2;
-               else
-                 subpk->backsig=1;
-             }
+           /* 2==valid, 1==invalid, 0==didn't check */
+           if(check_backsig(mainpk,subpk,backsig)==0)
+             subpk->backsig=2;
+           else
+             subpk->backsig=1;
 
-           iobuf_close(backsig_buf);
            free_seckey_enc(backsig);
          }
       }
@@ -2474,16 +2640,6 @@ finish_lookup (GETKEY_CTX ctx)
         goto found;
     }
     
-    if (!req_usage) {
-        PKT_public_key *pk = foundk->pkt->pkt.public_key;
-        if (pk->user_id)
-            free_user_id (pk->user_id);
-        pk->user_id = scopy_user_id (foundu);
-        ctx->found_key = foundk;
-        cache_user_id( keyblock );
-        return 1; /* found */
-    }
-    
     latest_date = 0;
     latest_key  = NULL;
     /* do not look at subkeys if a certification key is requested */
@@ -2530,8 +2686,13 @@ finish_lookup (GETKEY_CTX ctx)
             }
 
             if (DBG_CACHE)
-                log_debug( "\tsubkey looks fine\n");
-            if ( pk->timestamp > latest_date ) {
+                log_debug( "\tsubkey might be fine\n");
+            /* In case a key has a timestamp of 0 set, we make sure
+               that it is used.  A better change would be to compare
+               ">=" but that might also change the selected keys and
+               is as such a more intrusive change.  */
+            if ( pk->timestamp > latest_date
+                 || (!pk->timestamp && !latest_date)) {
                 latest_date = pk->timestamp;
                 latest_key  = k;
             }
@@ -2616,7 +2777,7 @@ lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode )
     rc = 0;
     while (!(rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems))) {
         /* If we are searching for the first key we have to make sure
-           that the next interation does not no an implicit reset.
+           that the next iteration does not do an implicit reset.
            This can be triggered by an empty key ring. */
         if (ctx->nitems && ctx->items->mode == KEYDB_SEARCH_MODE_FIRST)
             ctx->items->mode = KEYDB_SEARCH_MODE_NEXT;
@@ -2886,7 +3047,7 @@ get_user_id( u32 *keyid, size_t *rn )
             }
         }
     } while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
-    p = xstrdup( _("[User ID not found]") );
+    p = xstrdup( user_id_not_found_utf8 () );
     *rn = strlen(p);
     return p;
 }
@@ -2927,6 +3088,7 @@ release_akl(void)
     }
 }
 
+/* Returns false on error. */
 int
 parse_auto_key_locate(char *options)
 {
@@ -2934,14 +3096,19 @@ parse_auto_key_locate(char *options)
 
   while((tok=optsep(&options)))
     {
-      struct akl *akl,*last;
+      struct akl *akl,*check,*last=NULL;
+      int dupe=0;
 
       if(tok[0]=='\0')
        continue;
 
       akl=xmalloc_clear(sizeof(*akl));
 
-      if(ascii_strcasecmp(tok,"ldap")==0)
+      if(ascii_strcasecmp(tok,"nodefault")==0)
+       akl->type=AKL_NODEFAULT;
+      else if(ascii_strcasecmp(tok,"local")==0)
+       akl->type=AKL_LOCAL;
+      else if(ascii_strcasecmp(tok,"ldap")==0)
        akl->type=AKL_LDAP;
       else if(ascii_strcasecmp(tok,"keyserver")==0)
        akl->type=AKL_KEYSERVER;
@@ -2962,23 +3129,27 @@ parse_auto_key_locate(char *options)
        }
 
       /* We must maintain the order the user gave us */
-      for(last=opt.auto_key_locate;last && last->next;last=last->next)
+      for(check=opt.auto_key_locate;check;last=check,check=check->next)
        {
          /* Check for duplicates */
-         if(last && last->type==akl->type
+         if(check->type==akl->type
             && (akl->type!=AKL_SPEC
                 || (akl->type==AKL_SPEC
-                    && strcmp(last->spec->uri,akl->spec->uri)==0)))
+                    && strcmp(check->spec->uri,akl->spec->uri)==0)))
            {
+             dupe=1;
              free_akl(akl);
-             return 0;
+             break;
            }
        }
 
-      if(last)
-       last->next=akl;
-      else
-       opt.auto_key_locate=akl;
+      if(!dupe)
+       {
+         if(last)
+           last->next=akl;
+         else
+           opt.auto_key_locate=akl;
+       }
     }
 
   return 1;