ssh: Improve key lookup for many keys.
[gnupg.git] / agent / learncard.c
index 7223850..c60b3f4 100644 (file)
@@ -1,11 +1,11 @@
 /* learncard.c - Handle the LEARN command
- *     Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2002, 2003, 2004, 2009 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,
@@ -14,8 +14,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -33,7 +32,8 @@
 
 /* Structures used by the callback mechanism to convey information
    pertaining to key pairs.  */
-struct keypair_info_s {
+struct keypair_info_s
+{
   struct keypair_info_s *next;
   int no_cert;
   char *id;          /* points into grip */
@@ -44,24 +44,27 @@ struct keypair_info_s {
 };
 typedef struct keypair_info_s *KEYPAIR_INFO;
 
-struct kpinfo_cb_parm_s {
+struct kpinfo_cb_parm_s
+{
+  ctrl_t ctrl;
   int error;
   KEYPAIR_INFO info;
 };
 
 
-
 /* Structures used by the callback mechanism to convey information
    pertaining to certificates.  */
 struct certinfo_s {
   struct certinfo_s *next;
-  int type;  
+  int type;
   int done;
   char id[1];
 };
 typedef struct certinfo_s *CERTINFO;
 
-struct certinfo_cb_parm_s {
+struct certinfo_cb_parm_s
+{
+  ctrl_t ctrl;
   int error;
   CERTINFO info;
 };
@@ -72,12 +75,12 @@ struct certinfo_cb_parm_s {
 struct sinfo_s {
   struct sinfo_s *next;
   char *data;       /* Points into keyword. */
-  char keyword[1];  
+  char keyword[1];
 };
-typedef struct sinfo_s *SINFO;  
+typedef struct sinfo_s *SINFO;
 
 struct sinfo_cb_parm_s {
-  int error;;
+  int error;
   SINFO info;
 };
 
@@ -131,6 +134,11 @@ kpinfo_cb (void *opaque, const char *line)
 
   if (parm->error)
     return; /* no need to gather data after an error coccured */
+
+  if ((parm->error = agent_write_status (parm->ctrl, "PROGRESS",
+                                         "learncard", "k", "0", "0", NULL)))
+    return;
+
   item = xtrycalloc (1, sizeof *item + strlen (line));
   if (!item)
     {
@@ -164,7 +172,7 @@ kpinfo_cb (void *opaque, const char *line)
       return;
     }
   *p = 0; /* ignore trailing stuff */
-  
+
   /* store it */
   item->next = parm->info;
   parm->info = item;
@@ -184,13 +192,17 @@ certinfo_cb (void *opaque, const char *line)
   if (parm->error)
     return; /* no need to gather data after an error coccured */
 
+  if ((parm->error = agent_write_status (parm->ctrl, "PROGRESS",
+                                         "learncard", "c", "0", "0", NULL)))
+    return;
+
   type = strtol (line, &p, 10);
   while (spacep (p))
     p++;
   for (pend = p; *pend && !spacep (pend); pend++)
     ;
   if (p == pend || !*p)
-    { 
+    {
       parm->error = gpg_error (GPG_ERR_INV_RESPONSE);
       return;
     }
@@ -246,13 +258,27 @@ send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context)
   int rc;
   char *derbuf;
   size_t derbuflen;
-  
+
   rc = agent_card_readcert (ctrl, id, &derbuf, &derbuflen);
   if (rc)
     {
-      log_error ("error reading certificate: %s\n",
-                 gpg_strerror (rc));
-      return rc;
+      const char *action;
+
+      switch (gpg_err_code (rc))
+        {
+        case GPG_ERR_INV_ID:
+        case GPG_ERR_NOT_FOUND:
+          action = " - ignored";
+          break;
+        default:
+          action = "";
+          break;
+        }
+      if (opt.verbose || !*action)
+        log_info ("error reading certificate '%s': %s%s\n",
+                  id? id:"?", gpg_strerror (rc), action);
+
+      return *action? 0 : rc;
     }
 
   rc = assuan_send_data (assuan_context, derbuf, derbuflen);
@@ -264,8 +290,8 @@ send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context)
   if (rc)
     {
       log_error ("sending certificate failed: %s\n",
-                 assuan_strerror (rc));
-      return map_assuan_err (rc);
+                 gpg_strerror (rc));
+      return rc;
     }
   return 0;
 }
@@ -276,6 +302,7 @@ int
 agent_handle_learn (ctrl_t ctrl, void *assuan_context)
 {
   int rc;
+
   struct kpinfo_cb_parm_s parm;
   struct certinfo_cb_parm_s cparm;
   struct sinfo_cb_parm_s sparm;
@@ -285,11 +312,13 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
   unsigned char grip[20];
   char *p;
   int i;
-  static int certtype_list[] = { 
+  static int certtype_list[] = {
+    111, /* Root CA */
     101, /* trusted */
     102, /* useful */
     100, /* regular */
-    /* We don't include 110 here because gpgsm can't handle it. */
+    /* We don't include 110 here because gpgsm can't handle that
+       special root CA format. */
     -1 /* end of list */
   };
 
@@ -297,6 +326,8 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
   memset (&parm, 0, sizeof parm);
   memset (&cparm, 0, sizeof cparm);
   memset (&sparm, 0, sizeof sparm);
+  parm.ctrl = ctrl;
+  cparm.ctrl = ctrl;
 
   /* Check whether a card is present and get the serial number */
   rc = agent_card_serialno (ctrl, &serialno);
@@ -313,7 +344,7 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
       log_debug ("agent_card_learn failed: %s\n", gpg_strerror (rc));
       goto leave;
     }
-  
+
   log_info ("card has S/N: %s\n", serialno);
 
   /* Pass on all the collected status information. */
@@ -337,7 +368,7 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
           if (opt.verbose)
             log_info ("          id: %s    (type=%d)\n",
                       citem->id, citem->type);
-          
+
           if (assuan_context)
             {
               rc = send_cert_back (ctrl, citem->id, assuan_context);
@@ -347,7 +378,7 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
             }
         }
     }
-  
+
   for (item = parm.info; item; item = item->next)
     {
       unsigned char *pubkey, *shdkey;
@@ -359,12 +390,18 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
       if (item->no_cert)
         continue; /* No public key yet available. */
 
+      if (assuan_context)
+        {
+          agent_write_status (ctrl, "KEYPAIRINFO",
+                              item->hexgrip, item->id, NULL);
+        }
+
       for (p=item->hexgrip, i=0; i < 20; p += 2, i++)
         grip[i] = xtoi_2 (p);
-      
+
       if (!agent_key_available (grip))
         continue; /* The key is already available. */
-      
+
       /* Unknown key - store it. */
       rc = agent_card_readkey (ctrl, item->id, &pubkey);
       if (rc)
@@ -403,11 +440,11 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
 
       if (opt.verbose)
         log_info ("stored\n");
-      
+
       if (assuan_context)
         {
           CERTINFO citem;
-          
+
           /* only send the certificate if we have not done so before */
           for (citem = cparm.info; citem; citem = citem->next)
             {
@@ -423,7 +460,7 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
         }
     }
 
-  
+
  leave:
   xfree (serialno);
   release_keypair_info (parm.info);
@@ -431,5 +468,3 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
   release_sinfo (sparm.info);
   return rc;
 }
-
-