* main.h, seskey.c (encode_md_value): Modify to allow a q size greater
[gnupg.git] / g10 / getkey.c
index 5bd9907..1c85fb4 100644 (file)
@@ -1,6 +1,6 @@
 /* getkey.c -  Get a key from the database
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- *               2005 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ *               2006 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -35,6 +35,7 @@
 #include "main.h"
 #include "trustdb.h"
 #include "i18n.h"
+#include "keyserver-internal.h"
 
 #define MAX_PK_CACHE_ENTRIES   PK_UID_CACHE_SIZE
 #define MAX_UID_CACHE_ENTRIES  PK_UID_CACHE_SIZE
@@ -152,7 +153,7 @@ cache_public_key( PKT_public_key *pk )
        return;
     }
     pk_cache_entries++;
-    ce = m_alloc( sizeof *ce );
+    ce = xmalloc( sizeof *ce );
     ce->next = pk_cache;
     pk_cache = ce;
     ce->pk = copy_public_key( NULL, pk );
@@ -195,7 +196,7 @@ release_keyid_list ( keyid_list_t k )
 {
     while (  k ) {
         keyid_list_t k2 = k->next;
-        m_free (k);
+        xfree (k);
         k = k2;
     }
 }
@@ -216,7 +217,7 @@ cache_user_id( KBNODE keyblock )
     for (k=keyblock; k; k = k->next ) {
         if ( k->pkt->pkttype == PKT_PUBLIC_KEY
              || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
-            keyid_list_t a = m_alloc_clear ( sizeof *a );
+            keyid_list_t a = xmalloc_clear ( sizeof *a );
             /* Hmmm: For a long list of keyids it might be an advantage
              * to append the keys */
             keyid_from_pk( k->pkt->pkt.public_key, a->keyid );
@@ -229,7 +230,7 @@ cache_user_id( KBNODE keyblock )
                         if( DBG_CACHE )
                             log_debug("cache_user_id: already in cache\n");
                         release_keyid_list ( keyids );
-                        m_free ( a );
+                        xfree ( a );
                         return;
                     }
                 }
@@ -250,10 +251,10 @@ cache_user_id( KBNODE keyblock )
        r = user_id_db;
        user_id_db = r->next;
         release_keyid_list ( r->keyids );
-       m_free(r);
+       xfree(r);
        uid_cache_entries--;
     }
-    r = m_alloc( sizeof *r + uidlen-1 );
+    r = xmalloc( sizeof *r + uidlen-1 );
     r->keyids = keyids;
     r->len = uidlen;
     memcpy(r->name, uid, r->len);
@@ -273,7 +274,7 @@ getkey_disable_caches()
        for( ce = pk_cache; ce; ce = ce2 ) {
            ce2 = ce->next;
            free_public_key( ce->pk );
-           m_free( ce );
+           xfree( ce );
        }
        pk_cache_disabled=1;
        pk_cache_entries = 0;
@@ -338,7 +339,7 @@ get_pubkey( PKT_public_key *pk, u32 *keyid )
 #endif
     /* more init stuff */
     if( !pk ) {
-       pk = m_alloc_clear( sizeof *pk );
+       pk = xmalloc_clear( sizeof *pk );
        internal++;
     }
 
@@ -589,11 +590,13 @@ classify_user_id( const char *name, KEYDB_SEARCH_DESC *desc )
        case 0:    /* empty string is an error */
            return 0;
 
+#if 0
        case '.':  /* an email address, compare from end */
            mode = KEYDB_SEARCH_MODE_MAILEND;
            s++;
             desc->u.name = s;
            break;
+#endif
 
        case '<':  /* an email address */
            mode = KEYDB_SEARCH_MODE_MAIL;
@@ -618,11 +621,13 @@ classify_user_id( const char *name, KEYDB_SEARCH_DESC *desc )
             desc->u.name = s;
            break;
 
+#if 0
        case '+':  /* compare individual words */
            mode = KEYDB_SEARCH_MODE_WORDS;
            s++;
             desc->u.name = s;
            break;
+#endif
 
        case '#':  /* local user id */
             return 0; /* This is now obsolete and van't not be used anymore*/
@@ -810,7 +815,7 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
 
     if(!namelist)
       {
-       ctx = m_alloc_clear (sizeof *ctx);
+       ctx = xmalloc_clear (sizeof *ctx);
        ctx->nitems = 1;
        ctx->items[0].mode=KEYDB_SEARCH_MODE_FIRST;
        if(!include_unusable)
@@ -822,7 +827,7 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
        for(n=0, r=namelist; r; r = r->next )
          n++;
 
-       ctx = m_alloc_clear (sizeof *ctx + (n-1)*sizeof ctx->items );
+       ctx = xmalloc_clear (sizeof *ctx + (n-1)*sizeof ctx->items );
        ctx->nitems = n;
 
        for(n=0, r=namelist; r; r = r->next, n++ )
@@ -833,7 +838,7 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
              ctx->exact = 1;
            if (!ctx->items[n].mode)
              {
-               m_free (ctx);
+               xfree (ctx);
                return G10ERR_INV_USER_ID;
              }
            if(!include_unusable
@@ -886,24 +891,140 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
     return rc;
 }
 
-/*
- * Find a public key from NAME and returh 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.
- */
+
+
+/* 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. */
 int
 get_pubkey_byname (PKT_public_key *pk,
                   const char *name, KBNODE *ret_keyblock,
                    KEYDB_HANDLE *ret_kdbhd, int include_unusable )
 {
-    int rc;
-    STRLIST namelist = NULL;
+  int rc;
+  STRLIST namelist = NULL;
 
-    add_to_strlist( &namelist, name );
-    rc = key_byname( NULL, namelist, pk, NULL, 0,
-                    include_unusable, ret_keyblock, ret_kdbhd);
-    free_strlist( namelist );
-    return rc;
+  add_to_strlist( &namelist, name );
+
+  rc = key_byname( NULL, 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))
+    {
+      struct akl *akl;
+
+      for(akl=opt.auto_key_locate;akl;akl=akl->next)
+       {
+         unsigned char *fpr;
+         size_t fpr_len;
+
+         switch(akl->type)
+           {
+           case AKL_CERT:
+             glo_ctrl.in_auto_key_retrieve++;
+             rc=keyserver_import_cert(name,&fpr,&fpr_len);
+             glo_ctrl.in_auto_key_retrieve--;
+
+             if(rc==0)
+               log_info(_("Automatically retrieved `%s' via %s\n"),
+                        name,"DNS CERT");
+             break;
+
+           case AKL_PKA:
+             glo_ctrl.in_auto_key_retrieve++;
+             rc=keyserver_import_pka(name,&fpr,&fpr_len);
+
+             if(rc==0)
+               log_info(_("Automatically retrieved `%s' via %s\n"),
+                        name,"PKA");
+             break;
+
+           case AKL_LDAP:
+             glo_ctrl.in_auto_key_retrieve++;
+             rc=keyserver_import_ldap(name,&fpr,&fpr_len);
+             glo_ctrl.in_auto_key_retrieve--;
+
+             if(rc==0)
+               log_info(_("Automatically retrieved `%s' via %s\n"),
+                        name,"LDAP");
+             break;
+
+           case AKL_KEYSERVER:
+             /* Strictly speaking, we don't need to only use a valid
+                mailbox for the getname search, but it helps cut down
+                on the problem of searching for something like "john"
+                and getting a whole lot of keys back. */
+             if(opt.keyserver)
+               {
+                 glo_ctrl.in_auto_key_retrieve++;
+                 rc=keyserver_import_name(name,&fpr,&fpr_len,opt.keyserver);
+                 glo_ctrl.in_auto_key_retrieve--;
+
+                 if(rc==0)
+                   log_info(_("Automatically retrieved `%s' via %s\n"),
+                            name,opt.keyserver->uri);
+               }
+             break;
+
+           case AKL_SPEC:
+             {
+               struct keyserver_spec *keyserver;
+
+               keyserver=keyserver_match(akl->spec);
+               glo_ctrl.in_auto_key_retrieve++;
+               rc=keyserver_import_name(name,&fpr,&fpr_len,keyserver);
+               glo_ctrl.in_auto_key_retrieve--;
+
+               if(rc==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
+            the case of CERT and PKA, this is an actual security
+            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(rc==0 && fpr)
+           {
+             int i;
+             char fpr_string[MAX_FINGERPRINT_LEN*2+1];
+
+             assert(fpr_len<=MAX_FINGERPRINT_LEN);
+
+             free_strlist(namelist);
+             namelist=NULL;
+
+             for(i=0;i<fpr_len;i++)
+               sprintf(fpr_string+2*i,"%02X",fpr[i]);
+
+             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;
+       }
+    }
+
+  free_strlist( namelist );
+  return rc;
 }
 
 int
@@ -932,7 +1053,7 @@ get_pubkey_end( GETKEY_CTX ctx )
         memset (&ctx->kbpos, 0, sizeof ctx->kbpos);
         keydb_release (ctx->kr_handle);
        if( !ctx->not_allocated )
-           m_free( ctx );
+           xfree( ctx );
     }
 }
 
@@ -1291,16 +1412,24 @@ parse_key_usage(PKT_signature *sig)
       /* first octet of the keyflags */
       flags=*p;
 
-      if(flags & 3)
+      if(flags & 1)
+       {
+         key_usage |= PUBKEY_USAGE_CERT;
+         flags&=~1;
+       }
+
+      if(flags & 2)
        {
          key_usage |= PUBKEY_USAGE_SIG;
-         flags&=~3;
+         flags&=~2;
        }
 
-      if(flags & 12)
+      /* We do not distinguish between encrypting communications and
+        encrypting storage. */
+      if(flags & (0x04|0x08))
        {
          key_usage |= PUBKEY_USAGE_ENC;
-         flags&=~12;
+         flags&=~(0x04|0x08);
        }
 
       if(flags & 0x20)
@@ -1392,12 +1521,12 @@ fixup_uidnode ( KBNODE uidnode, KBNODE signode, u32 keycreated )
     p = parse_sig_subpkt ( sig->hashed, SIGSUBPKT_PREF_COMPR, &n );
     zip = p; nzip = p?n:0;
     if (uid->prefs) 
-        m_free (uid->prefs);
+        xfree (uid->prefs);
     n = nsym + nhash + nzip;
     if (!n)
         uid->prefs = NULL;
     else {
-        uid->prefs = m_alloc (sizeof (*uid->prefs) * (n+1));
+        uid->prefs = xmalloc (sizeof (*uid->prefs) * (n+1));
         n = 0;
         for (; nsym; nsym--, n++) {
             uid->prefs[n].type = PREFTYPE_SYM;
@@ -1416,16 +1545,16 @@ fixup_uidnode ( KBNODE uidnode, KBNODE signode, u32 keycreated )
     }
 
     /* see whether we have the MDC feature */
-    uid->mdc_feature = 0;
+    uid->flags.mdc = 0;
     p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n);
     if (p && n && (p[0] & 0x01))
-        uid->mdc_feature = 1;
+        uid->flags.mdc = 1;
 
     /* and the keyserver modify flag */
-    uid->ks_modify = 1;
+    uid->flags.ks_modify = 1;
     p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n);
     if (p && n && (p[0] & 0x80))
-        uid->ks_modify = 0;
+        uid->flags.ks_modify = 0;
 }
 
 static void
@@ -1477,7 +1606,7 @@ merge_selfsigs_main(KBNODE keyblock, int *r_revoked, struct revoke_info *rinfo)
      */
 
     /* In case this key was already merged */
-    m_free(pk->revkey);
+    xfree(pk->revkey);
     pk->revkey=NULL;
     pk->numrevkeys=0;
 
@@ -1514,7 +1643,7 @@ merge_selfsigs_main(KBNODE keyblock, int *r_revoked, struct revoke_info *rinfo)
                    int i;
 
                    pk->revkey=
-                     m_realloc(pk->revkey,sizeof(struct revocation_key)*
+                     xrealloc(pk->revkey,sizeof(struct revocation_key)*
                                (pk->numrevkeys+sig->numrevkeys));
 
                    for(i=0;i<sig->numrevkeys;i++)
@@ -1565,7 +1694,7 @@ merge_selfsigs_main(KBNODE keyblock, int *r_revoked, struct revoke_info *rinfo)
          }
 
        if(changed)
-         pk->revkey=m_realloc(pk->revkey,
+         pk->revkey=xrealloc(pk->revkey,
                               pk->numrevkeys*sizeof(struct revocation_key));
       }
 
@@ -1703,7 +1832,7 @@ merge_selfsigs_main(KBNODE keyblock, int *r_revoked, struct revoke_info *rinfo)
                  {
                    PKT_public_key *ultimate_pk;
 
-                   ultimate_pk=m_alloc_clear(sizeof(*ultimate_pk));
+                   ultimate_pk=xmalloc_clear(sizeof(*ultimate_pk));
 
                     /* We don't want to use the full get_pubkey to
                        avoid infinite recursion in certain cases.
@@ -1764,7 +1893,9 @@ merge_selfsigs_main(KBNODE keyblock, int *r_revoked, struct revoke_info *rinfo)
         if ( x ) /* mask it down to the actual allowed usage */
             key_usage &= x; 
     }
-    pk->pubkey_usage = key_usage;
+
+    /* Whatever happens, it's a primary key, so it can certify. */
+    pk->pubkey_usage = key_usage|PUBKEY_USAGE_CERT;
 
     if ( !key_expire_seen ) {
         /* find the latest valid user ID with a key expiration set 
@@ -1995,16 +2126,14 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
 
     subpk->is_valid = 1;
 
-#ifndef DO_BACKSIGS
-    /* Pretend the backsig is present and accounted for. */
-    subpk->backsig=2;
-#else
     /* Find the first 0x19 embedded signature on our self-sig. */
     if(subpk->backsig==0)
       {
        int seq=0;
        size_t n;
 
+       /* 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)))
@@ -2014,7 +2143,8 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
          {
            seq=0;
            /* It is safe to have this in the unhashed area since the
-              0x19 is located here for convenience, not security. */
+              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)))
@@ -2023,7 +2153,7 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
 
        if(p)
          {
-           PKT_signature *backsig=m_alloc_clear(sizeof(PKT_signature));
+           PKT_signature *backsig=xmalloc_clear(sizeof(PKT_signature));
            IOBUF backsig_buf=iobuf_temp_with_content(p,n);
 
            if(parse_signature(backsig_buf,PKT_SIGNATURE,n,backsig)==0)
@@ -2038,7 +2168,6 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
            free_seckey_enc(backsig);
          }
       }
-#endif
 }
 
 
@@ -2124,7 +2253,7 @@ merge_selfsigs( KBNODE keyblock )
            && !k->pkt->pkt.user_id->attrib_data
             && k->pkt->pkt.user_id->is_primary) {
             prefs = k->pkt->pkt.user_id->prefs;
-            mdc_feature = k->pkt->pkt.user_id->mdc_feature;
+            mdc_feature = k->pkt->pkt.user_id->flags.mdc;
             break;
         }
     }    
@@ -2133,7 +2262,7 @@ merge_selfsigs( KBNODE keyblock )
              || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
             PKT_public_key *pk = k->pkt->pkt.public_key;
             if (pk->prefs)
-                m_free (pk->prefs);
+                xfree (pk->prefs);
             pk->prefs = copy_prefs (prefs);
             pk->mdc_feature = mdc_feature;
         }
@@ -2299,7 +2428,7 @@ finish_lookup (GETKEY_CTX ctx)
     KBNODE k;
     KBNODE foundk = NULL;
     PKT_user_id *foundu = NULL;
-#define USAGE_MASK  (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC)
+#define USAGE_MASK  (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC|PUBKEY_USAGE_CERT)
     unsigned int req_usage = ( ctx->req_usage & USAGE_MASK );
     /* Request the primary if we're certifying another key, and also
        if signing data while --pgp6 or --pgp7 is on since pgp 6 and 7
@@ -2464,10 +2593,10 @@ finish_lookup (GETKEY_CTX ctx)
     if (latest_key != keyblock && opt.verbose)
       {
        char *tempkeystr=
-         m_strdup(keystr_from_pk(latest_key->pkt->pkt.public_key));
+         xstrdup(keystr_from_pk(latest_key->pkt->pkt.public_key));
         log_info(_("using subkey %s instead of primary key %s\n"),
                  tempkeystr, keystr_from_pk(keyblock->pkt->pkt.public_key));
-       m_free(tempkeystr);
+       xfree(tempkeystr);
       }
 
     cache_user_id( keyblock );
@@ -2610,7 +2739,7 @@ enum_secret_keys( void **context, PKT_secret_key *sk,
 
 
     if( !c ) { /* make a new context */
-       c = m_alloc_clear( sizeof *c );
+       c = xmalloc_clear( sizeof *c );
        *context = c;
        c->hd = keydb_new (1);
         c->first = 1;
@@ -2621,7 +2750,7 @@ enum_secret_keys( void **context, PKT_secret_key *sk,
     if( !sk ) { /* free the context */
         keydb_release (c->hd);
         release_kbnode (c->keyblock);
-       m_free( c );
+       xfree( c );
        *context = NULL;
        return 0;
     }
@@ -2668,7 +2797,7 @@ enum_secret_keys( void **context, PKT_secret_key *sk,
 
 /****************
  * Return a string with a printable representation of the user_id.
- * this string must be freed by m_free.
+ * this string must be freed by xfree.
  */
 char*
 get_user_id_string( u32 *keyid )
@@ -2686,14 +2815,14 @@ get_user_id_string( u32 *keyid )
            {
              if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] )
                {
-                 p = m_alloc( keystrlen() + 1 + r->len + 1 );
+                 p = xmalloc( keystrlen() + 1 + r->len + 1 );
                  sprintf(p, "%s %.*s", keystr(keyid), r->len, r->name );
                  return p;
                }
            }
         }
     } while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
-  p = m_alloc( keystrlen() + 5 );
+  p = xmalloc( keystrlen() + 5 );
   sprintf(p, "%s [?]", keystr(keyid));
   return p;
 }
@@ -2704,7 +2833,7 @@ get_user_id_string_native ( u32 *keyid )
 {
   char *p = get_user_id_string( keyid );
   char *p2 = utf8_to_native( p, strlen(p), 0 );
-  m_free(p);
+  xfree(p);
   return p2;
 }
 
@@ -2721,7 +2850,7 @@ get_long_user_id_string( u32 *keyid )
             keyid_list_t a;
             for (a=r->keyids; a; a= a->next ) {
                 if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) {
-                    p = m_alloc( r->len + 20 );
+                    p = xmalloc( r->len + 20 );
                     sprintf(p, "%08lX%08lX %.*s",
                             (ulong)keyid[0], (ulong)keyid[1],
                             r->len, r->name );
@@ -2730,7 +2859,7 @@ get_long_user_id_string( u32 *keyid )
             }
         }
     } while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
-    p = m_alloc( 25 );
+    p = xmalloc( 25 );
     sprintf(p, "%08lX%08lX [?]", (ulong)keyid[0], (ulong)keyid[1] );
     return p;
 }
@@ -2748,7 +2877,7 @@ get_user_id( u32 *keyid, size_t *rn )
             keyid_list_t a;
             for (a=r->keyids; a; a= a->next ) {
                 if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) {
-                    p = m_alloc( r->len );
+                    p = xmalloc( r->len );
                     memcpy(p, r->name, r->len );
                     *rn = r->len;
                     return p;
@@ -2756,7 +2885,7 @@ get_user_id( u32 *keyid, size_t *rn )
             }
         }
     } while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
-    p = m_strdup( _("[User ID not found]") );
+    p = xstrdup( _("[User ID not found]") );
     *rn = strlen(p);
     return p;
 }
@@ -2767,7 +2896,7 @@ get_user_id_native( u32 *keyid )
   size_t rn;
   char *p = get_user_id( keyid, &rn );
   char *p2 = utf8_to_native( p, rn, 0 );
-  m_free(p);
+  xfree(p);
   return p2;
 }
 
@@ -2776,3 +2905,85 @@ get_ctx_handle(GETKEY_CTX ctx)
 {
   return ctx->kr_handle;
 }
+
+static void
+free_akl(struct akl *akl)
+{
+  if(akl->spec)
+    free_keyserver_spec(akl->spec);
+
+  xfree(akl);
+}
+
+void
+release_akl(void)
+{
+  while(opt.auto_key_locate)
+    {
+      struct akl *akl2=opt.auto_key_locate;
+      opt.auto_key_locate=opt.auto_key_locate->next;
+      free_akl(akl2);
+    }
+}
+
+int
+parse_auto_key_locate(char *options)
+{
+  char *tok;
+
+  while((tok=optsep(&options)))
+    {
+      struct akl *akl,*last;
+      int dupe=0;
+
+      if(tok[0]=='\0')
+       continue;
+
+      akl=xmalloc_clear(sizeof(*akl));
+
+      if(ascii_strcasecmp(tok,"ldap")==0)
+       akl->type=AKL_LDAP;
+      else if(ascii_strcasecmp(tok,"keyserver")==0)
+       akl->type=AKL_KEYSERVER;
+#ifdef USE_DNS_CERT
+      else if(ascii_strcasecmp(tok,"cert")==0)
+       akl->type=AKL_CERT;
+#endif
+#ifdef USE_DNS_PKA
+      else if(ascii_strcasecmp(tok,"pka")==0)
+       akl->type=AKL_PKA;
+#endif
+      else if((akl->spec=parse_keyserver_uri(tok,1,NULL,0)))
+       akl->type=AKL_SPEC;
+      else
+       {
+         free_akl(akl);
+         return 0;
+       }
+
+      /* We must maintain the order the user gave us */
+      for(last=opt.auto_key_locate;last && last->next;last=last->next)
+       {
+         /* Check for duplicates */
+         if(last && last->type==akl->type
+            && (akl->type!=AKL_SPEC
+                || (akl->type==AKL_SPEC
+                    && strcmp(last->spec->uri,akl->spec->uri)==0)))
+           {
+             dupe=1;
+             free_akl(akl);
+             break;
+           }
+       }
+
+      if(!dupe)
+       {
+         if(last)
+           last->next=akl;
+         else
+           opt.auto_key_locate=akl;
+       }
+    }
+
+  return 1;
+}