diff --git a/etc/opensc.conf.in b/etc/opensc.conf.in index 6685243c..26de7395 100644 --- a/etc/opensc.conf.in +++ b/etc/opensc.conf.in @@ -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 diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index 25575514..0a19a0be 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -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) {