diff --git a/docs/opensc.xml b/docs/opensc.xml
index 8837351b..96028bb7 100644
--- a/docs/opensc.xml
+++ b/docs/opensc.xml
@@ -52,6 +52,10 @@
Nils Larsch larsch@trustcenter.de
+
+ Juan Antonio Martinez jonsito@teleline.es
+
+
Ville Skyttä
diff --git a/etc/opensc.conf.example b/etc/opensc.conf.example
index 614e27b5..720c10dc 100644
--- a/etc/opensc.conf.example
+++ b/etc/opensc.conf.example
@@ -35,6 +35,8 @@ app default {
# internal) driver is supplied, a separate configuration
# configuration block has to be written for the driver.
# Default: internal
+ # NOTE: if "internal" keyword is used, must be the
+ # last entry in reader_drivers list
#
# reader_drivers = openct, pcsc, ctapi;
@@ -90,25 +92,17 @@ app default {
# internal) driver is supplied, a separate configuration
# configuration block has to be written for the driver.
# Default: internal
+ # NOTE: When "internal" keyword is used, must be last entry
#
- # card_drivers = internal, customcos;
+ # card_drivers = customcos, internal;
+
+ # Card driver configuration blocks.
- # Card driver configuration blocks. For card drivers loaded
- # from an external shared library/DLL, you need to specify
- # the path name of the module, and the name of the constructor
- # function.
- # WARNING: this is not implemented yet.
- #
# For all drivers, you can specify ATRs of cards that
# should be handled by this driver (in addition to the
- # list of compiled-in ATRs). To do so, specify
+ # list of compiled-in ATRs).
#
- # card_driver foo {
- # atr = 00:11:22:33:44;
- # atr = 55:66:77:88:99:aa:bb;
- # }
- #
- # The card driver names are
+ # The supported internal card driver names are
# flex Cryptoflex/Multiflex
# setcos Setec
# etoken Aladdin eToken and other CardOS based cards
@@ -119,17 +113,21 @@ app default {
# tcos TCOS 2.0
# emv EMV compatible cards
- # card_driver customcos {
- # The location of the driver library
- #
- # module = /usr/lib/opensc/drivers/card_customcos.so
- # }
-
- # GPK card driver
+ # GPK card driver additional ATR entry:
card_driver gpk {
# atr = 00:11:22;
}
+ # For card drivers loaded from an external shared library/DLL,
+ # you need to specify the path name of the module
+ #
+ # card_driver customcos {
+ # The location of the driver library
+ # module = /usr/lib/opensc/drivers/card_customcos.so;
+ # atr = 00:11:22:33:44;
+ # atr = 55:66:77:88:99:aa:bb;
+ # }
+
# Force using specific card driver
#
# If this option is present, OpenSC will use the supplied
diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c
index 5791d814..cae04020 100644
--- a/src/libopensc/ctx.c
+++ b/src/libopensc/ctx.c
@@ -27,6 +27,8 @@
#include
#include
+#include
+
/* Default value for apdu_masquerade option */
#ifndef _WIN32
# define DEF_APDU_MASQ SC_APDU_MASQUERADE_NONE
@@ -307,6 +309,87 @@ static void load_reader_driver_options(sc_context_t *ctx,
}
}
+/**
+ * find library module for provided driver in configuration file
+ * if not found assume library name equals to module name
+ */
+static const char *find_library(struct sc_context *ctx, const char *name, int type)
+{
+ int i;
+ const char *libname = NULL;
+ scconf_block **blocks, *blk;
+
+ for (i = 0; ctx->conf_blocks[i]; i++) {
+ blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i],
+ (type==0) ? "reader_driver" : "card_driver", name);
+ blk = blocks[0];
+ free(blocks);
+ if (blk == NULL)
+ continue;
+ libname = scconf_get_str(blk, "module", name);
+#ifdef _WIN32
+ if (libname && libname[0] != '\\' ) {
+#else
+ if (libname && libname[0] != '/' ) {
+#endif
+ sc_debug(ctx, "warning: relative path to driver '%s' used\n",
+ libname);
+ }
+ break;
+ }
+
+ return libname;
+}
+
+/**
+ * load card/reader driver modules
+ * Every module should contain a function " void * sc_module_init(char *) "
+ * that returns a pointer to the function _sc_get_xxxx_driver()
+ * used to initialize static modules
+ * Also, an exported "char *sc_module_version" variable should exist in module
+ * type=1 -> carddriver Type=0 -> readerdriver
+ */
+static void *load_dynamic_driver(struct sc_context *ctx, void **dll,
+ const char *name, int type)
+{
+ const char *version, *libname;
+ void *handler;
+ void *(*modinit)(const char *) = NULL;
+ const char *(*modversion)(void) = NULL;
+
+ if (name == NULL) { /* should not occurr, but... */
+ sc_error(ctx,"No module specified\n",name);
+ return NULL;
+ }
+ libname = find_library(ctx, name, type);
+ if (libname == NULL)
+ return NULL;
+ handler = scdl_open(libname);
+ if (handler == NULL) {
+ sc_error(ctx, "Module %s: cannot load %s library\n",name,libname);
+ return NULL;
+ }
+ /* verify correctness of module */
+ modinit = scdl_get_address(handler, "sc_module_init");
+ modversion = scdl_get_address(handler, "sc_driver_version");
+ if (modinit == NULL || modversion == NULL) {
+ sc_error(ctx, "dynamic library '%s' is not a OpenSC module\n",libname);
+ scdl_close(handler);
+ return NULL;
+ }
+ /* verify module version */
+ version = modversion();
+ if (version == NULL || strncmp(version, "0.9.", strlen("0.9.")) > 0) {
+ sc_error(ctx,"dynamic library '%s': invalid module version\n",libname);
+ scdl_close(handler);
+ return NULL;
+ }
+ *dll = handler;
+ sc_debug(ctx, "successfully loaded %s driver '%s'\n",
+ type ? "card" : "reader", name);
+ return modinit(name);
+}
+
static int load_reader_drivers(struct sc_context *ctx,
struct _sc_ctx_options *opts)
{
@@ -319,7 +402,8 @@ static int load_reader_drivers(struct sc_context *ctx,
for (i = 0; i < opts->rcount; i++) {
struct sc_reader_driver *driver;
struct sc_reader_driver * (*func)(void) = NULL;
- int j;
+ int j;
+ void *dll = NULL;
ent = &opts->rdrv[i];
for (j = 0; internal_reader_drivers[j].name != NULL; j++)
@@ -327,14 +411,16 @@ static int load_reader_drivers(struct sc_context *ctx,
func = (struct sc_reader_driver * (*)(void)) internal_reader_drivers[j].func;
break;
}
+ /* if not initialized assume external module */
+ if (func == NULL)
+ func = load_dynamic_driver(ctx, &dll, ent->name, 0);
+ /* if still null, assume driver not found */
if (func == NULL) {
- /* External driver */
- /* FIXME: Load shared library */
- sc_error(ctx, "Unable to load '%s'. External drivers not supported yet.\n",
- ent->name);
+ sc_error(ctx, "Unable to load '%s'.\n", ent->name);
continue;
}
driver = func();
+ driver->dll = dll;
load_reader_driver_options(ctx, driver);
driver->ops->init(ctx, &ctx->reader_drv_data[i]);
@@ -394,7 +480,8 @@ static int load_card_drivers(struct sc_context *ctx,
for (i = 0; i < opts->ccount; i++) {
struct sc_card_driver * (* func)(void) = NULL;
- int j;
+ void *dll = NULL;
+ int j;
ent = &opts->cdrv[i];
for (j = 0; internal_card_drivers[j].name != NULL; j++)
@@ -402,14 +489,17 @@ static int load_card_drivers(struct sc_context *ctx,
func = (struct sc_card_driver * (*)(void)) internal_card_drivers[j].func;
break;
}
+ /* if not initialized assume external module */
+ if (func == NULL)
+ func = load_dynamic_driver(ctx, &dll, ent->name, 1);
+ /* if still null, assume driver not found */
if (func == NULL) {
- /* External driver */
- /* FIXME: Load shared library */
- sc_error(ctx, "Unable to load '%s'. External drivers not supported yet.\n",
- ent->name);
+ sc_error(ctx, "Unable to load '%s'.\n", ent->name);
continue;
}
+
ctx->card_drivers[drv_count] = func();
+ ctx->card_drivers[drv_count]->dll = dll;
load_card_driver_options(ctx, ctx->card_drivers[drv_count]);
drv_count++;
@@ -523,6 +613,13 @@ int sc_release_context(struct sc_context *ctx)
if (drv->ops->finish != NULL)
drv->ops->finish(ctx, ctx->reader_drv_data[i]);
+ if (drv->dll)
+ scdl_close(drv->dll);
+ }
+ for (i = 0; ctx->card_drivers[i]; i++) {
+ struct sc_card_driver *drv = ctx->card_drivers[i];
+ if (drv->dll)
+ scdl_close(drv->dll);
}
ctx->debug_file = ctx->error_file = NULL;
if (ctx->preferred_language)
diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h
index 71119d15..f5b70027 100644
--- a/src/libopensc/opensc.h
+++ b/src/libopensc/opensc.h
@@ -261,6 +261,7 @@ struct sc_reader_driver {
size_t max_send_size, max_recv_size;
int apdu_masquerade;
unsigned int forced_protocol;
+ void *dll;
};
#define SC_APDU_MASQUERADE_NONE 0x00
#define SC_APDU_MASQUERADE_4AS3 0x01
@@ -600,6 +601,7 @@ struct sc_card_driver {
struct sc_card_operations *ops;
struct sc_atr_table *atr_map;
unsigned int natrs;
+ void *dll;
};
struct sc_context {
@@ -865,7 +867,7 @@ struct sc_card_error {
extern const char *sc_get_version(void);
-#define IMPLEMENT_DRIVER_VERSION(a) \
+#define SC_IMPLEMENT_DRIVER_VERSION(a) \
static const char *drv_version = (a); \
const char *sc_driver_version()\
{ \