[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