diff --git a/src/libopensc/apdu.c b/src/libopensc/apdu.c index 3342049a..41ea25e1 100644 --- a/src/libopensc/apdu.c +++ b/src/libopensc/apdu.c @@ -389,7 +389,7 @@ static int do_single_transmit(sc_card_t *card, sc_apdu_t *apdu) /* send APDU to the reader driver */ if (card->reader->ops->transmit == NULL) return SC_ERROR_NOT_SUPPORTED; - r = card->reader->ops->transmit(card->reader, card->slot, apdu); + r = card->reader->ops->transmit(card->reader, apdu); if (r != 0) { sc_debug(ctx, "unable to transmit APDU"); return r; @@ -414,7 +414,7 @@ static int do_single_transmit(sc_card_t *card, sc_apdu_t *apdu) if (card->wait_resend_apdu != 0) msleep(card->wait_resend_apdu); /* re-transmit the APDU with new Le length */ - r = card->reader->ops->transmit(card->reader, card->slot, apdu); + r = card->reader->ops->transmit(card->reader, apdu); if (r != SC_SUCCESS) { sc_debug(ctx, "unable to transmit APDU"); return r; diff --git a/src/libopensc/card-belpic.c b/src/libopensc/card-belpic.c index 99bef3e1..04a56702 100644 --- a/src/libopensc/card-belpic.c +++ b/src/libopensc/card-belpic.c @@ -282,10 +282,6 @@ static char *pp_msg_pin_mismatch[] = { "Die von Ihnen eingegebenen PINs unterscheiden sich.\n\nErneut versuchen oder abbrechen?" }; -struct pcsc_slot_data { - SCARDHANDLE pcsc_card; -}; /* comes from reader-pcsc.c */ -#define GET_SLOT_DATA(r) ((struct pcsc_slot_data *) (r)->drv_data) #define PCSC_ERROR(ctx, desc, rv) sc_debug(ctx, desc ": %lx\n", rv); #endif /* BELPIC_PIN_PAD */ @@ -1041,7 +1037,7 @@ static int belpic_init(sc_card_t *card) #ifdef BELPIC_PIN_PAD r = belpic_detect_pin_pad(card, priv); if (r == 1) - card->slot->capabilities |= SC_SLOT_CAP_PIN_PAD; + card->reader->capabilities |= SC_READER_CAP_PIN_PAD; else if (r < 0) return r; /* error loading/initing pin pad lib */ @@ -1303,10 +1299,10 @@ static int belpic_pin_cmd_usage(sc_card_t *card, struct sc_pin_cmd_data *data, struct belpic_priv_data *priv = DRVDATA(card); int lang = belpic_calculate_lang(card); - if (card->slot->capabilities & SC_SLOT_CAP_PIN_PAD && priv->scr_init != NULL) { + if (card->reader->capabilities & SC_READER_CAP_PIN_PAD && priv->scr_init != NULL) { LONG r; SCR_Card scr_card = { - GET_SLOT_DATA(card->slot)->pcsc_card, + priv->pcsc_card, lang_codes[lang], {NULL, 0} , @@ -1385,7 +1381,7 @@ static int belpic_askpin_verify(sc_card_t *card, int pin_usage) #ifdef BELPIC_PIN_PAD /* In case of a pinpad reader */ - if (card->slot->capabilities & SC_SLOT_CAP_PIN_PAD && priv->scr_init != NULL) { + if (card->reader->capabilities & SC_READER_CAP_PIN_PAD && priv->scr_init != NULL) { data.pin1.data = NULL; data.pin1.len = 0; diff --git a/src/libopensc/card-gemsafeV1.c b/src/libopensc/card-gemsafeV1.c index e0844c33..bb6a9410 100644 --- a/src/libopensc/card-gemsafeV1.c +++ b/src/libopensc/card-gemsafeV1.c @@ -625,9 +625,7 @@ static int gemsafe_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, if (card->reader && card->reader->ops && card->reader->ops->perform_verify) { - r = card->reader->ops->perform_verify(card->reader, - card->slot, - data); + r = card->reader->ops->perform_verify(card->reader, data); /* sw1/sw2 filled in by reader driver */ } else { sc_debug(card->ctx, diff --git a/src/libopensc/card-gpk.c b/src/libopensc/card-gpk.c index 602f137b..41579a79 100644 --- a/src/libopensc/card-gpk.c +++ b/src/libopensc/card-gpk.c @@ -114,7 +114,7 @@ gpk_match_card(sc_card_t *card) i = _sc_match_atr(card, gpk_atrs, &card->type); if (i < 0) { - const u8 *hist_bytes = card->slot->atr_info.hist_bytes; + const u8 *hist_bytes = card->reader->atr_info.hist_bytes; /* Gemplus GPK docs say we can use just the * FMN and PRN fields of the historical bytes @@ -123,7 +123,7 @@ gpk_match_card(sc_card_t *card) * We'll use the first 2 bytes as well */ - if ((card->slot->atr_info.hist_bytes_len >= 7) + if ((card->reader->atr_info.hist_bytes_len >= 7) && (hist_bytes[0] == 0x80) && (hist_bytes[1] == 0x65) && (hist_bytes[2] == 0xa2)) { /* FMN */ diff --git a/src/libopensc/card-setcos.c b/src/libopensc/card-setcos.c index a17ea5ec..25a0c65a 100644 --- a/src/libopensc/card-setcos.c +++ b/src/libopensc/card-setcos.c @@ -72,8 +72,8 @@ static struct sc_card_driver setcos_drv = { static int match_hist_bytes(sc_card_t *card, const char *str, size_t len) { - const char *src = (const char *) card->slot->atr_info.hist_bytes; - size_t srclen = card->slot->atr_info.hist_bytes_len; + const char *src = (const char *) card->reader->atr_info.hist_bytes; + size_t srclen = card->reader->atr_info.hist_bytes_len; size_t offset = 0; if (len == 0) diff --git a/src/libopensc/card-westcos.c b/src/libopensc/card-westcos.c index 8dc27d34..a78562c8 100644 --- a/src/libopensc/card-westcos.c +++ b/src/libopensc/card-westcos.c @@ -792,8 +792,6 @@ static int westcos_pin_cmd(sc_card_t * card, struct sc_pin_cmd_data *data, && card->reader->ops->perform_verify) { r = card->reader->ops->perform_verify(card-> reader, - card-> - slot, data); } else { r = SC_ERROR_NOT_SUPPORTED; diff --git a/src/libopensc/card.c b/src/libopensc/card.c index f49076bf..e3c2311d 100644 --- a/src/libopensc/card.c +++ b/src/libopensc/card.c @@ -96,11 +96,10 @@ static void sc_card_free(sc_card_t *card) free(card); } -int sc_connect_card(sc_reader_t *reader, int slot_id, sc_card_t **card_out) +int sc_connect_card(sc_reader_t *reader, sc_card_t **card_out) { sc_card_t *card; sc_context_t *ctx; - sc_slot_info_t *slot = _sc_get_slot_info(reader, slot_id); struct sc_card_driver *driver; int i, r = 0, idx, connected = 0; @@ -110,29 +109,26 @@ int sc_connect_card(sc_reader_t *reader, int slot_id, sc_card_t **card_out) SC_FUNC_CALLED(ctx, 1); if (reader->ops->connect == NULL) SC_FUNC_RETURN(ctx, 0, SC_ERROR_NOT_SUPPORTED); - if (slot == NULL) - SC_FUNC_RETURN(ctx, 0, SC_ERROR_SLOT_NOT_FOUND); card = sc_card_new(ctx); if (card == NULL) SC_FUNC_RETURN(ctx, 1, SC_ERROR_OUT_OF_MEMORY); - r = reader->ops->connect(reader, slot); + r = reader->ops->connect(reader); if (r) goto err; connected = 1; card->reader = reader; - card->slot = slot; card->ctx = ctx; /* These can be overridden by the card driver */ card->max_send_size = reader->driver->max_send_size; card->max_recv_size = reader->driver->max_recv_size; - memcpy(card->atr, slot->atr, slot->atr_len); - card->atr_len = slot->atr_len; + memcpy(card->atr, reader->atr, reader->atr_len); + card->atr_len = reader->atr_len; - _sc_parse_atr(reader->ctx, slot); + _sc_parse_atr(reader); /* See if the ATR matches any ATR specified in the config file */ if ((driver = ctx->forced_driver) == NULL) { @@ -222,13 +218,13 @@ int sc_connect_card(sc_reader_t *reader, int slot_id, sc_card_t **card_out) SC_FUNC_RETURN(ctx, 1, 0); err: if (connected) - reader->ops->disconnect(reader, slot); + reader->ops->disconnect(reader); if (card != NULL) sc_card_free(card); SC_FUNC_RETURN(ctx, 1, r); } -int sc_disconnect_card(sc_card_t *card, int action) +int sc_disconnect_card(sc_card_t *card) { sc_context_t *ctx; assert(sc_card_valid(card)); @@ -242,7 +238,7 @@ int sc_disconnect_card(sc_card_t *card, int action) sc_strerror(r)); } if (card->reader->ops->disconnect) { - int r = card->reader->ops->disconnect(card->reader, card->slot); + int r = card->reader->ops->disconnect(card->reader); if (r) sc_debug(card->ctx, "disconnect() failed: %s\n", sc_strerror(r)); @@ -264,7 +260,7 @@ int sc_reset(sc_card_t *card) if (r != SC_SUCCESS) return r; - r = card->reader->ops->reset(card->reader, card->slot); + r = card->reader->ops->reset(card->reader); /* invalidate cache */ memset(&card->cache, 0, sizeof(card->cache)); card->cache_valid = 0; @@ -291,12 +287,12 @@ int sc_lock(sc_card_t *card) return r; if (card->lock_count == 0) { if (card->reader->ops->lock != NULL) { - r = card->reader->ops->lock(card->reader, card->slot); + r = card->reader->ops->lock(card->reader); if (r == SC_ERROR_CARD_RESET || r == SC_ERROR_READER_REATTACHED) { /* invalidate cache */ memset(&card->cache, 0, sizeof(card->cache)); card->cache_valid = 0; - r = card->reader->ops->lock(card->reader, card->slot); + r = card->reader->ops->lock(card->reader); } } if (r == 0) @@ -330,7 +326,7 @@ int sc_unlock(sc_card_t *card) card->cache_valid = 0; /* release reader lock */ if (card->reader->ops->unlock != NULL) - r = card->reader->ops->unlock(card->reader, card->slot); + r = card->reader->ops->unlock(card->reader); } r2 = sc_mutex_unlock(card->ctx, card->mutex); if (r2 != SC_SUCCESS) { diff --git a/src/libopensc/ctbcs.c b/src/libopensc/ctbcs.c index 114e667a..6525f1ee 100644 --- a/src/libopensc/ctbcs.c +++ b/src/libopensc/ctbcs.c @@ -77,7 +77,7 @@ ctbcs_build_output_apdu(sc_apdu_t *apdu, const char *message) #endif static int -ctbcs_build_perform_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *data, sc_slot_info_t *slot) +ctbcs_build_perform_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *data) { const char *prompt; size_t buflen, count = 0, j = 0, len; @@ -87,7 +87,7 @@ ctbcs_build_perform_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *d ctbcs_init_apdu(apdu, SC_APDU_CASE_3_SHORT, CTBCS_INS_PERFORM_VERIFICATION, - CTBCS_P1_INTERFACE1 + (slot ? slot->id : 0), + CTBCS_P1_INTERFACE1, 0); buflen = sizeof(buf); @@ -145,15 +145,14 @@ ctbcs_build_perform_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *d } static int -ctbcs_build_modify_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *data, sc_slot_info_t *slot) +ctbcs_build_modify_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *data) { /* to be implemented */ - return SC_ERROR_NOT_SUPPORTED; + return SC_ERROR_NOT_IMPLEMENTED; } int -ctbcs_pin_cmd(sc_reader_t *reader, sc_slot_info_t *slot, - struct sc_pin_cmd_data *data) +ctbcs_pin_cmd(sc_reader_t *reader, struct sc_pin_cmd_data *data) { sc_card_t dummy_card, *card; sc_apdu_t apdu; @@ -162,11 +161,11 @@ ctbcs_pin_cmd(sc_reader_t *reader, sc_slot_info_t *slot, switch (data->cmd) { case SC_PIN_CMD_VERIFY: - r = ctbcs_build_perform_verification_apdu(&apdu, data, slot); + r = ctbcs_build_perform_verification_apdu(&apdu, data); break; case SC_PIN_CMD_CHANGE: case SC_PIN_CMD_UNBLOCK: - r = ctbcs_build_modify_verification_apdu(&apdu, data, slot); + r = ctbcs_build_modify_verification_apdu(&apdu, data); break; default: sc_debug(reader->ctx, "Unknown PIN command %d", data->cmd); @@ -176,7 +175,6 @@ ctbcs_pin_cmd(sc_reader_t *reader, sc_slot_info_t *slot, memset(&ops, 0, sizeof(ops)); memset(&dummy_card, 0, sizeof(dummy_card)); dummy_card.reader = reader; - dummy_card.slot = slot; dummy_card.ctx = reader->ctx; r = sc_mutex_create(reader->ctx, &dummy_card.mutex); if (r != SC_SUCCESS) diff --git a/src/libopensc/ctbcs.h b/src/libopensc/ctbcs.h index a3136049..adf4fd15 100644 --- a/src/libopensc/ctbcs.h +++ b/src/libopensc/ctbcs.h @@ -186,6 +186,6 @@ /* * Functions for building CTBCS commands */ -int ctbcs_pin_cmd(struct sc_reader *, sc_slot_info_t *, struct sc_pin_cmd_data *); +int ctbcs_pin_cmd(struct sc_reader *, struct sc_pin_cmd_data *); #endif /* _CTBCS_ */ diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c index ac812970..2e6ed21a 100644 --- a/src/libopensc/ctx.c +++ b/src/libopensc/ctx.c @@ -36,10 +36,7 @@ int _sc_add_reader(sc_context_t *ctx, sc_reader_t *reader) { assert(reader != NULL); reader->ctx = ctx; - if (ctx->reader_count == SC_MAX_READERS) - return SC_ERROR_TOO_MANY_OBJECTS; - ctx->reader[ctx->reader_count] = reader; - ctx->reader_count++; + list_append(&ctx->readers, reader); return SC_SUCCESS; } @@ -118,6 +115,17 @@ struct _sc_ctx_options { char *forced_card_driver; }; + +/* Simclist helper to locate readers by name */ +static int reader_list_seeker(const void *el, const void *key) { + const struct sc_reader *reader = (struct sc_reader *)el; + if ((el == NULL) || (key == NULL)) + return 0; + if (strcmp(reader->name, (char*)key) == 0) + return 1; + return 0; +} + static void del_drvs(struct _sc_ctx_options *opts, int type) { struct _sc_driver_entry *lst; @@ -658,14 +666,22 @@ int sc_ctx_detect_readers(sc_context_t *ctx) sc_reader_t *sc_ctx_get_reader(sc_context_t *ctx, unsigned int i) { - if (i >= (unsigned int)ctx->reader_count || i >= SC_MAX_READERS) - return NULL; - return ctx->reader[i]; + return list_get_at(&ctx->readers, i); +} + +sc_reader_t *sc_ctx_get_reader_by_id(sc_context_t *ctx, unsigned int id) +{ + return list_get_at(&ctx->readers, id); +} + +sc_reader_t *sc_ctx_get_reader_by_name(sc_context_t *ctx, const char * name) +{ + return list_seek(&ctx->readers, name); } unsigned int sc_ctx_get_reader_count(sc_context_t *ctx) { - return (unsigned int)ctx->reader_count; + return list_size(&ctx->readers); } int sc_establish_context(sc_context_t **ctx_out, const char *app_name) @@ -703,6 +719,8 @@ int sc_context_create(sc_context_t **ctx_out, const sc_context_param_t *parm) return SC_ERROR_OUT_OF_MEMORY; } + list_init(&ctx->readers); + list_attributes_seeker(&ctx->readers, reader_list_seeker); /* set thread context and create mutex object (if specified) */ if (parm != NULL && parm->thread_ctx != NULL) ctx->thread_ctx = parm->thread_ctx; @@ -738,20 +756,51 @@ int sc_context_create(sc_context_t **ctx_out, const sc_context_param_t *parm) return SC_SUCCESS; } +/* Following two are only implemented with internal PC/SC and don't consume a reader object */ +int sc_cancel(sc_context_t *ctx) +{ + int i; + const struct sc_reader_driver *driver; + SC_FUNC_CALLED(ctx, 2); + for (i = 0; ctx->reader_drivers[i] != NULL; i++) { + sc_debug(ctx, "trying %s", ctx->reader_drivers[i]->short_name); + driver = ctx->reader_drivers[i]; + if (driver->ops->cancel != NULL) + return driver->ops->cancel(ctx, ctx->reader_drv_data[i]); + } + return SC_ERROR_NOT_SUPPORTED; +} + + +int sc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_reader_t **event_reader, unsigned int *event, int timeout) +{ + int i; + const struct sc_reader_driver *driver; + SC_FUNC_CALLED(ctx, 2); + for (i = 0; ctx->reader_drivers[i] != NULL; i++) { + sc_debug(ctx, "trying %s", ctx->reader_drivers[i]->short_name); + driver = ctx->reader_drivers[i]; + if (driver->ops->wait_for_event != NULL) + return driver->ops->wait_for_event(ctx, ctx->reader_drv_data[i], event_mask, event_reader, event, timeout); + } + return SC_ERROR_NOT_SUPPORTED; +} + + int sc_release_context(sc_context_t *ctx) { - int i; + unsigned int i; assert(ctx != NULL); SC_FUNC_CALLED(ctx, 1); - for (i = 0; i < ctx->reader_count; i++) { - sc_reader_t *rdr = ctx->reader[i]; - - if (rdr->ops->release != NULL) - rdr->ops->release(rdr); - free(rdr->name); - free(rdr); + for (i=0; ireaders); i++) { + sc_reader_t *rdr = (sc_reader_t *) list_get_at(&ctx->readers, i); + if (rdr->ops->release != NULL) + rdr->ops->release(rdr); + free(rdr->name); + free(rdr); } + for (i = 0; ctx->reader_drivers[i] != NULL; i++) { const struct sc_reader_driver *drv = ctx->reader_drivers[i]; @@ -783,6 +832,7 @@ int sc_release_context(sc_context_t *ctx) fclose(ctx->debug_file); if (ctx->app_name != NULL) free(ctx->app_name); + list_destroy(&ctx->readers); sc_mem_clear(ctx, sizeof(*ctx)); free(ctx); return SC_SUCCESS; diff --git a/src/libopensc/internal-winscard.h b/src/libopensc/internal-winscard.h index c194a6bc..f7224645 100644 --- a/src/libopensc/internal-winscard.h +++ b/src/libopensc/internal-winscard.h @@ -32,6 +32,7 @@ typedef unsigned __int8 uint8_t; #define SCARD_STATE_UNAWARE 0x0000 /**< App wants status */ #define SCARD_STATE_IGNORE 0x0001 /**< Ignore this reader */ #define SCARD_STATE_CHANGED 0x0002 /**< State has changed */ +#define SCARD_STATE_UNKNOWN 0x0004 /**< Reader unknown */ #define SCARD_STATE_EMPTY 0x0010 /**< Card removed */ #define SCARD_STATE_PRESENT 0x0020 /**< Card inserted */ diff --git a/src/libopensc/internal.h b/src/libopensc/internal.h index 1d8a5faa..b861a451 100644 --- a/src/libopensc/internal.h +++ b/src/libopensc/internal.h @@ -31,6 +31,7 @@ extern "C" { #endif #include "opensc.h" +#include "simclist.h" #include "log.h" #include "ui.h" #include "cards.h" @@ -68,8 +69,7 @@ struct sc_atr_table { /* Internal use only */ int _sc_add_reader(struct sc_context *ctx, struct sc_reader *reader); -int _sc_parse_atr(struct sc_context *ctx, struct sc_slot_info *slot); -struct sc_slot_info *_sc_get_slot_info(struct sc_reader *reader, int slot_id); +int _sc_parse_atr(struct sc_reader *reader); /* Add an ATR to the card driver's struct sc_atr_table */ int _sc_add_atr(struct sc_context *ctx, struct sc_card_driver *driver, struct sc_atr_table *src); diff --git a/src/libopensc/iso7816.c b/src/libopensc/iso7816.c index 3f4bd981..966eb0a8 100644 --- a/src/libopensc/iso7816.c +++ b/src/libopensc/iso7816.c @@ -950,9 +950,7 @@ static int iso7816_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, if (card->reader && card->reader->ops && card->reader->ops->perform_verify) { - r = card->reader->ops->perform_verify(card->reader, - card->slot, - data); + r = card->reader->ops->perform_verify(card->reader, data); /* sw1/sw2 filled in by reader driver */ } else { sc_debug(card->ctx, diff --git a/src/libopensc/libopensc.exports b/src/libopensc/libopensc.exports index 1e734b65..04087c22 100644 --- a/src/libopensc/libopensc.exports +++ b/src/libopensc/libopensc.exports @@ -24,6 +24,7 @@ sc_base64_decode sc_base64_encode sc_bin_to_hex sc_build_pin +sc_cancel sc_card_ctl sc_card_valid sc_change_reference_data @@ -39,6 +40,8 @@ sc_copy_asn1_entry sc_create_file sc_ctx_detect_readers sc_ctx_get_reader +sc_ctx_get_reader_by_id +sc_ctx_get_reader_by_name sc_ctx_get_reader_count sc_decipher sc_delete_file diff --git a/src/libopensc/log.c b/src/libopensc/log.c index 37ec6ff9..0cf5852b 100644 --- a/src/libopensc/log.c +++ b/src/libopensc/log.c @@ -94,8 +94,8 @@ void sc_do_log_va(sc_context_t *ctx, int type, const char *file, int line, const #else gettimeofday (&tv, NULL); tm = localtime (&tv.tv_sec); - strftime (time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", tm); - r = snprintf(p, left, "%s.%03ld ", time_string, tv.tv_usec / 1000); + strftime (time_string, sizeof(time_string), "%H:%M:%S", tm); + r = snprintf(p, left, "0x%lx %s.%03ld ", (unsigned long)pthread_self(), time_string, tv.tv_usec / 1000); #endif p += r; left -= r; diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index 52a71489..5a173d5c 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -123,7 +123,6 @@ extern "C" { #define SC_MAX_READERS 16 #define SC_MAX_CARD_DRIVERS 32 #define SC_MAX_CARD_DRIVER_SNAME_SIZE 16 -#define SC_MAX_SLOTS 4 #define SC_MAX_CARD_APPS 8 #define SC_MAX_APDU_BUFFER_SIZE 258 #define SC_MAX_EXT_APDU_BUFFER_SIZE 65538 @@ -206,6 +205,7 @@ extern "C" { /* Event masks for sc_wait_for_event() */ #define SC_EVENT_CARD_INSERTED 0x0001 #define SC_EVENT_CARD_REMOVED 0x0002 +#define SC_EVENT_READER_ATTACHED 0x0004 typedef struct sc_security_env { unsigned long flags; @@ -279,15 +279,20 @@ struct sc_reader_driver { void *dll; }; -/* slot flags */ -#define SC_SLOT_CARD_PRESENT 0x00000001 -#define SC_SLOT_CARD_CHANGED 0x00000002 -/* slot capabilities */ -#define SC_SLOT_CAP_DISPLAY 0x00000001 -#define SC_SLOT_CAP_PIN_PAD 0x00000002 +/* reader flags */ +#define SC_READER_CARD_PRESENT 0x00000001 +#define SC_READER_CARD_CHANGED 0x00000002 +/* reader capabilities */ +#define SC_READER_CAP_DISPLAY 0x00000001 +#define SC_READER_CAP_PIN_PAD 0x00000002 -typedef struct sc_slot_info { - int id; +typedef struct sc_reader { + struct sc_context *ctx; + const struct sc_reader_driver *driver; + const struct sc_reader_operations *ops; + void *drv_data; + char *name; + unsigned long flags, capabilities; unsigned int supported_protocols, active_protocol; u8 atr[SC_MAX_ATR_SIZE]; @@ -299,24 +304,6 @@ typedef struct sc_slot_info { int Fi, f, Di, N; u8 FI, DI; } atr_info; - - void *drv_data; -} sc_slot_info_t; - -struct sc_event_listener { - unsigned int event_mask; - void (*func)(void *, const struct sc_slot_info *, unsigned int event); -}; - -typedef struct sc_reader { - struct sc_context *ctx; - const struct sc_reader_driver *driver; - const struct sc_reader_operations *ops; - void *drv_data; - char *name; - - struct sc_slot_info slot[SC_MAX_SLOTS]; - int slot_count; } sc_reader_t; /* This will be the new interface for handling PIN commands. @@ -370,12 +357,6 @@ typedef struct sc_serial_number { size_t len; } sc_serial_number_t; -/* these flags are deprecated and shouldn't be used anymore */ -#define SC_DISCONNECT 0 -#define SC_DISCONNECT_AND_RESET 1 -#define SC_DISCONNECT_AND_UNPOWER 2 -#define SC_DISCONNECT_AND_EJECT 3 - struct sc_reader_operations { /* Called during sc_establish_context(), when the driver * is loaded */ @@ -386,36 +367,27 @@ struct sc_reader_operations { /* Called when library wish to detect new readers * should add only new readers. */ int (*detect_readers)(struct sc_context *ctx, void *priv_data); + int (*cancel)(struct sc_context *ctx, void *priv_data); /* Called when releasing a reader. release() has to * deallocate the private data. Other fields will be * freed by OpenSC. */ int (*release)(struct sc_reader *reader); - int (*detect_card_presence)(struct sc_reader *reader, - struct sc_slot_info *slot); - int (*connect)(struct sc_reader *reader, struct sc_slot_info *slot); - int (*disconnect)(struct sc_reader *reader, struct sc_slot_info *slot); - int (*transmit)(struct sc_reader *reader, struct sc_slot_info *slot, - sc_apdu_t *apdu); - int (*lock)(struct sc_reader *reader, struct sc_slot_info *slot); - int (*unlock)(struct sc_reader *reader, struct sc_slot_info *slot); - int (*set_protocol)(struct sc_reader *reader, struct sc_slot_info *slot, - unsigned int proto); + int (*detect_card_presence)(struct sc_reader *reader); + int (*connect)(struct sc_reader *reader); + int (*disconnect)(struct sc_reader *reader); + int (*transmit)(struct sc_reader *reader, sc_apdu_t *apdu); + int (*lock)(struct sc_reader *reader); + int (*unlock)(struct sc_reader *reader); + int (*set_protocol)(struct sc_reader *reader, unsigned int proto); /* Pin pad functions */ - int (*display_message)(struct sc_reader *, struct sc_slot_info *, - const char *); - int (*perform_verify)(struct sc_reader *, struct sc_slot_info *, - struct sc_pin_cmd_data *); + int (*display_message)(struct sc_reader *, const char *); + int (*perform_verify)(struct sc_reader *, struct sc_pin_cmd_data *); /* Wait for an event */ - int (*wait_for_event)(struct sc_reader **readers, - struct sc_slot_info **slots, - size_t nslots, - unsigned int event_mask, - int *reader_index, - unsigned int *event, - int timeout); - int (*reset)(struct sc_reader *, struct sc_slot_info *); + int (*wait_for_event)(struct sc_context *ctx, void *priv_data, unsigned int event_mask, sc_reader_t **event_reader, unsigned int *event, int timeout); + /* Reset a reader */ + int (*reset)(struct sc_reader *); }; /* @@ -472,7 +444,6 @@ struct sc_reader_operations { typedef struct sc_card { struct sc_context *ctx; struct sc_reader *reader; - struct sc_slot_info *slot; int type; /* Card type, for card driver internal use */ unsigned long caps, flags; @@ -663,13 +634,12 @@ typedef struct sc_context { FILE *debug_file; char *preferred_language; + list_t readers; + const struct sc_reader_driver *reader_drivers[SC_MAX_READER_DRIVERS]; void *reader_drv_data[SC_MAX_READER_DRIVERS]; - struct sc_reader *reader[SC_MAX_READERS]; - int reader_count; - - struct sc_card_driver *card_drivers[SC_MAX_CARD_DRIVERS]; + struct sc_card_driver *card_drivers[SC_MAX_CARD_DRIVERS]; struct sc_card_driver *forced_driver; sc_thread_context_t *thread_ctx; @@ -755,6 +725,16 @@ int sc_ctx_detect_readers(sc_context_t *ctx); */ sc_reader_t *sc_ctx_get_reader(sc_context_t *ctx, unsigned int i); +/** + * Returns a pointer to the specified sc_reader_t object + * @param ctx OpenSC context + * @param name name of the reader to look for + * @return the requested sc_reader object or NULL if the reader is + * not available + */ +sc_reader_t *sc_ctx_get_reader_by_name(sc_context_t *ctx, const char *name); + + /** * Returns the number a available sc_reader objects * @param ctx OpenSC context @@ -772,18 +752,16 @@ int sc_set_card_driver(sc_context_t *ctx, const char *short_name); * Connects to a card in a reader and auto-detects the card driver. * The ATR (Answer to Reset) string of the card is also retrieved. * @param reader Reader structure - * @param slot_id Slot ID to connect to * @param card The allocated card object will go here */ -int sc_connect_card(sc_reader_t *reader, int slot_id, sc_card_t **card); +int sc_connect_card(sc_reader_t *reader, sc_card_t **card); /** * Disconnects from a card, and frees the card structure. Any locks * made by the application must be released before calling this function. * NOTE: The card is not reset nor powered down after the operation. * @param card The card to disconnect - * @param flag currently not used (should be set to 0) * @return SC_SUCCESS on success and an error code otherwise */ -int sc_disconnect_card(sc_card_t *card, int flag); +int sc_disconnect_card(sc_card_t *card); /** * Returns 1 if the magic value of the card object is correct. Mostly * used internally by the library. @@ -794,27 +772,26 @@ int sc_card_valid(const sc_card_t *card); /** * Checks if a card is present in a reader * @param reader Reader structure - * @param slot_id Slot ID * @retval If an error occured, the return value is a (negative) * OpenSC error code. If no card is present, 0 is returned. * Otherwise, a positive value is returned, which is a - * combination of flags. The flag SC_SLOT_CARD_PRESENT is + * combination of flags. The flag SC_READER_CARD_PRESENT is * always set. In addition, if the card was exchanged, - * the SC_SLOT_CARD_CHANGED flag is set. + * the SC_READER_CARD_CHANGED flag is set. */ -int sc_detect_card_presence(sc_reader_t *reader, int slot_id); +int sc_detect_card_presence(sc_reader_t *reader); /** * Waits for an event on readers. Note: only the event is detected, * there is no update of any card or other info. - * @param readers array of pointer to a Reader structure - * @param reader_count amount of readers in the array - * @param slot_id Slot ID + * NOTE: Only PC/SC backend implements this. + * @param ctx pointer to a Context structure * @param event_mask The types of events to wait for; this should * be ORed from one of the following * SC_EVENT_CARD_REMOVED * SC_EVENT_CARD_INSERTED - * @param reader (OUT) the reader on which the event was detected + * SC_EVENT_READER_ATTACHED + * @param event_reader (OUT) the reader on which the event was detected, or NULL if new reader * @param event (OUT) the events that occurred. This is also ORed * from the SC_EVENT_CARD_* constants listed above. * @param timeout Amount of millisecs to wait; -1 means forever @@ -822,9 +799,8 @@ int sc_detect_card_presence(sc_reader_t *reader, int slot_id); * @retval = 0 if a an event happened * @retval = 1 if the timeout occured */ -int sc_wait_for_event(sc_reader_t **readers, int *slots, size_t nslots, - unsigned int event_mask, - int *reader, unsigned int *event, int timeout); +int sc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, + sc_reader_t **event_reader, unsigned int *event, int timeout); /** * Resets the card. @@ -834,6 +810,14 @@ int sc_wait_for_event(sc_reader_t **readers, int *slots, size_t nslots, */ int sc_reset(sc_card_t *card); +/** + * Cancel all pending PC/SC calls + * NOTE: only PC/SC backend implements this function. + * @param ctx pointer to application context + * @retval SC_SUCCESS on success + */ +int sc_cancel(sc_context_t *ctx); + /** * Tries acquire the reader lock. * @param card The card to lock diff --git a/src/libopensc/pkcs15-pin.c b/src/libopensc/pkcs15-pin.c index 97ffc307..54027e6b 100644 --- a/src/libopensc/pkcs15-pin.c +++ b/src/libopensc/pkcs15-pin.c @@ -184,7 +184,7 @@ static int _validate_pin(struct sc_pkcs15_card *p15card, return SC_ERROR_BUFFER_TOO_SMALL; /* if we use pinpad, no more checks are needed */ - if (p15card->card->slot->capabilities & SC_SLOT_CAP_PIN_PAD) + if (p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) return SC_SUCCESS; /* If pin is given, make sure it is within limits */ @@ -252,7 +252,7 @@ int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card, data.pin1.encoding = 0; } - if(p15card->card->slot->capabilities & SC_SLOT_CAP_PIN_PAD) { + if(p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) { data.flags |= SC_PIN_CMD_USE_PINPAD; if (pin->flags & SC_PKCS15_PIN_FLAG_SO_PIN) data.pin1.prompt = "Please enter SO PIN"; @@ -329,7 +329,7 @@ int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card, } if((!oldpin || !newpin) - && p15card->card->slot->capabilities & SC_SLOT_CAP_PIN_PAD) { + && p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) { data.flags |= SC_PIN_CMD_USE_PINPAD; if (pin->flags & SC_PKCS15_PIN_FLAG_SO_PIN) { data.pin1.prompt = "Please enter SO PIN"; @@ -439,7 +439,7 @@ int sc_pkcs15_unblock_pin(struct sc_pkcs15_card *p15card, break; } - if(p15card->card->slot->capabilities & SC_SLOT_CAP_PIN_PAD) { + if(p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) { data.flags |= SC_PIN_CMD_USE_PINPAD; if (pin->flags & SC_PKCS15_PIN_FLAG_SO_PIN) { data.pin1.prompt = "Please enter PUK"; @@ -524,7 +524,7 @@ int sc_pkcs15_pincache_revalidate(struct sc_pkcs15_card *p15card, const sc_pkcs1 if (obj->user_consent) return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; - if (p15card->card->slot->capabilities & SC_SLOT_CAP_PIN_PAD) + if (p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; r = sc_pkcs15_find_pin_by_auth_id(p15card, &obj->auth_id, &pin_obj); diff --git a/src/libopensc/reader-ctapi.c b/src/libopensc/reader-ctapi.c index bec36e6c..a11163af 100644 --- a/src/libopensc/reader-ctapi.c +++ b/src/libopensc/reader-ctapi.c @@ -27,7 +27,6 @@ #include #define GET_PRIV_DATA(r) ((struct ctapi_private_data *) (r)->drv_data) -#define GET_SLOT_DATA(r) ((struct ctapi_slot_data *) (r)->drv_data) #ifdef _WIN32 typedef char pascal CT_INIT_TYPE(unsigned short ctn, unsigned short Pn); @@ -72,14 +71,11 @@ struct ctapi_private_data { struct ctapi_functions funcs; unsigned short ctn; int ctapi_functional_units; + int slot; }; -struct ctapi_slot_data { - void *filler; -}; - -/* Reset slot or reader */ -static int ctapi_reset(sc_reader_t *reader, sc_slot_info_t *slot) +/* Reset reader */ +static int ctapi_reset(sc_reader_t *reader) { struct ctapi_private_data *priv = GET_PRIV_DATA(reader); char rv; @@ -88,7 +84,7 @@ static int ctapi_reset(sc_reader_t *reader, sc_slot_info_t *slot) cmd[0] = CTBCS_CLA; cmd[1] = CTBCS_INS_RESET; - cmd[2] = slot ? CTBCS_P1_INTERFACE1 + slot->id : CTBCS_P1_CT_KERNEL; + cmd[2] = priv->slot ? CTBCS_P1_INTERFACE1 + priv->slot : CTBCS_P1_CT_KERNEL; cmd[3] = 0x00; /* No response. We might also use 0x01 (return ATR) or 0x02 (return historical bytes) here */ cmd[4] = 0x00; dad = 1; @@ -107,138 +103,8 @@ static int ctapi_reset(sc_reader_t *reader, sc_slot_info_t *slot) return 0; } -static void set_default_fu(sc_reader_t *reader) -{ - if (!reader) return; - reader->slot_count = 1; - reader->slot[0].id = 0; - reader->slot[0].capabilities = 0; - reader->slot[0].atr_len = 0; - reader->slot[0].drv_data = NULL; -} - -/* Detect functional units of the reader according to CT-BCS spec version 1.0 - (14.04.2004, http://www.teletrust.de/down/mct1-0_t4.zip) */ -static void detect_functional_units(sc_reader_t *reader) -{ - struct ctapi_private_data *priv = GET_PRIV_DATA(reader); - char rv; - u8 cmd[5], rbuf[256], sad, dad; - unsigned short lr; - int NumUnits; - int i; - - priv->ctapi_functional_units = 0; - - cmd[0] = CTBCS_CLA; - cmd[1] = CTBCS_INS_STATUS; - cmd[2] = CTBCS_P1_CT_KERNEL; - cmd[3] = CTBCS_P2_STATUS_TFU; - cmd[4] = 0x00; - dad = 1; - sad = 2; - lr = 256; - - rv = priv->funcs.CT_data(priv->ctn, &dad, &sad, 5, cmd, &lr, rbuf); - if (rv || (lr < 4) || (rbuf[lr-2] != 0x90)) { - sc_debug(reader->ctx, "Error getting status of terminal: %d, using defaults\n", rv); - set_default_fu(reader); - return; - } - if (rbuf[0] != CTBCS_P2_STATUS_TFU) { - /* Number of slots might also detected by using CTBCS_P2_STATUS_ICC. - If you think that's important please do it... ;) */ - set_default_fu(reader); - sc_debug(reader->ctx, "Invalid data object returnd on CTBCS_P2_STATUS_TFU: 0x%x\n", rbuf[0]); - return; - } - NumUnits = rbuf[1]; - if (NumUnits + 4 > lr) { - set_default_fu(reader); - sc_debug(reader->ctx, "Invalid data returnd: %d functional units, size %d\n", NumUnits, rv); - set_default_fu(reader); - return; - } - reader->slot_count = 0; - for(i = 0; i < NumUnits; i++) { - switch(rbuf[i+2]) - { - case CTBCS_P1_INTERFACE1: - case CTBCS_P1_INTERFACE2: - case CTBCS_P1_INTERFACE3: - case CTBCS_P1_INTERFACE4: - case CTBCS_P1_INTERFACE5: - case CTBCS_P1_INTERFACE6: - case CTBCS_P1_INTERFACE7: - case CTBCS_P1_INTERFACE8: - case CTBCS_P1_INTERFACE9: - case CTBCS_P1_INTERFACE10: - case CTBCS_P1_INTERFACE11: - case CTBCS_P1_INTERFACE12: - case CTBCS_P1_INTERFACE13: - case CTBCS_P1_INTERFACE14: - /* Maybe a weak point here if multiple interfaces are present and not returned - in the "canonical" order. This is not forbidden by the specs, but why should - anyone want to do that? */ - if (reader->slot_count >= SC_MAX_SLOTS) { - sc_debug(reader->ctx, "Ignoring slot id 0x%x, can only handle %d slots\n", rbuf[i+2], SC_MAX_SLOTS); - } else { - reader->slot[reader->slot_count].id = reader->slot_count; - reader->slot[reader->slot_count].capabilities = 0; /* Just to start with */ - reader->slot[reader->slot_count].atr_len = 0; - reader->slot[reader->slot_count].drv_data = NULL; - reader->slot_count++; - } - break; - - case CTBCS_P1_DISPLAY: - priv->ctapi_functional_units |= CTAPI_FU_DISPLAY; - sc_debug(reader->ctx, "Display detected\n"); - break; - - case CTBCS_P1_KEYPAD: - priv->ctapi_functional_units |= CTAPI_FU_KEYBOARD; - sc_debug(reader->ctx, "Keypad detected\n"); - break; - - case CTBCS_P1_PRINTER: - priv->ctapi_functional_units |= CTAPI_FU_PRINTER; - sc_debug(reader->ctx, "Printer detected\n"); - break; - - case CTBCS_P1_FINGERPRINT: - case CTBCS_P1_VOICEPRINT: - case CTBCS_P1_DSV: - case CTBCS_P1_FACE_RECOGNITION: - case CTBCS_P1_IRISSCAN: - priv->ctapi_functional_units |= CTAPI_FU_BIOMETRIC; - sc_debug(reader->ctx, "Biometric sensor detected\n"); - break; - - default: - sc_debug(reader->ctx, "Unknown functional unit 0x%x\n", rbuf[i+2]); - } - - } - if (reader->slot_count == 0) { - sc_debug(reader->ctx, "No slots returned, assuming one default slot\n"); - set_default_fu(reader); - } - /* CT-BCS does not define Keyboard/Display for each slot, so I assume - those additional units can be used for each slot */ - if (priv->ctapi_functional_units) { - for(i = 0; i < reader->slot_count; i++) { - if (priv->ctapi_functional_units & CTAPI_FU_KEYBOARD) - reader->slot[i].capabilities |= SC_SLOT_CAP_PIN_PAD; - if (priv->ctapi_functional_units & CTAPI_FU_DISPLAY) - reader->slot[i].capabilities |= SC_SLOT_CAP_DISPLAY; - } - } -} - -static int refresh_slot_attributes(sc_reader_t *reader, - sc_slot_info_t *slot) +static int refresh_attributes(sc_reader_t *reader) { struct ctapi_private_data *priv = GET_PRIV_DATA(reader); char rv; @@ -254,7 +120,7 @@ static int refresh_slot_attributes(sc_reader_t *reader, sad = 2; lr = 256; - slot->flags = 0; + reader->flags = 0; rv = priv->funcs.CT_data(priv->ctn, &dad, &sad, 5, cmd, &lr, rbuf); if (rv || (lr < 3) || (rbuf[lr-2] != 0x90)) { @@ -262,31 +128,23 @@ static int refresh_slot_attributes(sc_reader_t *reader, return SC_ERROR_TRANSMIT_FAILED; } if (lr < 4) { - /* Looks like older readers do not return data tag and length field, so assume one slot only */ - if (slot->id > 0) { - sc_debug(reader->ctx, "Status for slot id %d not returned, have only 1\n", slot->id); - return SC_ERROR_SLOT_NOT_FOUND; - } if (rbuf[0] & CTBCS_DATA_STATUS_CARD) - slot->flags = SC_SLOT_CARD_PRESENT; + reader->flags = SC_READER_CARD_PRESENT; } else { if (rbuf[0] != CTBCS_P2_STATUS_ICC) { /* Should we be more tolerant here? I do not think so... */ sc_debug(reader->ctx, "Invalid data object returnd on CTBCS_P2_STATUS_ICC: 0x%x\n", rbuf[0]); return SC_ERROR_TRANSMIT_FAILED; - } - if (rbuf[1] <= slot->id) { - sc_debug(reader->ctx, "Status for slot id %d not returned, only %d\n", slot->id, rbuf[1]); - return SC_ERROR_SLOT_NOT_FOUND; } - if (rbuf[2+slot->id] & CTBCS_DATA_STATUS_CARD) - slot->flags = SC_SLOT_CARD_PRESENT; + /* Fixme - should not be reached */ + sc_debug(reader->ctx, "Returned status for %d slots\n", rbuf[1]); + reader->flags = SC_READER_CARD_PRESENT; } return 0; } -static int ctapi_internal_transmit(sc_reader_t *reader, sc_slot_info_t *slot, +static int ctapi_internal_transmit(sc_reader_t *reader, const u8 *sendbuf, size_t sendsize, u8 *recvbuf, size_t *recvsize, unsigned long control) @@ -298,10 +156,9 @@ static int ctapi_internal_transmit(sc_reader_t *reader, sc_slot_info_t *slot, if (control) dad = 1; - else if (!slot || slot->id == 0) - dad = 0; else - dad = slot->id + 1; /* Adressing of multiple slots, according to CT API 1.0 */ + dad = 0; + sad = 2; lr = *recvsize; @@ -315,8 +172,7 @@ static int ctapi_internal_transmit(sc_reader_t *reader, sc_slot_info_t *slot, return 0; } -static int ctapi_transmit(sc_reader_t *reader, sc_slot_info_t *slot, - sc_apdu_t *apdu) +static int ctapi_transmit(sc_reader_t *reader, sc_apdu_t *apdu) { size_t ssize, rsize, rbuflen = 0; u8 *sbuf = NULL, *rbuf = NULL; @@ -334,7 +190,7 @@ static int ctapi_transmit(sc_reader_t *reader, sc_slot_info_t *slot, goto out; if (reader->ctx->debug >= 6) sc_apdu_log(reader->ctx, sbuf, ssize, 1); - r = ctapi_internal_transmit(reader, slot, sbuf, ssize, + r = ctapi_internal_transmit(reader, sbuf, ssize, rbuf, &rsize, apdu->control); if (r < 0) { /* unable to transmit ... most likely a reader problem */ @@ -358,17 +214,17 @@ out: return r; } -static int ctapi_detect_card_presence(sc_reader_t *reader, sc_slot_info_t *slot) +static int ctapi_detect_card_presence(sc_reader_t *reader) { int r; - r = refresh_slot_attributes(reader, slot); + r = refresh_attributes(reader); if (r) return r; - return slot->flags; + return reader->flags; } -static int ctapi_connect(sc_reader_t *reader, sc_slot_info_t *slot) +static int ctapi_connect(sc_reader_t *reader) { struct ctapi_private_data *priv = GET_PRIV_DATA(reader); char rv; @@ -378,7 +234,7 @@ static int ctapi_connect(sc_reader_t *reader, sc_slot_info_t *slot) cmd[0] = CTBCS_CLA; cmd[1] = CTBCS_INS_REQUEST; - cmd[2] = CTBCS_P1_INTERFACE1+slot->id; + cmd[2] = CTBCS_P1_INTERFACE1; cmd[3] = CTBCS_P2_REQUEST_GET_ATR; cmd[4] = 0x00; dad = 1; @@ -395,18 +251,18 @@ static int ctapi_connect(sc_reader_t *reader, sc_slot_info_t *slot) lr -= 2; if (lr > SC_MAX_ATR_SIZE) lr = SC_MAX_ATR_SIZE; - memcpy(slot->atr, rbuf, lr); - slot->atr_len = lr; - r = _sc_parse_atr(reader->ctx, slot); + memcpy(reader->atr, rbuf, lr); + reader->atr_len = lr; + r = _sc_parse_atr(reader); #if 0 - if (slot->atr_info.Fi > 0) { + if (reader->atr_info.Fi > 0) { /* Perform PPS negotiation */ cmd[1] = CTBCS_INS_RESET; cmd[4] = 0x03; cmd[5] = 0xFF; cmd[6] = 0x10; - cmd[7] = (slot->atr_info.FI << 4) | slot->atr_info.DI; + cmd[7] = (reader->atr_info.FI << 4) | reader->atr_info.DI; cmd[8] = 0x00; dad = 1; sad = 2; @@ -422,17 +278,17 @@ static int ctapi_connect(sc_reader_t *reader, sc_slot_info_t *slot) return 0; } -static int ctapi_disconnect(sc_reader_t *reader, sc_slot_info_t *slot) +static int ctapi_disconnect(sc_reader_t *reader) { return 0; } -static int ctapi_lock(sc_reader_t *reader, sc_slot_info_t *slot) +static int ctapi_lock(sc_reader_t *reader) { return 0; } -static int ctapi_unlock(sc_reader_t *reader, sc_slot_info_t *slot) +static int ctapi_unlock(sc_reader_t *reader) { return 0; } @@ -480,7 +336,12 @@ static int ctapi_load_module(sc_context_t *ctx, struct ctapi_module *mod; const scconf_list *list; void *dlh; - int r, i; + int r, i, NumUnits; + char rv; + u8 cmd[5], rbuf[256], sad, dad; + unsigned short lr; + + list = scconf_find_list(conf, "ports"); if (list == NULL) { @@ -522,8 +383,99 @@ static int ctapi_load_module(sc_context_t *ctx, sc_debug(ctx, "CT_init() failed with %d\n", rv); continue; } + + /* Detect functional units of the reader according to CT-BCS spec version 1.0 + (14.04.2004, http://www.teletrust.de/down/mct1-0_t4.zip) */ + cmd[0] = CTBCS_CLA; + cmd[1] = CTBCS_INS_STATUS; + cmd[2] = CTBCS_P1_CT_KERNEL; + cmd[3] = CTBCS_P2_STATUS_TFU; + cmd[4] = 0x00; + dad = 1; + sad = 2; + lr = 256; + + rv = priv->funcs.CT_data(priv->ctn, &dad, &sad, 5, cmd, &lr, rbuf); + if (rv || (lr < 4) || (rbuf[lr-2] != 0x90)) { + sc_debug(reader->ctx, "Error getting status of terminal: %d, using defaults\n", rv); + } + if (rbuf[0] != CTBCS_P2_STATUS_TFU) { + /* Number of slots might also detected by using CTBCS_P2_STATUS_ICC. + If you think that's important please do it... ;) */ + sc_debug(reader->ctx, "Invalid data object returnd on CTBCS_P2_STATUS_TFU: 0x%x\n", rbuf[0]); + } + NumUnits = rbuf[1]; + if (NumUnits + 4 > lr) { + sc_debug(reader->ctx, "Invalid data returnd: %d functional units, size %d\n", NumUnits, rv); + } + + for(i = 0; i < NumUnits; i++) { + switch(rbuf[i+2]) { + case CTBCS_P1_INTERFACE1: + case CTBCS_P1_INTERFACE2: + case CTBCS_P1_INTERFACE3: + case CTBCS_P1_INTERFACE4: + case CTBCS_P1_INTERFACE5: + case CTBCS_P1_INTERFACE6: + case CTBCS_P1_INTERFACE7: + case CTBCS_P1_INTERFACE8: + case CTBCS_P1_INTERFACE9: + case CTBCS_P1_INTERFACE10: + case CTBCS_P1_INTERFACE11: + case CTBCS_P1_INTERFACE12: + case CTBCS_P1_INTERFACE13: + case CTBCS_P1_INTERFACE14: + /* Maybe a weak point here if multiple interfaces are present and not returned + in the "canonical" order. This is not forbidden by the specs, but why should + anyone want to do that? */ + sc_debug(reader->ctx, "Found slot id 0x%x\n", rbuf[i+2]); + break; + + case CTBCS_P1_DISPLAY: + priv->ctapi_functional_units |= CTAPI_FU_DISPLAY; + sc_debug(reader->ctx, "Display detected\n"); + break; + + case CTBCS_P1_KEYPAD: + priv->ctapi_functional_units |= CTAPI_FU_KEYBOARD; + sc_debug(reader->ctx, "Keypad detected\n"); + break; + + case CTBCS_P1_PRINTER: + priv->ctapi_functional_units |= CTAPI_FU_PRINTER; + sc_debug(reader->ctx, "Printer detected\n"); + break; + + case CTBCS_P1_FINGERPRINT: + case CTBCS_P1_VOICEPRINT: + case CTBCS_P1_DSV: + case CTBCS_P1_FACE_RECOGNITION: + case CTBCS_P1_IRISSCAN: + priv->ctapi_functional_units |= CTAPI_FU_BIOMETRIC; + sc_debug(reader->ctx, "Biometric sensor detected\n"); + break; + + default: + sc_debug(reader->ctx, "Unknown functional unit 0x%x\n", rbuf[i+2]); + } + } + /* CT-BCS does not define Keyboard/Display for each slot, so I assume + those additional units can be used for each slot */ + if (priv->ctapi_functional_units) { + if (priv->ctapi_functional_units & CTAPI_FU_KEYBOARD) + reader->capabilities |= SC_READER_CAP_PIN_PAD; + if (priv->ctapi_functional_units & CTAPI_FU_DISPLAY) + reader->capabilities |= SC_READER_CAP_DISPLAY; + } +} + + + + + reader = (sc_reader_t *) calloc(1, sizeof(sc_reader_t)); - priv = (struct ctapi_private_data *) malloc(sizeof(struct ctapi_private_data)); + priv = (struct ctapi_private_data *) calloc(1, sizeof(struct ctapi_private_data)); + if (!priv) return SC_ERROR_OUT_OF_MEMORY; reader->drv_data = priv; reader->ops = &ctapi_ops; reader->driver = &ctapi_drv; @@ -543,10 +495,7 @@ static int ctapi_load_module(sc_context_t *ctx, detect_functional_units(reader); ctapi_reset(reader, NULL); - for(i = 0; i < reader->slot_count; i++) { - refresh_slot_attributes(reader, &(reader->slot[i])); - } - + refresh_attributes(reader); mod->ctn_count++; } return 0; diff --git a/src/libopensc/reader-openct.c b/src/libopensc/reader-openct.c index 33fbf7cc..2c38d08b 100644 --- a/src/libopensc/reader-openct.c +++ b/src/libopensc/reader-openct.c @@ -26,22 +26,14 @@ static int openct_reader_init(sc_context_t *ctx, void **priv_data); static int openct_add_reader(sc_context_t *ctx, unsigned int num, ct_info_t *info); static int openct_reader_finish(sc_context_t *ctx, void *priv_data); static int openct_reader_release(sc_reader_t *reader); -static int openct_reader_detect_card_presence(sc_reader_t *reader, - sc_slot_info_t *slot); -static int openct_reader_connect(sc_reader_t *reader, - sc_slot_info_t *slot); -static int openct_reader_disconnect(sc_reader_t *reader, - sc_slot_info_t *slot); -static int openct_reader_transmit(sc_reader_t *reader, - sc_slot_info_t *slot, sc_apdu_t *apdu); -static int openct_reader_perform_verify(sc_reader_t *reader, - sc_slot_info_t *slot, - struct sc_pin_cmd_data *info); -static int openct_reader_lock(sc_reader_t *reader, - sc_slot_info_t *slot); -static int openct_reader_unlock(sc_reader_t *reader, - sc_slot_info_t *slot); -static int openct_error(sc_reader_t *, int); +static int openct_reader_detect_card_presence(sc_reader_t *reader); +static int openct_reader_connect(sc_reader_t *reader); +static int openct_reader_disconnect(sc_reader_t *reader); +static int openct_reader_transmit(sc_reader_t *reader, sc_apdu_t *apdu); +static int openct_reader_perform_verify(sc_reader_t *reader, struct sc_pin_cmd_data *info); +static int openct_reader_lock(sc_reader_t *reader); +static int openct_reader_unlock(sc_reader_t *reader); +static int openct_error(sc_reader_t *, int); static struct sc_reader_operations openct_ops; @@ -57,11 +49,9 @@ struct driver_data { ct_handle * h; unsigned int num; ct_info_t info; -}; - -struct slot_data { ct_lock_handle excl_lock; ct_lock_handle shared_lock; + unsigned int slot; }; /* @@ -78,7 +68,6 @@ openct_reader_init(sc_context_t *ctx, void **priv_data) SC_FUNC_CALLED(ctx, 1); - max_virtual = 2; conf_block = sc_get_conf_block(ctx, "reader_driver", "openct", 1); if (conf_block) { @@ -87,7 +76,7 @@ openct_reader_init(sc_context_t *ctx, void **priv_data) for (i = 0; i < OPENCT_MAX_READERS; i++) { ct_info_t info; - + /* XXX: As long as OpenCT has slots, multislot readers should create several instances here. */ if (ct_reader_info(i, &info) >= 0) { openct_add_reader(ctx, i, &info); } else if (i < max_virtual) { @@ -124,7 +113,6 @@ openct_add_reader(sc_context_t *ctx, unsigned int num, ct_info_t *info) reader->ops = &openct_ops; reader->drv_data = data; reader->name = strdup(data->info.ct_name); - reader->slot_count = data->info.ct_slots; if ((rc = _sc_add_reader(ctx, reader)) < 0) { free(data); @@ -133,15 +121,10 @@ openct_add_reader(sc_context_t *ctx, unsigned int num, ct_info_t *info) return rc; } - for (i = 0; i < SC_MAX_SLOTS; i++) { - reader->slot[i].drv_data = calloc(1, sizeof(struct slot_data)); - reader->slot[i].id = i; - if (data->info.ct_display) - reader->slot[i].capabilities |= SC_SLOT_CAP_DISPLAY; - if (data->info.ct_keypad) - reader->slot[i].capabilities |= SC_SLOT_CAP_PIN_PAD; - } - + if (data->info.ct_display) + reader->capabilities |= SC_READER_CAP_DISPLAY; + if (data->info.ct_keypad) + reader->capabilities |= SC_READER_CAP_PIN_PAD; return 0; } @@ -173,11 +156,6 @@ static int openct_reader_release(sc_reader_t *reader) reader->drv_data = NULL; free(data); } - - for (i = 0; i < SC_MAX_SLOTS; i++) { - if(reader->slot[i].drv_data) - free(reader->slot[i].drv_data); - } return SC_NO_ERROR; } @@ -185,32 +163,30 @@ static int openct_reader_release(sc_reader_t *reader) /* * Check whether a card was added/removed */ -static int openct_reader_detect_card_presence(sc_reader_t *reader, - sc_slot_info_t *slot) +static int openct_reader_detect_card_presence(sc_reader_t *reader) { struct driver_data *data = (struct driver_data *) reader->drv_data; int rc, status; SC_FUNC_CALLED(reader->ctx, 1); - slot->flags = 0; + reader->flags = 0; if (!data->h && !(data->h = ct_reader_connect(data->num))) return 0; - if ((rc = ct_card_status(data->h, slot->id, &status)) < 0) + if ((rc = ct_card_status(data->h, data->slot, &status)) < 0) return SC_ERROR_TRANSMIT_FAILED; if (status & IFD_CARD_PRESENT) { - slot->flags = SC_SLOT_CARD_PRESENT; + reader->flags = SC_READER_CARD_PRESENT; if (status & IFD_CARD_STATUS_CHANGED) - slot->flags = SC_SLOT_CARD_PRESENT; + reader->flags = SC_READER_CARD_PRESENT; } - return slot->flags; + return reader->flags; } static int -openct_reader_connect(sc_reader_t *reader, - sc_slot_info_t *slot) +openct_reader_connect(sc_reader_t *reader) { struct driver_data *data = (struct driver_data *) reader->drv_data; int rc; @@ -225,8 +201,8 @@ openct_reader_connect(sc_reader_t *reader, return SC_ERROR_CARD_NOT_PRESENT; } - rc = ct_card_request(data->h, slot->id, 0, NULL, - slot->atr, sizeof(slot->atr)); + rc = ct_card_request(data->h, reder->id, 0, NULL, + reader->atr, sizeof(reader->atr)); if (rc < 0) { sc_debug(reader->ctx, "openct_reader_connect read failed: %s\n", @@ -239,13 +215,12 @@ openct_reader_connect(sc_reader_t *reader, return SC_ERROR_READER; } - slot->atr_len = rc; + reader->atr_len = rc; return SC_NO_ERROR; } static int -openct_reader_reconnect(sc_reader_t *reader, - sc_slot_info_t *slot) +openct_reader_reconnect(sc_reader_t *reader) { struct driver_data *data = (struct driver_data *) reader->drv_data; int rc; @@ -253,12 +228,12 @@ openct_reader_reconnect(sc_reader_t *reader, if (data->h != NULL) return 0; - if ((rc = openct_reader_connect(reader, slot)) < 0) + if ((rc = openct_reader_connect(reader)) < 0) return SC_ERROR_READER_DETACHED; return SC_ERROR_READER_REATTACHED; } -static int openct_reader_disconnect(sc_reader_t *reader, sc_slot_info_t *slot) +static int openct_reader_disconnect(sc_reader_t *reader) { struct driver_data *data = (struct driver_data *) reader->drv_data; @@ -271,7 +246,6 @@ static int openct_reader_disconnect(sc_reader_t *reader, sc_slot_info_t *slot) static int openct_reader_internal_transmit(sc_reader_t *reader, - sc_slot_info_t *slot, const u8 *sendbuf, size_t sendsize, u8 *recvbuf, size_t *recvsize, unsigned long control) { @@ -279,10 +253,10 @@ openct_reader_internal_transmit(sc_reader_t *reader, int rc; /* Hotplug check */ - if ((rc = openct_reader_reconnect(reader, slot)) < 0) + if ((rc = openct_reader_reconnect(reader)) < 0) return rc; - rc = ct_card_transact(data->h, slot->id, + rc = ct_card_transact(data->h, data->slot, sendbuf, sendsize, recvbuf, *recvsize); @@ -298,8 +272,7 @@ openct_reader_internal_transmit(sc_reader_t *reader, return openct_error(reader, rc); } -static int openct_reader_transmit(sc_reader_t *reader, sc_slot_info_t *slot, - sc_apdu_t *apdu) +static int openct_reader_transmit(sc_reader_t *reader, sc_apdu_t *apdu) { size_t ssize, rsize, rbuflen = 0; u8 *sbuf = NULL, *rbuf = NULL; @@ -317,7 +290,7 @@ static int openct_reader_transmit(sc_reader_t *reader, sc_slot_info_t *slot, goto out; if (reader->ctx->debug >= 6) sc_apdu_log(reader->ctx, sbuf, ssize, 1); - r = openct_reader_internal_transmit(reader, slot, sbuf, ssize, + r = openct_reader_internal_transmit(reader, sbuf, ssize, rbuf, &rsize, apdu->control); if (r < 0) { /* unable to transmit ... most likely a reader problem */ @@ -341,8 +314,7 @@ out: return r; } -static int openct_reader_perform_verify(sc_reader_t *reader, - sc_slot_info_t *slot, struct sc_pin_cmd_data *info) +static int openct_reader_perform_verify(sc_reader_t *reader, struct sc_pin_cmd_data *info) { struct driver_data *data = (struct driver_data *) reader->drv_data; unsigned int pin_length = 0, pin_encoding; @@ -351,7 +323,7 @@ static int openct_reader_perform_verify(sc_reader_t *reader, int rc; /* Hotplug check */ - if ((rc = openct_reader_reconnect(reader, slot)) < 0) + if ((rc = openct_reader_reconnect(reader)) < 0) return rc; if (info->apdu == NULL) { @@ -384,7 +356,7 @@ static int openct_reader_perform_verify(sc_reader_t *reader, else return SC_ERROR_INVALID_ARGUMENTS; - rc = ct_card_verify(data->h, slot->id, + rc = ct_card_verify(data->h, data->slot, 0, /* no timeout?! */ info->pin1.prompt, pin_encoding, @@ -401,37 +373,35 @@ static int openct_reader_perform_verify(sc_reader_t *reader, return 0; } -static int openct_reader_lock(sc_reader_t *reader, sc_slot_info_t *slot) +static int openct_reader_lock(sc_reader_t *reader) { struct driver_data *data = (struct driver_data *) reader->drv_data; - struct slot_data *slot_data = (struct slot_data *) slot->drv_data; int rc; SC_FUNC_CALLED(reader->ctx, 1); /* Hotplug check */ - if ((rc = openct_reader_reconnect(reader, slot)) < 0) + if ((rc = openct_reader_reconnect(reader)) < 0) return rc; - rc = ct_card_lock(data->h, slot->id, + rc = ct_card_lock(data->h, data->slot, IFD_LOCK_EXCLUSIVE, - &slot_data->excl_lock); + &data->excl_lock); if (rc == IFD_ERROR_NOT_CONNECTED) { ct_reader_disconnect(data->h); data->h = NULL; /* Try to reconnect as reader may be plugged-in again */ - return openct_reader_reconnect(reader, slot); + return openct_reader_reconnect(reader); } return openct_error(reader, rc); } -static int openct_reader_unlock(sc_reader_t *reader, sc_slot_info_t *slot) +static int openct_reader_unlock(sc_reader_t *reader) { struct driver_data *data = (struct driver_data *) reader->drv_data; - struct slot_data *slot_data = (struct slot_data *) slot->drv_data; int rc; SC_FUNC_CALLED(reader->ctx, 1); @@ -440,7 +410,7 @@ static int openct_reader_unlock(sc_reader_t *reader, sc_slot_info_t *slot) if (data->h == NULL) return 0; - rc = ct_card_unlock(data->h, slot->id, slot_data->excl_lock); + rc = ct_card_unlock(data->h, data->slot, data->excl_lock); /* We couldn't care less */ if (rc == IFD_ERROR_NOT_CONNECTED) diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index c4ff9af3..0e3cdc8a 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -37,17 +37,19 @@ /* Some windows specific kludge */ #undef SCARD_PROTOCOL_ANY #define SCARD_PROTOCOL_ANY (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1) -/* Error printing */ -#define PCSC_ERROR(ctx, desc, rv) sc_debug(ctx, desc ": 0x%08lx\n", rv); + +/* 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) /* 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]) #define GET_PRIV_DATA(r) ((struct pcsc_private_data *) (r)->drv_data) -#define GET_SLOT_DATA(r) ((struct pcsc_slot_data *) (r)->drv_data) struct pcsc_global_private_data { SCARDCONTEXT pcsc_ctx; + SCARDCONTEXT pcsc_wait_ctx; int enable_pinpad; int connect_exclusive; int connect_reset; @@ -63,6 +65,7 @@ struct pcsc_global_private_data { SCardEndTransaction_t SCardEndTransaction; SCardStatus_t SCardStatus; SCardGetStatusChange_t SCardGetStatusChange; + SCardCancel_t SCardCancel; SCardControlOLD_t SCardControlOLD; SCardControl_t SCardControl; SCardTransmit_t SCardTransmit; @@ -71,9 +74,6 @@ struct pcsc_global_private_data { struct pcsc_private_data { struct pcsc_global_private_data *gpriv; -}; - -struct pcsc_slot_data { SCARDHANDLE pcsc_card; SCARD_READERSTATE_A reader_state; DWORD verify_ioctl; @@ -86,9 +86,9 @@ struct pcsc_slot_data { int locked; }; -static int pcsc_detect_card_presence(sc_reader_t *reader, sc_slot_info_t *slot); +static int pcsc_detect_card_presence(sc_reader_t *reader); -static int pcsc_ret_to_error(LONG rv) +static int pcsc_to_opensc_error(LONG rv) { switch (rv) { case SCARD_S_SUCCESS: @@ -114,7 +114,6 @@ static int pcsc_ret_to_error(LONG rv) return SC_ERROR_CARD_NOT_PRESENT; case SCARD_E_PROTO_MISMATCH: /* Should not happen */ return SC_ERROR_READER; - default: return SC_ERROR_UNKNOWN; } @@ -148,7 +147,7 @@ static DWORD opensc_proto_to_pcsc(unsigned int proto) } } -static int pcsc_internal_transmit(sc_reader_t *reader, sc_slot_info_t *slot, +static int pcsc_internal_transmit(sc_reader_t *reader, const u8 *sendbuf, size_t sendsize, u8 *recvbuf, size_t *recvsize, unsigned long control) @@ -158,15 +157,13 @@ static int pcsc_internal_transmit(sc_reader_t *reader, sc_slot_info_t *slot, DWORD dwSendLength, dwRecvLength; LONG rv; SCARDHANDLE card; - struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot); SC_FUNC_CALLED(reader->ctx, 3); - assert(pslot != NULL); - card = pslot->pcsc_card; + card = priv->pcsc_card; - sSendPci.dwProtocol = opensc_proto_to_pcsc(slot->active_protocol); + sSendPci.dwProtocol = opensc_proto_to_pcsc(reader->active_protocol); sSendPci.cbPciLength = sizeof(sSendPci); - sRecvPci.dwProtocol = opensc_proto_to_pcsc(slot->active_protocol); + sRecvPci.dwProtocol = opensc_proto_to_pcsc(reader->active_protocol); sRecvPci.cbPciLength = sizeof(sRecvPci); dwSendLength = sendsize; @@ -187,18 +184,15 @@ static int pcsc_internal_transmit(sc_reader_t *reader, sc_slot_info_t *slot, } if (rv != SCARD_S_SUCCESS) { + PCSC_TRACE(reader, "SCardTransmit/Control failed", rv); switch (rv) { case SCARD_W_REMOVED_CARD: return SC_ERROR_CARD_REMOVED; - case SCARD_E_NOT_TRANSACTED: - if (!(pcsc_detect_card_presence(reader, slot) & SC_SLOT_CARD_PRESENT)) - return SC_ERROR_CARD_REMOVED; - return SC_ERROR_TRANSMIT_FAILED; default: - /* Windows' PC/SC returns 0x8010002f (??) if a card is removed */ - if (pcsc_detect_card_presence(reader, slot) != 1) + /* Translate strange errors from card removal to a proper return code */ + pcsc_detect_card_presence(reader); + if (!(pcsc_detect_card_presence(reader) & SC_READER_CARD_PRESENT)) return SC_ERROR_CARD_REMOVED; - PCSC_ERROR(reader->ctx, "SCardTransmit failed", rv); return SC_ERROR_TRANSMIT_FAILED; } } @@ -209,8 +203,7 @@ static int pcsc_internal_transmit(sc_reader_t *reader, sc_slot_info_t *slot, return SC_SUCCESS; } -static int pcsc_transmit(sc_reader_t *reader, sc_slot_info_t *slot, - sc_apdu_t *apdu) +static int pcsc_transmit(sc_reader_t *reader, sc_apdu_t *apdu) { size_t ssize, rsize, rbuflen = 0; u8 *sbuf = NULL, *rbuf = NULL; @@ -228,7 +221,7 @@ static int pcsc_transmit(sc_reader_t *reader, sc_slot_info_t *slot, goto out; } /* encode and log the APDU */ - r = sc_apdu_get_octets(reader->ctx, apdu, &sbuf, &ssize, slot->active_protocol); + r = sc_apdu_get_octets(reader->ctx, apdu, &sbuf, &ssize, reader->active_protocol); if (r != SC_SUCCESS) goto out; if (reader->ctx->debug >= 6) { @@ -237,7 +230,7 @@ static int pcsc_transmit(sc_reader_t *reader, sc_slot_info_t *slot, sc_apdu_log(reader->ctx, sbuf, ssize, 1); } - r = pcsc_internal_transmit(reader, slot, sbuf, ssize, + r = pcsc_internal_transmit(reader, sbuf, ssize, rbuf, &rsize, apdu->control); if (r < 0) { /* unable to transmit ... most likely a reader problem */ @@ -262,45 +255,54 @@ out: } -static int refresh_slot_attributes(sc_reader_t *reader, sc_slot_info_t *slot) +static int refresh_attributes(sc_reader_t *reader) { struct pcsc_private_data *priv = GET_PRIV_DATA(reader); - struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot); - LONG ret; + LONG rv; - SC_FUNC_CALLED(reader->ctx, 3); - if (pslot->reader_state.szReader == NULL) { - pslot->reader_state.szReader = reader->name; - pslot->reader_state.dwCurrentState = SCARD_STATE_UNAWARE; - pslot->reader_state.dwEventState = SCARD_STATE_UNAWARE; + + 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; + priv->reader_state.dwEventState = SCARD_STATE_UNAWARE; } else { - pslot->reader_state.dwCurrentState = pslot->reader_state.dwEventState; + priv->reader_state.dwCurrentState = priv->reader_state.dwEventState; } - ret = priv->gpriv->SCardGetStatusChange(priv->gpriv->pcsc_ctx, 0, &pslot->reader_state, 1); - if (ret == (LONG)SCARD_E_TIMEOUT) { /* timeout: nothing changed */ - slot->flags &= ~SCARD_STATE_CHANGED; - return 0; + 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; + SC_FUNC_RETURN(reader->ctx, 4, SC_SUCCESS); + } + PCSC_TRACE(reader, "SCardGetStatusChange failed", rv); + return pcsc_to_opensc_error(rv); } - if (ret != SCARD_S_SUCCESS) { - PCSC_ERROR(reader->ctx, "SCardGetStatusChange failed", ret); - return pcsc_ret_to_error(ret); + sc_debug(reader->ctx, "event: 0x%04X", priv->reader_state.dwEventState); + sc_debug(reader->ctx, "state: 0x%04X", priv->reader_state.dwCurrentState); + + if (priv->reader_state.dwEventState & SCARD_STATE_UNKNOWN) { + /* State means "reader unknown", but we have listed it at least once */ + return SC_ERROR_READER_DETACHED; } - if (pslot->reader_state.dwEventState & SCARD_STATE_PRESENT) { - int old_flags = slot->flags; + + if (priv->reader_state.dwEventState & SCARD_STATE_PRESENT) { + int old_flags = reader->flags; int maybe_changed = 0; - - slot->flags |= SC_SLOT_CARD_PRESENT; - slot->atr_len = pslot->reader_state.cbAtr; - if (slot->atr_len > SC_MAX_ATR_SIZE) - slot->atr_len = SC_MAX_ATR_SIZE; - memcpy(slot->atr, pslot->reader_state.rgbAtr, slot->atr_len); + sc_debug(reader->ctx, "card present"); + reader->flags |= SC_READER_CARD_PRESENT; + reader->atr_len = priv->reader_state.cbAtr; + if (reader->atr_len > SC_MAX_ATR_SIZE) + reader->atr_len = SC_MAX_ATR_SIZE; + memcpy(reader->atr, priv->reader_state.rgbAtr, reader->atr_len); #ifndef _WIN32 /* On Linux, SCARD_STATE_CHANGED always means there was an * insert or removal. But we may miss events that way. */ - if (pslot->reader_state.dwEventState & SCARD_STATE_CHANGED) { - slot->flags |= SC_SLOT_CARD_CHANGED; + if (priv->reader_state.dwEventState & SCARD_STATE_CHANGED) { + reader->flags |= SC_READER_CARD_CHANGED; } else { maybe_changed = 1; } @@ -308,275 +310,163 @@ static int refresh_slot_attributes(sc_reader_t *reader, sc_slot_info_t *slot) /* On windows, SCARD_STATE_CHANGED is turned on by lots of * other events, so it gives us a lot of false positives. * But if it's off, there really was no change */ - if (pslot->reader_state.dwEventState & SCARD_STATE_CHANGED) { + if (priv->reader_state.dwEventState & SCARD_STATE_CHANGED) { maybe_changed = 1; } #endif /* If we aren't sure if the card state changed, check if * the card handle is still valid. If the card changed, * the handle will be invalid. */ - slot->flags &= ~SC_SLOT_CARD_CHANGED; + reader->flags &= ~SC_READER_CARD_CHANGED; if (maybe_changed) { - if (old_flags & SC_SLOT_CARD_PRESENT) { + if (old_flags & SC_READER_CARD_PRESENT) { DWORD readers_len = 0, state, prot, atr_len = SC_MAX_ATR_SIZE; unsigned char atr[SC_MAX_ATR_SIZE]; - LONG rv = priv->gpriv->SCardStatus(pslot->pcsc_card, NULL, &readers_len, + LONG rv = priv->gpriv->SCardStatus(priv->pcsc_card, NULL, &readers_len, &state, &prot, atr, &atr_len); if (rv == (LONG)SCARD_W_REMOVED_CARD) - slot->flags |= SC_SLOT_CARD_CHANGED; + reader->flags |= SC_READER_CARD_CHANGED; } else - slot->flags |= SC_SLOT_CARD_CHANGED; + reader->flags |= SC_READER_CARD_CHANGED; } } else { - slot->flags &= ~(SC_SLOT_CARD_PRESENT|SC_SLOT_CARD_CHANGED); + reader->flags &= ~(SC_READER_CARD_PRESENT|SC_READER_CARD_CHANGED); } - return 0; + return SC_SUCCESS; } -static int pcsc_detect_card_presence(sc_reader_t *reader, sc_slot_info_t *slot) +static int pcsc_detect_card_presence(sc_reader_t *reader) { int rv; + SC_FUNC_CALLED(reader->ctx, 3); - if ((rv = refresh_slot_attributes(reader, slot)) < 0) - return rv; - return slot->flags; + rv = refresh_attributes(reader); + if (rv != SC_SUCCESS) + SC_FUNC_RETURN(reader->ctx, 3, rv); + SC_FUNC_RETURN(reader->ctx, 3, reader->flags); } -/* Wait for an event to occur. - * This function ignores the list of slots, because with - * pcsc we have a 1:1 mapping of readers and slots anyway - */ -static int pcsc_wait_for_event(sc_reader_t **readers, - sc_slot_info_t **slots, - size_t nslots, - unsigned int event_mask, - int *reader, - unsigned int *event, int timeout) -{ - struct pcsc_private_data *priv = GET_PRIV_DATA(readers[0]); - sc_context_t *ctx; - SCARDCONTEXT pcsc_ctx; - LONG ret; - SCARD_READERSTATE_A rgReaderStates[SC_MAX_READERS]; - unsigned long on_bits, off_bits; - time_t end_time, now, delta; - size_t i; - /* Prevent buffer overflow */ - if (nslots >= SC_MAX_READERS) - return SC_ERROR_INVALID_ARGUMENTS; - - 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; - } - if (event_mask != 0) - return SC_ERROR_INVALID_ARGUMENTS; - - /* Find out the current status */ - ctx = readers[0]->ctx; - pcsc_ctx = priv->gpriv->pcsc_ctx; - for (i = 0; i < nslots; i++) { - struct pcsc_private_data *priv2 = GET_PRIV_DATA(readers[i]); - - rgReaderStates[i].szReader = readers[i]->name; - rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE; - rgReaderStates[i].dwEventState = SCARD_STATE_UNAWARE; - - /* Can we handle readers from different PCSC contexts? */ - if (priv2->gpriv->pcsc_ctx != pcsc_ctx) - return SC_ERROR_INVALID_ARGUMENTS; - } - - ret = priv->gpriv->SCardGetStatusChange(pcsc_ctx, 0, rgReaderStates, nslots); - if (ret != SCARD_S_SUCCESS) { - PCSC_ERROR(ctx, "SCardGetStatusChange(1) failed", ret); - return pcsc_ret_to_error(ret); - } - - time(&now); - end_time = now + (timeout + 999) / 1000; - - /* Wait for a status change and return if it's a card insert/removal - */ - for( ; ; ) { - SCARD_READERSTATE_A *rsp; - - /* Scan the current state of all readers to see if they - * match any of the events we're polling for */ - *event = 0; - for (i = 0, rsp = rgReaderStates; i < nslots; i++, rsp++) { - unsigned long state, prev_state; - - 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) { - *reader = i; - return SC_SUCCESS; - } - - /* No match - copy the state so pcscd knows - * what to watch out for */ - rsp->dwCurrentState = rsp->dwEventState; - } - - /* Set the timeout if caller wants to time out */ - if (timeout == 0) - return SC_ERROR_EVENT_TIMEOUT; - if (timeout > 0) { - time(&now); - if (now >= end_time) - return SC_ERROR_EVENT_TIMEOUT; - delta = end_time - now; - } else { - delta = 3600; - } - - ret = priv->gpriv->SCardGetStatusChange(pcsc_ctx, 1000 * delta, - rgReaderStates, nslots); - if (ret == (LONG) SCARD_E_TIMEOUT) { - if (timeout < 0) - continue; - return SC_ERROR_EVENT_TIMEOUT; - } - if (ret != SCARD_S_SUCCESS) { - PCSC_ERROR(ctx, "SCardGetStatusChange(2) failed", ret); - return pcsc_ret_to_error(ret); - } - } -} - -static int pcsc_reconnect(sc_reader_t * reader, sc_slot_info_t * slot, int reset) +static int pcsc_reconnect(sc_reader_t * reader, int reset) { DWORD active_proto, protocol; LONG rv; - struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot); struct pcsc_private_data *priv = GET_PRIV_DATA(reader); int r; sc_debug(reader->ctx, "Reconnecting to the card..."); - r = refresh_slot_attributes(reader, slot); - if (r) + r = refresh_attributes(reader); + if (r!= SC_SUCCESS) return r; - if (!(slot->flags & SC_SLOT_CARD_PRESENT)) + + if (!(reader->flags & SC_READER_CARD_PRESENT)) return SC_ERROR_CARD_NOT_PRESENT; /* reconnect always unlocks transaction */ - pslot->locked = 0; + priv->locked = 0; - rv = priv->gpriv->SCardReconnect(pslot->pcsc_card, + 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); /* Check for protocol difference */ if (rv == SCARD_S_SUCCESS && _sc_check_forced_protocol - (reader->ctx, slot->atr, slot->atr_len, + (reader->ctx, reader->atr, reader->atr_len, (unsigned int *)&protocol)) { protocol = opensc_proto_to_pcsc(protocol); if (pcsc_proto_to_opensc(active_proto) != protocol) { - rv = priv->gpriv->SCardReconnect(pslot->pcsc_card, + rv = priv->gpriv->SCardReconnect(priv->pcsc_card, priv->gpriv->connect_exclusive ? SCARD_SHARE_EXCLUSIVE : SCARD_SHARE_SHARED, protocol, SCARD_UNPOWER_CARD, &active_proto); } } if (rv != SCARD_S_SUCCESS) { - PCSC_ERROR(reader->ctx, "SCardReconnect failed", rv); - return pcsc_ret_to_error(rv); + PCSC_TRACE(reader, "SCardReconnect failed", rv); + return pcsc_to_opensc_error(rv); } - slot->active_protocol = pcsc_proto_to_opensc(active_proto); - return pcsc_ret_to_error(rv); + reader->active_protocol = pcsc_proto_to_opensc(active_proto); + return pcsc_to_opensc_error(rv); } -static int pcsc_connect(sc_reader_t *reader, sc_slot_info_t *slot) +static int pcsc_connect(sc_reader_t *reader) { DWORD active_proto, protocol; SCARDHANDLE card_handle; LONG rv; struct pcsc_private_data *priv = GET_PRIV_DATA(reader); - struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot); int r; - r = refresh_slot_attributes(reader, slot); - if (r) - return r; - if (!(slot->flags & SC_SLOT_CARD_PRESENT)) - return SC_ERROR_CARD_NOT_PRESENT; + SC_FUNC_CALLED(reader->ctx, 3); + + r = refresh_attributes(reader); + if (r != SC_SUCCESS) + SC_FUNC_RETURN(reader->ctx, 4, r); + + if (!(reader->flags & SC_READER_CARD_PRESENT)) + SC_FUNC_RETURN(reader->ctx, 4, SC_ERROR_CARD_NOT_PRESENT); /* Always connect with whatever protocol possible */ rv = priv->gpriv->SCardConnect(priv->gpriv->pcsc_ctx, reader->name, priv->gpriv->connect_exclusive ? SCARD_SHARE_EXCLUSIVE : SCARD_SHARE_SHARED, SCARD_PROTOCOL_ANY, &card_handle, &active_proto); if (rv != SCARD_S_SUCCESS) { - PCSC_ERROR(reader->ctx, "SCardConnect failed", rv); - return pcsc_ret_to_error(rv); + PCSC_TRACE(reader, "SCardConnect failed", rv); + return pcsc_to_opensc_error(rv); } - slot->active_protocol = pcsc_proto_to_opensc(active_proto); - pslot->pcsc_card = card_handle; + reader->active_protocol = pcsc_proto_to_opensc(active_proto); + priv->pcsc_card = card_handle; /* after connect reader is not locked yet */ - pslot->locked = 0; - sc_debug(reader->ctx, "After connect protocol = %d", slot->active_protocol); + 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, slot->atr, slot->atr_len, (unsigned int *) &protocol)) { + 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 */ - if (slot->active_protocol != protocol) { + if (reader->active_protocol != protocol) { sc_debug(reader->ctx, "Protocol difference, forcing protocol (%d)", protocol); /* Reconnect with a reset. pcsc_reconnect figures out the right forced protocol */ - r = pcsc_reconnect(reader, slot, 1); + r = pcsc_reconnect(reader, 1); if (r != SC_SUCCESS) { sc_debug(reader->ctx, "pcsc_reconnect (to force protocol) failed", r); return r; } - sc_debug(reader->ctx, "Proto after reconnect = %d", slot->active_protocol); + sc_debug(reader->ctx, "Proto after reconnect = %d", reader->active_protocol); } } return SC_SUCCESS; } -static int pcsc_disconnect(sc_reader_t * reader, sc_slot_info_t * slot) +static int pcsc_disconnect(sc_reader_t * reader) { - struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot); struct pcsc_private_data *priv = GET_PRIV_DATA(reader); - - priv->gpriv->SCardDisconnect(pslot->pcsc_card, priv->gpriv->connect_reset ? + + SC_FUNC_CALLED(reader->ctx, 3); + + priv->gpriv->SCardDisconnect(priv->pcsc_card, priv->gpriv->connect_reset ? SCARD_RESET_CARD : SCARD_LEAVE_CARD); - memset(pslot, 0, sizeof(*pslot)); - slot->flags = 0; + reader->flags = 0; return SC_SUCCESS; } -static int pcsc_lock(sc_reader_t *reader, sc_slot_info_t *slot) +static int pcsc_lock(sc_reader_t *reader) { LONG rv; int r; - struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot); struct pcsc_private_data *priv = GET_PRIV_DATA(reader); SC_FUNC_CALLED(reader->ctx, 3); - assert(pslot != NULL); - rv = priv->gpriv->SCardBeginTransaction(pslot->pcsc_card); + rv = priv->gpriv->SCardBeginTransaction(priv->pcsc_card); switch (rv) { case SCARD_E_INVALID_HANDLE: case SCARD_E_READER_UNAVAILABLE: - r = pcsc_connect(reader, slot); + r = pcsc_connect(reader); if (r != SC_SUCCESS) { sc_debug(reader->ctx, "pcsc_connect failed", r); return r; @@ -585,7 +475,7 @@ static int pcsc_lock(sc_reader_t *reader, sc_slot_info_t *slot) 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, slot, 0); + r = pcsc_reconnect(reader, 0); if (r != SC_SUCCESS) { sc_debug(reader->ctx, "pcsc_reconnect failed", r); return r; @@ -593,30 +483,28 @@ static int pcsc_lock(sc_reader_t *reader, sc_slot_info_t *slot) /* return failure so that upper layers will be notified and try to lock again */ return SC_ERROR_CARD_RESET; case SCARD_S_SUCCESS: - pslot->locked = 1; + priv->locked = 1; return SC_SUCCESS; default: - PCSC_ERROR(reader->ctx, "SCardBeginTransaction failed", rv); - return pcsc_ret_to_error(rv); + PCSC_TRACE(reader, "SCardBeginTransaction failed", rv); + return pcsc_to_opensc_error(rv); } } -static int pcsc_unlock(sc_reader_t *reader, sc_slot_info_t *slot) +static int pcsc_unlock(sc_reader_t *reader) { LONG rv; - struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot); struct pcsc_private_data *priv = GET_PRIV_DATA(reader); SC_FUNC_CALLED(reader->ctx, 3); - assert(pslot != NULL); - rv = priv->gpriv->SCardEndTransaction(pslot->pcsc_card, priv->gpriv->transaction_reset ? + rv = priv->gpriv->SCardEndTransaction(priv->pcsc_card, priv->gpriv->transaction_reset ? SCARD_RESET_CARD : SCARD_LEAVE_CARD); - pslot->locked = 0; + priv->locked = 0; if (rv != SCARD_S_SUCCESS) { - PCSC_ERROR(reader->ctx, "SCardEndTransaction failed", rv); - return pcsc_ret_to_error(rv); + PCSC_TRACE(reader, "SCardEndTransaction failed", rv); + return pcsc_to_opensc_error(rv); } return SC_SUCCESS; } @@ -626,29 +514,49 @@ static int pcsc_release(sc_reader_t *reader) struct pcsc_private_data *priv = GET_PRIV_DATA(reader); free(priv); - if (reader->slot[0].drv_data != NULL) { - free(reader->slot[0].drv_data); - reader->slot[0].drv_data = NULL; - } return SC_SUCCESS; } -static int pcsc_reset(sc_reader_t *reader, sc_slot_info_t *slot) +static int pcsc_reset(sc_reader_t *reader) { + struct pcsc_private_data *priv = GET_PRIV_DATA(reader); int r; - struct pcsc_slot_data *pslot = GET_SLOT_DATA(slot); - int old_locked = pslot->locked; + int old_locked = priv->locked; - r = pcsc_reconnect(reader, slot, 1); + r = pcsc_reconnect(reader, 1); if(r != SC_SUCCESS) return r; /* pcsc_reconnect unlocks card... try to lock it again if it was locked */ if(old_locked) - r = pcsc_lock(reader, slot); + r = pcsc_lock(reader); return r; } + + +static int pcsc_cancel(sc_context_t *ctx, void *reader_data) +{ + LONG rv = SCARD_S_SUCCESS; + struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *)reader_data; + + SC_FUNC_CALLED(ctx, 3); +#ifndef _WIN32 + if (gpriv->pcsc_wait_ctx != -1) { + rv = gpriv->SCardCancel(gpriv->pcsc_wait_ctx); + if (rv == SCARD_S_SUCCESS) + /* Also close and clear the waiting context */ + rv = gpriv->SCardReleaseContext(gpriv->pcsc_wait_ctx); + } +#else + rv = gpriv->SCardCancel(gpriv->pcsc_ctx); +#endif + if (rv != SCARD_S_SUCCESS) { + PCSC_LOG(ctx, "SCardCancel/SCardReleaseContext failed", rv); + return pcsc_to_opensc_error(rv); + } + return SC_SUCCESS; +} static struct sc_reader_operations pcsc_ops; @@ -680,6 +588,7 @@ static int pcsc_init(sc_context_t *ctx, void **reader_data) gpriv->enable_pinpad = 1; 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) { @@ -712,6 +621,7 @@ static int pcsc_init(sc_context_t *ctx, void **reader_data) gpriv->SCardEndTransaction = (SCardEndTransaction_t)lt_dlsym(gpriv->dlhandle, "SCardEndTransaction"); gpriv->SCardStatus = (SCardStatus_t)lt_dlsym(gpriv->dlhandle, "SCardStatus"); gpriv->SCardGetStatusChange = (SCardGetStatusChange_t)lt_dlsym(gpriv->dlhandle, "SCardGetStatusChange"); + gpriv->SCardCancel = (SCardCancel_t)lt_dlsym(gpriv->dlhandle, "SCardCancel"); gpriv->SCardTransmit = (SCardTransmit_t)lt_dlsym(gpriv->dlhandle, "SCardTransmit"); gpriv->SCardListReaders = (SCardListReaders_t)lt_dlsym(gpriv->dlhandle, "SCardListReaders"); @@ -746,6 +656,7 @@ static int pcsc_init(sc_context_t *ctx, void **reader_data) gpriv->SCardEndTransaction == NULL || gpriv->SCardStatus == NULL || gpriv->SCardGetStatusChange == NULL || + gpriv->SCardCancel == NULL || (gpriv->SCardControl == NULL && gpriv->SCardControlOLD == NULL) || gpriv->SCardTransmit == NULL || gpriv->SCardListReaders == NULL @@ -791,7 +702,7 @@ static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data) PCSC_TLV_STRUCTURE *pcsc_tlv; struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *) prv_data; LONG rv; - DWORD reader_buf_size, rcount, feature_len, display_ioctl; + DWORD reader_buf_size, rcount, feature_len, display_ioctl = 0x0; char *reader_buf = NULL, *reader_name; const char *mszGroups = NULL; int ret = SC_ERROR_INTERNAL; @@ -819,9 +730,9 @@ static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data) (LPDWORD) &reader_buf_size); } if (rv != SCARD_S_SUCCESS) { - if (rv != SCARD_E_INVALID_HANDLE) { - PCSC_ERROR(ctx, "SCardListReaders failed", rv); - ret = pcsc_ret_to_error(rv); + if (rv != (LONG)SCARD_E_INVALID_HANDLE) { + PCSC_LOG(ctx, "SCardListReaders failed", rv); + ret = pcsc_to_opensc_error(rv); goto out; } @@ -830,8 +741,8 @@ static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data) rv = gpriv->SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &gpriv->pcsc_ctx); if (rv != SCARD_S_SUCCESS) { - PCSC_ERROR(ctx, "SCardEstablishContext failed", rv); - ret = pcsc_ret_to_error(rv); + PCSC_LOG(ctx, "SCardEstablishContext failed", rv); + ret = pcsc_to_opensc_error(rv); goto out; } @@ -847,15 +758,13 @@ static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data) rv = gpriv->SCardListReaders(gpriv->pcsc_ctx, mszGroups, reader_buf, (LPDWORD) &reader_buf_size); if (rv != SCARD_S_SUCCESS) { - PCSC_ERROR(ctx, "SCardListReaders failed", rv); - ret = pcsc_ret_to_error(rv); + PCSC_LOG(ctx, "SCardListReaders failed", rv); + ret = pcsc_to_opensc_error(rv); goto out; } for (reader_name = reader_buf; *reader_name != '\x0'; reader_name += strlen (reader_name) + 1) { sc_reader_t *reader = NULL; struct pcsc_private_data *priv = NULL; - struct pcsc_slot_data *pslot = NULL; - sc_slot_info_t *slot = NULL; unsigned int i; int found = 0; @@ -881,11 +790,7 @@ static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data) ret = SC_ERROR_OUT_OF_MEMORY; goto err1; } - if ((priv = (struct pcsc_private_data *) malloc(sizeof(struct pcsc_private_data))) == NULL) { - ret = SC_ERROR_OUT_OF_MEMORY; - goto err1; - } - if ((pslot = (struct pcsc_slot_data *) malloc(sizeof(struct pcsc_slot_data))) == NULL) { + if ((priv = (struct pcsc_private_data *) calloc(1, sizeof(struct pcsc_private_data))) == NULL) { ret = SC_ERROR_OUT_OF_MEMORY; goto err1; } @@ -893,16 +798,11 @@ static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data) reader->drv_data = priv; reader->ops = &pcsc_ops; reader->driver = &pcsc_drv; - reader->slot_count = 1; if ((reader->name = strdup(reader_name)) == NULL) { ret = SC_ERROR_OUT_OF_MEMORY; goto err1; } priv->gpriv = gpriv; - slot = &reader->slot[0]; - memset(slot, 0, sizeof(*slot)); - slot->drv_data = pslot; - memset(pslot, 0, sizeof(*pslot)); if (_sc_add_reader(ctx, reader)) { ret = SC_SUCCESS; /* silent ignore */ goto err1; @@ -915,13 +815,27 @@ static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data) rv = gpriv->SCardConnect(gpriv->pcsc_ctx, reader->name, SCARD_SHARE_DIRECT, SCARD_PROTOCOL_ANY, &card_handle, &active_proto); #else rv = gpriv->SCardConnect(gpriv->pcsc_ctx, reader->name, SCARD_SHARE_DIRECT, 0, &card_handle, &active_proto); - if (rv == SCARD_E_SHARING_VIOLATION) /* Assume that there is a card in the reader in shared mode */ - rv = gpriv->SCardConnect(gpriv->pcsc_ctx, reader->name, SCARD_SHARE_SHARED, SCARD_PROTOCOL_ANY, &card_handle, &active_proto); #endif + 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); + } + if (rv == SCARD_S_SUCCESS) { + rv = gpriv->SCardBeginTransaction(card_handle); + PCSC_TRACE(reader, "SCardBeginTransaction", rv); + if (rv == (LONG)SCARD_W_RESET_CARD) { /* can only happen in indirect mode */ + rv = gpriv->SCardReconnect(card_handle, SCARD_SHARE_SHARED, SCARD_PROTOCOL_ANY, SCARD_LEAVE_CARD, &active_proto); + PCSC_TRACE(reader, "SCardReconnect", rv); + rv = gpriv->SCardBeginTransaction(card_handle); + PCSC_TRACE(reader, "SCardBeginTransaction", rv); + } + } + if (rv == SCARD_S_SUCCESS) { rv = gpriv->SCardControl(card_handle, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0, feature_buf, sizeof(feature_buf), &feature_len); - if (rv != SCARD_S_SUCCESS) { - sc_debug(ctx, "SCardControl failed %08x", rv); + if (rv != (LONG)SCARD_S_SUCCESS) { + PCSC_TRACE(reader, "SCardControl failed", rv); } else { if ((feature_len % sizeof(PCSC_TLV_STRUCTURE)) != 0) { @@ -936,17 +850,17 @@ static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data) for (i = 0; i < feature_len; i++) { sc_debug(ctx, "Reader feature %02x detected", pcsc_tlv[i].tag); if (pcsc_tlv[i].tag == FEATURE_VERIFY_PIN_DIRECT) { - pslot->verify_ioctl = ntohl(pcsc_tlv[i].value); + priv->verify_ioctl = ntohl(pcsc_tlv[i].value); } else if (pcsc_tlv[i].tag == FEATURE_VERIFY_PIN_START) { - pslot->verify_ioctl_start = ntohl(pcsc_tlv[i].value); + priv->verify_ioctl_start = ntohl(pcsc_tlv[i].value); } else if (pcsc_tlv[i].tag == FEATURE_VERIFY_PIN_FINISH) { - pslot->verify_ioctl_finish = ntohl(pcsc_tlv[i].value); + priv->verify_ioctl_finish = ntohl(pcsc_tlv[i].value); } else if (pcsc_tlv[i].tag == FEATURE_MODIFY_PIN_DIRECT) { - pslot->modify_ioctl = ntohl(pcsc_tlv[i].value); + priv->modify_ioctl = ntohl(pcsc_tlv[i].value); } else if (pcsc_tlv[i].tag == FEATURE_MODIFY_PIN_START) { - pslot->modify_ioctl_start = ntohl(pcsc_tlv[i].value); + priv->modify_ioctl_start = ntohl(pcsc_tlv[i].value); } else if (pcsc_tlv[i].tag == FEATURE_MODIFY_PIN_FINISH) { - pslot->modify_ioctl_finish = ntohl(pcsc_tlv[i].value); + priv->modify_ioctl_finish = ntohl(pcsc_tlv[i].value); } else if (pcsc_tlv[i].tag == FEATURE_IFD_PIN_PROPERTIES) { display_ioctl = ntohl(pcsc_tlv[i].value); } else { @@ -954,22 +868,22 @@ static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data) } } - /* Set slot capabilities based on detected IOCTLs */ - if (pslot->verify_ioctl || (pslot->verify_ioctl_start && pslot->verify_ioctl_finish)) { + /* 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"; if (priv->gpriv->enable_pinpad) { sc_debug(ctx, log_text); - slot->capabilities |= SC_SLOT_CAP_PIN_PAD; + reader->capabilities |= SC_READER_CAP_PIN_PAD; } else { sc_debug(ctx, "%s %s", log_text, log_disabled); } } - if (pslot->modify_ioctl || (pslot->modify_ioctl_start && pslot->modify_ioctl_finish)) { + 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) { sc_debug(ctx, log_text); - slot->capabilities |= SC_SLOT_CAP_PIN_PAD; + reader->capabilities |= SC_READER_CAP_PIN_PAD; } else { sc_debug(ctx, "%s %s", log_text, log_disabled); } @@ -983,7 +897,7 @@ static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data) PIN_PROPERTIES_STRUCTURE *caps = (PIN_PROPERTIES_STRUCTURE *)rbuf; if (caps->wLcdLayout > 0) { sc_debug(ctx, "Reader has a display: %04X", caps->wLcdLayout); - slot->capabilities |= SC_SLOT_CAP_DISPLAY; + reader->capabilities |= SC_READER_CAP_DISPLAY; } else sc_debug(ctx, "Reader does not have a display."); } else { @@ -993,13 +907,14 @@ static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data) } } } + gpriv->SCardEndTransaction(card_handle, SCARD_LEAVE_CARD); gpriv->SCardDisconnect(card_handle, SCARD_LEAVE_CARD); } else { - sc_debug(ctx, "SCardConnect failed %08x", rv); + PCSC_TRACE(reader, "SCardConnect failed", rv); } } - refresh_slot_attributes(reader, slot); + refresh_attributes(reader); continue; err1: @@ -1011,9 +926,6 @@ static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data) free(reader->name); free(reader); } - if (slot != NULL) - free(pslot); - goto out; } @@ -1027,6 +939,143 @@ out: SC_FUNC_RETURN(ctx, 3, ret); } + +/* Wait for an event to occur. + */ +static int pcsc_wait_for_event(sc_context_t *ctx, + void *reader_data, + unsigned int event_mask, + sc_reader_t **event_reader, + unsigned int *event, int timeout) +{ + 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; + size_t i; + unsigned int num_watch; + + 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; */ + + /* Find out the current status */ + num_watch = sc_ctx_get_reader_count(ctx); + sc_debug(ctx, "Watching %d readers\n", 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; + rgReaderStates[i].dwEventState = SCARD_STATE_UNAWARE; + } +#ifndef __APPLE__ + if (event_mask & SC_EVENT_READER_ATTACHED) { + rgReaderStates[i].szReader = "\\\\?PnP?\\Notification"; + rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE; + rgReaderStates[i].dwEventState = SCARD_STATE_UNAWARE; + num_watch++; + } +#endif +#ifndef _WIN32 + /* Establish a new context, assuming that it is called from a different thread with pcsc-lite */ + if (gpriv->pcsc_wait_ctx == -1) { + 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); + } + } +#else + gpriv->pcsc_wait_ctx = gpriv->pcsc_ctx; +#endif + + 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); + } + } + + /* Wait for a status change + */ + for( ; ; ) { + SCARD_READERSTATE_A *rsp; + sc_debug(ctx, "Looping..."); + + /* Scan the current state of all readers to see if they + * match any of the events we're polling for */ + *event = 0; + for (i = 0, rsp = rgReaderStates; i < num_watch; i++, rsp++) { + unsigned long state, prev_state; + 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); + } + + /* check for hotplug event */ + if (strcmp(rgReaderStates[i].szReader, "\\\\?PnP?\\Notification") == 0 && event_mask & SC_EVENT_READER_ATTACHED) { + if (state & SCARD_STATE_CHANGED) { + sc_debug(ctx, "detected hotplug event"); + *event = SC_EVENT_READER_ATTACHED; + *event_reader = NULL; + SC_FUNC_RETURN(ctx, 3, SC_SUCCESS); + } + } + + /* No match - copy the state so pcscd knows + * what to watch out for */ + rsp->dwCurrentState = rsp->dwEventState; + } + + /* Set the timeout if caller wants to time out */ + if (timeout == 0) + return SC_ERROR_EVENT_TIMEOUT; + + 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; + } + if (rv == (LONG) SCARD_E_TIMEOUT) { + return SC_ERROR_EVENT_TIMEOUT; + } + + if (rv != SCARD_S_SUCCESS) { + PCSC_LOG(ctx, "SCardGetStatusChange(2) failed", rv); + return pcsc_to_opensc_error(rv); + } + } +} + + + /* * Pinpad support, based on PC/SC v2 Part 10 interface * Similar to CCID in spirit. @@ -1043,7 +1092,7 @@ out: #define SC_CCID_PIN_UNITS_BYTES 0x80 /* Build a PIN verification block + APDU */ -static int part10_build_verify_pin_block(u8 * buf, size_t * size, sc_slot_info_t *slot, struct sc_pin_cmd_data *data) +static int part10_build_verify_pin_block(struct sc_reader *reader, u8 * buf, size_t * size, struct sc_pin_cmd_data *data) { int offset = 0, count = 0; sc_apdu_t *apdu = data->apdu; @@ -1103,7 +1152,7 @@ static int part10_build_verify_pin_block(u8 * buf, size_t * size, sc_slot_info_t pin_verify->bEntryValidationCondition = 0x02; /* Keypress only */ - if (slot->capabilities & SC_SLOT_CAP_DISPLAY) + if (reader->capabilities & SC_READER_CAP_DISPLAY) pin_verify->bNumberMessage = 0xFF; /* Default message */ else pin_verify->bNumberMessage = 0x00; /* No messages */ @@ -1138,7 +1187,7 @@ static int part10_build_verify_pin_block(u8 * buf, size_t * size, sc_slot_info_t /* Build a PIN modification block + APDU */ -static int part10_build_modify_pin_block(u8 * buf, size_t * size, sc_slot_info_t *slot, struct sc_pin_cmd_data *data) +static int part10_build_modify_pin_block(struct sc_reader *reader, u8 * buf, size_t * size, struct sc_pin_cmd_data *data) { int offset = 0, count = 0; sc_apdu_t *apdu = data->apdu; @@ -1217,7 +1266,7 @@ static int part10_build_modify_pin_block(u8 * buf, size_t * size, sc_slot_info_t * 0x03: Messages seen on Pinpad display: Enter Old Pin, New Pin, Confirm Pin * Could be 0xFF too. */ - if (slot->capabilities & SC_SLOT_CAP_DISPLAY) + if (reader->capabilities & SC_READER_CAP_DISPLAY) pin_modify->bNumberMessage = data->flags & SC_PIN_CMD_IMPLICIT_CHANGE ? 0x02 : 0x03; else pin_modify->bNumberMessage = 0x00; /* No messages */ @@ -1253,8 +1302,7 @@ static int part10_build_modify_pin_block(u8 * buf, size_t * size, sc_slot_info_t /* Do the PIN command */ static int -pcsc_pin_cmd(sc_reader_t *reader, sc_slot_info_t *slot, - struct sc_pin_cmd_data *data) +pcsc_pin_cmd(sc_reader_t *reader, struct sc_pin_cmd_data *data) { struct pcsc_private_data *priv = GET_PRIV_DATA(reader); u8 rbuf[SC_MAX_APDU_BUFFER_SIZE], sbuf[SC_MAX_APDU_BUFFER_SIZE]; @@ -1263,10 +1311,8 @@ pcsc_pin_cmd(sc_reader_t *reader, sc_slot_info_t *slot, int r; DWORD ioctl = 0; sc_apdu_t *apdu; - struct pcsc_slot_data *pslot = (struct pcsc_slot_data *) slot->drv_data; SC_FUNC_CALLED(reader->ctx, 3); - assert(pslot != NULL); if (priv->gpriv->SCardControl == NULL) return SC_ERROR_NOT_SUPPORTED; @@ -1280,21 +1326,21 @@ pcsc_pin_cmd(sc_reader_t *reader, sc_slot_info_t *slot, apdu = data->apdu; switch (data->cmd) { case SC_PIN_CMD_VERIFY: - if (!(pslot->verify_ioctl || (pslot->verify_ioctl_start && pslot->verify_ioctl_finish))) { + if (!(priv->verify_ioctl || (priv->verify_ioctl_start && priv->verify_ioctl_finish))) { sc_debug(reader->ctx, "Pinpad reader does not support verification!"); return SC_ERROR_NOT_SUPPORTED; } - r = part10_build_verify_pin_block(sbuf, &scount, slot, data); - ioctl = pslot->verify_ioctl ? pslot->verify_ioctl : pslot->verify_ioctl_start; + r = part10_build_verify_pin_block(reader, sbuf, &scount, data); + ioctl = priv->verify_ioctl ? priv->verify_ioctl : priv->verify_ioctl_start; break; case SC_PIN_CMD_CHANGE: case SC_PIN_CMD_UNBLOCK: - if (!(pslot->modify_ioctl || (pslot->modify_ioctl_start && pslot->modify_ioctl_finish))) { + if (!(priv->modify_ioctl || (priv->modify_ioctl_start && priv->modify_ioctl_finish))) { sc_debug(reader->ctx, "Pinpad reader does not support modification!"); return SC_ERROR_NOT_SUPPORTED; } - r = part10_build_modify_pin_block(sbuf, &scount, slot, data); - ioctl = pslot->modify_ioctl ? pslot->modify_ioctl : pslot->modify_ioctl_start; + r = part10_build_modify_pin_block(reader, sbuf, &scount, data); + ioctl = priv->modify_ioctl ? priv->modify_ioctl : priv->modify_ioctl_start; break; default: sc_debug(reader->ctx, "Unknown PIN command %d", data->cmd); @@ -1307,19 +1353,19 @@ pcsc_pin_cmd(sc_reader_t *reader, sc_slot_info_t *slot, sc_bin_to_hex(sbuf, scount, dbuf, sizeof(dbuf), ':'); sc_debug(reader->ctx, "PC/SC v2 pinpad block: %s", dbuf); - r = pcsc_internal_transmit(reader, slot, sbuf, scount, rbuf, &rcount, ioctl); + r = pcsc_internal_transmit(reader, sbuf, scount, rbuf, &rcount, ioctl); SC_TEST_RET(reader->ctx, r, "PC/SC v2 pinpad: block transmit failed!"); /* finish the call if it was a two-phase operation */ - if ((ioctl == pslot->verify_ioctl_start) - || (ioctl == pslot->modify_ioctl_start)) { + if ((ioctl == priv->verify_ioctl_start) + || (ioctl == priv->modify_ioctl_start)) { if (rcount != 0) { SC_FUNC_RETURN(reader->ctx, 2, SC_ERROR_UNKNOWN_DATA_RECEIVED); } - ioctl = (ioctl == pslot->verify_ioctl_start) ? pslot->verify_ioctl_finish : pslot->modify_ioctl_finish; + ioctl = (ioctl == priv->verify_ioctl_start) ? priv->verify_ioctl_finish : priv->modify_ioctl_finish; rcount = sizeof(rbuf); - r = pcsc_internal_transmit(reader, slot, sbuf, 0, rbuf, &rcount, ioctl); + r = pcsc_internal_transmit(reader, sbuf, 0, rbuf, &rcount, ioctl); SC_TEST_RET(reader->ctx, r, "PC/SC v2 pinpad: finish operation failed!"); } @@ -1368,6 +1414,7 @@ struct sc_reader_driver * sc_get_pcsc_driver(void) pcsc_ops.disconnect = pcsc_disconnect; pcsc_ops.perform_verify = pcsc_pin_cmd; pcsc_ops.wait_for_event = pcsc_wait_for_event; + pcsc_ops.cancel = pcsc_cancel; pcsc_ops.reset = pcsc_reset; return &pcsc_drv; diff --git a/src/libopensc/sc.c b/src/libopensc/sc.c index fd12dee6..09e5ac1b 100644 --- a/src/libopensc/sc.c +++ b/src/libopensc/sc.c @@ -181,60 +181,17 @@ int sc_compare_oid(const struct sc_object_id *oid1, const struct sc_object_id *o return 1; } -sc_slot_info_t * _sc_get_slot_info(sc_reader_t *reader, int slot_id) -{ - assert(reader != NULL); - if (slot_id < 0 || slot_id > reader->slot_count) - return NULL; - return &reader->slot[slot_id]; -} - -int sc_detect_card_presence(sc_reader_t *reader, int slot_id) +int sc_detect_card_presence(sc_reader_t *reader) { int r; - sc_slot_info_t *slot = _sc_get_slot_info(reader, slot_id); - - if (slot == NULL) - SC_FUNC_RETURN(reader->ctx, 0, SC_ERROR_SLOT_NOT_FOUND); SC_FUNC_CALLED(reader->ctx, 1); if (reader->ops->detect_card_presence == NULL) SC_FUNC_RETURN(reader->ctx, 0, SC_ERROR_NOT_SUPPORTED); - r = reader->ops->detect_card_presence(reader, slot); + r = reader->ops->detect_card_presence(reader); SC_FUNC_RETURN(reader->ctx, 1, r); } -int sc_wait_for_event(sc_reader_t *readers[], int slot_id[], size_t nslots, - unsigned int event_mask, - int *reader, unsigned int *event, int timeout) -{ - sc_slot_info_t *slotp[SC_MAX_SLOTS * SC_MAX_READERS]; - sc_context_t *ctx; - unsigned int j; - int r; - - if (nslots == 0 || nslots > SC_MAX_SLOTS * SC_MAX_READERS) - return SC_ERROR_INVALID_ARGUMENTS; - ctx = readers[0]->ctx; - - SC_FUNC_CALLED(ctx, 1); - for (j = 0; j < nslots; j++) { - slotp[j] = _sc_get_slot_info(readers[j], slot_id[j]); - - if (slotp[j] == NULL) - SC_FUNC_RETURN(ctx, 0, SC_ERROR_SLOT_NOT_FOUND); - /* XXX check to make sure all readers share the same operations - * struct */ - } - - if (readers[0]->ops->wait_for_event == NULL) - SC_FUNC_RETURN(ctx, 0, SC_ERROR_NOT_SUPPORTED); - - r = readers[0]->ops->wait_for_event(readers, slotp, nslots, - event_mask, reader, event, timeout); - SC_FUNC_RETURN(ctx, 1, r); -} - int sc_path_set(sc_path_t *path, int type, const u8 *id, size_t id_len, int idx, int count) { @@ -642,10 +599,10 @@ int sc_file_valid(const sc_file_t *file) { return file->magic == SC_FILE_MAGIC; } -int _sc_parse_atr(sc_context_t *ctx, sc_slot_info_t *slot) +int _sc_parse_atr(sc_reader_t *reader) { - u8 *p = slot->atr; - int atr_len = (int) slot->atr_len; + u8 *p = reader->atr; + int atr_len = (int) reader->atr_len; int n_hist, x; int tx[4]; int i, FI, DI; @@ -659,16 +616,16 @@ int _sc_parse_atr(sc_context_t *ctx, sc_slot_info_t *slot) -1, 1, 2, 4, 8, 16, 32, -1, 12, 20, -1, -1, -1, -1, -1, -1 }; - slot->atr_info.hist_bytes_len = 0; - slot->atr_info.hist_bytes = NULL; + reader->atr_info.hist_bytes_len = 0; + reader->atr_info.hist_bytes = NULL; if (atr_len == 0) { - sc_debug(ctx, "empty ATR - card not present?\n"); + sc_debug(reader->ctx, "empty ATR - card not present?\n"); return SC_ERROR_INTERNAL; } if (p[0] != 0x3B && p[0] != 0x3F) { - sc_debug(ctx, "invalid sync byte in ATR: 0x%02X\n", p[0]); + sc_debug(reader->ctx, "invalid sync byte in ATR: 0x%02X\n", p[0]); return SC_ERROR_INTERNAL; } n_hist = p[1] & 0x0F; @@ -684,20 +641,20 @@ int _sc_parse_atr(sc_context_t *ctx, sc_slot_info_t *slot) tx[i] = -1; } if (tx[0] >= 0) { - slot->atr_info.FI = FI = tx[0] >> 4; - slot->atr_info.DI = DI = tx[0] & 0x0F; - slot->atr_info.Fi = Fi_table[FI]; - slot->atr_info.f = f_table[FI]; - slot->atr_info.Di = Di_table[DI]; + reader->atr_info.FI = FI = tx[0] >> 4; + reader->atr_info.DI = DI = tx[0] & 0x0F; + reader->atr_info.Fi = Fi_table[FI]; + reader->atr_info.f = f_table[FI]; + reader->atr_info.Di = Di_table[DI]; } else { - slot->atr_info.Fi = -1; - slot->atr_info.f = -1; - slot->atr_info.Di = -1; + reader->atr_info.Fi = -1; + reader->atr_info.f = -1; + reader->atr_info.Di = -1; } if (tx[2] >= 0) - slot->atr_info.N = tx[3]; + reader->atr_info.N = tx[3]; else - slot->atr_info.N = -1; + reader->atr_info.N = -1; while (tx[3] > 0 && tx[3] & 0xF0 && atr_len > 0) { x = tx[3] >> 4; for (i = 0; i < 4 && atr_len > 0; i++) { @@ -713,8 +670,8 @@ int _sc_parse_atr(sc_context_t *ctx, sc_slot_info_t *slot) return 0; if (n_hist > atr_len) n_hist = atr_len; - slot->atr_info.hist_bytes_len = n_hist; - slot->atr_info.hist_bytes = p; + reader->atr_info.hist_bytes_len = n_hist; + reader->atr_info.hist_bytes = p; return 0; } diff --git a/src/libopensc/types.h b/src/libopensc/types.h index 94016ccf..5ede7de6 100644 --- a/src/libopensc/types.h +++ b/src/libopensc/types.h @@ -25,6 +25,7 @@ extern "C" { #endif +#include "simclist.h" typedef unsigned char u8; #define SC_MAX_OBJECT_ID_OCTETS 16