PC/SC: make (dis)connect actions configurable, SCardDisconnect, SCardEndTransaction and SCardReconnect

actions can now be configured via opensc.conf in better detail.

git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4891 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
martin 2010-11-29 13:56:19 +00:00
parent 77c8cfc37d
commit c1c3aa1d55
2 changed files with 47 additions and 26 deletions

View File

@ -55,17 +55,26 @@ app default {
# max_send_size = 255;
# max_recv_size = 256;
# Connect to reader in exclusive mode.
# Connect to reader in exclusive mode?
# Default: false
# connect_exclusive = true;
#
# Reset the card after disconnect.
# Default: true
# connect_reset = false;
# What to do when disconnecting from a card (SCardDisconnect)
# Valid values: leave, reset, unpower.
# Default: reset
# disconnect_action = unpower;
#
# Reset the card after each transaction.
# Default: false
# transaction_reset = true;
# What to do at the end of a transaction (SCardEndTransaction)
# Valid values: leave, reset, unpower.
# Default: leave
# transaction_end_action = reset;
#
# What to do when reconnection to a card (SCardReconnect)
# Valid values: leave, reset, unpower.
# Note that this affects only the internal reconnect (after a SCARD_W_RESET_CARD).
# A forced reset via sc_reset() always does a full powerup.
# Default: leave
# reconnect_action = reset;
#
# Enable pinpad if detected (PC/SC v2.0.2 Part 10)
# Default: true

View File

@ -51,8 +51,9 @@ struct pcsc_global_private_data {
SCARDCONTEXT pcsc_wait_ctx;
int enable_pinpad;
int connect_exclusive;
int connect_reset;
int transaction_reset;
DWORD disconnect_action;
DWORD transaction_end_action;
DWORD reconnect_action;
const char *provider_library;
lt_dlhandle dlhandle;
SCardEstablishContext_t SCardEstablishContext;
@ -91,6 +92,16 @@ struct pcsc_private_data {
static int pcsc_detect_card_presence(sc_reader_t *reader);
static DWORD pcsc_reset_action(const char *str)
{
if (!strcmp(str, "reset"))
return SCARD_RESET_CARD;
else if (!strcmp(str, "unpower"))
return SCARD_UNPOWER_CARD;
else
return SCARD_LEAVE_CARD;
}
static int pcsc_to_opensc_error(LONG rv)
{
switch (rv) {
@ -254,7 +265,7 @@ out:
return r;
}
/* Calls SCardGetStatusChange on the reader to set ATR and associated flags (card present/changed) */
static int refresh_attributes(sc_reader_t *reader)
{
struct pcsc_private_data *priv = GET_PRIV_DATA(reader);
@ -378,7 +389,7 @@ static int check_forced_protocol(sc_context_t *ctx, u8 *atr, size_t atr_len, DWO
}
static int pcsc_reconnect(sc_reader_t * reader, int reset)
static int pcsc_reconnect(sc_reader_t * reader, DWORD action)
{
DWORD active_proto, tmp, protocol = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
LONG rv;
@ -403,7 +414,7 @@ static int pcsc_reconnect(sc_reader_t * reader, int reset)
rv = priv->gpriv->SCardReconnect(priv->pcsc_card,
priv->gpriv->connect_exclusive ? SCARD_SHARE_EXCLUSIVE : SCARD_SHARE_SHARED,
protocol, reset ? SCARD_UNPOWER_CARD : SCARD_LEAVE_CARD, &active_proto);
protocol, action, &active_proto);
if (rv != SCARD_S_SUCCESS) {
PCSC_TRACE(reader, "SCardReconnect failed", rv);
@ -466,8 +477,7 @@ static int pcsc_disconnect(sc_reader_t * reader)
SC_FUNC_CALLED(reader->ctx, SC_LOG_DEBUG_NORMAL);
priv->gpriv->SCardDisconnect(priv->pcsc_card, priv->gpriv->connect_reset ?
SCARD_RESET_CARD : SCARD_LEAVE_CARD);
priv->gpriv->SCardDisconnect(priv->pcsc_card, priv->gpriv->disconnect_action);
reader->flags = 0;
return SC_SUCCESS;
}
@ -494,7 +504,7 @@ static int pcsc_lock(sc_reader_t *reader)
return SC_ERROR_READER_REATTACHED;
case SCARD_W_RESET_CARD:
/* try to reconnect if the card was reset by some other application */
r = pcsc_reconnect(reader, 0);
r = pcsc_reconnect(reader, SCARD_LEAVE_CARD);
if (r != SC_SUCCESS) {
sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "pcsc_reconnect failed", r);
return r;
@ -517,8 +527,7 @@ static int pcsc_unlock(sc_reader_t *reader)
SC_FUNC_CALLED(reader->ctx, SC_LOG_DEBUG_NORMAL);
rv = priv->gpriv->SCardEndTransaction(priv->pcsc_card, priv->gpriv->transaction_reset ?
SCARD_RESET_CARD : SCARD_LEAVE_CARD);
rv = priv->gpriv->SCardEndTransaction(priv->pcsc_card, priv->gpriv->transaction_end_action);
priv->locked = 0;
if (rv != SCARD_S_SUCCESS) {
@ -542,7 +551,7 @@ static int pcsc_reset(sc_reader_t *reader)
int r;
int old_locked = priv->locked;
r = pcsc_reconnect(reader, 1);
r = pcsc_reconnect(reader, SCARD_UNPOWER_CARD);
if(r != SC_SUCCESS)
return r;
@ -600,9 +609,10 @@ static int pcsc_init(sc_context_t *ctx)
}
/* Defaults */
gpriv->connect_reset = 1;
gpriv->connect_exclusive = 0;
gpriv->transaction_reset = 0;
gpriv->disconnect_action = SCARD_RESET_CARD;
gpriv->transaction_end_action = SCARD_LEAVE_CARD;
gpriv->reconnect_action = SCARD_LEAVE_CARD;
gpriv->enable_pinpad = 1;
gpriv->provider_library = DEFAULT_PCSC_PROVIDER;
gpriv->pcsc_ctx = -1;
@ -610,19 +620,21 @@ static int pcsc_init(sc_context_t *ctx)
conf_block = sc_get_conf_block(ctx, "reader_driver", "pcsc", 1);
if (conf_block) {
gpriv->connect_reset =
scconf_get_bool(conf_block, "connect_reset", gpriv->connect_reset);
gpriv->connect_exclusive =
scconf_get_bool(conf_block, "connect_exclusive", gpriv->connect_exclusive);
gpriv->transaction_reset =
scconf_get_bool(conf_block, "transaction_reset", gpriv->transaction_reset);
gpriv->disconnect_action =
pcsc_reset_action(scconf_get_str(conf_block, "disconnect_action", "reset"));
gpriv->transaction_end_action =
pcsc_reset_action(scconf_get_str(conf_block, "transaction_end_action", "leave"));
gpriv->reconnect_action =
pcsc_reset_action(scconf_get_str(conf_block, "reconnect_action", "leave"));
gpriv->enable_pinpad =
scconf_get_bool(conf_block, "enable_pinpad", gpriv->enable_pinpad);
gpriv->provider_library =
scconf_get_str(conf_block, "provider_library", gpriv->provider_library);
}
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "PC/SC options: connect_reset=%d connect_exclusive=%d transaction_reset=%d enable_pinpad=%d",
gpriv->connect_reset, gpriv->connect_exclusive, gpriv->transaction_reset, gpriv->enable_pinpad);
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "PC/SC options: connect_exclusive=%d disconnect_action=%d transaction_end_action=%d reconnect_action=%d enable_pinpad=%d",
gpriv->connect_exclusive, gpriv->disconnect_action, gpriv->transaction_end_action, gpriv->reconnect_action, gpriv->enable_pinpad);
gpriv->dlhandle = lt_dlopen(gpriv->provider_library);
if (gpriv->dlhandle == NULL) {