Plug&Play support
This is not the best solution, but focus on smallest code change. Changes: 1. Add detect_readers() to reader opts, this adds new readers to the end of the readers list until list is full. 2. Add sc_ctx_detect_readers() that calls readers' detect_readers(). 3. Fixup pcsc_lock() so that it reconnect to the card and report proper error so caller may be notified if session was lost. 4. Allow context to be created without readers. 5. Call sc_ctx_detect_readers() from PKCS#11 C_GetSlotList with NULL_PTR. 6. Allow no reader at detect_card, as reader my be removed. 7. Since I broke ABI, I updated the external module version requirement to match OpenSC version. In the future a separate version should be maintained for each interface, this should be unrelated to the package version. Alon --- svn merge -r 3480:3505 https://www.opensc-project.org/svn/opensc/branches/alonbl/pnp M src/tools/opensc-tool.c M src/pkcs11/pkcs11-global.c M src/pkcs11/slot.c M src/libopensc/reader-pcsc.c M src/libopensc/internal-winscard.h M src/libopensc/ctx.c M src/libopensc/reader-ctapi.c M src/libopensc/libopensc.exports M src/libopensc/reader-openct.c M src/libopensc/opensc.h git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@3506 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
c862f88ce7
commit
e237574742
|
@ -354,7 +354,8 @@ static void *load_dynamic_driver(sc_context_t *ctx, void **dll,
|
|||
}
|
||||
/* verify module version */
|
||||
version = modversion();
|
||||
if (version == NULL || strncmp(version, "0.9.", strlen("0.9.")) > 0) {
|
||||
/* XXX: We really need to have ABI version for each interface */
|
||||
if (version == NULL || strncmp(version, PACKAGE_VERSION, strlen(PACKAGE_VERSION)) != 0) {
|
||||
sc_error(ctx,"dynamic library '%s': invalid module version\n",libname);
|
||||
lt_dlclose(handle);
|
||||
return NULL;
|
||||
|
@ -637,6 +638,25 @@ static void process_config_file(sc_context_t *ctx, struct _sc_ctx_options *opts)
|
|||
load_parameters(ctx, ctx->conf_blocks[i], opts);
|
||||
}
|
||||
|
||||
int sc_ctx_detect_readers(sc_context_t *ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
sc_mutex_lock(ctx, ctx->mutex);
|
||||
|
||||
for (i = 0; ctx->reader_drivers[i] != NULL; i++) {
|
||||
const struct sc_reader_driver *drv = ctx->reader_drivers[i];
|
||||
|
||||
if (drv->ops->detect_readers != NULL)
|
||||
drv->ops->detect_readers(ctx, ctx->reader_drv_data[i]);
|
||||
}
|
||||
|
||||
sc_mutex_unlock(ctx, ctx->mutex);
|
||||
|
||||
/* XXX: Do not ignore erros? */
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -724,10 +744,7 @@ int sc_context_create(sc_context_t **ctx_out, const sc_context_param_t *parm)
|
|||
}
|
||||
del_drvs(&opts, 0);
|
||||
del_drvs(&opts, 1);
|
||||
if (ctx->reader_count == 0) {
|
||||
sc_release_context(ctx);
|
||||
return SC_ERROR_NO_READERS_FOUND;
|
||||
}
|
||||
sc_ctx_detect_readers(ctx);
|
||||
*ctx_out = ctx;
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -51,9 +51,11 @@ typedef unsigned __int8 uint8_t;
|
|||
#define SCARD_SCOPE_USER 0x0000 /**< Scope in user space */
|
||||
|
||||
#define SCARD_S_SUCCESS 0x00000000 /**< No error was encountered. */
|
||||
#define SCARD_E_INVALID_HANDLE 0x80100003 /**< The supplied handle was invalid. */
|
||||
#define SCARD_E_TIMEOUT 0x8010000A /**< The user-specified timeout value has expired. */
|
||||
#define SCARD_E_SHARING_VIOLATION 0x8010000B /**< The smart card cannot be accessed because of other connections outstanding. */
|
||||
#define SCARD_E_NOT_TRANSACTED 0x80100016 /**< An attempt was made to end a non-existent transaction. */
|
||||
#define SCARD_E_READER_UNAVAILABLE 0x80100017 /**< The specified reader is not currently available for use. */
|
||||
#define SCARD_E_NO_READERS_AVAILABLE 0x8010002E /**< Cannot find a smart card reader. */
|
||||
#define SCARD_W_UNRESPONSIVE_CARD 0x80100066 /**< The smart card is not responding to a reset. */
|
||||
#define SCARD_W_UNPOWERED_CARD 0x80100067 /**< Power has been removed from the smart card, so that further communication is not possible. */
|
||||
|
|
|
@ -37,6 +37,7 @@ sc_connect_card
|
|||
sc_context_create
|
||||
sc_copy_asn1_entry
|
||||
sc_create_file
|
||||
sc_ctx_detect_readers
|
||||
sc_ctx_get_reader
|
||||
sc_ctx_get_reader_count
|
||||
sc_ctx_suppress_errors_off
|
||||
|
|
|
@ -373,6 +373,9 @@ struct sc_reader_operations {
|
|||
/* Called when the driver is being unloaded. finish() has to
|
||||
* deallocate the private data and any resources. */
|
||||
int (*finish)(struct sc_context *ctx, void *priv_data);
|
||||
/* Called when library wish to detect new readers
|
||||
* should add only new readers. */
|
||||
int (*detect_readers)(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. */
|
||||
|
@ -726,6 +729,13 @@ int sc_context_create(sc_context_t **ctx, const sc_context_param_t *parm);
|
|||
*/
|
||||
int sc_release_context(sc_context_t *ctx);
|
||||
|
||||
/**
|
||||
* Detect new readers available on system.
|
||||
* @param ctx OpenSC context
|
||||
* @return SC_SUCCESS on success and an error code otherwise.
|
||||
*/
|
||||
int sc_ctx_detect_readers(sc_context_t *ctx);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the specified sc_reader_t object
|
||||
* @param ctx OpenSC context
|
||||
|
|
|
@ -611,6 +611,7 @@ struct sc_reader_driver * sc_get_ctapi_driver(void)
|
|||
{
|
||||
ctapi_ops.init = ctapi_init;
|
||||
ctapi_ops.finish = ctapi_finish;
|
||||
ctapi_ops.detect_readers = NULL;
|
||||
ctapi_ops.transmit = ctapi_transmit;
|
||||
ctapi_ops.detect_card_presence = ctapi_detect_card_presence;
|
||||
ctapi_ops.lock = ctapi_lock;
|
||||
|
|
|
@ -479,6 +479,7 @@ struct sc_reader_driver *sc_get_openct_driver(void)
|
|||
{
|
||||
openct_ops.init = openct_reader_init;
|
||||
openct_ops.finish = openct_reader_finish;
|
||||
openct_ops.detect_readers = NULL;
|
||||
openct_ops.release = openct_reader_release;
|
||||
openct_ops.detect_card_presence = openct_reader_detect_card_presence;
|
||||
openct_ops.connect = openct_reader_connect;
|
||||
|
|
|
@ -644,26 +644,32 @@ static int pcsc_lock(sc_reader_t *reader, sc_slot_info_t *slot)
|
|||
|
||||
rv = priv->gpriv->SCardBeginTransaction(pslot->pcsc_card);
|
||||
|
||||
if ((unsigned int)rv == SCARD_W_RESET_CARD) {
|
||||
/* try to reconnect if the card was reset by some other application */
|
||||
rv = pcsc_reconnect(reader, slot, 0);
|
||||
if (rv != SCARD_S_SUCCESS) {
|
||||
PCSC_ERROR(reader->ctx, "SCardReconnect failed", rv);
|
||||
switch (rv) {
|
||||
case SCARD_E_INVALID_HANDLE:
|
||||
case SCARD_E_READER_UNAVAILABLE:
|
||||
rv = pcsc_connect(reader, slot);
|
||||
if (rv != SCARD_S_SUCCESS) {
|
||||
PCSC_ERROR(reader->ctx, "SCardConnect failed", rv);
|
||||
return pcsc_ret_to_error(rv);
|
||||
}
|
||||
/* return failure so that upper layers will be notified and try to lock again */
|
||||
return SC_ERROR_READER_REATTACHED;
|
||||
case SCARD_W_RESET_CARD:
|
||||
/* try to reconnect if the card was reset by some other application */
|
||||
rv = pcsc_reconnect(reader, slot, 0);
|
||||
if (rv != SCARD_S_SUCCESS) {
|
||||
PCSC_ERROR(reader->ctx, "SCardReconnect failed", rv);
|
||||
return pcsc_ret_to_error(rv);
|
||||
}
|
||||
/* 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;
|
||||
return SC_SUCCESS;
|
||||
default:
|
||||
PCSC_ERROR(reader->ctx, "SCardBeginTransaction failed", rv);
|
||||
return pcsc_ret_to_error(rv);
|
||||
}
|
||||
/* Now try to begin a new transaction after we reconnected and we fail if
|
||||
some other program was faster to lock the reader */
|
||||
rv = priv->gpriv->SCardBeginTransaction(pslot->pcsc_card);
|
||||
}
|
||||
|
||||
if (rv != SCARD_S_SUCCESS) {
|
||||
PCSC_ERROR(reader->ctx, "SCardBeginTransaction failed", rv);
|
||||
return pcsc_ret_to_error(rv);
|
||||
}
|
||||
|
||||
pslot->locked = 1;
|
||||
|
||||
return SC_SUCCESS;
|
||||
}
|
||||
|
||||
static int pcsc_unlock(sc_reader_t *reader, sc_slot_info_t *slot)
|
||||
|
@ -731,10 +737,6 @@ static struct sc_reader_driver pcsc_drv = {
|
|||
static int pcsc_init(sc_context_t *ctx, void **reader_data)
|
||||
{
|
||||
LONG rv;
|
||||
DWORD reader_buf_size;
|
||||
char *reader_buf = NULL, *p;
|
||||
const char *mszGroups = NULL;
|
||||
int r;
|
||||
struct pcsc_global_private_data *gpriv;
|
||||
scconf_block *conf_block = NULL;
|
||||
int ret = SC_ERROR_INTERNAL;
|
||||
|
@ -753,6 +755,7 @@ static int pcsc_init(sc_context_t *ctx, void **reader_data)
|
|||
gpriv->transaction_reset = 0;
|
||||
gpriv->enable_pinpad = 0;
|
||||
gpriv->provider_library = DEFAULT_PCSC_PROVIDER;
|
||||
gpriv->pcsc_ctx = -1;
|
||||
|
||||
conf_block = sc_get_conf_block(ctx, "reader_driver", "pcsc", 1);
|
||||
if (conf_block) {
|
||||
|
@ -818,72 +821,6 @@ static int pcsc_init(sc_context_t *ctx, void **reader_data)
|
|||
goto out;
|
||||
}
|
||||
|
||||
rv = gpriv->SCardEstablishContext(SCARD_SCOPE_USER,
|
||||
NULL, NULL, &gpriv->pcsc_ctx);
|
||||
if (rv != SCARD_S_SUCCESS) {
|
||||
ret = pcsc_ret_to_error(rv);
|
||||
goto out;
|
||||
}
|
||||
rv = gpriv->SCardListReaders(gpriv->pcsc_ctx, NULL, NULL,
|
||||
(LPDWORD) &reader_buf_size);
|
||||
if (rv != SCARD_S_SUCCESS || reader_buf_size < 2) {
|
||||
ret = pcsc_ret_to_error(rv); /* No readers configured */
|
||||
goto out;
|
||||
}
|
||||
|
||||
reader_buf = (char *) malloc(sizeof(char) * reader_buf_size);
|
||||
if (!reader_buf) {
|
||||
ret = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
rv = gpriv->SCardListReaders(gpriv->pcsc_ctx, mszGroups, reader_buf,
|
||||
(LPDWORD) &reader_buf_size);
|
||||
if (rv != SCARD_S_SUCCESS) {
|
||||
ret = pcsc_ret_to_error(rv);
|
||||
goto out;
|
||||
}
|
||||
p = reader_buf;
|
||||
do {
|
||||
sc_reader_t *reader = (sc_reader_t *) calloc(1, sizeof(sc_reader_t));
|
||||
struct pcsc_private_data *priv = (struct pcsc_private_data *) malloc(sizeof(struct pcsc_private_data));
|
||||
struct pcsc_slot_data *pslot = (struct pcsc_slot_data *) malloc(sizeof(struct pcsc_slot_data));
|
||||
sc_slot_info_t *slot;
|
||||
|
||||
if (reader == NULL || priv == NULL || pslot == NULL) {
|
||||
if (reader)
|
||||
free(reader);
|
||||
if (priv)
|
||||
free(priv);
|
||||
if (pslot)
|
||||
free(pslot);
|
||||
break;
|
||||
}
|
||||
|
||||
reader->drv_data = priv;
|
||||
reader->ops = &pcsc_ops;
|
||||
reader->driver = &pcsc_drv;
|
||||
reader->slot_count = 1;
|
||||
reader->name = strdup(p);
|
||||
priv->gpriv = gpriv;
|
||||
priv->reader_name = strdup(p);
|
||||
r = _sc_add_reader(ctx, reader);
|
||||
if (r) {
|
||||
free(priv->reader_name);
|
||||
free(priv);
|
||||
free(reader->name);
|
||||
free(reader);
|
||||
free(pslot);
|
||||
break;
|
||||
}
|
||||
slot = &reader->slot[0];
|
||||
memset(slot, 0, sizeof(*slot));
|
||||
slot->drv_data = pslot;
|
||||
memset(pslot, 0, sizeof(*pslot));
|
||||
refresh_slot_attributes(reader, slot);
|
||||
|
||||
while (*p++ != 0);
|
||||
} while (p < (reader_buf + reader_buf_size - 1));
|
||||
|
||||
*reader_data = gpriv;
|
||||
gpriv = NULL;
|
||||
ret = SC_SUCCESS;
|
||||
|
@ -892,8 +829,6 @@ out:
|
|||
if (ret != SC_SUCCESS) {
|
||||
if (gpriv->pcsc_ctx != 0)
|
||||
gpriv->SCardReleaseContext(gpriv->pcsc_ctx);
|
||||
if (reader_buf != NULL)
|
||||
free(reader_buf);
|
||||
if (gpriv->dlhandle != NULL)
|
||||
lt_dlclose(gpriv->dlhandle);
|
||||
if (gpriv != NULL)
|
||||
|
@ -916,6 +851,141 @@ static int pcsc_finish(sc_context_t *ctx, void *prv_data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int pcsc_detect_readers(sc_context_t *ctx, void *prv_data)
|
||||
{
|
||||
struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *) prv_data;
|
||||
LONG rv;
|
||||
DWORD reader_buf_size;
|
||||
char *reader_buf = NULL, *p;
|
||||
const char *mszGroups = NULL;
|
||||
int ret = SC_ERROR_INTERNAL;
|
||||
int again;
|
||||
|
||||
if (!prv_data) {
|
||||
ret = SC_ERROR_NO_READERS_FOUND;
|
||||
goto out;
|
||||
}
|
||||
|
||||
do {
|
||||
rv = gpriv->SCardListReaders(gpriv->pcsc_ctx, NULL, NULL,
|
||||
(LPDWORD) &reader_buf_size);
|
||||
if (rv != SCARD_S_SUCCESS) {
|
||||
if (rv != SCARD_E_INVALID_HANDLE) {
|
||||
ret = pcsc_ret_to_error(rv);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rv = gpriv->SCardEstablishContext(SCARD_SCOPE_USER,
|
||||
NULL, NULL, &gpriv->pcsc_ctx);
|
||||
if (rv != SCARD_S_SUCCESS) {
|
||||
ret = pcsc_ret_to_error(rv);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rv = SCARD_E_INVALID_HANDLE;
|
||||
}
|
||||
} while (rv != SCARD_S_SUCCESS);
|
||||
|
||||
reader_buf = (char *) malloc(sizeof(char) * reader_buf_size);
|
||||
if (!reader_buf) {
|
||||
ret = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
rv = gpriv->SCardListReaders(gpriv->pcsc_ctx, mszGroups, reader_buf,
|
||||
(LPDWORD) &reader_buf_size);
|
||||
if (rv != SCARD_S_SUCCESS) {
|
||||
ret = pcsc_ret_to_error(rv);
|
||||
goto out;
|
||||
}
|
||||
for (p = reader_buf; *p != '\x0'; p += strlen (p) + 1) {
|
||||
sc_reader_t *reader = NULL;
|
||||
struct pcsc_private_data *priv = NULL;
|
||||
struct pcsc_slot_data *pslot = NULL;
|
||||
sc_slot_info_t *slot = NULL;
|
||||
int i;
|
||||
int found = 0;
|
||||
|
||||
for (i=0;i < sc_ctx_get_reader_count (ctx) && !found;i++) {
|
||||
sc_reader_t *reader = sc_ctx_get_reader (ctx, i);
|
||||
if (reader == NULL) {
|
||||
ret = SC_ERROR_INTERNAL;
|
||||
goto err1;
|
||||
}
|
||||
if (reader->ops == &pcsc_ops && !strcmp (reader->name, p)) {
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reader already available, skip */
|
||||
if (found) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((reader = (sc_reader_t *) calloc(1, sizeof(sc_reader_t))) == NULL) {
|
||||
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) {
|
||||
ret = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
reader->drv_data = priv;
|
||||
reader->ops = &pcsc_ops;
|
||||
reader->driver = &pcsc_drv;
|
||||
reader->slot_count = 1;
|
||||
if ((reader->name = strdup(p)) == NULL) {
|
||||
ret = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto err1;
|
||||
}
|
||||
priv->gpriv = gpriv;
|
||||
if ((priv->reader_name = strdup(p)) == NULL) {
|
||||
ret = SC_ERROR_OUT_OF_MEMORY;
|
||||
goto err1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
refresh_slot_attributes(reader, slot);
|
||||
|
||||
continue;
|
||||
|
||||
err1:
|
||||
if (priv != NULL) {
|
||||
if (priv->reader_name)
|
||||
free(priv->reader_name);
|
||||
free(priv);
|
||||
}
|
||||
if (reader != NULL) {
|
||||
if (reader->name)
|
||||
free(reader->name);
|
||||
free(reader);
|
||||
}
|
||||
if (slot != NULL)
|
||||
free(pslot);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = SC_SUCCESS;
|
||||
|
||||
out:
|
||||
|
||||
if (reader_buf != NULL)
|
||||
free (reader_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
pcsc_pin_cmd(sc_reader_t *reader, sc_slot_info_t * slot, struct sc_pin_cmd_data *data)
|
||||
{
|
||||
|
@ -931,6 +1001,7 @@ struct sc_reader_driver * sc_get_pcsc_driver(void)
|
|||
{
|
||||
pcsc_ops.init = pcsc_init;
|
||||
pcsc_ops.finish = pcsc_finish;
|
||||
pcsc_ops.detect_readers = pcsc_detect_readers;
|
||||
pcsc_ops.transmit = pcsc_transmit;
|
||||
pcsc_ops.detect_card_presence = pcsc_detect_card_presence;
|
||||
pcsc_ops.lock = pcsc_lock;
|
||||
|
|
|
@ -347,6 +347,9 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token prese
|
|||
}
|
||||
|
||||
sc_debug(context, "Getting slot listing\n");
|
||||
if (pSlotList == NULL_PTR) {
|
||||
sc_ctx_detect_readers(context);
|
||||
}
|
||||
card_detect_all();
|
||||
|
||||
numMatches = 0;
|
||||
|
|
|
@ -86,7 +86,7 @@ CK_RV card_detect(int reader)
|
|||
sc_reader_t *rdr = sc_ctx_get_reader(context, (unsigned int)reader);
|
||||
|
||||
if (rdr == NULL)
|
||||
return CKR_GENERAL_ERROR;
|
||||
return CKR_TOKEN_NOT_PRESENT;
|
||||
slot = virtual_slots + card->first_slot + i;
|
||||
strcpy_bp(slot->slot_info.slotDescription, rdr->name, 64);
|
||||
slot->reader = reader;
|
||||
|
|
|
@ -246,7 +246,7 @@ static int list_readers(void)
|
|||
unsigned int i, rcount = sc_ctx_get_reader_count(ctx);
|
||||
|
||||
if (rcount == 0) {
|
||||
printf("No readers configured!\n");
|
||||
printf("No readers found.\n");
|
||||
return 0;
|
||||
}
|
||||
printf("Readers known about:\n");
|
||||
|
|
Loading…
Reference in New Issue