* apdu.c (apdu_open_reader): Load pcsc_get_status_change fucntion.
authorWerner Koch <wk@gnupg.org>
Wed, 20 Oct 2004 09:39:56 +0000 (09:39 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 20 Oct 2004 09:39:56 +0000 (09:39 +0000)
(pcsc_get_status): Implemented.
(reset_pcsc_reader): Implemented.
(open_pcsc_reader): Succeed even with no card inserted.
(open_ccid_reader): Set LAST_STATUS.

* iso7816.c (iso7816_select_application): Always use 0 for P1.

g10/ChangeLog
g10/apdu.c
g10/apdu.h
g10/app-common.h
g10/ccid-driver.c
g10/ccid-driver.h
g10/iso7816.c
g10/iso7816.h

index e0d03c2..495f7e8 100644 (file)
@@ -1,3 +1,17 @@
+2004-10-20  Werner Koch  <wk@g10code.com>
+
+       * apdu.c (apdu_open_reader): Load pcsc_get_status_change fucntion.
+       (pcsc_get_status): Implemented.
+       (reset_pcsc_reader): Implemented.
+       (open_pcsc_reader): Succeed even with no card inserted.
+       (open_ccid_reader): Set LAST_STATUS.
+
+       * iso7816.c (iso7816_select_application): Always use 0 for P1.
+
+2004-10-18  Werner Koch  <wk@g10code.com>
+
+       * ccid-driver.c (ccid_get_atr): Reset T=1 state info.
+
 2004-10-17  Werner Koch  <wk@g10code.com>
 
        * passphrase.c (agent_get_passphrase): Cast UIDLEN to int.  Noted
index e58be59..f4b32d1 100644 (file)
@@ -125,6 +125,8 @@ struct reader_table_s {
     rapdu_t handle;
   } rapdu;
 #endif /*USE_G10CODE_RAPDU*/
+  char *rdrname;     /* Name of the connected reader or NULL if unknown. */
+  int last_status;
   int status;
   unsigned char atr[33];
   size_t atrlen;           /* A zero length indicates that the ATR has
@@ -169,13 +171,47 @@ static char (* DLSTDCALL CT_close) (unsigned short ctn);
 #define PCSC_UNPOWER_CARD    2
 #define PCSC_EJECT_CARD      3
 
-struct pcsc_io_request_s {
+#define PCSC_UNKNOWN    0x0001  
+#define PCSC_ABSENT     0x0002  /* Card is absent.  */
+#define PCSC_PRESENT    0x0004  /* Card is present.  */
+#define PCSC_SWALLOWED  0x0008  /* Card is present and electrical connected. */
+#define PCSC_POWERED    0x0010  /* Card is powered.  */
+#define PCSC_NEGOTIABLE 0x0020  /* Card is awaiting PTS.  */
+#define PCSC_SPECIFIC   0x0040  /* Card is ready for use.  */
+
+#define PCSC_STATE_UNAWARE     0x0000  /* Want status.  */
+#define PCSC_STATE_IGNORE      0x0001  /* Ignore this reader.  */
+#define PCSC_STATE_CHANGED     0x0002  /* State has changed.  */
+#define PCSC_STATE_UNKNOWN     0x0004  /* Reader unknown.  */
+#define PCSC_STATE_UNAVAILABLE 0x0008  /* Status unavailable.  */
+#define PCSC_STATE_EMPTY       0x0010  /* Card removed.  */
+#define PCSC_STATE_PRESENT     0x0020  /* Card inserted.  */
+#define PCSC_STATE_ATRMATCH    0x0040  /* ATR matches card. */
+#define PCSC_STATE_EXCLUSIVE   0x0080  /* Exclusive Mode.  */
+#define PCSC_STATE_INUSE       0x0100  /* Shared mode.  */
+#define PCSC_STATE_MUTE               0x0200  /* Unresponsive card.  */
+
+
+struct pcsc_io_request_s 
+{
   unsigned long protocol; 
   unsigned long pci_len;
 };
 
 typedef struct pcsc_io_request_s *pcsc_io_request_t;
 
+struct pcsc_readerstate_s
+{
+  const char *reader;
+  void *user_data;
+  unsigned long current_state;
+  unsigned long event_state;
+  unsigned long atrlen;
+  unsigned char atr[33];
+};
+
+typedef struct pcsc_readerstate_s *pcsc_readerstate_t;
+
 long (* DLSTDCALL pcsc_establish_context) (unsigned long scope,
                                            const void *reserved1,
                                            const void *reserved2,
@@ -184,12 +220,21 @@ long (* DLSTDCALL pcsc_release_context) (unsigned long context);
 long (* DLSTDCALL pcsc_list_readers) (unsigned long context,
                                       const char *groups,
                                       char *readers, unsigned long*readerslen);
+long (* DLSTDCALL pcsc_get_status_change) (unsigned long context,
+                                           unsigned long timeout,
+                                           pcsc_readerstate_t readerstates,
+                                           unsigned long nreaderstates);
 long (* DLSTDCALL pcsc_connect) (unsigned long context,
                                  const char *reader,
                                  unsigned long share_mode,
                                  unsigned long preferred_protocols,
                                  unsigned long *r_card,
                                  unsigned long *r_active_protocol);
+long (* DLSTDCALL pcsc_reconnect) (unsigned long card,
+                                   unsigned long share_mode,
+                                   unsigned long preferred_protocols,
+                                   unsigned long initialization,
+                                   unsigned long *r_active_protocol);
 long (* DLSTDCALL pcsc_disconnect) (unsigned long card,
                                     unsigned long disposition);
 long (* DLSTDCALL pcsc_status) (unsigned long card,
@@ -211,7 +256,6 @@ long (* DLSTDCALL pcsc_set_timeout) (unsigned long context,
 
 
 
-
 \f
 /* 
       Helper
@@ -254,11 +298,13 @@ new_reader_slot (void)
   reader_table[reader].dump_status_reader = NULL;
 
   reader_table[reader].used = 1;
+  reader_table[reader].last_status = 0;
 #ifdef NEED_PCSC_WRAPPER
   reader_table[reader].pcsc.req_fd = -1;
   reader_table[reader].pcsc.rsp_fd = -1;
   reader_table[reader].pcsc.pid = (pid_t)(-1);
 #endif
+
   return reader;
 }
 
@@ -662,18 +708,293 @@ dump_pcsc_reader_status (int slot)
 }
 
 
-
 static int
-pcsc_get_status (int slot, unsigned int *status)
+reset_pcsc_reader (int slot)
 {
-  *status = 1|2|4;  /* FIXME!!!! */
+#ifdef NEED_PCSC_WRAPPER
+  long err;
+  reader_table_t slotp;
+  size_t len;
+  int i, n;
+  unsigned char msgbuf[9];
+
+  slotp = reader_table + slot;
+
+  if (slotp->pcsc.req_fd == -1 
+      || slotp->pcsc.rsp_fd == -1 
+      || slotp->pcsc.pid == (pid_t)(-1) )
+    {
+      log_error ("pcsc_get_status: pcsc-wrapper not running\n");
+      return SW_HOST_CARD_IO_ERROR;
+    }
+
+  msgbuf[0] = 0x05; /* RESET command. */
+  len = 0;
+  msgbuf[1] = (len >> 24);
+  msgbuf[2] = (len >> 16);
+  msgbuf[3] = (len >>  8);
+  msgbuf[4] = (len      );
+  if ( writen (slotp->pcsc.req_fd, msgbuf, 5) )
+    {
+      log_error ("error sending PC/SC RESET request: %s\n",
+                 strerror (errno));
+      goto command_failed;
+    }
+
+  /* Read the response. */
+  if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
+    {
+      log_error ("error receiving PC/SC RESET response: %s\n",
+                 i? strerror (errno) : "premature EOF");
+      goto command_failed;
+    }
+  len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
+  if (msgbuf[0] != 0x81 || len < 4)
+    {
+      log_error ("invalid response header from PC/SC received\n");
+      goto command_failed;
+    }
+  len -= 4; /* Already read the error code. */
+  if (len > DIM (slotp->atr))
+    {
+      log_error ("PC/SC returned a too large ATR (len=%x)\n", len);
+      goto command_failed;
+    }
+  err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
+  if (err)
+    {
+      log_error ("PC/SC RESET failed: %s\n", pcsc_error_string (err));
+      goto command_failed;
+    }
+
+  /* The open fucntion may return a zero for the ATR length to
+     indicate that no card is present.  */
+  n = len;
+  if (n)
+    {
+      if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n)
+        {
+          log_error ("error receiving PC/SC RESET response: %s\n",
+                     i? strerror (errno) : "premature EOF");
+          goto command_failed;
+        }
+    }
+  slotp->atrlen = len;
+
+  return 0;
+
+ command_failed:
+  close (slotp->pcsc.req_fd);
+  close (slotp->pcsc.rsp_fd);
+  slotp->pcsc.req_fd = -1;
+  slotp->pcsc.rsp_fd = -1;
+  kill (slotp->pcsc.pid, SIGTERM);
+  slotp->pcsc.pid = (pid_t)(-1);
+  slotp->used = 0;
+  return -1;
+
+#else /* !NEED_PCSC_WRAPPER */
+  long err;
+  char reader[250];
+  unsigned long nreader, atrlen;
+  unsigned long card_state, card_protocol;
+
+  if (reader_table[slot].pcsc.card)
+    {
+      err = pcsc_disconnect (reader_table[slot].pcsc.card, PCSC_LEAVE_CARD);
+      if (err)
+        {
+          log_error ("pcsc_disconnect failed: %s (0x%lx)\n",
+                     pcsc_error_string (err), err);
+          return SW_HOST_CARD_IO_ERROR;
+        }
+      reader_table[slot].pcsc.card = 0;
+    }
+
+  err = pcsc_connect (reader_table[slot].pcsc.context,
+                      reader_table[slot].rdrname,
+                      PCSC_SHARE_EXCLUSIVE,
+                      PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
+                      &reader_table[slot].pcsc.card,
+                      &reader_table[slot].pcsc.protocol);
+  if (err)
+    {
+      log_error ("pcsc_connect failed: %s (0x%lx)\n",
+                  pcsc_error_string (err), err);
+      reader_table[slot].pcsc.card = 0;
+      return SW_HOST_CARD_IO_ERROR;
+    }      
+
+  
+  atrlen = 33;
+  nreader = sizeof reader - 1;
+  err = pcsc_status (reader_table[slot].pcsc.card,
+                     reader, &nreader,
+                     &card_state, &card_protocol,
+                     reader_table[slot].atr, &atrlen);
+  if (err)
+    {
+      log_error ("pcsc_status failed: %s (0x%lx)\n",
+                  pcsc_error_string (err), err);
+      reader_table[slot].atrlen = 0;
+      return SW_HOST_CARD_IO_ERROR;
+    }
+  if (atrlen >= DIM (reader_table[0].atr))
+    log_bug ("ATR returned by pcsc_status is too large\n");
+  reader_table[slot].atrlen = atrlen;
+
   return 0;
+#endif /* !NEED_PCSC_WRAPPER */
 }
 
+
 static int
-reset_pcsc_reader (int slot)
+pcsc_get_status (int slot, unsigned int *status)
 {
-  return SW_HOST_NOT_SUPPORTED;
+#ifdef NEED_PCSC_WRAPPER
+  long err;
+  reader_table_t slotp;
+  size_t len, full_len;
+  int i, n;
+  unsigned char msgbuf[9];
+  unsigned char buffer[12];
+
+  slotp = reader_table + slot;
+
+  if (slotp->pcsc.req_fd == -1 
+      || slotp->pcsc.rsp_fd == -1 
+      || slotp->pcsc.pid == (pid_t)(-1) )
+    {
+      log_error ("pcsc_get_status: pcsc-wrapper not running\n");
+      return SW_HOST_CARD_IO_ERROR;
+    }
+
+  msgbuf[0] = 0x04; /* STATUS command. */
+  len = 0;
+  msgbuf[1] = (len >> 24);
+  msgbuf[2] = (len >> 16);
+  msgbuf[3] = (len >>  8);
+  msgbuf[4] = (len      );
+  if ( writen (slotp->pcsc.req_fd, msgbuf, 5) )
+    {
+      log_error ("error sending PC/SC STATUS request: %s\n",
+                 strerror (errno));
+      goto command_failed;
+    }
+
+  /* Read the response. */
+  if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
+    {
+      log_error ("error receiving PC/SC STATUS response: %s\n",
+                 i? strerror (errno) : "premature EOF");
+      goto command_failed;
+    }
+  len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
+  if (msgbuf[0] != 0x81 || len < 4)
+    {
+      log_error ("invalid response header from PC/SC received\n");
+      goto command_failed;
+    }
+  len -= 4; /* Already read the error code. */
+  err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
+  if (err)
+    {
+      log_error ("pcsc_status failed: %s (0x%lx)\n",
+                 pcsc_error_string (err), err);
+      return SW_HOST_CARD_IO_ERROR;
+    }
+
+  full_len = len;
+  
+  n = 8 < len ? 8 : len;
+  if ((i=readn (slotp->pcsc.rsp_fd, buffer, n, &len)) || len != 8)
+    {
+      log_error ("error receiving PC/SC STATUS response: %s\n",
+                 i? strerror (errno) : "premature EOF");
+      goto command_failed;
+    }
+
+  full_len -= len;
+  /* Newer versions of the wrapper might send more status bytes.
+     Read them. */
+  while (full_len)
+    {
+      unsigned char dummybuf[128];
+
+      n = full_len < DIM (dummybuf) ? full_len : DIM (dummybuf);
+      if ((i=readn (slotp->pcsc.rsp_fd, dummybuf, n, &len)) || len != n)
+        {
+          log_error ("error receiving PC/SC TRANSMIT response: %s\n",
+                     i? strerror (errno) : "premature EOF");
+          goto command_failed;
+        }
+      full_len -= n;
+    }
+   
+  /* We are lucky: The wrapper already returns the data in the
+     required format. */
+  *status = buffer[3];
+
+  return 0;
+
+ command_failed:
+  close (slotp->pcsc.req_fd);
+  close (slotp->pcsc.rsp_fd);
+  slotp->pcsc.req_fd = -1;
+  slotp->pcsc.rsp_fd = -1;
+  kill (slotp->pcsc.pid, SIGTERM);
+  slotp->pcsc.pid = (pid_t)(-1);
+  slotp->used = 0;
+  return -1;
+
+#else /*!NEED_PCSC_WRAPPER*/
+
+  long err;
+  struct pcsc_readerstate_s rdrstates[1];
+  
+  memset (rdrstates, 0, sizeof *rdrstates);
+  rdrstates[0].reader = reader_table[slot].rdrname;
+  rdrstates[0].current_state = PCSC_STATE_UNAWARE;
+  err = pcsc_get_status_change (reader_table[slot].pcsc.context,
+                                0,
+                                rdrstates, 1);
+  if (err == 0x8010000a) /* Timeout.  */
+    err = 0;
+  if (err)
+    {
+      log_error ("pcsc_get_status_change failed: %s (0x%lx)\n",
+                 pcsc_error_string (err), err);
+      return SW_HOST_CARD_IO_ERROR;
+    }
+
+
+  /*   log_debug  */
+  /*     ("pcsc_get_status_change: %s%s%s%s%s%s%s%s%s%s\n", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_IGNORE)? " ignore":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_CHANGED)? " changed":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_UNKNOWN)? " unknown":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_UNAVAILABLE)?" unavail":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_EMPTY)? " empty":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_PRESENT)? " present":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_ATRMATCH)? " atr":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_EXCLUSIVE)? " excl":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_INUSE)? " unuse":"", */
+  /*      (rdrstates[0].event_state & PCSC_STATE_MUTE)? " mute":"" ); */
+
+  *status = 0;
+  if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
+    *status |= 2;
+  if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
+    *status |= 4;
+  /* We indicate a useful card if it is not in use by another
+     application.  This is because we only use exclusive access
+     mode.  */
+  if ( (*status & 6) == 6
+       && !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
+    *status |= 1;
+  
+  return 0; 
+#endif /*!NEED_PCSC_WRAPPER*/
 }
 
 
@@ -889,6 +1210,8 @@ close_pcsc_reader (int slot)
 #else /*!NEED_PCSC_WRAPPER*/
 
   pcsc_release_context (reader_table[slot].pcsc.context);
+  xfree (reader_table[slot].rdrname);
+  reader_table[slot].rdrname = NULL;
   reader_table[slot].used = 0;
   return 0;
 #endif /*!NEED_PCSC_WRAPPER*/
@@ -999,8 +1322,14 @@ open_pcsc_reader (const char *portstr)
   slotp->pcsc.rsp_fd = rp[0];
 
   /* Wait for the intermediate child to terminate. */
-  while ( (i=pth_waitpid (pid, NULL, 0)) == -1 && errno == EINTR)
+#ifdef USE_GNU_PTH
+#define WAIT pth_waitpid 
+#else
+#define WAIT waitpid 
+#endif
+  while ( (i=WAIT (pid, NULL, 0)) == -1 && errno == EINTR)
     ;
+#undef X
 
   /* Now send the open request. */
   msgbuf[0] = 0x01; /* OPEN command. */
@@ -1041,12 +1370,23 @@ open_pcsc_reader (const char *portstr)
       log_error ("PC/SC OPEN failed: %s\n", pcsc_error_string (err));
       goto command_failed;
     }
+
+  slotp->last_status = 0;
+
+  /* The open fucntion may return a zero for the ATR length to
+     indicate that no card is present.  */
   n = len;
-  if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n)
+  if (n)
     {
-      log_error ("error receiving PC/SC OPEN response: %s\n",
-                 i? strerror (errno) : "premature EOF");
-      goto command_failed;
+      if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n)
+        {
+          log_error ("error receiving PC/SC OPEN response: %s\n",
+                     i? strerror (errno) : "premature EOF");
+          goto command_failed;
+        }
+      /* If we got to here we know that a card is present
+         and usable.  Thus remember this.  */
+      slotp->last_status = (1|2|4| 0x8000);
     }
   slotp->atrlen = len;
 
@@ -1132,41 +1472,63 @@ open_pcsc_reader (const char *portstr)
       p += strlen (p) + 1;
     }
 
+  reader_table[slot].rdrname = xtrymalloc (strlen (portstr? portstr : list)+1);
+  if (!reader_table[slot].rdrname)
+    {
+      log_error ("error allocating memory for reader name\n");
+      pcsc_release_context (reader_table[slot].pcsc.context);
+      reader_table[slot].used = 0;
+      return -1;
+    }
+  strcpy (reader_table[slot].rdrname, portstr? portstr : list);
+  xfree (list);
+
   err = pcsc_connect (reader_table[slot].pcsc.context,
-                      portstr? portstr : list,
+                      reader_table[slot].rdrname,
                       PCSC_SHARE_EXCLUSIVE,
                       PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
                       &reader_table[slot].pcsc.card,
                       &reader_table[slot].pcsc.protocol);
-  if (err)
+  if (err == 0x8010000c) /* No smartcard.  */
+    reader_table[slot].pcsc.card = 0;
+  else if (err)
     {
       log_error ("pcsc_connect failed: %s (0x%lx)\n",
                   pcsc_error_string (err), err);
       pcsc_release_context (reader_table[slot].pcsc.context);
+      xfree (reader_table[slot].rdrname);
+      reader_table[slot].rdrname = NULL;
       reader_table[slot].used = 0;
       xfree (list);
       return -1;
     }      
-  
-  atrlen = 32;
-  /* (We need to pass a dummy buffer.  We use LIST because it ought to
-     be large enough.) */
-  err = pcsc_status (reader_table[slot].pcsc.card,
-                     list, &listlen,
-                     &card_state, &card_protocol,
-                     reader_table[slot].atr, &atrlen);
-  xfree (list);
-  if (err)
+
+  reader_table[slot].atrlen = 0;
+  reader_table[slot].last_status = 0;
+  if (!err)
     {
-      log_error ("pcsc_status failed: %s (0x%lx)\n",
-                  pcsc_error_string (err), err);
-      pcsc_release_context (reader_table[slot].pcsc.context);
-      reader_table[slot].used = 0;
-      return -1;
+      char reader[250];
+      unsigned long readerlen;
+
+      atrlen = 32;
+      readerlen = sizeof reader -1 ;
+      err = pcsc_status (reader_table[slot].pcsc.card,
+                         reader, &readerlen,
+                         &card_state, &card_protocol,
+                         reader_table[slot].atr, &atrlen);
+      if (err)
+        log_error ("pcsc_status failed: %s (0x%lx) %lu\n",
+                   pcsc_error_string (err), err, readerlen);
+      else
+        {
+          if (atrlen >= DIM (reader_table[0].atr))
+            log_bug ("ATR returned by pcsc_status is too large\n");
+          reader_table[slot].atrlen = atrlen;
+          /* If we got to here we know that a card is present
+             and usable.  Thus remember this.  */
+          reader_table[slot].last_status = (1|2|4| 0x8000);
+        }
     }
-  if (atrlen >= DIM (reader_table[0].atr))
-    log_bug ("ATR returned by pcsc_status is too large\n");
-  reader_table[slot].atrlen = atrlen;
 
   reader_table[slot].close_reader = close_pcsc_reader;
   reader_table[slot].reset_reader = reset_pcsc_reader;
@@ -1311,6 +1673,12 @@ open_ccid_reader (const char *portstr)
       slotp->atrlen = 0;
       err = 0;
     }
+  else
+    {
+      /* If we got to here we know that a card is present
+         and usable.  Thus remember this.  */
+      reader_table[slot].last_status = (1|2|4| 0x8000);
+    }
 
   reader_table[slot].close_reader = close_ccid_reader;
   reader_table[slot].shutdown_reader = shutdown_ccid_reader;
@@ -1971,11 +2339,21 @@ apdu_open_reader (const char *portstr)
       if (!pcsc_list_readers)
         pcsc_list_readers    = dlsym (handle, "SCardListReadersA");
 #endif
+      pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange");
+#ifdef _WIN32
+      if (!pcsc_get_status_change)
+        pcsc_get_status_change = dlsym (handle, "SCardGetStatusChangeA");
+#endif
       pcsc_connect           = dlsym (handle, "SCardConnect");
 #ifdef _WIN32
       if (!pcsc_connect)
         pcsc_connect         = dlsym (handle, "SCardConnectA");
 #endif
+      pcsc_reconnect         = dlsym (handle, "SCardReconnect");
+#ifdef _WIN32
+      if (!pcsc_reconnect)
+        pcsc_reconnect       = dlsym (handle, "SCardReconnectA");
+#endif
       pcsc_disconnect        = dlsym (handle, "SCardDisconnect");
       pcsc_status            = dlsym (handle, "SCardStatus");
 #ifdef _WIN32
@@ -1990,7 +2368,9 @@ apdu_open_reader (const char *portstr)
       if (!pcsc_establish_context
           || !pcsc_release_context  
           || !pcsc_list_readers     
+          || !pcsc_get_status_change
           || !pcsc_connect          
+          || !pcsc_reconnect
           || !pcsc_disconnect
           || !pcsc_status
           || !pcsc_begin_transaction
@@ -2001,11 +2381,13 @@ apdu_open_reader (const char *portstr)
           /* Note that set_timeout is currently not used and also not
              available under Windows. */
           log_error ("apdu_open_reader: invalid PC/SC driver "
-                     "(%d%d%d%d%d%d%d%d%d%d)\n",
+                     "(%d%d%d%d%d%d%d%d%d%d%d%d)\n",
                      !!pcsc_establish_context,
                      !!pcsc_release_context,  
                      !!pcsc_list_readers,     
+                     !!pcsc_get_status_change,     
                      !!pcsc_connect,          
+                     !!pcsc_reconnect,          
                      !!pcsc_disconnect,
                      !!pcsc_status,
                      !!pcsc_begin_transaction,
@@ -2106,9 +2488,17 @@ apdu_reset (int slot)
   if ((sw = lock_slot (slot)))
     return sw;
 
+  reader_table[slot].last_status = 0;
   if (reader_table[slot].reset_reader)
     sw = reader_table[slot].reset_reader (slot);
 
+  if (!sw)
+    {
+      /* If we got to here we know that a card is present
+         and usable.  Thus remember this.  */
+      reader_table[slot].last_status = (1|2|4| 0x8000);
+    }
+
   unlock_slot (slot);
   return sw;
 }
@@ -2143,7 +2533,16 @@ apdu_activate (int slot)
           /* We don't have an ATR or a card is present though inactive:
              do a reset now. */
           if (reader_table[slot].reset_reader)
-            sw = reader_table[slot].reset_reader (slot);
+            {
+              reader_table[slot].last_status = 0;
+              sw = reader_table[slot].reset_reader (slot);
+              if (!sw)
+                {
+                  /* If we got to here we know that a card is present
+                     and usable.  Thus remember this.  */
+                  reader_table[slot].last_status = (1|2|4| 0x8000);
+                }
+            }
         }
     }
   
@@ -2205,7 +2604,22 @@ apdu_get_status (int slot, int hang,
   unlock_slot (slot);
 
   if (sw)
-    return sw;
+    {
+      reader_table[slot].last_status = 0;
+      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 )
+    {
+      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);
 
   if (status)
     *status = s;
index f31e42e..e0f50b7 100644 (file)
@@ -16,6 +16,8 @@
  * 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
+ *
+ * $Id$
  */
 
 #ifndef APDU_H
index 8392b48..f54f6da 100644 (file)
@@ -16,6 +16,8 @@
  * 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
+ *
+ * $Id$
  */
 
 #ifndef GNUPG_SCD_APP_COMMON_H
@@ -95,6 +97,7 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
 /*-- app.c --*/
 app_t select_application (ctrl_t ctrl, int slot, const char *name);
 void release_application (app_t app);
+int app_munge_serialno (app_t app);
 int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
 int app_write_learn_status (app_t app, ctrl_t ctrl);
 int app_readcert (app_t app, const char *certid,
@@ -143,7 +146,6 @@ int app_openpgp_cardinfo (app_t app,
                           unsigned char **fpr1,
                           unsigned char **fpr2,
                           unsigned char **fpr3);
-#endif /* GNUPG_MAJOR_VERSION != 1 */
 int app_openpgp_storekey (app_t app, int keyno,
                           unsigned char *template, size_t template_len,
                           time_t created_at,
@@ -154,16 +156,18 @@ int app_openpgp_storekey (app_t app, int keyno,
 int app_openpgp_readkey (app_t app, int keyno,
                          unsigned char **m, size_t *mlen,
                          unsigned char **e, size_t *elen);
-#if GNUPG_MAJOR_VERSION == 1
-#else
 /*-- app-nks.c --*/
 int app_select_nks (app_t app);
 
 /*-- app-dinsig.c --*/
 int app_select_dinsig (app_t app);
 
+/*-- app-p15.c --*/
+int app_select_p15 (app_t app);
+
+
+#endif
 
-#endif /* GNUPG_MAJOR_VERSION != 1 */
 
 
 #endif /*GNUPG_SCD_APP_COMMON_H*/
index 0a876f0..01c8a99 100644 (file)
@@ -1307,6 +1307,8 @@ ccid_get_atr (ccid_driver_t handle,
   /* Note that we ignore the error code on purpose. */
   bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, seqno);
 
+  handle->t1_ns = 0;
+  handle->t1_nr = 0;
 
   /* Send an S-Block with our maximun IFSD to the CCID.  */
   if (!handle->auto_ifsd)
index 9cb2325..82feed5 100644 (file)
@@ -50,6 +50,8 @@
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id$
  */
 
 #ifndef CCID_DRIVER_H
index cbb314e..9eff9d3 100644 (file)
@@ -16,6 +16,8 @@
  * 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
+ *
+ * $Id$
  */
 
 #include <config.h>
@@ -103,6 +105,17 @@ map_sw (int sw)
   return gpg_error (ec);
 }
 
+/* Map a status word from the APDU layer to a gpg-error code.  */
+gpg_error_t
+iso7816_map_sw (int sw)
+{
+  /* All APDU functions should return 0x9000 on success but for
+     historical reasons of the implementation some return 0 to
+     indicate success.  We allow for that here. */
+  return sw? map_sw (sw) : 0;
+}
+
+
 /* This function is specialized version of the SELECT FILE command.
    SLOT is the card and reader as created for example by
    apdu_open_reader (), AID is a buffer of size AIDLEN holding the
@@ -113,15 +126,8 @@ map_sw (int sw)
 gpg_error_t
 iso7816_select_application (int slot, const char *aid, size_t aidlen)
 {
-  static char const openpgp_aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 };
   int sw;
-  int p1 = 0x0C; /* No FCI to be returned. */
-  
-  if (aidlen == sizeof openpgp_aid
-      && !memcmp (aid, openpgp_aid, sizeof openpgp_aid))
-    p1 = 0; /* The current openpgp cards don't allow 0x0c. */
-
-  sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, p1, aidlen, aid);
+  sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, 0, aidlen, aid);
   return map_sw (sw);
 }
 
index 97de9ab..b9ba180 100644 (file)
@@ -16,6 +16,8 @@
  * 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
+ *
+ * $Id$
  */
 
 #ifndef ISO7816_H