[git] GnuPG - branch, master, updated. gnupg-2.1.17-39-g8a41e73

by NIIBE Yutaka cvs at cvs.gnupg.org
Fri Jan 6 01:49:37 CET 2017


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  8a41e73c31adb86d4a7dca4da695e5ad1347811f (commit)
      from  6170eb809033c9d144abf3b1f31f8b936878cdd4 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 8a41e73c31adb86d4a7dca4da695e5ad1347811f
Author: NIIBE Yutaka <gniibe at fsij.org>
Date:   Fri Jan 6 09:14:13 2017 +0900

    scd: Support multiple readers by CCID driver.
    
    * scd/apdu.c (new_reader_slot): Lock is now in apdu_dev_list_start.
    (close_pcsc_reader_direct, close_ccid_reader): RDRNAME is handled...
    (apdu_close_reader): ... by this function now.
    (apdu_prepare_exit): Likewise.
    (open_ccid_reader): Open with dev_list.
    (apdu_dev_list_start, apdu_dev_list_finish): New.
    (apdu_open_one_reader): New.
    (apdu_open_reader): Support multiple readers.
    * scd/app.c (select_application): With SCAN, opening all readers
    available, and register as new APP.
    (app_write_learn_status): app->ref_count == 0 is valid for APP which is
    not yet used.
    (app_list_start, app_list_finish): New.
    * scd/ccid-driver.c (struct ccid_driver_s): Remove RID and BCD_DEVICE.
    Add BAI.
    (parse_ccid_descriptor): BCD_DEVICE is now on the arguments.
    (ccid_dev_scan, ccid_dev_scan_finish): New.
    (ccid_get_BAI, ccid_compare_BAI, ccid_open_usb_reader): New.
    (ccid_open_reader): Support multiple readers.
    (ccid_set_progress_cb, ccid_close_reader): No RID any more.
    --
    
    With this change, multiple readers/tokens are supported by the internal
    CCID driver of GnuPG.  Until the changes of upper layers (scdaemon,
    gpg-agent, and gpg front end), only a single reader is used, though.
    
    Signed-off-by: NIIBE Yutaka <gniibe at fsij.org>

diff --git a/scd/apdu.c b/scd/apdu.c
index d0b75c8..50363ce 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -66,6 +66,13 @@
 #define CCID_DRIVER_INCLUDE_USB_IDS 1
 #include "ccid-driver.h"
 
+struct dev_list {
+  struct ccid_dev_table *ccid_table;
+  const char *portstr;
+  int idx;
+  int idx_max;
+};
+
 /* Due to conflicting use of threading libraries we usually can't link
    against libpcsclite if we are using Pth.  Instead we use a wrapper
    program.  Note that with nPth there is no need for a wrapper. */
@@ -428,7 +435,6 @@ new_reader_slot (void)
 {
   int i, reader = -1;
 
-  npth_mutex_lock (&reader_table_lock);
   for (i=0; i < MAX_READER; i++)
     if (!reader_table[i].used)
       {
@@ -436,7 +442,6 @@ new_reader_slot (void)
         reader_table[reader].used = 1;
         break;
       }
-  npth_mutex_unlock (&reader_table_lock);
 
   if (reader == -1)
     {
@@ -1428,8 +1433,6 @@ static int
 close_pcsc_reader_direct (int slot)
 {
   pcsc_release_context (reader_table[slot].pcsc.context);
-  xfree (reader_table[slot].rdrname);
-  reader_table[slot].rdrname = NULL;
   return 0;
 }
 #endif /*!NEED_PCSC_WRAPPER*/
@@ -2432,7 +2435,6 @@ static int
 close_ccid_reader (int slot)
 {
   ccid_close_reader (reader_table[slot].ccid.handle);
-  reader_table[slot].rdrname = NULL;
   return 0;
 }
 
@@ -2566,7 +2568,7 @@ ccid_pinpad_operation (int slot, int class, int ins, int p0, int p1,
 
 /* Open the reader and try to read an ATR.  */
 static int
-open_ccid_reader (const char *portstr)
+open_ccid_reader (struct dev_list *dl)
 {
   int err;
   int slot;
@@ -2577,8 +2579,8 @@ open_ccid_reader (const char *portstr)
     return -1;
   slotp = reader_table + slot;
 
-  err = ccid_open_reader (&slotp->ccid.handle, portstr,
-                          (const char **)&slotp->rdrname);
+  err = ccid_open_reader (dl->portstr, dl->idx, dl->ccid_table,
+                          &slotp->ccid.handle, &slotp->rdrname);
   if (err)
     {
       slotp->used = 0;
@@ -2611,12 +2613,7 @@ open_ccid_reader (const char *portstr)
   unlock_slot (slot);
   return slot;
 }
-
-
-
 #endif /* HAVE_LIBUSB */
-
-
 

 #ifdef USE_G10CODE_RAPDU
 /*
@@ -2919,63 +2916,80 @@ open_rapdu_reader (int portno,
 /*
        Driver Access
  */
+gpg_error_t
+apdu_dev_list_start (const char *portstr, struct dev_list **l_p)
+{
+  gpg_error_t err;
+  struct dev_list *dl = xtrymalloc (sizeof (struct dev_list));
 
+  *l_p = NULL;
+  if (!dl)
+    return gpg_error_from_syserror ();
 
-/* Open the reader and return an internal slot number or -1 on
-   error. If PORTSTR is NULL we default to a suitable port (for ctAPI:
-   the first USB reader.  For PC/SC the first listed reader). */
-int
-apdu_open_reader (const char *portstr)
-{
-  static int pcsc_api_loaded, ct_api_loaded;
-  int slot;
+  dl->portstr = portstr;
+  dl->idx = 0;
 
-  if (DBG_READER)
-    log_debug ("enter: apdu_open_reader: portstr=%s\n", portstr);
+  npth_mutex_lock (&reader_table_lock);
 
 #ifdef HAVE_LIBUSB
-  if (!opt.disable_ccid)
+  if (opt.disable_ccid)
     {
-      static int once_available;
-      int i;
-      const char *s;
-
-      slot = open_ccid_reader (portstr);
-      if (slot != -1)
-        {
-          once_available = 1;
-          if (DBG_READER)
-            log_debug ("leave: apdu_open_reader => slot=%d [ccid]\n", slot);
-          return slot; /* got one */
-        }
+      dl->ccid_table = NULL;
+      dl->idx_max = 1;
+    }
+  else
+    {
+      err = ccid_dev_scan (&dl->idx_max, &dl->ccid_table);
+      if (err)
+        return err;
 
-      /* If we ever loaded successfully loaded a CCID reader we never
-         want to fallback to another driver.  This solves a problem
-         where ccid was used, the card unplugged and then scdaemon
-         tries to find a new reader and will eventually try PC/SC over
-         and over again.  To reset this flag "gpgconf --kill scdaemon"
-         can be used.  */
-      if (once_available)
+      if (dl->idx_max == 0)
         {
-          if (DBG_READER)
-            log_debug ("leave: apdu_open_reader => slot=-1 (once_avail)\n");
-          return -1;
-        }
-
-      /* If a CCID reader specification has been given, the user does
-         not want a fallback to other drivers. */
-      if (portstr)
-        for (s=portstr, i=0; *s; s++)
-          if (*s == ':' && (++i == 3))
+          /* If a CCID reader specification has been given, the user does
+             not want a fallback to other drivers. */
+          if (portstr && strlen (portstr) > 5 && portstr[4] == ':')
             {
               if (DBG_READER)
                 log_debug ("leave: apdu_open_reader => slot=-1 (no ccid)\n");
-              return -1;
+
+              xfree (dl);
+              npth_mutex_unlock (&reader_table_lock);
+              return gpg_error (GPG_ERR_ENODEV);
             }
+          else
+            dl->idx_max = 1;
+        }
     }
-
+#else
+  dl->ccid_table = NULL;
+  dl->idx_max = 1;
 #endif /* HAVE_LIBUSB */
 
+  *l_p = dl;
+  return 0;
+}
+
+void
+apdu_dev_list_finish (struct dev_list *dl)
+{
+  ccid_dev_scan_finish (dl->ccid_table, dl->idx_max);
+  xfree (dl);
+  npth_mutex_unlock (&reader_table_lock);
+}
+
+
+/* Open the reader and return an internal slot number or -1 on
+   error. If PORTSTR is NULL we default to a suitable port (for ctAPI:
+   the first USB reader.  For PC/SC the first listed reader). */
+static int
+apdu_open_one_reader (const char *portstr)
+{
+  static int pcsc_api_loaded, ct_api_loaded;
+  int slot;
+
+  if (DBG_READER)
+    log_debug ("enter: apdu_open_reader: portstr=%s\n", portstr);
+
   if (opt.ctapi_driver && *opt.ctapi_driver)
     {
       int port = portstr? atoi (portstr) : 32768;
@@ -3005,7 +3019,6 @@ apdu_open_reader (const char *portstr)
       return open_ct_reader (port);
     }
 
-
   /* No ctAPI configured, so lets try the PC/SC API */
   if (!pcsc_api_loaded)
     {
@@ -3099,6 +3112,96 @@ apdu_open_reader (const char *portstr)
   return slot;
 }
 
+int
+apdu_open_reader (struct dev_list *dl)
+{
+  int slot;
+
+  if (dl->ccid_table)
+    { /* CCID readers.  */
+      int readerno;
+
+      /* See whether we want to use the reader ID string or a reader
+         number. A readerno of -1 indicates that the reader ID string is
+         to be used. */
+      if (dl->portstr && strchr (dl->portstr, ':'))
+        readerno = -1; /* We want to use the readerid.  */
+      else if (dl->portstr)
+        {
+          readerno = atoi (dl->portstr);
+          if (readerno < 0)
+            {
+              return -1;
+            }
+        }
+      else
+        readerno = 0;  /* Default. */
+
+      if (readerno > 0)
+        { /* Use single, the specific reader.  */
+          if (readerno >= dl->idx_max)
+            return -1;
+
+          dl->idx = readerno;
+          dl->portstr = NULL;
+          slot = open_ccid_reader (dl);
+          dl->idx = dl->idx_max;
+          if (slot >= 0)
+            return slot;
+          else
+            return -1;
+        }
+
+      while (dl->idx < dl->idx_max)
+        {
+          unsigned int bai = ccid_get_BAI (dl->idx, dl->ccid_table);
+
+          if (DBG_READER)
+            log_debug ("apdu_open_reader: BAI=%x\n", bai);
+
+          /* Check identity by BAI against already opened HANDLEs.  */
+          for (slot = 0; slot < MAX_READER; slot++)
+            if (reader_table[slot].used
+                && ccid_compare_BAI (reader_table[slot].ccid.handle, bai))
+              break;
+
+          if (slot == MAX_READER)
+            { /* Found a new device.  */
+              if (DBG_READER)
+                log_debug ("apdu_open_reader: new device=%x\n", bai);
+
+              slot = open_ccid_reader (dl);
+
+              dl->idx++;
+              if (slot >= 0)
+                return slot;
+              else
+                {
+                  /* Skip this reader.  */
+                  log_error ("ccid open error: skip\n");
+                  continue;
+                }
+            }
+          else
+            dl->idx++;
+        }
+
+      slot = -1;
+    }
+  else
+    { /* PC/SC readers.  */
+      if (dl->idx++ == 0)
+        slot = apdu_open_one_reader (dl->portstr);
+      else
+        slot = -1;
+    }
+
+  if (DBG_READER)
+    log_debug ("leave: apdu_open_reader => slot=%d [ccid]\n", slot);
+
+  return slot;
+}
+
 
 /* Open an remote reader and return an internal slot number or -1 on
    error. This function is an alternative to apdu_open_reader and used
@@ -3177,6 +3280,8 @@ apdu_close_reader (int slot)
         log_debug ("leave: apdu_close_reader => 0x%x (close_reader)\n", sw);
       return sw;
     }
+  xfree (reader_table[slot].rdrname);
+  reader_table[slot].rdrname = NULL;
   reader_table[slot].used = 0;
   if (DBG_READER)
     log_debug ("leave: apdu_close_reader => SW_HOST_NOT_SUPPORTED\n");
@@ -3204,6 +3309,8 @@ apdu_prepare_exit (void)
             apdu_disconnect (slot);
             if (reader_table[slot].close_reader)
               reader_table[slot].close_reader (slot);
+            xfree (reader_table[slot].rdrname);
+            reader_table[slot].rdrname = NULL;
             reader_table[slot].used = 0;
           }
       npth_mutex_unlock (&reader_table_lock);
diff --git a/scd/apdu.h b/scd/apdu.h
index 3021cf7..473def5 100644
--- a/scd/apdu.h
+++ b/scd/apdu.h
@@ -74,6 +74,7 @@ enum {
   SW_HOST_ALREADY_CONNECTED = 0x1000f
 };
 
+struct dev_list;
 
 #define SW_EXACT_LENGTH_P(a) (((a)&~0xff) == SW_EXACT_LENGTH)
 
@@ -86,8 +87,11 @@ enum {
 
 gpg_error_t apdu_init (void);
 
+gpg_error_t apdu_dev_list_start (const char *portstr, struct dev_list **l_p);
+void apdu_dev_list_finish (struct dev_list *l);
+
 /* Note, that apdu_open_reader returns no status word but -1 on error. */
-int apdu_open_reader (const char *portstr);
+int apdu_open_reader (struct dev_list *l);
 int apdu_open_remote_reader (const char *portstr,
                              const unsigned char *cookie, size_t length,
                              int (*readfnc) (void *opaque,
@@ -117,9 +121,9 @@ int apdu_reset (int slot);
 int apdu_get_status (int slot, int hang, unsigned int *status);
 int apdu_check_pinpad (int slot, int command, pininfo_t *pininfo);
 int apdu_pinpad_verify (int slot, int class, int ins, int p0, int p1,
-			pininfo_t *pininfo);
+                        pininfo_t *pininfo);
 int apdu_pinpad_modify (int slot, int class, int ins, int p0, int p1,
-			pininfo_t *pininfo);
+                        pininfo_t *pininfo);
 int apdu_send_simple (int slot, int extended_mode,
                       int class, int ins, int p0, int p1,
                       int lc, const char *data);
diff --git a/scd/app-common.h b/scd/app-common.h
index 781bf46..2371818 100644
--- a/scd/app-common.h
+++ b/scd/app-common.h
@@ -121,6 +121,9 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
 
 
 /*-- app.c --*/
+app_t app_list_start (void);
+void app_list_finish (void);
+
 void app_dump_state (void);
 void application_notify_card_reset (int slot);
 gpg_error_t check_application_conflict (const char *name, app_t app);
diff --git a/scd/app.c b/scd/app.c
index a499724..6db9e27 100644
--- a/scd/app.c
+++ b/scd/app.c
@@ -319,22 +319,30 @@ app_new_register (int slot, ctrl_t ctrl, const char *name)
 gpg_error_t
 select_application (ctrl_t ctrl, const char *name, app_t *r_app, int scan)
 {
-  gpg_error_t err;
+  gpg_error_t err = 0;
   app_t app;
-  int slot;
 
   *r_app = NULL;
 
-  if ((scan && !app_top)
-      /* FIXME: Here, we can change code to support multiple readers.
-         For now, we only open a single reader.
-      */
-      || !app_top)
+  if (scan || !app_top)
     {
-      slot = apdu_open_reader (opt.reader_port);
-      if (slot >= 0)
+      struct dev_list *l;
+
+      err = apdu_dev_list_start (opt.reader_port, &l);
+      if (err)
+        return err;
+
+      while (1)
         {
-          int sw = apdu_connect (slot);
+          int slot;
+          int sw;
+
+          slot = apdu_open_reader (l);
+          if (slot < 0)
+            break;
+
+          err = 0;
+          sw = apdu_connect (slot);
 
           if (sw == SW_HOST_CARD_INACTIVE)
             {
@@ -346,23 +354,17 @@ select_application (ctrl_t ctrl, const char *name, app_t *r_app, int scan)
             err = 0;
           else
             err = gpg_error (GPG_ERR_ENODEV);
+
+          if (!err)
+            err = app_new_register (slot, ctrl, name);
+          else
+            apdu_close_reader (slot);
         }
-      else
-        err = gpg_error (GPG_ERR_ENODEV);
 
-      if (!err)
-        err = app_new_register (slot, ctrl, name);
-      else
-        apdu_close_reader (slot);
+      apdu_dev_list_finish (l);
     }
-  else
-    err = 0;
-
-  if (!err)
-    app = app_top;
-  else
-    app = NULL;
 
+  app = app_top;
   if (app)
     {
       lock_app (app, ctrl);
@@ -552,8 +554,6 @@ app_write_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
 
   if (!app)
     return gpg_error (GPG_ERR_INV_VALUE);
-  if (!app->ref_count)
-    return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
   if (!app->fnc.learn_status)
     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
 
@@ -1071,3 +1071,16 @@ initialize_module_command (void)
 
   return apdu_init ();
 }
+
+app_t
+app_list_start (void)
+{
+  npth_mutex_lock (&app_list_lock);
+  return app_top;
+}
+
+void
+app_list_finish (void)
+{
+  npth_mutex_unlock (&app_list_lock);
+}
diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c
index 6d81122..5e02628 100644
--- a/scd/ccid-driver.c
+++ b/scd/ccid-driver.c
@@ -239,12 +239,11 @@ static struct
 struct ccid_driver_s
 {
   libusb_device_handle *idev;
-  char *rid;
   int dev_fd;  /* -1 for USB transport or file descriptor of the
                    transport device. */
+  unsigned int bai;
   unsigned short id_vendor;
   unsigned short id_product;
-  unsigned short bcd_device;
   int ifc_no;
   int ep_bulk_out;
   int ep_bulk_in;
@@ -744,14 +743,13 @@ prepare_special_transport (ccid_driver_t handle)
    Note, that this code is based on the one in lsusb.c of the
    usb-utils package, I wrote on 2003-09-01. -wk. */
 static int
-parse_ccid_descriptor (ccid_driver_t handle,
+parse_ccid_descriptor (ccid_driver_t handle, unsigned short bcd_device,
                        const unsigned char *buf, size_t buflen)
 {
   unsigned int i;
   unsigned int us;
   int have_t1 = 0, have_tpdu=0;
 
-
   handle->nonnull_nad = 0;
   handle->auto_ifsd = 0;
   handle->max_ifsd = 32;
@@ -761,7 +759,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
   handle->auto_param = 0;
   handle->auto_pps = 0;
   DEBUGOUT_3 ("idVendor: %04X  idProduct: %04X  bcdDevice: %04X\n",
-              handle->id_vendor, handle->id_product, handle->bcd_device);
+              handle->id_vendor, handle->id_product, bcd_device);
   if (buflen < 54 || buf[0] < 54)
     {
       DEBUGOUT ("CCID device descriptor is too short\n");
@@ -964,11 +962,11 @@ parse_ccid_descriptor (ccid_driver_t handle,
   */
   if (handle->id_vendor == VENDOR_SCM
       && handle->max_ifsd > 48
-      && (  (handle->id_product == SCM_SCR331   && handle->bcd_device < 0x0516)
-          ||(handle->id_product == SCM_SCR331DI && handle->bcd_device < 0x0620)
-          ||(handle->id_product == SCM_SCR335   && handle->bcd_device < 0x0514)
-          ||(handle->id_product == SCM_SPR532   && handle->bcd_device < 0x0504)
-          ||(handle->id_product == SCM_SCR3320  && handle->bcd_device < 0x0522)
+      && (  (handle->id_product == SCM_SCR331   && bcd_device < 0x0516)
+          ||(handle->id_product == SCM_SCR331DI && bcd_device < 0x0620)
+          ||(handle->id_product == SCM_SCR335   && bcd_device < 0x0514)
+          ||(handle->id_product == SCM_SPR532   && bcd_device < 0x0504)
+          ||(handle->id_product == SCM_SCR3320  && bcd_device < 0x0522)
           ))
     {
       DEBUGOUT ("enabling workaround for buggy SCM readers\n");
@@ -1534,23 +1532,33 @@ ccid_vendor_specific_init (ccid_driver_t handle)
 }
 
 
-/* Open the reader with the internal number READERNO and return a
-   pointer to be used as handle in HANDLE.  Returns 0 on success. */
-int
-ccid_open_reader (ccid_driver_t *handle, const char *readerid,
-                  const char **rdrname_p)
-{
-  int rc = 0;
-  libusb_device_handle *idev = NULL;
-  int dev_fd = -1;
-  char *rid = NULL;
-  unsigned char *ifcdesc_extra = NULL;
+#define MAX_DEVICE 4 /* See MAX_READER in apdu.c.  */
+
+struct ccid_dev_table {
+  int n;                        /* Index to ccid_usb_dev_list */
+  int transport;
+  int interface_number;
+  int setting_number;
+  unsigned char *ifcdesc_extra;
+  int ep_bulk_out;
+  int ep_bulk_in;
+  int ep_intr;
   size_t ifcdesc_extra_len;
-  int readerno;
-  int ifc_no, set_no, ep_bulk_out, ep_bulk_in, ep_intr;
-  struct libusb_device_descriptor desc;
+};
 
-  *handle = NULL;
+static libusb_device **ccid_usb_dev_list;
+static struct ccid_dev_table ccid_dev_table[MAX_DEVICE];
+
+gpg_error_t
+ccid_dev_scan (int *idx_max_p, struct ccid_dev_table **t_p)
+{
+  ssize_t n;
+  libusb_device *dev;
+  int i;
+  int ifc_no;
+  int set_no;
+  int idx = 0;
+  int err = 0;
 
   if (!initialized_usb)
     {
@@ -1558,122 +1566,379 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid,
       initialized_usb = 1;
     }
 
-  /* See whether we want to use the reader ID string or a reader
-     number. A readerno of -1 indicates that the reader ID string is
-     to be used. */
-  if (readerid && strchr (readerid, ':'))
-    readerno = -1; /* We want to use the readerid.  */
-  else if (readerid)
+  n = libusb_get_device_list (NULL, &ccid_usb_dev_list);
+  for (i = 0; i < n; i++)
+    {
+      struct libusb_config_descriptor *config;
+      struct libusb_device_descriptor desc;
+
+      dev = ccid_usb_dev_list[i];
+
+      if (libusb_get_device_descriptor (dev, &desc))
+        continue;
+
+      if (libusb_get_active_config_descriptor (dev, &config))
+        continue;
+
+      for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++)
+        for (set_no=0; set_no < config->interface[ifc_no].num_altsetting;
+             set_no++)
+          {
+            const struct libusb_interface_descriptor *ifcdesc;
+
+            ifcdesc = &config->interface[ifc_no].altsetting[set_no];
+            /* The second condition is for older SCM SPR 532 who did
+               not know about the assigned CCID class.  The third
+               condition does the same for a Cherry SmartTerminal
+               ST-2000.  Instead of trying to interpret the strings
+               we simply check the product ID. */
+            if (ifcdesc && ifcdesc->extra
+                && ((ifcdesc->bInterfaceClass == 11
+                     && ifcdesc->bInterfaceSubClass == 0
+                     && ifcdesc->bInterfaceProtocol == 0)
+                    || (ifcdesc->bInterfaceClass == 255
+                        && desc.idVendor == VENDOR_SCM
+                        && desc.idProduct == SCM_SPR532)
+                    || (ifcdesc->bInterfaceClass == 255
+                        && desc.idVendor == VENDOR_CHERRY
+                        && desc.idProduct == CHERRY_ST2000)))
+              {
+                /* Found a reader.  */
+                unsigned char *ifcdesc_extra;
+
+                ifcdesc_extra = malloc (ifcdesc->extra_length);
+                if (!ifcdesc_extra)
+                  {
+                    err = gpg_error_from_syserror ();
+                    libusb_free_config_descriptor (config);
+                    goto scan_finish;
+                  }
+                memcpy (ifcdesc_extra, ifcdesc->extra, ifcdesc->extra_length);
+
+                ccid_dev_table[idx].transport = TRANSPORT_USB;
+                ccid_dev_table[idx].n = i;
+                ccid_dev_table[idx].interface_number = ifc_no;
+                ccid_dev_table[idx].setting_number = set_no;
+                ccid_dev_table[idx].ifcdesc_extra = ifcdesc_extra;
+                ccid_dev_table[idx].ifcdesc_extra_len = ifcdesc->extra_length;
+                ccid_dev_table[idx].ep_bulk_out = find_endpoint (ifcdesc, 0);
+                ccid_dev_table[idx].ep_bulk_in = find_endpoint (ifcdesc, 1);
+                ccid_dev_table[idx].ep_intr = find_endpoint (ifcdesc, 2);
+
+                idx++;
+                if (idx >= MAX_DEVICE)
+                  {
+                    libusb_free_config_descriptor (config);
+                    err = 0;
+                    goto scan_finish;
+                  }
+              }
+          }
+
+      libusb_free_config_descriptor (config);
+    }
+
+  /* Now check whether there are any devices with special transport types. */
+  for (i=0; transports[i].name; i++)
     {
-      readerno = atoi (readerid);
-      if (readerno < 0)
+      if (access (transports[i].name, (R_OK|W_OK)) == 0)
         {
-          DEBUGOUT ("no CCID readers found\n");
-          rc = CCID_DRIVER_ERR_NO_READER;
-          goto leave;
+          /* Found a device. */
+          DEBUGOUT_1 ("Found CCID reader %d\n", idx);
+
+          ccid_dev_table[idx].transport = TRANSPORT_CM4040;
+          ccid_dev_table[idx].n = i;
+          ccid_dev_table[idx].interface_number = 0;
+          ccid_dev_table[idx].setting_number = 0;
+          ccid_dev_table[idx].ifcdesc_extra = NULL;
+          ccid_dev_table[idx].ifcdesc_extra_len = 0;
+          ccid_dev_table[idx].ep_bulk_out = 0;
+          ccid_dev_table[idx].ep_bulk_in = 0;
+          ccid_dev_table[idx].ep_intr = 0;
+
+          idx++;
+          if (idx >= MAX_DEVICE)
+            goto scan_finish;
         }
     }
-  else
-    readerno = 0;  /* Default. */
 
-  if (scan_or_find_devices (readerno, readerid, &rid, &desc, &ifcdesc_extra,
-                            &ifcdesc_extra_len, &ifc_no, &set_no, &ep_bulk_out,
-                            &ep_bulk_in, &ep_intr, &idev, &dev_fd))
+ scan_finish:
+
+  if (err)
+    {
+      *idx_max_p = 0;
+      *t_p = NULL;
+      for (i = 0; i < idx; i++)
+        {
+          free (ccid_dev_table[idx].ifcdesc_extra);
+          ccid_dev_table[idx].transport = 0;
+          ccid_dev_table[idx].n = 0;
+          ccid_dev_table[idx].interface_number = 0;
+          ccid_dev_table[idx].setting_number = 0;
+          ccid_dev_table[idx].ifcdesc_extra = NULL;
+          ccid_dev_table[idx].ifcdesc_extra_len = 0;
+          ccid_dev_table[idx].ep_bulk_out = 0;
+          ccid_dev_table[idx].ep_bulk_in = 0;
+          ccid_dev_table[idx].ep_intr = 0;
+        }
+      libusb_free_device_list (ccid_usb_dev_list, 1);
+      ccid_usb_dev_list = NULL;
+    }
+  else
     {
-      if (readerno == -1)
-        DEBUGOUT_1 ("no CCID reader with ID %s\n", readerid );
+      *idx_max_p = idx;
+      if (idx)
+        *t_p = ccid_dev_table;
       else
-        DEBUGOUT_1 ("no CCID reader with number %d\n", readerno );
-      rc = CCID_DRIVER_ERR_NO_READER;
-      goto leave;
+        *t_p = NULL;
     }
 
-  /* Okay, this is a CCID reader. */
-  *handle = calloc (1, sizeof **handle);
-  if (!*handle)
+  return err;
+}
+
+void
+ccid_dev_scan_finish (struct ccid_dev_table *tbl, int max)
+{
+  int i;
+
+  for (i = 0; i < max; i++)
     {
-      DEBUGOUT ("out of memory\n");
-      rc = CCID_DRIVER_ERR_OUT_OF_CORE;
-      goto leave;
+      free (tbl[i].ifcdesc_extra);
+      tbl[i].transport = 0;
+      tbl[i].n = 0;
+      tbl[i].interface_number = 0;
+      tbl[i].setting_number = 0;
+      tbl[i].ifcdesc_extra = NULL;
+      tbl[i].ifcdesc_extra_len = 0;
+      tbl[i].ep_bulk_out = 0;
+      tbl[i].ep_bulk_in = 0;
+      tbl[i].ep_intr = 0;
     }
-  (*handle)->rid = rid;
-  if (idev) /* Regular USB transport. */
+  libusb_free_device_list (ccid_usb_dev_list, 1);
+  ccid_usb_dev_list = NULL;
+}
+
+unsigned int
+ccid_get_BAI (int idx, struct ccid_dev_table *tbl)
+{
+  int n;
+  int bus, addr, intf;
+  unsigned int bai;
+
+  if (tbl[idx].transport == TRANSPORT_USB)
     {
-      (*handle)->idev = idev;
-      (*handle)->dev_fd = -1;
-      (*handle)->id_vendor = desc.idVendor;
-      (*handle)->id_product = desc.idProduct;
-      (*handle)->bcd_device = desc.bcdDevice;
-      (*handle)->ifc_no = ifc_no;
-      (*handle)->ep_bulk_out = ep_bulk_out;
-      (*handle)->ep_bulk_in = ep_bulk_in;
-      (*handle)->ep_intr = ep_intr;
+      libusb_device *dev;
+
+      n = tbl[idx].n;
+      dev = ccid_usb_dev_list[n];
+
+      bus = libusb_get_bus_number (dev);
+      addr = libusb_get_device_address (dev);
+      intf = tbl[idx].interface_number;
+      bai = (bus << 16) | (addr << 8) | intf;
     }
-  else if (dev_fd != -1) /* Device transport. */
+  else
     {
-      (*handle)->idev = NULL;
-      (*handle)->dev_fd = dev_fd;
-      (*handle)->id_vendor = 0;  /* Magic vendor for special transport. */
-      (*handle)->id_product = ifc_no; /* Transport type */
-      prepare_special_transport (*handle);
+      n = tbl[idx].n;
+      bai = 0xFFFF0000 | n;
     }
-  else
+
+  return bai;
+}
+
+int
+ccid_compare_BAI (ccid_driver_t handle, unsigned int bai)
+{
+  return handle->bai == bai;
+}
+
+static int
+ccid_open_usb_reader (const char *spec_reader_name,
+                      int idx, struct ccid_dev_table *ccid_table,
+                      ccid_driver_t *handle, char **rdrname_p)
+{
+  libusb_device *dev;
+  libusb_device_handle *idev = NULL;
+  char *rid;
+  int rc = 0;
+  int ifc_no, set_no;
+  struct libusb_device_descriptor desc;
+  int n;
+  int bus, addr;
+  unsigned int bai;
+
+  n = ccid_table[idx].n;
+  ifc_no = ccid_table[idx].interface_number;
+  set_no = ccid_table[idx].setting_number;
+
+  dev = ccid_usb_dev_list[n];
+  bus = libusb_get_bus_number (dev);
+  addr = libusb_get_device_address (dev);
+  bai = (bus << 16) | (addr << 8) | ifc_no;
+
+  rc = libusb_open (dev, &idev);
+  if (rc)
     {
-      assert (!"no transport"); /* Bug. */
+      DEBUGOUT_1 ("usb_open failed: %s\n", libusb_error_name (rc));
+      free (*handle);
+      *handle = NULL;
+      return rc;
     }
 
-  DEBUGOUT_2 ("using CCID reader %d (ID=%s)\n",  readerno, rid );
+  rc = libusb_get_device_descriptor (dev, &desc);
+  if (rc)
+    {
+      libusb_close (idev);
+      free (*handle);
+      *handle = NULL;
+      return rc;
+    }
 
-  if (idev)
+  rid = make_reader_id (idev, desc.idVendor, desc.idProduct,
+                        desc.iSerialNumber);
+
+  /* Check to see if reader name matches the spec.  */
+  if (spec_reader_name
+      && strncmp (rid, spec_reader_name, strlen (spec_reader_name)))
     {
-      if (parse_ccid_descriptor (*handle, ifcdesc_extra, ifcdesc_extra_len))
-        {
-          DEBUGOUT ("device not supported\n");
-          rc = CCID_DRIVER_ERR_NO_READER;
-          goto leave;
-        }
+      DEBUGOUT ("device not matched\n");
+      rc = CCID_DRIVER_ERR_NO_READER;
+      goto leave;
+    }
 
-      rc = libusb_claim_interface (idev, ifc_no);
+  (*handle)->id_vendor = desc.idVendor;
+  (*handle)->id_product = desc.idProduct;
+  (*handle)->idev = idev;
+  (*handle)->dev_fd = -1;
+  (*handle)->bai = bai;
+  (*handle)->ifc_no = ifc_no;
+  (*handle)->ep_bulk_out = ccid_table[idx].ep_bulk_out;
+  (*handle)->ep_bulk_in = ccid_table[idx].ep_bulk_in;
+  (*handle)->ep_intr = ccid_table[idx].ep_intr;
+
+  DEBUGOUT_2 ("using CCID reader %d (ID=%s)\n", idx, rid);
+
+  if (parse_ccid_descriptor (*handle, desc.bcdDevice,
+                             ccid_table[idx].ifcdesc_extra,
+                             ccid_table[idx].ifcdesc_extra_len))
+    {
+      DEBUGOUT ("device not supported\n");
+      rc = CCID_DRIVER_ERR_NO_READER;
+      goto leave;
+    }
+
+  rc = libusb_claim_interface (idev, ifc_no);
+  if (rc)
+    {
+      DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
+      rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
+      goto leave;
+    }
+
+  if (set_no != 0)
+    {
+      rc = libusb_set_interface_alt_setting (idev, ifc_no, set_no);
       if (rc)
         {
-          DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
+          DEBUGOUT_1 ("usb_set_interface_alt_setting failed: %d\n", rc);
           rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
           goto leave;
         }
-
-      if (set_no != 0)
-        {
-          rc = libusb_set_interface_alt_setting (idev, ifc_no, set_no);
-          if (rc)
-            {
-              DEBUGOUT_1 ("usb_set_interface_alt_setting failed: %d\n", rc);
-              rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
-              goto leave;
-            }
-        }
     }
 
   rc = ccid_vendor_specific_init (*handle);
 
  leave:
-  free (ifcdesc_extra);
   if (rc)
     {
       free (rid);
-      if (idev)
-        libusb_close (idev);
-      if (dev_fd != -1)
-        close (dev_fd);
+      libusb_close (idev);
       free (*handle);
       *handle = NULL;
     }
   else
-    if (rdrname_p)
-      *rdrname_p = (*handle)->rid;
+    {
+      if (rdrname_p)
+        *rdrname_p = rid;
+      else
+        free (rid);
+    }
 
   return rc;
 }
 
+/* Open the reader with the internal number READERNO and return a
+   pointer to be used as handle in HANDLE.  Returns 0 on success. */
+int
+ccid_open_reader (const char *spec_reader_name,
+                  int idx, struct ccid_dev_table *ccid_table,
+                  ccid_driver_t *handle, char **rdrname_p)
+{
+  int n;
+  int fd;
+  char *rid;
+
+  *handle = calloc (1, sizeof **handle);
+  if (!*handle)
+    {
+      DEBUGOUT ("out of memory\n");
+      return CCID_DRIVER_ERR_OUT_OF_CORE;
+    }
+
+  if (ccid_table[idx].transport == TRANSPORT_USB)
+    return ccid_open_usb_reader (spec_reader_name, idx, ccid_table,
+                                 handle, rdrname_p);
+
+  /* Special transport support.  */
+
+  n = ccid_table[idx].n;
+  fd = open (transports[n].name, O_RDWR);
+  if (fd < 0)
+    {
+      DEBUGOUT_2 ("failed to open '%s': %s\n",
+                  transports[n].name, strerror (errno));
+      free (*handle);
+      *handle = NULL;
+      return -1;
+    }
+
+  rid = malloc (strlen (transports[n].name) + 30 + 10);
+  if (!rid)
+    {
+      close (fd);
+      free (*handle);
+      *handle = NULL;
+      return -1; /* Error. */
+    }
+
+  sprintf (rid, "0000:%04X:%s:0", transports[n].type, transports[n].name);
+
+  /* Check to see if reader name matches the spec.  */
+  if (spec_reader_name
+      && strncmp (rid, spec_reader_name, strlen (spec_reader_name)))
+    {
+      DEBUGOUT ("device not matched\n");
+      free (rid);
+      close (fd);
+      free (*handle);
+      *handle = NULL;
+      return -1;
+    }
+
+  (*handle)->id_vendor = 0;
+  (*handle)->id_product = transports[n].type;
+  (*handle)->idev = NULL;
+  (*handle)->dev_fd = fd;
+  (*handle)->bai = 0xFFFF0000 | n;
+  prepare_special_transport (*handle);
+  if (rdrname_p)
+    *rdrname_p = rid;
+  else
+    free (rid);
+
+  return 0;
+}
+
 
 static void
 do_close_reader (ccid_driver_t handle)
@@ -1719,7 +1984,7 @@ ccid_set_progress_cb (ccid_driver_t handle,
                       void (*cb)(void *, const char *, int, int, int),
                       void *cb_arg)
 {
-  if (!handle || !handle->rid)
+  if (!handle)
     return CCID_DRIVER_ERR_INV_VALUE;
 
   handle->progress_cb = cb;
@@ -1736,7 +2001,6 @@ ccid_close_reader (ccid_driver_t handle)
     return 0;
 
   do_close_reader (handle);
-  free (handle->rid);
   free (handle);
   return 0;
 }
diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h
index e3aed9f..9e71f5e 100644
--- a/scd/ccid-driver.h
+++ b/scd/ccid-driver.h
@@ -1,5 +1,5 @@
-/* ccid-driver.c - USB ChipCardInterfaceDevices driver
- *	Copyright (C) 2003 Free Software Foundation, Inc.
+/* ccid-driver.h - USB ChipCardInterfaceDevices driver
+ * Copyright (C) 2003 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -109,10 +109,18 @@ enum {
 struct ccid_driver_s;
 typedef struct ccid_driver_s *ccid_driver_t;
 
+struct ccid_dev_table;
+
 int ccid_set_debug_level (int level);
 char *ccid_get_reader_list (void);
-int ccid_open_reader (ccid_driver_t *handle, const char *readerid,
-                      const char **rdrname_p);
+
+gpg_error_t ccid_dev_scan (int *idx_max, struct ccid_dev_table **t_p);
+void ccid_dev_scan_finish (struct ccid_dev_table *tbl, int max);
+unsigned int ccid_get_BAI (int, struct ccid_dev_table *tbl);
+int ccid_compare_BAI (ccid_driver_t handle, unsigned int);
+int ccid_open_reader (const char *spec_reader_name,
+                      int idx, struct ccid_dev_table *ccid_table,
+                      ccid_driver_t *handle, char **rdrname_p);
 int ccid_set_progress_cb (ccid_driver_t handle,
                           void (*cb)(void *, const char *, int, int, int),
                           void *cb_arg);
@@ -126,7 +134,7 @@ int ccid_transceive (ccid_driver_t handle,
                      unsigned char *resp, size_t maxresplen, size_t *nresp);
 int ccid_transceive_secure (ccid_driver_t handle,
                      const unsigned char *apdu, size_t apdulen,
-		     pininfo_t *pininfo,
+                     pininfo_t *pininfo,
                      unsigned char *resp, size_t maxresplen, size_t *nresp);
 int ccid_transceive_escape (ccid_driver_t handle,
                             const unsigned char *data, size_t datalen,

-----------------------------------------------------------------------

Summary of changes:
 scd/apdu.c        | 219 ++++++++++++++++++-------
 scd/apdu.h        |  10 +-
 scd/app-common.h  |   3 +
 scd/app.c         |  63 +++++---
 scd/ccid-driver.c | 466 ++++++++++++++++++++++++++++++++++++++++++------------
 scd/ccid-driver.h |  18 ++-
 6 files changed, 589 insertions(+), 190 deletions(-)


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list