[svn] GnuPG - r5085 - in branches/STABLE-BRANCH-1-4: . g10 include m4 util

svn author wk cvs at cvs.gnupg.org
Tue Jul 21 16:30:14 CEST 2009


Author: wk
Date: 2009-07-21 16:30:13 +0200 (Tue, 21 Jul 2009)
New Revision: 5085

Added:
   branches/STABLE-BRANCH-1-4/include/estream-printf.h
   branches/STABLE-BRANCH-1-4/m4/estream.m4
   branches/STABLE-BRANCH-1-4/util/convert.c
   branches/STABLE-BRANCH-1-4/util/estream-printf.c
Modified:
   branches/STABLE-BRANCH-1-4/AUTHORS
   branches/STABLE-BRANCH-1-4/ChangeLog
   branches/STABLE-BRANCH-1-4/NEWS
   branches/STABLE-BRANCH-1-4/configure.ac
   branches/STABLE-BRANCH-1-4/g10/ChangeLog
   branches/STABLE-BRANCH-1-4/g10/apdu.c
   branches/STABLE-BRANCH-1-4/g10/apdu.h
   branches/STABLE-BRANCH-1-4/g10/app-common.h
   branches/STABLE-BRANCH-1-4/g10/app-openpgp.c
   branches/STABLE-BRANCH-1-4/g10/card-util.c
   branches/STABLE-BRANCH-1-4/g10/cardglue.c
   branches/STABLE-BRANCH-1-4/g10/cardglue.h
   branches/STABLE-BRANCH-1-4/g10/ccid-driver.c
   branches/STABLE-BRANCH-1-4/g10/ccid-driver.h
   branches/STABLE-BRANCH-1-4/g10/gpg.c
   branches/STABLE-BRANCH-1-4/g10/iso7816.c
   branches/STABLE-BRANCH-1-4/g10/iso7816.h
   branches/STABLE-BRANCH-1-4/g10/keyedit.c
   branches/STABLE-BRANCH-1-4/g10/keygen.c
   branches/STABLE-BRANCH-1-4/g10/main.h
   branches/STABLE-BRANCH-1-4/g10/options.h
   branches/STABLE-BRANCH-1-4/include/ChangeLog
   branches/STABLE-BRANCH-1-4/include/distfiles
   branches/STABLE-BRANCH-1-4/include/memory.h
   branches/STABLE-BRANCH-1-4/include/types.h
   branches/STABLE-BRANCH-1-4/include/util.h
   branches/STABLE-BRANCH-1-4/m4/ChangeLog
   branches/STABLE-BRANCH-1-4/m4/Makefile.am
   branches/STABLE-BRANCH-1-4/util/ChangeLog
   branches/STABLE-BRANCH-1-4/util/Makefile.am
   branches/STABLE-BRANCH-1-4/util/memory.c
   branches/STABLE-BRANCH-1-4/util/strgutil.c
   branches/STABLE-BRANCH-1-4/util/ttyio.c
Log:
First set of changes to backport the new card code from 2.0.
For compatibility reasons a few new files had to be added.
Also added estream-printf as this is now used in app-openpgp.c and provides
a better and generic asprintf implementation than the hack we used for the
W32 code in ttyio.c.  Card code is not yet finished.


[The diff below has been truncated]

Modified: branches/STABLE-BRANCH-1-4/ChangeLog
===================================================================
--- branches/STABLE-BRANCH-1-4/ChangeLog	2009-07-21 14:21:05 UTC (rev 5084)
+++ branches/STABLE-BRANCH-1-4/ChangeLog	2009-07-21 14:30:13 UTC (rev 5085)
@@ -1,3 +1,8 @@
+2009-07-21  Werner Koch  <wk at g10code.com>
+
+	* configure.ac (AH_BOTTOM): Add macros for estream-printf.
+	(estream_PRINTF_INIT): Add it.
+
 2009-06-05  David Shaw  <dshaw at jabberwocky.com>
 
 	* configure.ac: Remove Camellia restriction.

Modified: branches/STABLE-BRANCH-1-4/g10/ChangeLog
===================================================================
--- branches/STABLE-BRANCH-1-4/g10/ChangeLog	2009-07-21 14:21:05 UTC (rev 5084)
+++ branches/STABLE-BRANCH-1-4/g10/ChangeLog	2009-07-21 14:30:13 UTC (rev 5085)
@@ -1,3 +1,31 @@
+2009-07-21  Werner Koch  <wk at g10code.com>
+
+	* app-common.h, app-openpgp.c, iso7816.c, iso7816.h, apdu.c,
+	* apdu.h, ccid-driver.c, ccid-driver.h, card-util.c: Update from
+	GnuPG 2.0 SVN revision 5084.
+
+	* cardglue.h (GCRY_MD_SHA256): Add more GCRY_MD constants.
+	(gcry_handler_progress_t): Add definition.
+	(struct agent_card_info_s): Add fields apptype, is_v2, key_attr.
+	* cardglue.c (learn_status_cb): Set them.
+	(agent_release_card_info): Release APPTYPE.
+	(unescape_status_string, send_status_direct): New.
+	(gcry_mpi_release, gcry_mpi_set_opaque): New.
+	(gcry_md_algo_name): New.
+	(open_card): s/initialized/ref_count/.
+	(agent_learn): Pass new new flag arg to learn_status.
+	(agent_scd_genkey): Add new arg createtime.
+	* keygen.c (gen_card_key, gen_card_key_with_backup): Add new arg
+	TIMESTAMP.
+	(write_direct_sig, write_selfsigs, write_keybinding)
+	(make_backsig): Ditto.
+	(do_generate_keypair): Pass timestamp to all signing functions. 
+	(generate_card_subkeypair): Ditto.
+	* keyedit.c (menu_backsign): Pass a new timestamp to all backsisg.
+
+	* gpg.c (main): Disable keypad support.
+	* options.h (struct): Add field disable_keypad.
+
 2009-07-17  Werner Koch  <wk at g10code.com>
 
 	* keyring.c (keyring_rebuild_cache): Replace the assert by a

Modified: branches/STABLE-BRANCH-1-4/include/ChangeLog
===================================================================
--- branches/STABLE-BRANCH-1-4/include/ChangeLog	2009-07-21 14:21:05 UTC (rev 5084)
+++ branches/STABLE-BRANCH-1-4/include/ChangeLog	2009-07-21 14:30:13 UTC (rev 5085)
@@ -1,3 +1,15 @@
+2009-07-21  Werner Koch  <wk at g10code.com>
+
+	* estream-printf.h: New.  Taken from libestream.x
+
+2009-07-20  Werner Koch  <wk at g10code.com>
+
+	* types.h (strlist_t): Add new alias for STRLIST.
+
+	* memory.h (xtrymalloc,xtrystrdup): New.
+
+	* util.h: Add prototypes for util/convert.c.
+
 2009-05-26  David Shaw  <dshaw at jabberwocky.com>
 
 	* http.h: Pass in a STRLIST for additional headers on http_open

Modified: branches/STABLE-BRANCH-1-4/m4/ChangeLog
===================================================================
--- branches/STABLE-BRANCH-1-4/m4/ChangeLog	2009-07-21 14:21:05 UTC (rev 5084)
+++ branches/STABLE-BRANCH-1-4/m4/ChangeLog	2009-07-21 14:30:13 UTC (rev 5085)
@@ -1,3 +1,7 @@
+2009-07-21  Werner Koch  <wk at g10code.com>
+
+	* estream.m4: New.  Taken from libestream.
+
 2007-12-17  Werner Koch  <wk at g10code.com>
 
 	* ldap.m4: Test for ldap_start_tls_sA.

Modified: branches/STABLE-BRANCH-1-4/util/ChangeLog
===================================================================
--- branches/STABLE-BRANCH-1-4/util/ChangeLog	2009-07-21 14:21:05 UTC (rev 5084)
+++ branches/STABLE-BRANCH-1-4/util/ChangeLog	2009-07-21 14:30:13 UTC (rev 5085)
@@ -1,3 +1,20 @@
+2009-07-21  Werner Koch  <wk at g10code.com>
+
+	* ttyio.c (tty_printf): Replace vasprintf by xtryasprintf.
+	(tty_fprintf): Ditto.
+
+	* strgutil.c: Include estream-printf.h.
+	(xasprintf, xtryasprintf): New.
+	(vasprintf, asprintf): Remove.
+
+	* estream-printf.c: New.  Taken from libestream.
+	* Makefile.am (libutil_a_SOURCES): Add it.
+
+	* memory.c (trymalloc,trystrdup): New.
+
+	* convert.c: New.  Taken from GnuPG 2.0 SVN.
+	* Makefile.am (libutil_a_SOURCES): Add it.
+
 2009-05-26  David Shaw  <dshaw at jabberwocky.com>
 
 	* http.c (send_request): Pass in a STRLIST for additional headers.

Modified: branches/STABLE-BRANCH-1-4/AUTHORS
===================================================================
--- branches/STABLE-BRANCH-1-4/AUTHORS	2009-07-21 14:21:05 UTC (rev 5084)
+++ branches/STABLE-BRANCH-1-4/AUTHORS	2009-07-21 14:30:13 UTC (rev 5085)
@@ -1,6 +1,6 @@
 Program: GnuPG
 Maintainer:  Werner Koch <wk at gnupg.org>
-Bug reports: <bug-gnupg at gnu.org>
+Bug reports: http://bugs.gnupg.org
 Security related bug reports: <security at gnupg.org>
 License: GPLv3+
 

Modified: branches/STABLE-BRANCH-1-4/NEWS
===================================================================
--- branches/STABLE-BRANCH-1-4/NEWS	2009-07-21 14:21:05 UTC (rev 5084)
+++ branches/STABLE-BRANCH-1-4/NEWS	2009-07-21 14:30:13 UTC (rev 5085)
@@ -8,7 +8,11 @@
 
     * Fixed a memory leak which made imports of many keys very slow.
 
+    * Support v2 OpenPGP cards.
 
+    * FIXME:  Anything else?
+
+
 Noteworthy changes in version 1.4.9 (2008-03-26)
 ------------------------------------------------
 

Modified: branches/STABLE-BRANCH-1-4/configure.ac
===================================================================
--- branches/STABLE-BRANCH-1-4/configure.ac	2009-07-21 14:21:05 UTC (rev 5084)
+++ branches/STABLE-BRANCH-1-4/configure.ac	2009-07-21 14:30:13 UTC (rev 5085)
@@ -499,6 +499,11 @@
 #define SAFE_VERSION_DOT  '.'
 #define SAFE_VERSION_DASH '-'
 
+/* We want to use our memory allocator for estream-printf.  */
+#define _ESTREAM_PRINTF_MALLOC        xtrymalloc
+#define _ESTREAM_PRINTF_FREE          xfree
+#define _ESTREAM_PRINTF_EXTRA_INCLUDE "memory.h"
+
 #endif /*GNUPG_CONFIG_H_INCLUDED*/
 ])
 
@@ -1049,6 +1054,12 @@
 GNUPG_CHECK_MLOCK
 GNUPG_FUNC_MKDIR_TAKES_ONE_ARG
 
+#
+# Prepare building of estream-printf
+#
+estream_PRINTF_INIT
+
+
 dnl
 dnl Check whether we can use Linux capabilities as requested
 dnl

Modified: branches/STABLE-BRANCH-1-4/g10/apdu.c
===================================================================
--- branches/STABLE-BRANCH-1-4/g10/apdu.c	2009-07-21 14:21:05 UTC (rev 5084)
+++ branches/STABLE-BRANCH-1-4/g10/apdu.c	2009-07-21 14:30:13 UTC (rev 5085)
@@ -1,5 +1,5 @@
 /* apdu.c - ISO 7816 APDU functions and low level I/O
- *	Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2003, 2004, 2008, 2009 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -31,9 +31,9 @@
 #include <assert.h>
 #include <signal.h>
 #ifdef USE_GNU_PTH
-# include <pth.h>
 # include <unistd.h>
 # include <fcntl.h>
+# include <pth.h>
 #endif
 
 
@@ -54,13 +54,14 @@
 #include "memory.h"
 #include "util.h"
 #include "i18n.h"
+#include "dynload.h"
 #include "cardglue.h"
 #else /* GNUPG_MAJOR_VERSION != 1 */
 #include "scdaemon.h"
+#include "exechelp.h"
 #endif /* GNUPG_MAJOR_VERSION != 1 */
 
 #include "apdu.h"
-#include "dynload.h"
 #include "ccid-driver.h"
 
 
@@ -82,13 +83,8 @@
 #define DLSTDCALL
 #endif
 
-#ifdef _POSIX_OPEN_MAX
-#define MAX_OPEN_FDS _POSIX_OPEN_MAX
-#else
-#define MAX_OPEN_FDS 20
-#endif
 
-/* Helper to pass patrameters related to keypad based operations. */
+/* Helper to pass parameters related to keypad based operations. */
 struct pininfo_s
 {
   int mode;
@@ -104,6 +100,8 @@
   unsigned short port; /* Port number:  0 = unused, 1 - dev/tty */
 
   /* Function pointers intialized to the various backends.  */
+  int (*connect_card)(int);
+  int (*disconnect_card)(int);
   int (*close_reader)(int);
   int (*shutdown_reader)(int);
   int (*reset_reader)(int);
@@ -112,6 +110,7 @@
                           unsigned char *, size_t *, struct pininfo_s *);
   int (*check_keypad)(int, int, int, int, int, int);
   void (*dump_status_reader)(int);
+  int (*set_progress_cb)(int, gcry_handler_progress_t, void*);
 
   struct {
     ccid_driver_t handle;
@@ -132,6 +131,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. */
@@ -220,7 +220,12 @@
 #define PCSC_E_READER_UNAVAILABLE      0x80100017
 #define PCSC_W_REMOVED_CARD            0x80100069
 
+/* The PC/SC error is defined as a long as per specs.  Due to left
+   shifts bit 31 will get sign extended.  We use this mask to fix
+   it. */
+#define PCSC_ERR_MASK(a)  ((a) & 0xffffffff)
 
+
 struct pcsc_io_request_s
 {
   unsigned long protocol;
@@ -272,7 +277,8 @@
                                 unsigned long *r_protocol,
                                 unsigned char *atr, unsigned long *atrlen);
 long (* DLSTDCALL pcsc_begin_transaction) (unsigned long card);
-long (* DLSTDCALL pcsc_end_transaction) (unsigned long card);
+long (* DLSTDCALL pcsc_end_transaction) (unsigned long card,
+                                         unsigned long disposition);
 long (* DLSTDCALL pcsc_transmit) (unsigned long card,
                                   const pcsc_io_request_t send_pci,
                                   const unsigned char *send_buffer,
@@ -286,6 +292,10 @@
 
 /*  Prototypes.  */
 static int pcsc_get_status (int slot, unsigned int *status);
+static int reset_pcsc_reader (int slot);
+static int apdu_get_status_internal (int slot, int hang, int no_atr_reset,
+                                     unsigned int *status,
+                                     unsigned int *changed);
 
 
 
@@ -322,6 +332,8 @@
       reader_table[reader].lock_initialized = 1;
     }
 #endif /*USE_GNU_PTH*/
+  reader_table[reader].connect_card = NULL;
+  reader_table[reader].disconnect_card = NULL;
   reader_table[reader].close_reader = NULL;
   reader_table[reader].shutdown_reader = NULL;
   reader_table[reader].reset_reader = NULL;
@@ -329,8 +341,10 @@
   reader_table[reader].send_apdu_reader = NULL;
   reader_table[reader].check_keypad = NULL;
   reader_table[reader].dump_status_reader = NULL;
+  reader_table[reader].set_progress_cb = 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
@@ -381,6 +395,7 @@
     case SW_HOST_NO_READER: return "no reader";
     case SW_HOST_ABORTED: return "aborted";
     case SW_HOST_NO_KEYPAD: return "no keypad"; 
+    case SW_HOST_ALREADY_CONNECTED: return "already connected"; 
     default: return "unknown host status error";
     }
 }
@@ -402,6 +417,7 @@
     case SW_FILE_NOT_FOUND : return "file not found";
     case SW_RECORD_NOT_FOUND:return "record not found";
     case SW_REF_NOT_FOUND  : return "reference not found";
+    case SW_BAD_LC         : return "bad Lc";
     case SW_BAD_P0_P1      : return "bad P0 or P1";
     case SW_INS_NOT_SUP    : return "instruction not supported";
     case SW_CLA_NOT_SUP    : return "class not supported";
@@ -531,10 +547,11 @@
 static int
 ct_get_status (int slot, unsigned int *status)
 {
-  *status = 1|2|4;  /* FIXME */
+  (void)slot;
+  /* The status we returned is wrong but we don't care becuase ctAPI
+     is not anymore required.  */
+  *status = APDU_CARD_USABLE|APDU_CARD_PRESENT|APDU_CARD_ACTIVE;
   return 0;
-
-  return SW_HOST_NOT_SUPPORTED;
 }
 
 /* Actually send the APDU of length APDULEN to SLOT and return a
@@ -548,6 +565,8 @@
   unsigned char dad[1], sad[1];
   unsigned short ctbuflen;
 
+  (void)pininfo;
+
   /* If we don't have an ATR, we need to reset the reader first. */
   if (!reader_table[slot].atrlen
       && (rc = reset_ct_reader (slot)))
@@ -655,6 +674,9 @@
   while (nleft > 0)
     {
 #ifdef USE_GNU_PTH
+# ifdef HAVE_W32_SYSTEM
+#  error Cannot use pth_read here because it expects a system HANDLE.
+# endif
       n = pth_read (fd, buf, nleft);
 #else
       n = read (fd, buf, nleft);
@@ -736,7 +758,7 @@
 {
   int rc;
 
-  switch (ec)
+  switch ( PCSC_ERR_MASK (ec) )
     {
     case 0:  rc = 0; break;
 
@@ -762,177 +784,87 @@
 static void
 dump_pcsc_reader_status (int slot)
 {
-  log_info ("reader slot %d: active protocol:", slot);
-  if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T0))
-    log_printf (" T0");
-  else if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
-    log_printf (" T1");
-  else if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_RAW))
-    log_printf (" raw");
-  log_printf ("\n");
+  if (reader_table[slot].pcsc.card)
+    {
+      log_info ("reader slot %d: active protocol:", slot);
+      if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T0))
+        log_printf (" T0");
+      else if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
+        log_printf (" T1");
+      else if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_RAW))
+        log_printf (" raw");
+      log_printf ("\n");
+    }
+  else
+    log_info ("reader slot %d: not connected\n", slot);
 }
 
 
-/* Send an PC/SC reset command and return a status word on error or 0
-   on success. */
+#ifndef NEED_PCSC_WRAPPER
 static int
-reset_pcsc_reader (int slot)
+pcsc_get_status_direct (int slot, unsigned int *status)
 {
-#ifdef NEED_PCSC_WRAPPER
   long err;
-  reader_table_t slotp;
-  size_t len;
-  int i, n;
-  unsigned char msgbuf[9];
-  unsigned int dummy_status;
-  int sw = SW_HOST_CARD_IO_ERROR;
+  struct pcsc_readerstate_s rdrstates[1];
 
-  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;
-    }
-
-  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=%lx)\n",
-                 (unsigned long)len);
-      sw = SW_HOST_GENERAL_ERROR;
-      goto command_failed;
-    }
-  err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
+  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 == PCSC_E_TIMEOUT)
+    err = 0; /* Timeout is no error error here. */
   if (err)
     {
-      log_error ("PC/SC RESET failed: %s (0x%lx)\n",
+      log_error ("pcsc_get_status_change failed: %s (0x%lx)\n",
                  pcsc_error_string (err), err);
-      /* If the error code is no smart card, we should not considere
-         this a major error and close the wrapper.  */
-      sw = pcsc_error_to_sw (err);
-      if (err == PCSC_E_NO_SMARTCARD)
-        return sw;
-      goto command_failed;
-    }
-
-  /* The open function 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;
-
-  /* Read the status so that IS_T0 will be set. */
-  pcsc_get_status (slot, &dummy_status);
-
-  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 sw;
-
-#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 pcsc_error_to_sw (err);
     }
 
+  /*   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":"" ); */
 
-  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 pcsc_error_to_sw (err);
-    }
-  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].is_t0 = !!(card_protocol & PCSC_PROTOCOL_T0);
+  *status = 0;
+  if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
+    *status |= APDU_CARD_PRESENT;
+  if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
+    *status |= APDU_CARD_ACTIVE;
+#ifndef HAVE_W32_SYSTEM
+  /* 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 & (APDU_CARD_PRESENT|APDU_CARD_ACTIVE))
+       == (APDU_CARD_PRESENT|APDU_CARD_ACTIVE)
+       && !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
+    *status |= APDU_CARD_USABLE;
+#else
+  /* Some winscard drivers may set EXCLUSIVE and INUSE at the same
+     time when we are the only user (SCM SCR335) under Windows.  */
+  if ((*status & (APDU_CARD_PRESENT|APDU_CARD_ACTIVE))
+      == (APDU_CARD_PRESENT|APDU_CARD_ACTIVE))
+    *status |= APDU_CARD_USABLE;
+#endif
 
   return 0;
-#endif /* !NEED_PCSC_WRAPPER */
 }
+#endif /*!NEED_PCSC_WRAPPER*/
 
 
+#ifdef NEED_PCSC_WRAPPER
 static int
-pcsc_get_status (int slot, unsigned int *status)
+pcsc_get_status_wrapped (int slot, unsigned int *status)
 {
-#ifdef NEED_PCSC_WRAPPER
   long err;
   reader_table_t slotp;
   size_t len, full_len;
@@ -978,7 +910,8 @@
       goto command_failed;
     }
   len -= 4; /* Already read the error code. */
-  err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
+  err = PCSC_ERR_MASK ((msgbuf[5] << 24) | (msgbuf[6] << 16)
+                       | (msgbuf[7] << 8 ) | msgbuf[8]);
   if (err)
     {
       log_error ("pcsc_status failed: %s (0x%lx)\n",
@@ -1023,7 +956,6 @@
   /* We are lucky: The wrapper already returns the data in the
      required format. */
   *status = buffer[3];
-
   return 0;
 
  command_failed:
@@ -1035,67 +967,63 @@
   slotp->pcsc.pid = (pid_t)(-1);
   slotp->used = 0;
   return sw;
+}
+#endif /*NEED_PCSC_WRAPPER*/
 
-#else /*!NEED_PCSC_WRAPPER*/
 
+static int
+pcsc_get_status (int slot, unsigned int *status)
+{
+#ifdef NEED_PCSC_WRAPPER
+  return pcsc_get_status_wrapped (slot, status);
+#else
+  return pcsc_get_status_direct (slot, status);
+#endif
+}
+
+
+#ifndef NEED_PCSC_WRAPPER
+static int
+pcsc_send_apdu_direct (int slot, unsigned char *apdu, size_t apdulen,
+                       unsigned char *buffer, size_t *buflen, 
+                       struct pininfo_s *pininfo)
+{
   long err;
-  struct pcsc_readerstate_s rdrstates[1];
+  struct pcsc_io_request_s send_pci;
+  unsigned long recv_len;
 
-  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 == PCSC_E_TIMEOUT)
-    err = 0; /* Timeout is no error error here. */
-  if (err)
-    {
-      log_error ("pcsc_get_status_change failed: %s (0x%lx)\n",
-                 pcsc_error_string (err), err);
-      return pcsc_error_to_sw (err);
-    }
+  if (!reader_table[slot].atrlen
+      && (err = reset_pcsc_reader (slot)))
+    return err;
 
+  if (DBG_CARD_IO)
+    log_printhex ("  PCSC_data:", apdu, apdulen);
 
-  /*   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":"" ); */
+  if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
+      send_pci.protocol = PCSC_PROTOCOL_T1;
+  else
+      send_pci.protocol = PCSC_PROTOCOL_T0;
+  send_pci.pci_len = sizeof send_pci;
+  recv_len = *buflen;
+  err = pcsc_transmit (reader_table[slot].pcsc.card,
+                       &send_pci, apdu, apdulen,
+                       NULL, buffer, &recv_len);
+  *buflen = recv_len;
+  if (err)
+    log_error ("pcsc_transmit failed: %s (0x%lx)\n",
+               pcsc_error_string (err), err);
 
-  *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;
+  return pcsc_error_to_sw (err);
+}
 #endif /*!NEED_PCSC_WRAPPER*/
-}
 
 
-/* Actually send the APDU of length APDULEN to SLOT and return a
-   maximum of *BUFLEN data in BUFFER, the actual returned size will be
-   set to BUFLEN.  Returns: CT API error code. */
+#ifdef NEED_PCSC_WRAPPER
 static int
-pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
-                unsigned char *buffer, size_t *buflen, 
-                struct pininfo_s *pininfo)
+pcsc_send_apdu_wrapped (int slot, unsigned char *apdu, size_t apdulen,
+                        unsigned char *buffer, size_t *buflen, 
+                        struct pininfo_s *pininfo)
 {
-#ifdef NEED_PCSC_WRAPPER
   long err;
   reader_table_t slotp;
   size_t len, full_len;
@@ -1103,6 +1031,8 @@
   unsigned char msgbuf[9];
   int sw = SW_HOST_CARD_IO_ERROR;
 
+  (void)pininfo;
+
   if (!reader_table[slot].atrlen
       && (err = reset_pcsc_reader (slot)))
     return err;
@@ -1148,7 +1078,8 @@
       goto command_failed;
     }
   len -= 4; /* Already read the error code. */
-  err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
+  err = PCSC_ERR_MASK ((msgbuf[5] << 24) | (msgbuf[6] << 16)
+                       | (msgbuf[7] << 8 ) | msgbuf[8]);
   if (err)
     {
       log_error ("pcsc_transmit failed: %s (0x%lx)\n",
@@ -1174,7 +1105,7 @@
        err = SW_HOST_INV_VALUE;
      }
    /* We need to read any rest of the response, to keep the
-      protocol runnng. */
+      protocol running.  */
    while (full_len)
      {
        unsigned char dummybuf[128];
@@ -1200,43 +1131,43 @@
   slotp->pcsc.pid = (pid_t)(-1);
   slotp->used = 0;
   return sw;
+}
+#endif /*NEED_PCSC_WRAPPER*/
 
-#else /*!NEED_PCSC_WRAPPER*/
 
-  long err;
-  struct pcsc_io_request_s send_pci;
-  unsigned long recv_len;
+/* Send the APDU of length APDULEN to SLOT and return a maximum of
+   *BUFLEN data in BUFFER, the actual returned size will be stored at
+   BUFLEN.  Returns: A status word. */
+static int
+pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
+                unsigned char *buffer, size_t *buflen, 
+                struct pininfo_s *pininfo)
+{
+#ifdef NEED_PCSC_WRAPPER
+  return pcsc_send_apdu_wrapped (slot, apdu, apdulen, buffer, buflen, pininfo);
+#else
+  return pcsc_send_apdu_direct (slot, apdu, apdulen, buffer, buflen, pininfo);
+#endif
+}
 
-  if (!reader_table[slot].atrlen
-      && (err = reset_pcsc_reader (slot)))
-    return err;
 
-  if (DBG_CARD_IO)
-    log_printhex ("  PCSC_data:", apdu, apdulen);
-
-  if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
-      send_pci.protocol = PCSC_PROTOCOL_T1;
-  else
-      send_pci.protocol = PCSC_PROTOCOL_T0;
-  send_pci.pci_len = sizeof send_pci;
-  recv_len = *buflen;
-  err = pcsc_transmit (reader_table[slot].pcsc.card,
-                       &send_pci, apdu, apdulen,
-                       NULL, buffer, &recv_len);
-  *buflen = recv_len;
-  if (err)
-    log_error ("pcsc_transmit failed: %s (0x%lx)\n",
-               pcsc_error_string (err), err);
-
-  return pcsc_error_to_sw (err);
+#ifndef NEED_PCSC_WRAPPER
+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;
+  reader_table[slot].used = 0;
+  return 0;
+}
 #endif /*!NEED_PCSC_WRAPPER*/
-}
 
 
+#ifdef NEED_PCSC_WRAPPER
 static int
-close_pcsc_reader (int slot)
+close_pcsc_reader_wrapped (int slot)
 {
-#ifdef NEED_PCSC_WRAPPER
   long err;
   reader_table_t slotp;
   size_t len;
@@ -1280,7 +1211,8 @@
       goto command_failed;
     }
   len -= 4; /* Already read the error code. */
-  err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
+  err = PCSC_ERR_MASK ((msgbuf[5] << 24) | (msgbuf[6] << 16)
+                       | (msgbuf[7] << 8 ) | msgbuf[8]);
   if (err)
     log_error ("pcsc_close failed: %s (0x%lx)\n",
                pcsc_error_string (err), err);
@@ -1297,25 +1229,348 @@
   slotp->pcsc.pid = (pid_t)(-1);
   slotp->used = 0;
   return 0;
+}
+#endif /*NEED_PCSC_WRAPPER*/
 
-#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;
+static int
+close_pcsc_reader (int slot)
+{
+#ifdef NEED_PCSC_WRAPPER
+  return close_pcsc_reader_wrapped (slot);
+#else
+  return close_pcsc_reader_direct (slot);
+#endif
+}
+
+
+/* Connect a PC/SC card.  */
+#ifndef NEED_PCSC_WRAPPER
+static int
+connect_pcsc_card (int slot)
+{
+  long err;
+
+  assert (slot >= 0 && slot < MAX_READER);
+
+  if (reader_table[slot].pcsc.card)
+    return SW_HOST_ALREADY_CONNECTED;
+
+  reader_table[slot].atrlen = 0;
+  reader_table[slot].last_status = 0;
+  reader_table[slot].is_t0 = 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)
+    {
+      reader_table[slot].pcsc.card = 0;
+      if (err != PCSC_E_NO_SMARTCARD) 
+        log_error ("pcsc_connect failed: %s (0x%lx)\n",
+                   pcsc_error_string (err), err);
+    }
+  else
+    {
+      char reader[250];
+      unsigned long readerlen, atrlen;
+      unsigned long card_state, card_protocol;
+
+      atrlen = DIM (reader_table[0].atr);
+      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.  Remember this.  */
+          reader_table[slot].last_status = (   APDU_CARD_USABLE
+                                             | APDU_CARD_PRESENT
+                                             | APDU_CARD_ACTIVE);
+          reader_table[slot].is_t0 = !!(card_protocol & PCSC_PROTOCOL_T0);
+        }
+    }
+
+  dump_reader_status (slot);
+  return pcsc_error_to_sw (err);
+}
+#endif /*!NEED_PCSC_WRAPPER*/
+
+
+/* Disconnect a PC/SC card.  Note that this succeeds even if the card
+   is not connected.  */
+#ifndef NEED_PCSC_WRAPPER
+static int
+disconnect_pcsc_card (int slot)
+{
+  long err;
+
+  assert (slot >= 0 && slot < MAX_READER);
+
+  if (!reader_table[slot].pcsc.card)
+    return 0; 
+
+  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;
   return 0;
+}
 #endif /*!NEED_PCSC_WRAPPER*/
+
+
+#ifndef NEED_PCSC_WRAPPER
+static int
+reset_pcsc_reader_direct (int slot)
+{
+  int sw;
+
+  sw = disconnect_pcsc_card (slot);
+  if (!sw)
+    sw = connect_pcsc_card (slot);
+
+  return sw;
 }
+#endif /*NEED_PCSC_WRAPPER*/
 
-/* Note:  It is a pitty that we can't return proper error codes.  */
+
+#ifdef NEED_PCSC_WRAPPER
 static int
-open_pcsc_reader (const char *portstr)
+reset_pcsc_reader_wrapped (int slot)
 {
+  long err;
+  reader_table_t slotp;
+  size_t len;
+  int i, n;
+  unsigned char msgbuf[9];
+  unsigned int dummy_status;
+  int sw = SW_HOST_CARD_IO_ERROR;
+
+  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;
+    }
+
+  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=%lx)\n",
+                 (unsigned long)len);
+      sw = SW_HOST_GENERAL_ERROR;
+      goto command_failed;
+    }
+  err = PCSC_ERR_MASK ((msgbuf[5] << 24) | (msgbuf[6] << 16)
+                       | (msgbuf[7] << 8 ) | msgbuf[8]);
+  if (err)
+    {
+      log_error ("PC/SC RESET failed: %s (0x%lx)\n",
+                 pcsc_error_string (err), err);
+      /* If the error code is no smart card, we should not considere
+         this a major error and close the wrapper.  */
+      sw = pcsc_error_to_sw (err);
+      if (err == PCSC_E_NO_SMARTCARD)
+        return sw;
+      goto command_failed;
+    }
+
+  /* The open function 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;
+
+  /* Read the status so that IS_T0 will be set. */
+  pcsc_get_status (slot, &dummy_status);
+
+  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 sw;
+}
+#endif /* !NEED_PCSC_WRAPPER */
+
+
+/* Send an PC/SC reset command and return a status word on error or 0
+   on success. */
+static int
+reset_pcsc_reader (int slot)
+{
 #ifdef NEED_PCSC_WRAPPER
+  return reset_pcsc_reader_wrapped (slot);
+#else
+  return reset_pcsc_reader_direct (slot);
+#endif
+}
+
+
+/* Open the PC/SC reader without using the wrapper.  Returns -1 on
+   error or a slot number for the reader.  */
+#ifndef NEED_PCSC_WRAPPER
+static int
+open_pcsc_reader_direct (const char *portstr)
+{
+  long err;
+  int slot;
+  char *list = NULL;
+  unsigned long nreader, listlen;
+  char *p;
+
+  slot = new_reader_slot ();
+  if (slot == -1)
+    return -1;
+
+  /* Fixme: Allocating a context for each slot is not required.  One
+     global context should be sufficient.  */
+  err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL,
+                                &reader_table[slot].pcsc.context);
+  if (err)
+    {
+      log_error ("pcsc_establish_context failed: %s (0x%lx)\n",
+                 pcsc_error_string (err), err);
+      reader_table[slot].used = 0;
+      return -1;
+    }
+
+  err = pcsc_list_readers (reader_table[slot].pcsc.context,
+                           NULL, NULL, &nreader);
+  if (!err)
+    {
+      list = xtrymalloc (nreader+1); /* Better add 1 for safety reasons. */
+      if (!list)
+        {
+          log_error ("error allocating memory for reader list\n");
+          pcsc_release_context (reader_table[slot].pcsc.context);
+          reader_table[slot].used = 0;
+          return -1 /*SW_HOST_OUT_OF_CORE*/;
+        }
+      err = pcsc_list_readers (reader_table[slot].pcsc.context,
+                               NULL, list, &nreader);
+    }
+  if (err)
+    {
+      log_error ("pcsc_list_readers failed: %s (0x%lx)\n",
+                 pcsc_error_string (err), err);
+      pcsc_release_context (reader_table[slot].pcsc.context);
+      reader_table[slot].used = 0;
+      xfree (list);
+      return -1;
+    }
+
+  listlen = nreader;
+  p = list;
+  while (nreader)
+    {
+      if (!*p && !p[1])
+        break;
+      if (*p)
+        log_info ("detected reader `%s'\n", p);
+      if (nreader < (strlen (p)+1))
+        {
+          log_error ("invalid response from pcsc_list_readers\n");
+          break;
+        }
+      nreader -= strlen (p)+1;
+      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);
+  list = NULL;
+
+  reader_table[slot].pcsc.card = 0;
+  reader_table[slot].atrlen = 0;
+  reader_table[slot].last_status = 0;
+
+  reader_table[slot].connect_card = connect_pcsc_card;
+  reader_table[slot].disconnect_card = disconnect_pcsc_card;
+  reader_table[slot].close_reader = close_pcsc_reader;
+  reader_table[slot].reset_reader = reset_pcsc_reader;
+  reader_table[slot].get_status_reader = pcsc_get_status;
+  reader_table[slot].send_apdu_reader = pcsc_send_apdu;
+  reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
+
+  dump_reader_status (slot);
+  return slot;
+}
+#endif /*!NEED_PCSC_WRAPPER */
+
+
 /* Open the PC/SC reader using the pcsc_wrapper program.  This is
    needed to cope with different thread models and other peculiarities
    of libpcsclite. */
+#ifdef NEED_PCSC_WRAPPER
+static int
+open_pcsc_reader_wrapped (const char *portstr)
+{
   int slot;
   reader_table_t slotp;
   int fd, rp[2], wp[2];
@@ -1326,14 +1581,24 @@
   int err;
   unsigned int dummy_status;
   int sw = SW_HOST_CARD_IO_ERROR;
+  /* Note that we use the constant and not the fucntion because this
+     code won't be be used under Windows.  */
+  const char *wrapperpgm = GNUPG_LIBEXECDIR "/gnupg-pcsc-wrapper";
 
+  if (access (wrapperpgm, X_OK))
+    {
+      log_error ("can't run PC/SC access module `%s': %s\n",
+                 wrapperpgm, strerror (errno));
+      return -1;
+    }
+
   slot = new_reader_slot ();
   if (slot == -1)
     return -1;
   slotp = reader_table + slot;
 
-  /* Fire up the pcsc wrapper.  We don't use any fork/exec code from
-     the common directy but implement it direclty so that this file
+  /* Fire up the PC/SCc wrapper.  We don't use any fork/exec code from
+     the common directy but implement it directly so that this file
      may still be source copied. */
 
   if (pipe (rp) == -1)
@@ -1391,14 +1656,9 @@
         log_fatal ("dup2 stderr failed: %s\n", strerror (errno));
 
       /* Close all other files. */
-      n = sysconf (_SC_OPEN_MAX);
-      if (n < 0)
-        n = MAX_OPEN_FDS;
-      for (i=3; i < n; i++)
-        close(i);
-      errno = 0;
+      close_all_fds (3, NULL);
 
-      execl (GNUPG_LIBDIR "/pcsc-wrapper",
+      execl (wrapperpgm,
              "pcsc-wrapper",
              "--",
              "1", /* API version */
@@ -1423,7 +1683,7 @@
 #endif
   while ( (i=WAIT (pid, NULL, 0)) == -1 && errno == EINTR)
     ;
-#undef X
+#undef WAIT
 
   /* Now send the open request. */
   msgbuf[0] = 0x01; /* OPEN command. */
@@ -1459,7 +1719,8 @@
                  (unsigned long)len);
       goto command_failed;
     }
-  err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
+  err = PCSC_ERR_MASK ((msgbuf[5] << 24) | (msgbuf[6] << 16)
+                       | (msgbuf[7] << 8 ) | msgbuf[8]);
   if (err)
     {
       log_error ("PC/SC OPEN failed: %s\n", pcsc_error_string (err));
@@ -1482,7 +1743,9 @@
         }
       /* 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->last_status = (  APDU_CARD_USABLE
+                            | APDU_CARD_PRESENT
+                            | APDU_CARD_ACTIVE);
     }
   slotp->atrlen = len;
 
@@ -1490,7 +1753,6 @@
   reader_table[slot].reset_reader = reset_pcsc_reader;
   reader_table[slot].get_status_reader = pcsc_get_status;
   reader_table[slot].send_apdu_reader = pcsc_send_apdu;
-  reader_table[slot].check_keypad = NULL;
   reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
 
   /* Read the status so that IS_T0 will be set. */
@@ -1510,146 +1772,21 @@
   /* There is no way to return SW. */
   return -1;
 
-#else /*!NEED_PCSC_WRAPPER */
-  long err;
-  int slot;
-  char *list = NULL;
-  unsigned long nreader, listlen, atrlen;
-  char *p;
-  unsigned long card_state, card_protocol;
+}
+#endif /*NEED_PCSC_WRAPPER*/
 
-  slot = new_reader_slot ();
-  if (slot == -1)
-    return -1;
 
-  err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL,
-                                &reader_table[slot].pcsc.context);
-  if (err)
-    {
-      log_error ("pcsc_establish_context failed: %s (0x%lx)\n",
-                 pcsc_error_string (err), err);
-      reader_table[slot].used = 0;
-      return -1;
-    }
-
-  err = pcsc_list_readers (reader_table[slot].pcsc.context,
-                           NULL, NULL, &nreader);
-  if (!err)
-    {
-      list = xtrymalloc (nreader+1); /* Better add 1 for safety reasons. */
-      if (!list)
-        {
-          log_error ("error allocating memory for reader list\n");
-          pcsc_release_context (reader_table[slot].pcsc.context);
-          reader_table[slot].used = 0;
-          return -1 /*SW_HOST_OUT_OF_CORE*/;
-        }
-      err = pcsc_list_readers (reader_table[slot].pcsc.context,
-                               NULL, list, &nreader);
-    }
-  if (err)
-    {
-      log_error ("pcsc_list_readers failed: %s (0x%lx)\n",
-                 pcsc_error_string (err), err);
-      pcsc_release_context (reader_table[slot].pcsc.context);
-      reader_table[slot].used = 0;
-      xfree (list);
-      return -1 /*pcsc_error_to_sw (err)*/;
-    }
-
-  listlen = nreader;
-  p = list;
-  while (nreader)
-    {
-      if (!*p && !p[1])
-        break;
-      if (*p)
-        log_info ("detected reader `%s'\n", p);
-      if (nreader < (strlen (p)+1))
-        {
-          log_error ("invalid response from pcsc_list_readers\n");
-          break;
-        }
-      nreader -= strlen (p)+1;
-      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 /*SW_HOST_OUT_OF_CORE*/;
-    }
-  strcpy (reader_table[slot].rdrname, portstr? portstr : list);
-  xfree (list);
-  list = NULL;
-
-  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 == PCSC_E_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;
-      return -1 /*pcsc_error_to_sw (err)*/;
-    }
-
-  reader_table[slot].atrlen = 0;
-  reader_table[slot].last_status = 0;
-  if (!err)
-    {
-      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);
-          reader_table[slot].is_t0 = !!(card_protocol & PCSC_PROTOCOL_T0);
-        }
-    }
-
-  reader_table[slot].close_reader = close_pcsc_reader;
-  reader_table[slot].reset_reader = reset_pcsc_reader;
-  reader_table[slot].get_status_reader = pcsc_get_status;
-  reader_table[slot].send_apdu_reader = pcsc_send_apdu;
-  reader_table[slot].check_keypad = NULL;
-  reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
-
-/*   log_debug ("state    from pcsc_status: 0x%lx\n", card_state); */
-/*   log_debug ("protocol from pcsc_status: 0x%lx\n", card_protocol); */
-
-  dump_reader_status (slot);
-  return slot;
-#endif /*!NEED_PCSC_WRAPPER */
+static int
+open_pcsc_reader (const char *portstr)
+{
+#ifdef NEED_PCSC_WRAPPER
+  return open_pcsc_reader_wrapped (portstr);
+#else
+  return open_pcsc_reader_direct (portstr);
+#endif
 }
 
 
-
 
 #ifdef HAVE_LIBUSB
 /*
@@ -1701,6 +1838,15 @@
 
 
 static int
+set_progress_cb_ccid_reader (int slot, gcry_handler_progress_t cb, void *cb_arg)
+{
+  reader_table_t slotp = reader_table + slot;
+
+  return ccid_set_progress_cb (slotp->ccid.handle, cb, cb_arg);
+}
+
+
+static int
 get_status_ccid (int slot, unsigned int *status)
 {
   int rc;
@@ -1708,12 +1854,12 @@
 
   rc = ccid_slot_status (reader_table[slot].ccid.handle, &bits);
   if (rc)
-    return -1;
+    return rc;
 
   if (bits == 0)
-    *status = 1|2|4;
+    *status = (APDU_CARD_USABLE|APDU_CARD_PRESENT|APDU_CARD_ACTIVE);
   else if (bits == 1)
-    *status = 2;
+    *status = APDU_CARD_PRESENT;
   else
     *status = 0;
 
@@ -1738,7 +1884,7 @@
     return err;
 
   if (DBG_CARD_IO)
-    log_printhex ("  APDU_data:", apdu, apdulen);
+    log_printhex (" raw apdu:", apdu, apdulen);
 
   maxbuflen = *buflen;
   if (pininfo)
@@ -1809,7 +1955,9 @@
     {
       /* 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].last_status = (APDU_CARD_USABLE
+                                        | APDU_CARD_PRESENT
+                                        | APDU_CARD_ACTIVE);
     }
 
   reader_table[slot].close_reader = close_ccid_reader;
@@ -1819,6 +1967,10 @@
   reader_table[slot].send_apdu_reader = send_apdu_ccid;
   reader_table[slot].check_keypad = check_ccid_keypad;
   reader_table[slot].dump_status_reader = dump_ccid_reader_status;
+  reader_table[slot].set_progress_cb = set_progress_cb_ccid_reader;
+  /* Our CCID reader code does not support T=0 at all, thus reset the
+     flag.  */
+  reader_table[slot].is_t0 = 0;
 
   dump_reader_status (slot);
   return slot;
@@ -1913,7 +2065,7 @@
       rapdu_msg_release (msg);
       return sw;
     }
-  if (msg->datalen >= DIM (slotp->atr))
+  if (msg->datalen > DIM (slotp->atr))
     {
       log_error ("ATR returned by the RAPDU layer is too large\n");
       rapdu_msg_release (msg);
@@ -2094,7 +2246,7 @@
                  rapdu_strerror (msg->cmd));
       goto failure;
     }
-  if (msg->datalen >= DIM (slotp->atr))
+  if (msg->datalen > DIM (slotp->atr))
     {
       log_error ("ATR returned by the RAPDU layer is too large\n");
       goto failure;
@@ -2338,6 +2490,15 @@
                             writefnc, writefnc_value,
                             closefnc, closefnc_value);
 #else
+  (void)portstr;
+  (void)cookie;
+  (void)length;
+  (void)readfnc;
+  (void)readfnc_value;
+  (void)writefnc;
+  (void)writefnc_value;
+  (void)closefnc;
+  (void)closefnc_value;
 #ifdef _WIN32
   errno = ENOENT;
 #else
@@ -2351,21 +2512,58 @@
 int
 apdu_close_reader (int slot)
 {
+  int sw;
+
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
+  sw = apdu_disconnect (slot);
+  if (sw)
+    return sw;
   if (reader_table[slot].close_reader)
     return reader_table[slot].close_reader (slot);
   return SW_HOST_NOT_SUPPORTED;
 }
 
+
+/* Function suitable for a cleanup function to close all reader.  It
+   should not be used if the reader will be opened again.  The reason
+   for implementing this to properly close USB devices so that they
+   will startup the next time without error. */
+void
+apdu_prepare_exit (void)
+{
+  static int sentinel;
+  int slot;
+
+  if (!sentinel)
+    {
+      sentinel = 1;
+      for (slot = 0; slot < MAX_READER; slot++)
+        if (reader_table[slot].used)
+          {
+            apdu_disconnect (slot);
+            if (reader_table[slot].close_reader)
+              reader_table[slot].close_reader (slot);
+            reader_table[slot].used = 0;
+          }
+      sentinel = 0;
+    }
+}
+
+
 /* Shutdown a reader; that is basically the same as a close but keeps
-   the handle ready for later use. A apdu_reset_header should be used
-   to get it active again. */
+   the handle ready for later use. A apdu_reset_reader or apdu_connect
+   should be used to get it active again. */
 int
 apdu_shutdown_reader (int slot)
 {
+  int sw;
+
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
+  sw = apdu_disconnect (slot);
+  if (sw)
+    return sw;
   if (reader_table[slot].shutdown_reader)
     return reader_table[slot].shutdown_reader (slot);
   return SW_HOST_NOT_SUPPORTED;
@@ -2383,6 +2581,91 @@
   return 0;
 }
 
+
+/* Connect a card.  This is used to power up the card and make sure
+   that an ATR is available.  */
+int
+apdu_connect (int slot)
+{
+  int sw;
+
+  if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
+    return SW_HOST_NO_DRIVER;
+
+  /* Only if the access method provides a connect function we use it.




More information about the Gnupg-commits mailing list