agent: Send back all public keys for available cards.
authorNIIBE Yutaka <gniibe@fsij.org>
Fri, 17 Feb 2017 10:39:28 +0000 (19:39 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Fri, 17 Feb 2017 10:46:01 +0000 (19:46 +0900)
* agent/call-scd.c (card_cardlist_cb, agent_card_cardlist): New.
* agent/command-ssh.c (card_key_list): New.
(ssh_handler_request_identities): Call card_key_list and loop for the
list to send public keys for all available cards.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
agent/agent.h
agent/call-scd.c
agent/command-ssh.c

index 2178384..2a722fd 100644 (file)
@@ -556,6 +556,7 @@ int agent_card_writekey (ctrl_t ctrl, int force, const char *serialno,
                          int (*getpin_cb)(void *, const char *, char*, size_t),
                          void *getpin_cb_arg);
 gpg_error_t agent_card_getattr (ctrl_t ctrl, const char *name, char **result);
+gpg_error_t agent_card_cardlist (ctrl_t ctrl, strlist_t *result);
 int agent_card_scd (ctrl_t ctrl, const char *cmdline,
                     int (*getpin_cb)(void *, const char *, char*, size_t),
                     void *getpin_cb_arg, void *assuan_context);
index 15a2ba5..71e0f58 100644 (file)
@@ -39,6 +39,7 @@
 
 #include "agent.h"
 #include <assuan.h>
+#include "strlist.h"
 
 #ifdef _POSIX_OPEN_MAX
 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
@@ -1189,9 +1190,74 @@ agent_card_getattr (ctrl_t ctrl, const char *name, char **result)
 
   return unlock_scd (ctrl, err);
 }
+\f
+struct card_cardlist_parm_s {
+  int error;
+  strlist_t list;
+};
 
+/* Callback function for agent_card_cardlist.  */
+static gpg_error_t
+card_cardlist_cb (void *opaque, const char *line)
+{
+  struct card_cardlist_parm_s *parm = opaque;
+  const char *keyword = line;
+  int keywordlen;
 
+  for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
+    ;
+  while (spacep (line))
+    line++;
 
+  if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
+    {
+      const char *s;
+      int n;
+
+      for (n=0,s=line; hexdigitp (s); s++, n++)
+        ;
+
+      if (!n || (n&1) || *s)
+        parm->error = gpg_error (GPG_ERR_ASS_PARAMETER);
+      else
+        add_to_strlist (&parm->list, line);
+    }
+
+  return 0;
+}
+
+/* Call the scdaemon to retrieve list of available cards. On success
+   the allocated strlist is stored at RESULT.  On error an error code is
+   returned and NULL stored at RESULT. */
+gpg_error_t
+agent_card_cardlist (ctrl_t ctrl, strlist_t *result)
+{
+  int err;
+  struct card_cardlist_parm_s parm;
+  char line[ASSUAN_LINELENGTH];
+
+  *result = NULL;
+
+  memset (&parm, 0, sizeof parm);
+  strcpy (line, "GETINFO card_list");
+
+  err = start_scd (ctrl);
+  if (err)
+    return err;
+
+  err = assuan_transact (ctrl->scd_local->ctx, line,
+                         NULL, NULL, NULL, NULL,
+                         card_cardlist_cb, &parm);
+  if (!err && parm.error)
+    err = parm.error;
+
+  if (!err)
+    *result = parm.list;
+  else
+    free_strlist (parm.list);
+
+  return unlock_scd (ctrl, err);
+}
 \f
 static gpg_error_t
 pass_status_thru (void *opaque, const char *line)
index 1d4453c..2c74618 100644 (file)
@@ -2382,6 +2382,29 @@ ssh_key_grip (gcry_sexp_t key, unsigned char *buffer)
 }
 
 
+static gpg_error_t
+card_key_list (ctrl_t ctrl, char **r_serialno, strlist_t *result)
+{
+  gpg_error_t err;
+
+  err = agent_card_serialno (ctrl, r_serialno, NULL);
+  if (err)
+    {
+      if (opt.verbose)
+        log_info (_("error getting serial number of card: %s\n"),
+                  gpg_strerror (err));
+      return err;
+    }
+
+  err = agent_card_cardlist (ctrl, result);
+  if (err)
+    {
+      xfree (*r_serialno);
+      *r_serialno = NULL;
+    }
+  return err;
+}
+
 /* Check whether a smartcard is available and whether it has a usable
    key.  Store a copy of that key at R_PK and return 0.  If no key is
    available store NULL at R_PK and return an error code.  If CARDSN
@@ -2561,17 +2584,54 @@ ssh_handler_request_identities (ctrl_t ctrl,
      reader - this should be allowed even without being listed in
      sshcontrol. */
 
-  if (!opt.disable_scdaemon
-      && !card_key_available (ctrl, &key_public, &cardsn))
+  if (!opt.disable_scdaemon)
     {
-      err = ssh_send_key_public (key_blobs, key_public, cardsn);
-      gcry_sexp_release (key_public);
-      key_public = NULL;
-      xfree (cardsn);
+      char *serialno;
+      strlist_t card_list, sl;
+
+      err = card_key_list (ctrl, &serialno, &card_list);
       if (err)
-        goto out;
+        {
+          if (opt.verbose)
+            log_info (_("error getting list of cards: %s\n"),
+                      gpg_strerror (err));
+          goto out;
+        }
 
-      key_counter++;
+      for (sl = card_list; sl; sl = sl->next)
+        {
+          char *serialno0;
+          err = agent_card_serialno (ctrl, &serialno0, sl->d);
+          if (err)
+            {
+              if (opt.verbose)
+                log_info (_("error getting serial number of card: %s\n"),
+                          gpg_strerror (err));
+              xfree (serialno);
+              free_strlist (card_list);
+              goto out;
+            }
+
+          xfree (serialno0);
+          if (card_key_available (ctrl, &key_public, &cardsn))
+            continue;
+
+          err = ssh_send_key_public (key_blobs, key_public, cardsn);
+          gcry_sexp_release (key_public);
+          key_public = NULL;
+          xfree (cardsn);
+          if (err)
+            {
+              xfree (serialno);
+              free_strlist (card_list);
+              goto out;
+            }
+
+          key_counter++;
+        }
+
+      xfree (serialno);
+      free_strlist (card_list);
     }
 
   /* Then look at all the registered and non-disabled keys. */