[PC/SC] detect other events besides card insertion/removal

* remove whitespace.
 * don't use SC_MAX_READERS and allocate memory dynamically.


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3987 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
martin 2010-02-03 09:54:02 +00:00
parent 4c34f5b28c
commit 36992b4001
1 changed files with 92 additions and 69 deletions

View File

@ -2,6 +2,7 @@
* reader-pcsc.c: Reader driver for PC/SC interface
*
* Copyright (C) 2002 Juha Yrjölä <juha.yrjola@iki.fi>
* Copyright (C) 2009,2010 Martin Paljak <martin@paljak.pri.ee>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -40,7 +41,7 @@
/* Logging */
#define PCSC_TRACE(reader, desc, rv) do { if (reader->ctx->debug >= 3) sc_debug(reader->ctx, "%s:" desc ": 0x%08lx\n", reader->name, rv); } while (0)
#define PCSC_LOG(ctx, desc, rv) do { if (ctx->debug >= 3) sc_debug(ctx, desc ": 0x%08lx\n", rv); } while (0)
#define PCSC_LOG(ctx, desc, rv) do { if (ctx->debug >= 3) sc_debug(ctx, desc ": 0x%08lx\n", rv); } while (0)
/* Utility for handling big endian IOCTL codes. */
#define dw2i_be(a, x) ((((((a[x] << 8) + a[x+1]) << 8) + a[x+2]) << 8) + a[x+3])
@ -79,7 +80,7 @@ struct pcsc_private_data {
DWORD verify_ioctl;
DWORD verify_ioctl_start;
DWORD verify_ioctl_finish;
DWORD modify_ioctl;
DWORD modify_ioctl_start;
DWORD modify_ioctl_finish;
@ -250,7 +251,7 @@ out:
sc_mem_clear(rbuf, rbuflen);
free(rbuf);
}
return r;
}
@ -261,7 +262,7 @@ static int refresh_attributes(sc_reader_t *reader)
LONG rv;
sc_debug(reader->ctx, "%s status check", reader->name);
sc_debug(reader->ctx, "%s status check", reader->name);
if (priv->reader_state.szReader == NULL) {
priv->reader_state.szReader = reader->name;
priv->reader_state.dwCurrentState = SCARD_STATE_UNAWARE;
@ -271,7 +272,7 @@ static int refresh_attributes(sc_reader_t *reader)
}
rv = priv->gpriv->SCardGetStatusChange(priv->gpriv->pcsc_ctx, 0, &priv->reader_state, 1);
if (rv != SCARD_S_SUCCESS && rv != (LONG)SCARD_E_TIMEOUT) {
if (rv == (LONG)SCARD_E_TIMEOUT) {
reader->flags &= ~SCARD_STATE_CHANGED;
@ -287,7 +288,7 @@ static int refresh_attributes(sc_reader_t *reader)
/* State means "reader unknown", but we have listed it at least once */
return SC_ERROR_READER_DETACHED;
}
if (priv->reader_state.dwEventState & SCARD_STATE_PRESENT) {
int old_flags = reader->flags;
int maybe_changed = 0;
@ -366,7 +367,7 @@ static int pcsc_reconnect(sc_reader_t * reader, int reset)
/* reconnect always unlocks transaction */
priv->locked = 0;
rv = priv->gpriv->SCardReconnect(priv->pcsc_card,
priv->gpriv->connect_exclusive ? SCARD_SHARE_EXCLUSIVE : SCARD_SHARE_SHARED,
SCARD_PROTOCOL_ANY, reset ? SCARD_UNPOWER_CARD : SCARD_LEAVE_CARD, &active_proto);
@ -387,7 +388,7 @@ static int pcsc_reconnect(sc_reader_t * reader, int reset)
PCSC_TRACE(reader, "SCardReconnect failed", rv);
return pcsc_to_opensc_error(rv);
}
reader->active_protocol = pcsc_proto_to_opensc(active_proto);
return pcsc_to_opensc_error(rv);
}
@ -401,7 +402,7 @@ static int pcsc_connect(sc_reader_t *reader)
int r;
SC_FUNC_CALLED(reader->ctx, 3);
r = refresh_attributes(reader);
if (r != SC_SUCCESS)
SC_FUNC_RETURN(reader->ctx, 4, r);
@ -423,7 +424,7 @@ static int pcsc_connect(sc_reader_t *reader)
/* after connect reader is not locked yet */
priv->locked = 0;
sc_debug(reader->ctx, "After connect protocol = %d", reader->active_protocol);
/* If we need a specific protocol, reconnect if needed */
if (_sc_check_forced_protocol(reader->ctx, reader->atr, reader->atr_len, (unsigned int *) &protocol)) {
/* If current protocol differs from the protocol we want to force */
@ -444,9 +445,9 @@ static int pcsc_connect(sc_reader_t *reader)
static int pcsc_disconnect(sc_reader_t * reader)
{
struct pcsc_private_data *priv = GET_PRIV_DATA(reader);
SC_FUNC_CALLED(reader->ctx, 3);
priv->gpriv->SCardDisconnect(priv->pcsc_card, priv->gpriv->connect_reset ?
SCARD_RESET_CARD : SCARD_LEAVE_CARD);
reader->flags = 0;
@ -544,7 +545,7 @@ static int pcsc_cancel(sc_context_t *ctx, void *reader_data)
#ifndef _WIN32
if (gpriv->pcsc_wait_ctx != -1) {
rv = gpriv->SCardCancel(gpriv->pcsc_wait_ctx);
if (rv == SCARD_S_SUCCESS)
if (rv == SCARD_S_SUCCESS)
/* Also close and clear the waiting context */
rv = gpriv->SCardReleaseContext(gpriv->pcsc_wait_ctx);
}
@ -557,7 +558,7 @@ static int pcsc_cancel(sc_context_t *ctx, void *reader_data)
}
return SC_SUCCESS;
}
static struct sc_reader_operations pcsc_ops;
static struct sc_reader_driver pcsc_drv = {
@ -589,7 +590,7 @@ static int pcsc_init(sc_context_t *ctx, void **reader_data)
gpriv->provider_library = DEFAULT_PCSC_PROVIDER;
gpriv->pcsc_ctx = -1;
gpriv->pcsc_wait_ctx = -1;
conf_block = sc_get_conf_block(ctx, "reader_driver", "pcsc", 1);
if (conf_block) {
gpriv->connect_reset =
@ -633,7 +634,7 @@ static int pcsc_init(sc_context_t *ctx, void **reader_data)
gpriv->SCardGetStatusChange = (SCardGetStatusChange_t)lt_dlsym(gpriv->dlhandle, "SCardGetStatusChangeA");
if (gpriv->SCardListReaders == NULL)
gpriv->SCardListReaders = (SCardListReaders_t)lt_dlsym(gpriv->dlhandle, "SCardListReadersA");
/* If we have SCardGetAttrib it is correct API */
if (lt_dlsym(gpriv->dlhandle, "SCardGetAttrib") != NULL) {
#ifdef __APPLE__
@ -683,6 +684,8 @@ static int pcsc_finish(sc_context_t *ctx, void *prv_data)
{
struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *) prv_data;
SC_FUNC_CALLED(ctx, 3);
if (gpriv) {
if (gpriv->pcsc_ctx != -1)
gpriv->SCardReleaseContext(gpriv->pcsc_ctx);
@ -819,7 +822,7 @@ static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data)
PCSC_TRACE(reader, "SCardConnect", rv);
if (rv == (LONG)SCARD_E_SHARING_VIOLATION) { /* Assume that there is a card in the reader in shared mode if direct communcation failed */
rv = gpriv->SCardConnect(gpriv->pcsc_ctx, reader->name, SCARD_SHARE_SHARED, SCARD_PROTOCOL_ANY, &card_handle, &active_proto);
PCSC_TRACE(reader, "SCardConnect", rv);
PCSC_TRACE(reader, "SCardConnect", rv);
}
if (rv == SCARD_S_SUCCESS) {
rv = gpriv->SCardBeginTransaction(card_handle);
@ -867,7 +870,7 @@ static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data)
sc_debug(ctx, "Reader feature %02x is not supported", pcsc_tlv[i].tag);
}
}
/* Set reader capabilities based on detected IOCTLs */
if (priv->verify_ioctl || (priv->verify_ioctl_start && priv->verify_ioctl_finish)) {
char *log_text = "Reader supports pinpad PIN verification";
@ -878,7 +881,7 @@ static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data)
sc_debug(ctx, "%s %s", log_text, log_disabled);
}
}
if (priv->modify_ioctl || (priv->modify_ioctl_start && priv->modify_ioctl_finish)) {
char *log_text = "Reader supports pinpad PIN modification";
if (priv->gpriv->enable_pinpad) {
@ -912,11 +915,11 @@ static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data)
}
else {
PCSC_TRACE(reader, "SCardConnect failed", rv);
}
}
}
refresh_attributes(reader);
continue;
err1:
if (priv != NULL) {
free(priv);
@ -950,30 +953,20 @@ static int pcsc_wait_for_event(sc_context_t *ctx,
{
struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *)reader_data;
LONG rv;
SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS + 1];
unsigned long on_bits, off_bits;
SCARD_READERSTATE_A *rgReaderStates;
size_t i;
unsigned int num_watch;
int r = SC_ERROR_INTERNAL;
SC_FUNC_CALLED(ctx, 3);
on_bits = off_bits = 0;
if (event_mask & SC_EVENT_CARD_INSERTED) {
event_mask &= ~SC_EVENT_CARD_INSERTED;
on_bits |= SCARD_STATE_PRESENT;
}
if (event_mask & SC_EVENT_CARD_REMOVED) {
event_mask &= ~SC_EVENT_CARD_REMOVED;
off_bits |= SCARD_STATE_PRESENT;
}
/* FIXME check for unhandled masks?
if (event_mask != 0)
return SC_ERROR_INVALID_ARGUMENTS; */
rgReaderStates = (SCARD_READERSTATE_A *) calloc(sc_ctx_get_reader_count(ctx) + 1, sizeof(SCARD_READERSTATE_A));
if (!rgReaderStates)
return SC_ERROR_OUT_OF_MEMORY;
/* Find out the current status */
num_watch = sc_ctx_get_reader_count(ctx);
sc_debug(ctx, "Watching %d readers\n", num_watch);
sc_debug(ctx, "Trying to watch %d readers", num_watch);
for (i = 0; i < num_watch; i++) {
rgReaderStates[i].szReader = sc_ctx_get_reader(ctx, i)->name;
rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE;
@ -993,7 +986,8 @@ static int pcsc_wait_for_event(sc_context_t *ctx,
rv = gpriv->SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &gpriv->pcsc_wait_ctx);
if (rv != SCARD_S_SUCCESS) {
PCSC_LOG(ctx, "SCardEstablishContext(wait) failed", rv);
return pcsc_to_opensc_error(rv);
r = pcsc_to_opensc_error(rv);
goto out;
}
}
#else
@ -1002,14 +996,16 @@ static int pcsc_wait_for_event(sc_context_t *ctx,
if (num_watch == 0) {
sc_debug(ctx, "No readers available, PnP notification not supported");
*event_reader = NULL;
return SC_ERROR_NO_READERS_FOUND;
r = SC_ERROR_NO_READERS_FOUND;
goto out;
}
rv = gpriv->SCardGetStatusChange(gpriv->pcsc_wait_ctx, 0, rgReaderStates, num_watch);
if (rv != SCARD_S_SUCCESS) {
if (rv != (LONG)SCARD_E_TIMEOUT) {
PCSC_LOG(ctx, "SCardGetStatusChange(1) failed", rv);
return pcsc_to_opensc_error(rv);
r = pcsc_to_opensc_error(rv);
goto out;
}
}
@ -1027,26 +1023,43 @@ static int pcsc_wait_for_event(sc_context_t *ctx,
sc_debug(ctx, "%s before=0x%04X now=0x%04X", rsp->szReader, rsp->dwCurrentState, rsp->dwEventState);
prev_state = rsp->dwCurrentState;
state = rsp->dwEventState;
if ((state & on_bits & SCARD_STATE_PRESENT) &&
(prev_state & SCARD_STATE_EMPTY))
*event |= SC_EVENT_CARD_INSERTED;
if ((~state & off_bits & SCARD_STATE_PRESENT) &&
(prev_state & SCARD_STATE_PRESENT))
*event |= SC_EVENT_CARD_REMOVED;
if (*event) {
sc_debug(ctx, "Event 0x%02X in reader %s", *event, rsp->szReader);
*event_reader = sc_ctx_get_reader_by_name(ctx, rsp->szReader);
SC_FUNC_RETURN(ctx, 3, SC_SUCCESS);
}
if (state & SCARD_STATE_CHANGED) {
/* check for hotplug event */
if (strcmp(rgReaderStates[i].szReader, "\\\\?PnP?\\Notification") == 0 && event_mask & SC_EVENT_READER_ATTACHED) {
if (state & SCARD_STATE_CHANGED) {
/* check for hotplug events */
if (!strcmp(rgReaderStates[i].szReader, "\\\\?PnP?\\Notification")) {
sc_debug(ctx, "detected hotplug event");
*event = SC_EVENT_READER_ATTACHED;
*event |= SC_EVENT_READER_ATTACHED;
*event_reader = NULL;
}
if ((state & SCARD_STATE_PRESENT) && !(prev_state & SCARD_STATE_PRESENT)) {
sc_debug(ctx, "card inserted event");
*event |= SC_EVENT_CARD_INSERTED;
}
if ((prev_state & SCARD_STATE_PRESENT) && !(state & SCARD_STATE_PRESENT)) {
sc_debug(ctx, "card removed event");
*event |= SC_EVENT_CARD_REMOVED;
}
if ((state & SCARD_STATE_UNKNOWN) && !(prev_state & SCARD_STATE_UNKNOWN)) {
sc_debug(ctx, "reader detached event");
*event |= SC_EVENT_READER_DETACHED;
}
if ((prev_state & SCARD_STATE_UNKNOWN) && !(state & SCARD_STATE_UNKNOWN)) {
sc_debug(ctx, "reader re-attached event");
*event |= SC_EVENT_READER_ATTACHED;
}
if (*event & event_mask) {
sc_debug(ctx, "Matching event 0x%02X in reader %s", *event, rsp->szReader);
*event_reader = sc_ctx_get_reader_by_name(ctx, rsp->szReader);
r = SC_SUCCESS;
goto out;
SC_FUNC_RETURN(ctx, 3, SC_SUCCESS);
}
}
/* No match - copy the state so pcscd knows
@ -1054,29 +1067,39 @@ static int pcsc_wait_for_event(sc_context_t *ctx,
rsp->dwCurrentState = rsp->dwEventState;
}
/* Set the timeout if caller wants to time out */
if (timeout == 0)
return SC_ERROR_EVENT_TIMEOUT;
if (timeout == 0) {
r = SC_ERROR_EVENT_TIMEOUT;
goto out;
}
/* Set the timeout if caller wants to time out */
if (timeout == -1) {
timeout = INFINITE;
}
sc_debug(ctx, "Sleeping call, timeout 0x%lx", timeout);
rv = gpriv->SCardGetStatusChange(gpriv->pcsc_wait_ctx, timeout, rgReaderStates, num_watch);
if (rv == (LONG) SCARD_E_CANCELLED) {
/* C_Finalize was called, events don't matter */
return SC_ERROR_EVENT_TIMEOUT;
r = SC_ERROR_EVENT_TIMEOUT;
goto out;
}
if (rv == (LONG) SCARD_E_TIMEOUT) {
return SC_ERROR_EVENT_TIMEOUT;
r = SC_ERROR_EVENT_TIMEOUT;
goto out;
}
if (rv != SCARD_S_SUCCESS) {
PCSC_LOG(ctx, "SCardGetStatusChange(2) failed", rv);
return pcsc_to_opensc_error(rv);
r = pcsc_to_opensc_error(rv);
goto out;
}
}
out:
free(rgReaderStates);
SC_FUNC_RETURN(ctx, 3, r);
}
@ -1104,11 +1127,11 @@ static int part10_build_verify_pin_block(struct sc_reader *reader, u8 * buf, siz
u8 tmp;
unsigned int tmp16;
PIN_VERIFY_STRUCTURE *pin_verify = (PIN_VERIFY_STRUCTURE *)buf;
/* PIN verification control message */
pin_verify->bTimerOut = SC_CCID_PIN_TIMEOUT;
pin_verify->bTimerOut2 = SC_CCID_PIN_TIMEOUT;
/* bmFormatString */
tmp = 0x00;
if (data->pin1.encoding == SC_PIN_ENCODING_ASCII) {
@ -1154,7 +1177,7 @@ static int part10_build_verify_pin_block(struct sc_reader *reader, u8 * buf, siz
tmp16 = (data->pin1.min_length << 8 ) + data->pin1.max_length;
pin_verify->wPINMaxExtraDigit = HOST_TO_CCID_16(tmp16); /* Min Max */
pin_verify->bEntryValidationCondition = 0x02; /* Keypress only */
if (reader->capabilities & SC_READER_CAP_DISPLAY)
@ -1183,7 +1206,7 @@ static int part10_build_verify_pin_block(struct sc_reader *reader, u8 * buf, siz
}
pin_verify->ulDataLength = HOST_TO_CCID_32(offset); /* APDU size */
count = sizeof(PIN_VERIFY_STRUCTURE) + offset -1;
*size = count;
return SC_SUCCESS;
@ -1255,7 +1278,7 @@ static int part10_build_modify_pin_block(struct sc_reader *reader, u8 * buf, siz
if (!data->pin1.min_length || !data->pin1.max_length)
return SC_ERROR_INVALID_ARGUMENTS;
tmp16 = (data->pin1.min_length << 8 ) + data->pin1.max_length;
pin_modify->wPINMaxExtraDigit = HOST_TO_CCID_16(tmp16); /* Min Max */
@ -1265,7 +1288,7 @@ static int part10_build_modify_pin_block(struct sc_reader *reader, u8 * buf, siz
*/
pin_modify->bConfirmPIN = data->flags & SC_PIN_CMD_IMPLICIT_CHANGE ? 0x01 : 0x03;
pin_modify->bEntryValidationCondition = 0x02; /* bEntryValidationCondition, keypress only */
/* bNumberMessage flags
* 0x02: Messages seen on Pinpad display: New Pin, Confirm Pin
* 0x03: Messages seen on Pinpad display: Enter Old Pin, New Pin, Confirm Pin
@ -1299,7 +1322,7 @@ static int part10_build_modify_pin_block(struct sc_reader *reader, u8 * buf, siz
}
pin_modify->ulDataLength = HOST_TO_CCID_32(offset); /* APDU size */
count = sizeof(PIN_MODIFY_STRUCTURE) + offset -1;
*size = count;
return SC_SUCCESS;