aboutsummaryrefslogtreecommitdiffstats
path: root/scd
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--scd/ChangeLog42
-rw-r--r--scd/apdu.c978
-rw-r--r--scd/apdu.h14
-rw-r--r--scd/command.c43
-rw-r--r--scd/sc-copykeys.c2
-rw-r--r--scd/scdaemon.c24
6 files changed, 687 insertions, 416 deletions
diff --git a/scd/ChangeLog b/scd/ChangeLog
index dec9d87d5..85177e535 100644
--- a/scd/ChangeLog
+++ b/scd/ChangeLog
@@ -1,3 +1,45 @@
+2008-10-14 Werner Koch <[email protected]>
+
+
+ * apdu.c (reader_table_s): Add fields connect_card and
+ disconnect_card.
+ (new_reader_slot): Set them to NULL.
+ (apdu_connect, apdu_disconnect): New.
+ (apdu_close_reader, apdu_shutdown_reader): Call apdu_disconnect.
+ (connect_pcsc_card, disconnect_pcsc_card): new.
+ (reset_pcsc_reader_direct): Implement in terms of
+ disconnect_pcsc_card and connect_pcsc_card.
+ (apdu_get_atr): Return NULL if there is no ATR.
+ * sc-copykeys.c (main): Add call to apdu_connect.
+ * command.c (open_card): Ditto.
+
+ * apdu.h (SW_HOST_ALREADY_CONNECTED): New.
+ (APDU_CARD_USABLE, APDU_CARD_PRESENT, APDU_CARD_ACTIVE): New.
+ * apdu.c: Replace constants by the new macros.
+ (open_pcsc_reader): Factor code out to ...
+ (open_pcsc_reader_direct, open_pcsc_reader_wrapped): New.
+ (reset_pcsc_reader): Factor code out to ...
+ (reset_pcsc_reader_direct, reset_pcsc_reader_wrapped): New.
+ (pcsc_get_status): Factor code out to ...
+ (pcsc_get_status_direct, pcsc_get_status_wrapped): New.
+ (pcsc_send_apdu): Factor code out to ...
+ (pcsc_send_apdu_direct, pcsc_send_apdu_wrapped): New.
+ (close_pcsc_reader): Factor code out to ...
+ (close_pcsc_reader_direct, close_pcsc_reader_wrapped): New.
+
+ * command.c (update_reader_status_file): Open the reader if not
+ yet done.
+
+ * scdaemon.c (TIMERTICK_INTERVAL_SEC, TIMERTICK_INTERVAL_USEC):
+ New to replace TIMERTICK_INTERVAL. Chnage from 2s (4 under W32)
+ to 250ms.
+
+2008-10-13 Werner Koch <[email protected]>
+
+ * command.c (option_handler) [W32]: Use strtoul with base 16.
+ (update_reader_status_file) [W32]: Set Event.
+ (scd_command_handler): Use INT2FD to silent warning.
+
2008-09-29 Werner Koch <[email protected]>
* scdaemon.h (GCRY_MD_USER): Rename to GCRY_MODULE_ID_USER.
diff --git a/scd/apdu.c b/scd/apdu.c
index 38a400bdf..c0c5c5d3e 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -103,6 +103,8 @@ struct reader_table_s {
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);
@@ -291,6 +293,7 @@ long (* DLSTDCALL pcsc_set_timeout) (unsigned long context,
/* Prototypes. */
static int pcsc_get_status (int slot, unsigned int *status);
+static int reset_pcsc_reader (int slot);
@@ -327,6 +330,8 @@ new_reader_slot (void)
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;
@@ -386,6 +391,7 @@ host_sw_string (long err)
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";
}
}
@@ -536,10 +542,10 @@ reset_ct_reader (int slot)
static int
ct_get_status (int slot, unsigned int *status)
{
- *status = 1|2|4; /* FIXME */
+ /* 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
@@ -767,178 +773,87 @@ pcsc_error_to_sw (long ec)
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;
-
- 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;
- }
+ struct pcsc_readerstate_s rdrstates[1];
- /* 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]);
+ 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 = DIM(reader_table[0].atr);
- 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;
@@ -1030,7 +945,6 @@ pcsc_get_status (int slot, unsigned int *status)
/* We are lucky: The wrapper already returns the data in the
required format. */
*status = buffer[3];
-
return 0;
command_failed:
@@ -1042,74 +956,63 @@ pcsc_get_status (int slot, unsigned int *status)
slotp->pcsc.pid = (pid_t)(-1);
slotp->used = 0;
return sw;
+}
+#endif /*NEED_PCSC_WRAPPER*/
-#else /*!NEED_PCSC_WRAPPER*/
- long err;
- struct pcsc_readerstate_s rdrstates[1];
+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
+}
- 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);
- }
+#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_io_request_s send_pci;
+ unsigned long recv_len;
+
+ if (!reader_table[slot].atrlen
+ && (err = reset_pcsc_reader (slot)))
+ return 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":"" ); */
+ if (DBG_CARD_IO)
+ log_printhex (" PCSC_data:", apdu, apdulen);
- *status = 0;
- if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
- *status |= 2;
- if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
- *status |= 4;
-#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 & 6) == 6
- && !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
- *status |= 1;
-#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 & 6) == 6)
- *status |= 1;
-#endif
+ 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 0;
-#endif /*!NEED_PCSC_WRAPPER*/
+ 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;
@@ -1215,43 +1118,43 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
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;
-
- if (!reader_table[slot].atrlen
- && (err = reset_pcsc_reader (slot)))
- return err;
- if (DBG_CARD_IO)
- log_printhex (" PCSC_data:", apdu, apdulen);
+/* 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].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);
-#endif /*!NEED_PCSC_WRAPPER*/
+#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;
@@ -1313,25 +1216,349 @@ close_pcsc_reader (int slot)
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
+ | 0x8000);
+ 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];
@@ -1358,8 +1585,8 @@ open_pcsc_reader (const char *portstr)
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)
@@ -1449,7 +1676,7 @@ open_pcsc_reader (const char *portstr)
#endif
while ( (i=WAIT (pid, NULL, 0)) == -1 && errno == EINTR)
;
-#undef X
+#undef WAIT
/* Now send the open request. */
msgbuf[0] = 0x01; /* OPEN command. */
@@ -1509,7 +1736,10 @@ open_pcsc_reader (const char *portstr)
}
/* 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
+ | 0x8000);
}
slotp->atrlen = len;
@@ -1517,7 +1747,6 @@ open_pcsc_reader (const char *portstr)
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. */
@@ -1537,146 +1766,21 @@ open_pcsc_reader (const char *portstr)
/* 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;
-
- 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 = 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. 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;
+}
+#endif /*NEED_PCSC_WRAPPER*/
-/* 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
/*
@@ -1738,9 +1842,9 @@ get_status_ccid (int slot, unsigned int *status)
return -1;
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;
@@ -1836,7 +1940,10 @@ open_ccid_reader (const char *portstr)
{
/* 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
+ | 0x8000);
}
reader_table[slot].close_reader = close_ccid_reader;
@@ -2335,7 +2442,11 @@ apdu_open_reader (const char *portstr)
pcsc_api_loaded = 1;
}
+#ifdef NEED_PCSC_WRAPPER
+ return open_pcsc_reader_wrapped (portstr);
+#else
return open_pcsc_reader (portstr);
+#endif
}
@@ -2378,21 +2489,31 @@ apdu_open_remote_reader (const char *portstr,
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;
}
/* Shutdown a reader; that is basically the same as a close but keeps
- the handle ready for later use. A apdu_reset_reader 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;
@@ -2410,6 +2531,58 @@ apdu_enum_reader (int slot, int *used)
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.
+ If not, we expect that the card has been implicitly connected by
+ apdu_open_reader. */
+ if (reader_table[slot].connect_card)
+ {
+ sw = lock_slot (slot);
+ if (!sw)
+ {
+ sw = reader_table[slot].connect_card (slot);
+ unlock_slot (slot);
+ }
+ }
+ else
+ sw = 0;
+ return sw;
+}
+
+int
+apdu_disconnect (int slot)
+{
+ int sw;
+
+ if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
+ return SW_HOST_NO_DRIVER;
+
+ if (reader_table[slot].disconnect_card)
+ {
+ sw = lock_slot (slot);
+ if (!sw)
+ {
+ sw = reader_table[slot].disconnect_card (slot);
+ unlock_slot (slot);
+ }
+ }
+ else
+ sw = 0;
+ return sw;
+}
+
+
+
/* Do a reset for the card in reader at SLOT. */
int
apdu_reset (int slot)
@@ -2430,7 +2603,10 @@ apdu_reset (int slot)
{
/* 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
+ | 0x8000);
}
unlock_slot (slot);
@@ -2474,7 +2650,10 @@ apdu_activate (int slot)
{
/* 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
+ | 0x8000);
}
}
}
@@ -2493,7 +2672,8 @@ apdu_get_atr (int slot, size_t *atrlen)
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
return NULL;
-
+ if (!reader_table[slot].atrlen)
+ return NULL;
buf = xtrymalloc (reader_table[slot].atrlen);
if (!buf)
return NULL;
@@ -2508,12 +2688,12 @@ apdu_get_atr (int slot, size_t *atrlen)
card to become available if HANG is set to true. On success the
bits in STATUS will be set to
- bit 0 = card present and usable
- bit 1 = card present
- bit 2 = card active
- bit 3 = card access locked [not yet implemented]
+ APDU_CARD_USABLE (bit 0) = card present and usable
+ APDU_CARD_PRESENT (bit 1) = card present
+ APDU_CARD_ACTIVE (bit 2) = card active
+ (bit 3) = card access locked [not yet implemented]
- For must application, testing bit 0 is sufficient.
+ For must applications, testing bit 0 is sufficient.
CHANGED will receive the value of the counter tracking the number
of card insertions. This value may be used to detect a card
diff --git a/scd/apdu.h b/scd/apdu.h
index 361dfdead..007bda767 100644
--- a/scd/apdu.h
+++ b/scd/apdu.h
@@ -65,13 +65,20 @@ enum {
SW_HOST_GENERAL_ERROR = 0x1000b,
SW_HOST_NO_READER = 0x1000c,
SW_HOST_ABORTED = 0x1000d,
- SW_HOST_NO_KEYPAD = 0x1000e
+ SW_HOST_NO_KEYPAD = 0x1000e,
+ SW_HOST_ALREADY_CONNECTED = 0x1000f
};
#define SW_EXACT_LENGTH_P(a) (((a)&~0xff) == SW_EXACT_LENGTH)
+/* Bit flags for the card status. */
+#define APDU_CARD_USABLE (1) /* Card is present and ready for use. */
+#define APDU_CARD_PRESENT (2) /* Card is just present. */
+#define APDU_CARD_ACTIVE (4) /* Card is active. */
+
+
/* Note , that apdu_open_reader returns no status word but -1 on error. */
int apdu_open_reader (const char *portstr);
int apdu_open_remote_reader (const char *portstr,
@@ -92,7 +99,10 @@ unsigned char *apdu_get_atr (int slot, size_t *atrlen);
const char *apdu_strerror (int rc);
-/* These apdu functions do return status words. */
+/* These APDU functions return status words. */
+
+int apdu_connect (int slot);
+int apdu_disconnect (int slot);
int apdu_activate (int slot);
int apdu_reset (int slot);
diff --git a/scd/command.c b/scd/command.c
index 696fa67ee..aabd93c25 100644
--- a/scd/command.c
+++ b/scd/command.c
@@ -102,8 +102,12 @@ struct server_local_s
/* The Assuan context used by this session/server. */
assuan_context_t assuan_ctx;
- int event_signal; /* Or 0 if not used. */
-
+#ifdef HAVE_W32_SYSTEM
+ unsigned long event_signal; /* Or 0 if not used. */
+#else
+ int event_signal; /* Or 0 if not used. */
+#endif
+
/* True if the card has been removed and a reset is required to
continue operation. */
int card_removed;
@@ -165,6 +169,7 @@ update_card_removed (int slot, int value)
{
sl->card_removed = value;
}
+ /* Let the card application layer know about the removal. */
if (value)
application_notify_card_removed (slot);
}
@@ -319,10 +324,16 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
if (!strcmp (key, "event-signal"))
{
/* A value of 0 is allowed to reset the event signal. */
+#ifdef HAVE_W32_SYSTEM
+ if (!*value)
+ return gpg_error (GPG_ERR_ASS_PARAMETER);
+ ctrl->server_local->event_signal = strtoul (value, NULL, 16);
+#else
int i = *value? atoi (value) : -1;
if (i < 0)
return gpg_error (GPG_ERR_ASS_PARAMETER);
ctrl->server_local->event_signal = i;
+#endif
}
return 0;
@@ -389,7 +400,15 @@ open_card (ctrl_t ctrl, const char *apptype)
if (slot == -1)
err = gpg_error (GPG_ERR_CARD);
else
- err = select_application (ctrl, slot, apptype, &ctrl->app_ctx);
+ {
+ /* Fixme: We should move the apdu_connect call to
+ select_application. */
+ int sw = apdu_connect (slot);
+ if (sw && sw != SW_HOST_ALREADY_CONNECTED)
+ err = gpg_error (GPG_ERR_CARD);
+ else
+ err = select_application (ctrl, slot, apptype, &ctrl->app_ctx);
+ }
TEST_CARD_REMOVAL (ctrl, err);
return err;
@@ -1774,7 +1793,7 @@ scd_command_handler (ctrl_t ctrl, int fd)
}
else
{
- rc = assuan_init_socket_server_ext (&ctx, fd, 2);
+ rc = assuan_init_socket_server_ext (&ctx, INT2FD(fd), 2);
}
if (rc)
{
@@ -1911,6 +1930,11 @@ update_reader_status_file (void)
int idx;
unsigned int status, changed;
+ /* Make sure that the reader has been opened. Like get_reader_slot,
+ this part of the code assumes that there is only one reader. */
+ if (!slot_table[0].valid)
+ (void)get_reader_slot ();
+
/* Note, that we only try to get the status, because it does not
make sense to wait here for a operation to complete. If we are
busy working with a card, delays in the status file update should
@@ -2007,11 +2031,20 @@ update_reader_status_file (void)
if (sl->event_signal && sl->assuan_ctx)
{
pid_t pid = assuan_get_pid (sl->assuan_ctx);
+
+#ifdef HAVE_W32_SYSTEM
+ HANDLE handle = (void *)sl->event_signal;
+
+ log_info ("client pid is %d, triggering event %lx (%p)\n",
+ pid, sl->event_signal, handle);
+ if (!SetEvent (handle))
+ log_error ("SetEvent(%lx) failed: %s\n",
+ sl->event_signal, w32_strerror (-1));
+#else
int signo = sl->event_signal;
log_info ("client pid is %d, sending signal %d\n",
pid, signo);
-#ifndef HAVE_W32_SYSTEM
if (pid != (pid_t)(-1) && pid && signo > 0)
kill (pid, signo);
#endif
diff --git a/scd/sc-copykeys.c b/scd/sc-copykeys.c
index 6a6c0e0d3..275bcf877 100644
--- a/scd/sc-copykeys.c
+++ b/scd/sc-copykeys.c
@@ -142,6 +142,8 @@ main (int argc, char **argv )
slot = apdu_open_reader (reader_port);
if (slot == -1)
exit (1);
+ if (apdu_connect (slot))
+ exit (1);
/* FIXME: Use select_application. */
appbuf.slot = slot;
diff --git a/scd/scdaemon.c b/scd/scdaemon.c
index 68119f592..384df51bf 100644
--- a/scd/scdaemon.c
+++ b/scd/scdaemon.c
@@ -148,15 +148,18 @@ static ARGPARSE_OPTS opts[] = {
#define DEFAULT_PCSC_DRIVER "libpcsclite.so"
#endif
-/* The timer tick used for housekeeping stuff. For Windows we use a
- longer period as the SetWaitableTimer seems to signal earlier than
- the 2 seconds. */
-#ifdef HAVE_W32_SYSTEM
-#define TIMERTICK_INTERVAL (4)
-#else
-#define TIMERTICK_INTERVAL (2) /* Seconds. */
-#endif
-
+/* The timer tick used for housekeeping stuff. We poll every 250ms to
+ let the user immediately know a status change.
+
+ This is not too good for power saving but given that there is no
+ easy way to block on card status changes it is the best we can do.
+ For PC/SC we could in theory use an extra thread to wait for status
+ changes but that requires a native thread because there is no way
+ to make the underlying PC/SC card change function block using a Pth
+ mechanism. Given that a native thread could only be used under W32
+ we don't do that at all. */
+#define TIMERTICK_INTERVAL_SEC (0)
+#define TIMERTICK_INTERVAL_USEC (250000)
/* Flag to indicate that a shutdown was requested. */
static int shutdown_pending;
@@ -1107,7 +1110,8 @@ handle_connections (int listen_fd)
/* Create a timeout event if needed. */
if (!time_ev)
time_ev = pth_event (PTH_EVENT_TIME,
- pth_timeout (TIMERTICK_INTERVAL, 0));
+ pth_timeout (TIMERTICK_INTERVAL_SEC,
+ TIMERTICK_INTERVAL_USEC));
/* POSIX says that fd_set should be implemented as a structure,
thus a simple assignment is fine to copy the entire set. */