* main.h, seskey.c (encode_md_value): Modify to allow a q size greater
[gnupg.git] / g10 / getkey.c
index 35e74f1..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.
  *
@@ -905,41 +905,122 @@ get_pubkey_byname (PKT_public_key *pk,
                    KEYDB_HANDLE *ret_kdbhd, int include_unusable )
 {
   int rc;
-  int again = 0;
   STRLIST namelist = NULL;
 
   add_to_strlist( &namelist, name );
- retry:
+
   rc = key_byname( NULL, namelist, pk, NULL, 0,
                    include_unusable, ret_keyblock, ret_kdbhd);
-  if (rc == G10ERR_NO_PUBKEY
-      && !again
-      && (opt.keyserver_options.options&KEYSERVER_AUTO_PKA_RETRIEVE)
-      && is_valid_mailbox (name))
+
+  /* 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 the requested name resembles a valid mailbox and
-         automatic retrieval via PKA records has been enabled, we
-         try to import the key via the URI and try again. */
-      unsigned char fpr[MAX_FINGERPRINT_LEN];
-      char *uri;
-      struct keyserver_spec *spec;
-      
-      uri = get_pka_info (name, fpr);
-      if (uri)
-        {
-          spec = parse_keyserver_uri (uri, 0, NULL, 0);
-          if (spec)
-            {
-              glo_ctrl.in_auto_key_retrieve++;
-              if (!keyserver_import_fprint (fpr, 20, spec))
-                again = 1;
-              glo_ctrl.in_auto_key_retrieve--;
-              free_keyserver_spec (spec);
-            }
-          xfree (uri);
-        }
-      if (again)
-        goto retry;
+      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 );
@@ -1464,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
@@ -1812,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 
@@ -2170,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;
         }
     }    
@@ -2822,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;
+}