[svn] GnuPG - r4906 - in trunk: agent po scd

svn author wk cvs at cvs.gnupg.org
Thu Dec 18 17:34:32 CET 2008


Author: wk
Date: 2008-12-18 17:34:28 +0100 (Thu, 18 Dec 2008)
New Revision: 4906

Modified:
   trunk/agent/gpg-agent.c
   trunk/po/be.po
   trunk/po/ca.po
   trunk/po/cs.po
   trunk/po/da.po
   trunk/po/de.po
   trunk/po/el.po
   trunk/po/eo.po
   trunk/po/es.po
   trunk/po/et.po
   trunk/po/fi.po
   trunk/po/fr.po
   trunk/po/gl.po
   trunk/po/hu.po
   trunk/po/id.po
   trunk/po/it.po
   trunk/po/ja.po
   trunk/po/nb.po
   trunk/po/pl.po
   trunk/po/pt.po
   trunk/po/pt_BR.po
   trunk/po/ro.po
   trunk/po/ru.po
   trunk/po/sk.po
   trunk/po/sv.po
   trunk/po/tr.po
   trunk/po/zh_CN.po
   trunk/po/zh_TW.po
   trunk/scd/ChangeLog
   trunk/scd/apdu.c
   trunk/scd/ccid-driver.c
   trunk/scd/command.c
Log:
Fixed some card related problems.


Modified: trunk/scd/ChangeLog
===================================================================
--- trunk/scd/ChangeLog	2008-12-17 19:42:17 UTC (rev 4905)
+++ trunk/scd/ChangeLog	2008-12-18 16:34:28 UTC (rev 4906)
@@ -1,3 +1,17 @@
+2008-12-18  Werner Koch  <wk at g10code.com>
+
+	* ccid-driver.c (abort_cmd): New. 
+	(bulk_in): Call abort_cmd after severe errors.
+
+	* apdu.c (reader_table_s): Add field ANY_STATUS.
+	(new_reader_slot): Clear it.
+	(apdu_get_status): Use ANY_STATUS to update the change counter.
+	Remove the use of the flag bit from LAST_STATUS everywhere.
+	* command.c (update_reader_status_file): Factor code out to ...
+	(send_client_notifications): New.  Track signals already sent.
+	(update_reader_status_file): Shutdown the reader  after a failed
+	apdu_get_status.
+
 2008-12-09  Werner Koch  <wk at g10code.com>
 
 	* scdaemon.c (main): Call i18n_init before init_common_subsystems.

Modified: trunk/agent/gpg-agent.c
===================================================================
--- trunk/agent/gpg-agent.c	2008-12-17 19:42:17 UTC (rev 4905)
+++ trunk/agent/gpg-agent.c	2008-12-18 16:34:28 UTC (rev 4906)
@@ -1602,7 +1602,7 @@
 agent_sigusr2_action (void)
 {
   if (opt.verbose)
-    log_info ("SIGUSR2 received - checking smartcard status\n");
+    log_info ("SIGUSR2 received - updating card event counter\n");
   /* Nothing to check right now.  We only increment a counter.  */
   bump_card_eventcounter ();
 }

Modified: trunk/po/be.po  [not shown]
Modified: trunk/po/ca.po  [not shown]
Modified: trunk/po/cs.po  [not shown]
Modified: trunk/po/da.po  [not shown]
Modified: trunk/po/de.po  [not shown]
Modified: trunk/po/el.po  [not shown]
Modified: trunk/po/eo.po  [not shown]
Modified: trunk/po/es.po  [not shown]
Modified: trunk/po/et.po  [not shown]
Modified: trunk/po/fi.po  [not shown]
Modified: trunk/po/fr.po  [not shown]
Modified: trunk/po/gl.po  [not shown]
Modified: trunk/po/hu.po  [not shown]
Modified: trunk/po/id.po  [not shown]
Modified: trunk/po/it.po  [not shown]
Modified: trunk/po/ja.po  [not shown]
Modified: trunk/po/nb.po  [not shown]
Modified: trunk/po/pl.po  [not shown]
Modified: trunk/po/pt.po  [not shown]
Modified: trunk/po/pt_BR.po  [not shown]
Modified: trunk/po/ro.po  [not shown]
Modified: trunk/po/ru.po  [not shown]
Modified: trunk/po/sk.po  [not shown]
Modified: trunk/po/sv.po  [not shown]
Modified: trunk/po/tr.po  [not shown]
Modified: trunk/po/zh_CN.po  [not shown]
Modified: trunk/po/zh_TW.po  [not shown]
Modified: trunk/scd/apdu.c
===================================================================
--- trunk/scd/apdu.c	2008-12-17 19:42:17 UTC (rev 4905)
+++ trunk/scd/apdu.c	2008-12-18 16:34:28 UTC (rev 4906)
@@ -133,6 +133,7 @@
   } rapdu;
 #endif /*USE_G10CODE_RAPDU*/
   char *rdrname;     /* Name of the connected reader or NULL if unknown. */
+  int any_status;    /* True if we have seen any status.  */
   int last_status;
   int status;
   int is_t0;         /* True if we know that we are running T=0. */
@@ -340,7 +341,8 @@
   reader_table[reader].check_keypad = NULL;
   reader_table[reader].dump_status_reader = NULL;
 
-  reader_table[reader].used = 1;
+  reader_table[reader].used = 1;  
+  reader_table[reader].any_status = 0;
   reader_table[reader].last_status = 0;
   reader_table[reader].is_t0 = 1;
 #ifdef NEED_PCSC_WRAPPER
@@ -1289,8 +1291,7 @@
              and usable.  Remember this.  */
           reader_table[slot].last_status = (   APDU_CARD_USABLE
                                              | APDU_CARD_PRESENT
-                                             | APDU_CARD_ACTIVE
-                                             | 0x8000);
+                                             | APDU_CARD_ACTIVE);
           reader_table[slot].is_t0 = !!(card_protocol & PCSC_PROTOCOL_T0);
         }
     }
@@ -1743,8 +1744,7 @@
          and usable.  Thus remember this.  */
       slotp->last_status = (  APDU_CARD_USABLE
                             | APDU_CARD_PRESENT
-                            | APDU_CARD_ACTIVE
-                            | 0x8000);
+                            | APDU_CARD_ACTIVE);
     }
   slotp->atrlen = len;
 
@@ -1947,8 +1947,7 @@
          and usable.  Thus remember this.  */
       reader_table[slot].last_status = (APDU_CARD_USABLE
                                         | APDU_CARD_PRESENT
-                                        | APDU_CARD_ACTIVE 
-                                        | 0x8000);
+                                        | APDU_CARD_ACTIVE);
     }
 
   reader_table[slot].close_reader = close_ccid_reader;
@@ -2615,8 +2614,7 @@
          and usable.  Thus remember this.  */
       reader_table[slot].last_status = (APDU_CARD_USABLE
                                         | APDU_CARD_PRESENT
-                                        | APDU_CARD_ACTIVE 
-                                        | 0x8000);
+                                        | APDU_CARD_ACTIVE);
     }
 
   unlock_slot (slot);
@@ -2662,8 +2660,7 @@
                      and usable.  Thus remember this.  */
                   reader_table[slot].last_status = (APDU_CARD_USABLE
                                                     | APDU_CARD_PRESENT
-                                                    | APDU_CARD_ACTIVE
-                                                    | 0x8000);
+                                                    | APDU_CARD_ACTIVE);
                 }
             }
         }
@@ -2733,17 +2730,16 @@
       return sw;
     }
 
-  /* Keep track of changes.  We use one extra bit to test whether we
-     have checked the status at least once. */
-  if ( s != (reader_table[slot].last_status & 0x07ff)
-       || !reader_table[slot].last_status )
+  /* Keep track of changes.  */
+  if (s != reader_table[slot].last_status
+      || !reader_table[slot].any_status )
     {
       reader_table[slot].change_counter++;
       /* Make sure that the ATR is invalid so that a reset will be by
          activate.  */
       reader_table[slot].atrlen = 0;
     }
-  reader_table[slot].last_status = (s | 0x8000);
+  reader_table[slot].any_status = 1;
 
   if (status)
     *status = s;

Modified: trunk/scd/ccid-driver.c
===================================================================
--- trunk/scd/ccid-driver.c	2008-12-17 19:42:17 UTC (rev 4905)
+++ trunk/scd/ccid-driver.c	2008-12-18 16:34:28 UTC (rev 4906)
@@ -1,5 +1,6 @@
 /* ccid-driver.c - USB ChipCardInterfaceDevices driver
- * Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007
+ *               2008  Free Software Foundation, Inc.
  * Written by Werner Koch.
  *
  * This file is part of GnuPG.
@@ -262,6 +263,7 @@
 static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
                     size_t *nread, int expected_type, int seqno, int timeout,
                     int no_debug);
+static int abort_cmd (ccid_driver_t handle);
 
 /* Convert a little endian stored 4 byte value into an unsigned
    integer. */
@@ -1069,7 +1071,10 @@
 /* Set the level of debugging to LEVEL and return the old level.  -1
    just returns the old level.  A level of 0 disables debugging, 1
    enables debugging, 2 enables additional tracing of the T=1
-   protocol, other values are not yet defined. */
+   protocol, other values are not yet defined.
+
+   Note that libusb may provide its own debugging feature which is
+   enabled by setting the envvar USB_DEBUG.  */
 int
 ccid_set_debug_level (int level)
 {
@@ -1395,7 +1400,7 @@
       rc = usb_bulk_write (handle->idev, 
                            handle->ep_bulk_out,
                            (char*)msg, msglen,
-                           1000 /* ms timeout */);
+                           5000 /* ms timeout */);
       if (rc == msglen)
         return 0;
       if (rc == -1)
@@ -1463,17 +1468,20 @@
   if (msglen < 10)
     {
       DEBUGOUT_1 ("bulk-in msg too short (%u)\n", (unsigned int)msglen);
+      abort_cmd (handle);
       return CCID_DRIVER_ERR_INV_VALUE;
     }
   if (buffer[5] != 0)    
     {
       DEBUGOUT_1 ("unexpected bulk-in slot (%d)\n", buffer[5]);
+      abort_cmd (handle);
       return CCID_DRIVER_ERR_INV_VALUE;
     }
   if (buffer[6] != seqno)    
     {
       DEBUGOUT_2 ("bulk-in seqno does not match (%d/%d)\n",
                   seqno, buffer[6]);
+      abort_cmd (handle);
       return CCID_DRIVER_ERR_INV_VALUE;
     }
 
@@ -1492,6 +1500,7 @@
   if (buffer[0] != expected_type)
     {
       DEBUGOUT_1 ("unexpected bulk-in msg type (%02x)\n", buffer[0]);
+      abort_cmd (handle);
       return CCID_DRIVER_ERR_INV_VALUE;
     }
 
@@ -1521,6 +1530,113 @@
 }
 
 
+
+/* Send an abort sequence and wait until everything settled.  */
+static int
+abort_cmd (ccid_driver_t handle)
+{
+  int rc;
+  char dummybuf[8];
+  unsigned char seqno;
+  unsigned char msg[100];
+  size_t msglen;
+  int i;
+
+  if (!handle->idev)
+    {
+      /* I don't know how to send an abort to non-USB devices.  */
+      rc = CCID_DRIVER_ERR_NOT_SUPPORTED;
+    }
+  
+  DEBUGOUT ("sending abort sequence\n");
+  /* Send the abort command to the control pipe.  Note that we don't
+     need to keep track of sent abort commands because there should
+     never be another thread using the same slot concurrently.  */
+  seqno = (handle->seqno & 0xff);
+  rc = usb_control_msg (handle->idev, 
+                        0x21,/* bmRequestType: host-to-device,
+                                class specific, to interface.  */
+                        1,   /* ABORT */
+                        (seqno << 8 | 0 /* slot */),
+                        handle->ifc_no,
+                        dummybuf, 0,
+                        1000 /* ms timeout */);
+  if (rc < 0)
+    {
+      DEBUGOUT_1 ("usb_control_msg error: %s\n", strerror (errno));
+      return CCID_DRIVER_ERR_CARD_IO_ERROR;
+    }
+
+  /* Now send the abort command to the bulk out pipe using the same
+     SEQNO and SLOT. */
+  msg[0] = PC_to_RDR_Abort;
+  msg[5] = 0; /* slot */
+  msg[6] = seqno;
+  msg[7] = 0; /* RFU */
+  msg[8] = 0; /* RFU */
+  msg[9] = 0; /* RFU */
+  msglen = 10;
+  set_msg_len (msg, 0);
+  handle->seqno++;  /* Bumb up for the next use. */
+
+  DEBUGOUT ("sending");
+  for (i=0; i < msglen; i++)
+    DEBUGOUT_CONT_1 (" %02X", msg[i]);
+  DEBUGOUT_LF ();
+  rc = usb_bulk_write (handle->idev, 
+                       handle->ep_bulk_out,
+                       (char*)msg, msglen,
+                       5000 /* ms timeout */);
+  if (rc == msglen)
+    rc = 0;
+  else if (rc == -1)
+    DEBUGOUT_1 ("usb_bulk_write error in abort_cmd: %s\n", strerror (errno));
+  else
+    DEBUGOUT_1 ("usb_bulk_write failed in abort_cmd: %d\n", rc);
+
+  if (rc)
+    return rc;
+
+  /* Wait for the expected response.  */
+  do
+    {
+      rc = usb_bulk_read (handle->idev, 
+                          handle->ep_bulk_in,
+                          (char*)msg, sizeof msg, 
+                          5000 /*ms timeout*/);
+      if (rc < 0)
+        {
+          DEBUGOUT_1 ("usb_bulk_read error in abort_cmd: %s\n",
+                      strerror (errno));
+          return CCID_DRIVER_ERR_CARD_IO_ERROR;
+        }
+      msglen = rc;
+
+      if (msglen < 10)
+        {
+          DEBUGOUT_1 ("bulk-in msg in abort_cmd too short (%u)\n",
+                      (unsigned int)msglen);
+          return CCID_DRIVER_ERR_INV_VALUE;
+        }
+      if (msg[5] != 0)    
+        {
+          DEBUGOUT_1 ("unexpected bulk-in slot (%d) in abort_cmd\n", msg[5]);
+          return CCID_DRIVER_ERR_INV_VALUE;
+        }
+
+      DEBUGOUT_3 ("status: %02X  error: %02X  octet[9]: %02X\n",
+                  msg[7], msg[8], msg[9]);
+      if (CCID_COMMAND_FAILED (msg))
+        print_command_failed (msg);
+    }
+  while (msg[0] != RDR_to_PC_SlotStatus && msg[5] != 0 && msg[6] != seqno);
+
+  DEBUGOUT ("sending abort sequence succeeded\n");
+
+  return 0;
+}
+
+
 /* Note that this function won't return the error codes NO_CARD or
    CARD_INACTIVE.  IF RESULT is not NULL, the result from the
    operation will get returned in RESULT and its length in RESULTLEN.

Modified: trunk/scd/command.c
===================================================================
--- trunk/scd/command.c	2008-12-17 19:42:17 UTC (rev 4905)
+++ trunk/scd/command.c	2008-12-18 16:34:28 UTC (rev 4906)
@@ -1964,6 +1964,84 @@
 }
 
 
+
+/* Helper to send the clients a status change notification.  */
+static void
+send_client_notifications (void)
+{
+  struct {
+    pid_t pid; 
+#ifdef HAVE_W32_SYSTEM
+    HANDLE handle;
+#else
+    int signo; 
+#endif
+  } killed[50];
+  int killidx = 0;
+  int kidx;
+  struct server_local_s *sl;
+  
+  for (sl=session_list; sl; sl = sl->next_session)
+    {
+      if (sl->event_signal && sl->assuan_ctx)
+        {
+          pid_t pid = assuan_get_pid (sl->assuan_ctx);
+#ifdef HAVE_W32_SYSTEM
+          HANDLE handle = (void *)sl->event_signal;
+          
+          for (kidx=0; kidx < killidx; kidx++)
+            if (killed[kidx].pid == pid 
+                && killed[kidx].handle == handle)
+              break;
+          if (kidx < killidx)
+            log_info ("event %lx (%p) already triggered for client %d\n",
+                      sl->event_signal, handle, (int)pid);
+          else
+            {
+              log_info ("triggering event %lx (%p) for client %d\n",
+                        sl->event_signal, handle, (int)pid);
+              if (!SetEvent (handle))
+                log_error ("SetEvent(%lx) failed: %s\n",
+                           sl->event_signal, w32_strerror (-1));
+              if (killidx < DIM (killed))
+                {
+                  killed[killidx].pid = pid;
+                  killed[killidx].handle = handle;
+                  killidx++;
+                }
+            }
+#else /*!HAVE_W32_SYSTEM*/
+          int signo = sl->event_signal;
+          
+          if (pid != (pid_t)(-1) && pid && signo > 0)
+            {
+              for (kidx=0; kidx < killidx; kidx++)
+                if (killed[kidx].pid == pid 
+                    && killed[kidx].signo == signo)
+                  break;
+              if (kidx < killidx)
+                log_info ("signal %d already sent to client %d\n",
+                          signo, (int)pid);
+              else
+                {
+                  log_info ("sending signal %d to client %d\n",
+                            signo, (int)pid);
+                  kill (pid, signo);
+                  if (killidx < DIM (killed))
+                    {
+                      killed[killidx].pid = pid;
+                      killed[killidx].signo = signo;
+                      killidx++;
+                    }
+                }
+#endif /*!HAVE_W32_SYSTEM*/
+            }
+        }
+    }
+}
+
+
+
 /* This is the core of scd_update_reader_status_file but the caller
    needs to take care of the locking.  */
 static void
@@ -1985,12 +2063,17 @@
     {
       struct slot_status_s *ss = slot_table + idx;
       struct server_local_s *sl;
+      int sw_apdu;
 
       if (!ss->valid || ss->slot == -1)
         continue; /* Not valid or reader not yet open. */
       
-      if ( apdu_get_status (ss->slot, 0, &status, &changed) )
-        continue; /* Get status failed. */
+      sw_apdu = apdu_get_status (ss->slot, 0, &status, &changed);
+      if (sw_apdu)
+        {
+          /* Get status failed.  Ignore that.  */
+          continue; 
+        }
 
       if (!ss->any || ss->status != status || ss->changed != changed )
         {
@@ -1998,8 +2081,10 @@
           char templ[50];
           FILE *fp;
 
-          log_info ("updating status of slot %d to 0x%04X\n",
-                    ss->slot, status);
+          log_info ("updating slot %d status: 0x%04X->0x%04X (%u->%u)\n",
+                    ss->slot, ss->status, status, ss->changed, changed);
+          ss->status = status;
+          ss->changed = changed;
 
 	  /* FIXME: Should this be IDX instead of ss->slot?  This
 	     depends on how client sessions will associate the reader
@@ -2065,33 +2150,9 @@
             update_card_removed (idx, 1);
           
           ss->any = 1;
-          ss->status = status;
-          ss->changed = changed;
 
           /* Send a signal to all clients who applied for it.  */
-          for (sl=session_list; sl; sl = sl->next_session)
-            if (sl->event_signal && sl->assuan_ctx)
-              {
-                pid_t pid = assuan_get_pid (sl->assuan_ctx);
-
-#ifdef HAVE_W32_SYSTEM
-                HANDLE handle = (void *)sl->event_signal;
-                
-                log_info ("client pid is %d, triggering event %lx (%p)\n",
-                          pid, sl->event_signal, handle);
-                if (!SetEvent (handle))
-                  log_error ("SetEvent(%lx) failed: %s\n",
-                             sl->event_signal, w32_strerror (-1));
-#else
-                int signo = sl->event_signal;
-                
-                log_info ("client pid is %d, sending signal %d\n",
-                          pid, signo);
-                if (pid != (pid_t)(-1) && pid && signo > 0)
-                  kill (pid, signo);
-#endif
-              }
-
+          send_client_notifications ();
         }
       
       /* Check whether a disconnect is pending.  */
@@ -2104,7 +2165,7 @@
             {
               /* FIXME: Use a real timeout.  */
               /* At least one connection and all allow a disconnect.  */
-              log_debug ("disconnecting card in slot %d\n", ss->slot);
+              log_info ("disconnecting card in slot %d\n", ss->slot);
               apdu_disconnect (ss->slot);
             }
         }




More information about the Gnupg-commits mailing list