2002-03-24 22:47:35 +00:00
|
|
|
/*
|
|
|
|
* ctx.c: Context related functions
|
|
|
|
*
|
2006-12-19 21:32:31 +00:00
|
|
|
* Copyright (C) 2002 Juha Yrjölä <juha.yrjola@iki.fi>
|
2002-03-24 22:47:35 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
2010-03-04 08:14:36 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2002-03-24 22:47:35 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
2003-01-09 09:18:02 +00:00
|
|
|
#include <errno.h>
|
2003-08-29 16:26:59 +00:00
|
|
|
#include <sys/stat.h>
|
2003-01-09 09:18:02 +00:00
|
|
|
#include <limits.h>
|
2005-09-01 14:01:58 +00:00
|
|
|
#include <ltdl.h>
|
2004-10-18 08:24:12 +00:00
|
|
|
|
2005-03-23 23:10:50 +00:00
|
|
|
#ifdef _WIN32
|
2010-03-09 13:39:29 +00:00
|
|
|
#include <windows.h>
|
2005-03-23 23:10:50 +00:00
|
|
|
#include <winreg.h>
|
|
|
|
#endif
|
|
|
|
|
2010-03-09 13:39:29 +00:00
|
|
|
#include "internal.h"
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int _sc_add_reader(sc_context_t *ctx, sc_reader_t *reader)
|
2002-03-24 22:47:35 +00:00
|
|
|
{
|
|
|
|
assert(reader != NULL);
|
|
|
|
reader->ctx = ctx;
|
2010-09-11 13:01:06 +00:00
|
|
|
list_append(&ctx->readers, reader);
|
2005-02-20 08:26:27 +00:00
|
|
|
return SC_SUCCESS;
|
2002-03-24 22:47:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct _sc_driver_entry {
|
2010-03-28 21:02:56 +00:00
|
|
|
const char *name;
|
2005-09-11 20:40:58 +00:00
|
|
|
void *(*func)(void);
|
2002-03-24 22:47:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct _sc_driver_entry internal_card_drivers[] = {
|
2006-01-23 21:44:37 +00:00
|
|
|
{ "cardos", (void *(*)(void)) sc_get_cardos_driver },
|
2005-09-15 05:41:29 +00:00
|
|
|
{ "flex", (void *(*)(void)) sc_get_cryptoflex_driver },
|
|
|
|
{ "cyberflex", (void *(*)(void)) sc_get_cyberflex_driver },
|
2008-03-06 16:06:59 +00:00
|
|
|
#ifdef ENABLE_OPENSSL
|
2005-09-15 05:41:29 +00:00
|
|
|
{ "gpk", (void *(*)(void)) sc_get_gpk_driver },
|
2002-03-24 22:47:35 +00:00
|
|
|
#endif
|
2007-11-12 10:18:54 +00:00
|
|
|
{ "gemsafeV1", (void *(*)(void)) sc_get_gemsafeV1_driver },
|
2005-09-15 05:41:29 +00:00
|
|
|
{ "miocos", (void *(*)(void)) sc_get_miocos_driver },
|
|
|
|
{ "mcrd", (void *(*)(void)) sc_get_mcrd_driver },
|
2007-07-03 20:44:34 +00:00
|
|
|
{ "asepcos", (void *(*)(void)) sc_get_asepcos_driver },
|
2005-09-15 05:41:29 +00:00
|
|
|
{ "starcos", (void *(*)(void)) sc_get_starcos_driver },
|
|
|
|
{ "tcos", (void *(*)(void)) sc_get_tcos_driver },
|
|
|
|
{ "opengpg", (void *(*)(void)) sc_get_openpgp_driver },
|
|
|
|
{ "jcop", (void *(*)(void)) sc_get_jcop_driver },
|
2008-03-06 16:06:59 +00:00
|
|
|
#ifdef ENABLE_OPENSSL
|
2005-09-15 05:41:29 +00:00
|
|
|
{ "oberthur", (void *(*)(void)) sc_get_oberthur_driver },
|
2004-06-16 20:59:59 +00:00
|
|
|
#endif
|
2005-09-15 05:41:29 +00:00
|
|
|
{ "belpic", (void *(*)(void)) sc_get_belpic_driver },
|
2009-10-03 14:41:14 +00:00
|
|
|
{ "ias", (void *(*)(void)) sc_get_ias_driver },
|
2005-10-24 21:58:35 +00:00
|
|
|
{ "incrypto34", (void *(*)(void)) sc_get_incrypto34_driver },
|
2007-03-13 13:38:24 +00:00
|
|
|
{ "acos5", (void *(*)(void)) sc_get_acos5_driver },
|
2007-07-17 20:01:55 +00:00
|
|
|
{ "akis", (void *(*)(void)) sc_get_akis_driver },
|
2008-08-20 05:41:20 +00:00
|
|
|
#ifdef ENABLE_OPENSSL
|
|
|
|
{ "entersafe",(void *(*)(void)) sc_get_entersafe_driver },
|
|
|
|
#endif
|
2010-09-11 13:01:06 +00:00
|
|
|
{ "rutoken", (void *(*)(void)) sc_get_rutoken_driver },
|
2009-06-24 15:26:37 +00:00
|
|
|
{ "rutoken_ecp",(void *(*)(void)) sc_get_rtecp_driver },
|
2009-09-12 11:46:00 +00:00
|
|
|
{ "westcos", (void *(*)(void)) sc_get_westcos_driver },
|
2010-08-16 08:59:09 +00:00
|
|
|
{ "myeid", (void *(*)(void)) sc_get_myeid_driver },
|
2010-02-11 14:15:13 +00:00
|
|
|
|
2010-09-11 13:01:06 +00:00
|
|
|
/* Here should be placed drivers that need some APDU transactions to
|
2010-02-11 14:15:13 +00:00
|
|
|
* recognise its cards. */
|
|
|
|
{ "setcos", (void *(*)(void)) sc_get_setcos_driver },
|
|
|
|
{ "muscle", (void *(*)(void)) sc_get_muscle_driver },
|
|
|
|
{ "atrust-acos",(void *(*)(void)) sc_get_atrust_acos_driver },
|
|
|
|
{ "PIV-II", (void *(*)(void)) sc_get_piv_driver },
|
2010-08-16 08:59:09 +00:00
|
|
|
{ "itacns", (void *(*)(void)) sc_get_itacns_driver },
|
2010-02-11 14:47:34 +00:00
|
|
|
/* javacard without supported applet - last before default */
|
|
|
|
{ "javacard", (void *(*)(void)) sc_get_javacard_driver },
|
2002-03-24 22:47:35 +00:00
|
|
|
/* The default driver should be last, as it handles all the
|
|
|
|
* unrecognized cards. */
|
2005-09-15 05:41:29 +00:00
|
|
|
{ "default", (void *(*)(void)) sc_get_default_driver },
|
2005-02-20 08:26:27 +00:00
|
|
|
{ NULL, NULL }
|
2002-03-24 22:47:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _sc_ctx_options {
|
2005-02-20 08:26:27 +00:00
|
|
|
struct _sc_driver_entry cdrv[SC_MAX_CARD_DRIVERS];
|
2002-03-24 22:47:35 +00:00
|
|
|
int ccount;
|
2002-04-19 20:07:56 +00:00
|
|
|
char *forced_card_driver;
|
2002-03-24 22:47:35 +00:00
|
|
|
};
|
|
|
|
|
2010-01-24 15:25:08 +00:00
|
|
|
|
|
|
|
/* Simclist helper to locate readers by name */
|
|
|
|
static int reader_list_seeker(const void *el, const void *key) {
|
2010-09-11 13:01:06 +00:00
|
|
|
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;
|
2010-01-24 15:25:08 +00:00
|
|
|
}
|
2010-09-11 13:01:06 +00:00
|
|
|
|
2010-09-11 13:00:47 +00:00
|
|
|
static void del_drvs(struct _sc_ctx_options *opts)
|
2002-03-24 22:47:35 +00:00
|
|
|
{
|
|
|
|
struct _sc_driver_entry *lst;
|
|
|
|
int *cp, i;
|
2005-02-06 19:40:40 +00:00
|
|
|
|
2010-09-11 13:00:47 +00:00
|
|
|
lst = opts->cdrv;
|
|
|
|
cp = &opts->ccount;
|
|
|
|
|
2002-03-24 22:47:35 +00:00
|
|
|
for (i = 0; i < *cp; i++) {
|
2010-03-28 21:02:56 +00:00
|
|
|
free((void *)lst[i].name);
|
2002-03-24 22:47:35 +00:00
|
|
|
}
|
|
|
|
*cp = 0;
|
|
|
|
}
|
|
|
|
|
2010-09-11 13:00:47 +00:00
|
|
|
static void add_drv(struct _sc_ctx_options *opts, const char *name)
|
2002-03-24 22:47:35 +00:00
|
|
|
{
|
|
|
|
struct _sc_driver_entry *lst;
|
2005-02-20 08:26:27 +00:00
|
|
|
int *cp, max, i;
|
2010-09-11 13:00:47 +00:00
|
|
|
|
|
|
|
lst = opts->cdrv;
|
|
|
|
cp = &opts->ccount;
|
|
|
|
max = SC_MAX_CARD_DRIVERS;
|
2005-02-20 08:26:27 +00:00
|
|
|
if (*cp == max) /* No space for more drivers... */
|
2002-03-24 22:47:35 +00:00
|
|
|
return;
|
|
|
|
for (i = 0; i < *cp; i++)
|
|
|
|
if (strcmp(name, lst[i].name) == 0)
|
|
|
|
return;
|
|
|
|
lst[*cp].name = strdup(name);
|
|
|
|
|
|
|
|
*cp = *cp + 1;
|
|
|
|
}
|
|
|
|
|
2010-09-11 13:00:47 +00:00
|
|
|
static void add_internal_drvs(struct _sc_ctx_options *opts)
|
2002-03-24 22:47:35 +00:00
|
|
|
{
|
|
|
|
const struct _sc_driver_entry *lst;
|
|
|
|
int i;
|
2005-02-06 19:40:40 +00:00
|
|
|
|
2010-09-11 13:00:47 +00:00
|
|
|
lst = internal_card_drivers;
|
2002-03-24 22:47:35 +00:00
|
|
|
i = 0;
|
|
|
|
while (lst[i].name != NULL) {
|
2010-09-11 13:00:47 +00:00
|
|
|
add_drv(opts, lst[i].name);
|
2002-03-24 22:47:35 +00:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static void set_defaults(sc_context_t *ctx, struct _sc_ctx_options *opts)
|
2002-03-28 14:13:36 +00:00
|
|
|
{
|
|
|
|
ctx->debug = 0;
|
2009-09-15 12:29:17 +00:00
|
|
|
if (ctx->debug_file && (ctx->debug_file != stderr && ctx->debug_file != stdout))
|
2002-03-28 14:13:36 +00:00
|
|
|
fclose(ctx->debug_file);
|
2009-09-14 08:46:59 +00:00
|
|
|
ctx->debug_file = stderr;
|
2010-06-16 14:12:27 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
/* Override the default debug log for OpenSC.tokend to be different from PKCS#11.
|
|
|
|
* TODO: Could be moved to OpenSC.tokend */
|
|
|
|
if (!strcmp(ctx->app_name, "tokend"))
|
|
|
|
ctx->debug_file = fopen("/tmp/opensc-tokend.log", "a");
|
|
|
|
#endif
|
2002-03-28 14:13:36 +00:00
|
|
|
ctx->forced_driver = NULL;
|
2010-09-11 13:00:47 +00:00
|
|
|
add_internal_drvs(opts);
|
2002-03-28 14:13:36 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int load_parameters(sc_context_t *ctx, scconf_block *block,
|
2002-03-24 22:47:35 +00:00
|
|
|
struct _sc_ctx_options *opts)
|
|
|
|
{
|
2002-03-26 11:38:40 +00:00
|
|
|
int err = 0;
|
|
|
|
const scconf_list *list;
|
2005-02-20 08:26:27 +00:00
|
|
|
const char *val, *s_internal = "internal";
|
2006-10-30 07:37:44 +00:00
|
|
|
const char *debug = NULL;
|
2005-02-06 19:40:40 +00:00
|
|
|
|
2002-03-26 11:38:40 +00:00
|
|
|
ctx->debug = scconf_get_int(block, "debug", ctx->debug);
|
2006-10-30 07:37:44 +00:00
|
|
|
debug = getenv("OPENSC_DEBUG");
|
|
|
|
if (debug)
|
|
|
|
ctx->debug = atoi(debug);
|
|
|
|
|
2002-03-26 11:38:40 +00:00
|
|
|
val = scconf_get_str(block, "debug_file", NULL);
|
|
|
|
if (val) {
|
2009-09-15 12:29:17 +00:00
|
|
|
if (ctx->debug_file && (ctx->debug_file != stderr && ctx->debug_file != stdout))
|
2002-03-26 11:38:40 +00:00
|
|
|
fclose(ctx->debug_file);
|
2009-09-14 08:46:59 +00:00
|
|
|
if (!strcmp(val, "stdout"))
|
2010-09-11 13:01:06 +00:00
|
|
|
ctx->debug_file = stdout;
|
|
|
|
else if (!strcmp(val, "stderr"))
|
|
|
|
ctx->debug_file = stderr;
|
2002-03-26 11:38:40 +00:00
|
|
|
else
|
2010-09-11 13:01:06 +00:00
|
|
|
ctx->debug_file = fopen(val, "a");
|
2002-03-26 11:38:40 +00:00
|
|
|
}
|
2002-04-19 20:07:56 +00:00
|
|
|
val = scconf_get_str(block, "force_card_driver", NULL);
|
|
|
|
if (val) {
|
|
|
|
if (opts->forced_card_driver)
|
|
|
|
free(opts->forced_card_driver);
|
|
|
|
opts->forced_card_driver = strdup(val);
|
|
|
|
}
|
2002-03-24 22:47:35 +00:00
|
|
|
|
2002-03-26 11:38:40 +00:00
|
|
|
list = scconf_find_list(block, "card_drivers");
|
2002-03-28 14:13:36 +00:00
|
|
|
if (list != NULL)
|
2010-09-11 13:00:47 +00:00
|
|
|
del_drvs(opts);
|
2002-03-26 11:38:40 +00:00
|
|
|
while (list != NULL) {
|
|
|
|
if (strcmp(list->data, s_internal) == 0)
|
2010-09-11 13:00:47 +00:00
|
|
|
add_internal_drvs(opts);
|
2002-03-26 11:38:40 +00:00
|
|
|
else
|
2010-09-11 13:00:47 +00:00
|
|
|
add_drv(opts, list->data);
|
2002-03-26 11:38:40 +00:00
|
|
|
list = list->next;
|
2002-03-24 22:47:35 +00:00
|
|
|
}
|
2002-03-26 11:38:40 +00:00
|
|
|
|
2002-03-24 22:47:35 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2010-09-11 13:00:47 +00:00
|
|
|
static void load_reader_driver_options(sc_context_t *ctx)
|
2003-12-18 16:35:28 +00:00
|
|
|
{
|
2010-09-11 13:00:47 +00:00
|
|
|
struct sc_reader_driver *driver = ctx->reader_driver;
|
|
|
|
scconf_block *conf_block = NULL;
|
|
|
|
|
2010-09-13 07:40:45 +00:00
|
|
|
driver->max_send_size = 0;
|
|
|
|
driver->max_recv_size = 0;
|
2010-09-11 13:00:47 +00:00
|
|
|
|
|
|
|
conf_block = sc_get_conf_block(ctx, "reader_driver", driver->name, 1);
|
|
|
|
|
2003-12-18 16:35:28 +00:00
|
|
|
if (conf_block != NULL) {
|
2010-09-11 13:00:47 +00:00
|
|
|
driver->max_send_size = scconf_get_int(conf_block, "max_send_size", driver->max_send_size);
|
|
|
|
driver->max_recv_size = scconf_get_int(conf_block, "max_recv_size", driver->max_recv_size);
|
2003-12-18 16:35:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-10-18 08:24:12 +00:00
|
|
|
/**
|
|
|
|
* find library module for provided driver in configuration file
|
|
|
|
* if not found assume library name equals to module name
|
|
|
|
*/
|
2010-09-11 13:00:47 +00:00
|
|
|
static const char *find_library(sc_context_t *ctx, const char *name)
|
2004-10-18 08:24:12 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
const char *libname = NULL;
|
|
|
|
scconf_block **blocks, *blk;
|
|
|
|
|
|
|
|
for (i = 0; ctx->conf_blocks[i]; i++) {
|
2010-09-11 13:00:47 +00:00
|
|
|
blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i], "card_driver", name);
|
2005-12-05 21:35:31 +00:00
|
|
|
if (!blocks)
|
|
|
|
continue;
|
2004-10-18 08:24:12 +00:00
|
|
|
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
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "warning: relative path to driver '%s' used\n",
|
2004-10-18 08:24:12 +00:00
|
|
|
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
|
|
|
|
*/
|
2010-09-11 13:00:47 +00:00
|
|
|
static void *load_dynamic_driver(sc_context_t *ctx, void **dll, const char *name)
|
2004-10-18 08:24:12 +00:00
|
|
|
{
|
|
|
|
const char *version, *libname;
|
2005-09-01 14:01:58 +00:00
|
|
|
lt_dlhandle handle;
|
2004-10-18 08:24:12 +00:00
|
|
|
void *(*modinit)(const char *) = NULL;
|
2005-09-11 20:40:58 +00:00
|
|
|
void *(**tmodi)(const char *) = &modinit;
|
2004-10-18 08:24:12 +00:00
|
|
|
const char *(*modversion)(void) = NULL;
|
2005-09-11 20:40:58 +00:00
|
|
|
const char *(**tmodv)(void) = &modversion;
|
2004-10-18 08:24:12 +00:00
|
|
|
|
|
|
|
if (name == NULL) { /* should not occurr, but... */
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL,"No module specified\n",name);
|
2004-10-18 08:24:12 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-09-11 13:00:47 +00:00
|
|
|
libname = find_library(ctx, name);
|
2004-10-18 08:24:12 +00:00
|
|
|
if (libname == NULL)
|
|
|
|
return NULL;
|
2005-09-01 14:01:58 +00:00
|
|
|
handle = lt_dlopen(libname);
|
|
|
|
if (handle == NULL) {
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Module %s: cannot load %s library: %s\n", name, libname, lt_dlerror());
|
2004-10-18 08:24:12 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2004-12-15 13:53:36 +00:00
|
|
|
|
2004-10-18 08:24:12 +00:00
|
|
|
/* verify correctness of module */
|
2005-09-11 20:40:58 +00:00
|
|
|
*(void **)tmodi = lt_dlsym(handle, "sc_module_init");
|
|
|
|
*(void **)tmodv = lt_dlsym(handle, "sc_driver_version");
|
2004-10-18 08:24:12 +00:00
|
|
|
if (modinit == NULL || modversion == NULL) {
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "dynamic library '%s' is not a OpenSC module\n",libname);
|
2005-09-01 14:01:58 +00:00
|
|
|
lt_dlclose(handle);
|
2004-10-18 08:24:12 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* verify module version */
|
|
|
|
version = modversion();
|
2008-04-29 17:01:19 +00:00
|
|
|
/* XXX: We really need to have ABI version for each interface */
|
|
|
|
if (version == NULL || strncmp(version, PACKAGE_VERSION, strlen(PACKAGE_VERSION)) != 0) {
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL,"dynamic library '%s': invalid module version\n",libname);
|
2005-09-01 14:01:58 +00:00
|
|
|
lt_dlclose(handle);
|
2004-10-18 08:24:12 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2005-09-01 14:01:58 +00:00
|
|
|
*dll = handle;
|
2010-09-11 13:00:47 +00:00
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "successfully loaded card driver '%s'\n", name);
|
2004-10-18 08:24:12 +00:00
|
|
|
return modinit(name);
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int load_card_driver_options(sc_context_t *ctx,
|
2002-12-03 15:40:40 +00:00
|
|
|
struct sc_card_driver *driver)
|
|
|
|
{
|
|
|
|
scconf_block **blocks, *blk;
|
2005-02-06 19:40:40 +00:00
|
|
|
int i;
|
2002-12-03 15:40:40 +00:00
|
|
|
|
|
|
|
for (i = 0; ctx->conf_blocks[i]; i++) {
|
|
|
|
blocks = scconf_find_blocks(ctx->conf,
|
|
|
|
ctx->conf_blocks[i],
|
|
|
|
"card_driver", driver->short_name);
|
2005-12-05 21:35:31 +00:00
|
|
|
if (!blocks)
|
|
|
|
continue;
|
2002-12-03 15:40:40 +00:00
|
|
|
blk = blocks[0];
|
|
|
|
free(blocks);
|
|
|
|
|
|
|
|
if (blk == NULL)
|
|
|
|
continue;
|
|
|
|
|
2005-02-22 07:59:42 +00:00
|
|
|
/* no options at the moment */
|
2002-12-03 15:40:40 +00:00
|
|
|
}
|
2005-02-20 08:26:27 +00:00
|
|
|
return SC_SUCCESS;
|
2002-12-03 15:40:40 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static int load_card_drivers(sc_context_t *ctx,
|
2002-03-24 22:47:35 +00:00
|
|
|
struct _sc_ctx_options *opts)
|
|
|
|
{
|
|
|
|
const struct _sc_driver_entry *ent;
|
|
|
|
int drv_count;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (drv_count = 0; ctx->card_drivers[drv_count] != NULL; drv_count++);
|
|
|
|
|
|
|
|
for (i = 0; i < opts->ccount; i++) {
|
2004-12-15 13:53:36 +00:00
|
|
|
struct sc_card_driver *(*func)(void) = NULL;
|
2005-09-11 20:40:58 +00:00
|
|
|
struct sc_card_driver *(**tfunc)(void) = &func;
|
2004-10-18 08:24:12 +00:00
|
|
|
void *dll = NULL;
|
|
|
|
int j;
|
2002-03-24 22:47:35 +00:00
|
|
|
|
|
|
|
ent = &opts->cdrv[i];
|
|
|
|
for (j = 0; internal_card_drivers[j].name != NULL; j++)
|
|
|
|
if (strcmp(ent->name, internal_card_drivers[j].name) == 0) {
|
2004-12-15 13:53:36 +00:00
|
|
|
func = (struct sc_card_driver *(*)(void)) internal_card_drivers[j].func;
|
2002-03-24 22:47:35 +00:00
|
|
|
break;
|
|
|
|
}
|
2004-10-18 08:24:12 +00:00
|
|
|
/* if not initialized assume external module */
|
|
|
|
if (func == NULL)
|
2010-09-11 13:00:47 +00:00
|
|
|
*(void **)(tfunc) = load_dynamic_driver(ctx, &dll, ent->name);
|
2004-10-18 08:24:12 +00:00
|
|
|
/* if still null, assume driver not found */
|
2002-03-24 22:47:35 +00:00
|
|
|
if (func == NULL) {
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Unable to load '%s'.\n", ent->name);
|
2002-03-24 22:47:35 +00:00
|
|
|
continue;
|
|
|
|
}
|
2004-10-18 08:24:12 +00:00
|
|
|
|
2002-03-24 22:47:35 +00:00
|
|
|
ctx->card_drivers[drv_count] = func();
|
2004-10-18 08:24:12 +00:00
|
|
|
ctx->card_drivers[drv_count]->dll = dll;
|
2002-12-03 15:40:40 +00:00
|
|
|
|
2005-02-14 09:12:44 +00:00
|
|
|
ctx->card_drivers[drv_count]->atr_map = NULL;
|
|
|
|
ctx->card_drivers[drv_count]->natrs = 0;
|
|
|
|
|
2002-12-03 15:40:40 +00:00
|
|
|
load_card_driver_options(ctx, ctx->card_drivers[drv_count]);
|
2005-02-20 08:26:27 +00:00
|
|
|
drv_count++;
|
2002-03-24 22:47:35 +00:00
|
|
|
}
|
2005-02-20 08:26:27 +00:00
|
|
|
return SC_SUCCESS;
|
2002-12-03 15:40:40 +00:00
|
|
|
}
|
2002-03-24 22:47:35 +00:00
|
|
|
|
2010-09-11 13:01:00 +00:00
|
|
|
static int load_card_atrs(sc_context_t *ctx)
|
2005-02-22 07:59:42 +00:00
|
|
|
{
|
|
|
|
struct sc_card_driver *driver;
|
|
|
|
scconf_block **blocks;
|
|
|
|
int i, j, k;
|
|
|
|
|
|
|
|
for (i = 0; ctx->conf_blocks[i] != NULL; i++) {
|
|
|
|
blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i], "card_atr", NULL);
|
|
|
|
if (!blocks)
|
|
|
|
continue;
|
|
|
|
for (j = 0; blocks[j] != NULL; j++) {
|
|
|
|
scconf_block *b = blocks[j];
|
|
|
|
char *atr = b->name->data;
|
|
|
|
const scconf_list *list;
|
|
|
|
struct sc_atr_table t;
|
|
|
|
const char *dname;
|
|
|
|
|
|
|
|
driver = NULL;
|
|
|
|
|
|
|
|
if (strlen(atr) < 4)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* The interesting part. If there's no card
|
|
|
|
* driver assigned for the ATR, add it to
|
|
|
|
* the default driver. This will reduce the
|
|
|
|
* amount of code required to process things
|
|
|
|
* related to card_atr blocks in situations,
|
|
|
|
* where the code is not exactly related to
|
|
|
|
* card driver settings, but for example
|
|
|
|
* forcing a protocol at the reader driver.
|
|
|
|
*/
|
|
|
|
dname = scconf_get_str(b, "driver", "default");
|
|
|
|
|
|
|
|
/* Find the card driver structure according to dname */
|
|
|
|
for (k = 0; ctx->card_drivers[k] != NULL; k++) {
|
|
|
|
driver = ctx->card_drivers[k];
|
|
|
|
if (!strcmp(dname, driver->short_name))
|
|
|
|
break;
|
|
|
|
driver = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!driver)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
memset(&t, 0, sizeof(struct sc_atr_table));
|
|
|
|
t.atr = atr;
|
|
|
|
t.atrmask = (char *) scconf_get_str(b, "atrmask", NULL);
|
|
|
|
t.name = (char *) scconf_get_str(b, "name", NULL);
|
|
|
|
t.type = scconf_get_int(b, "type", -1);
|
|
|
|
list = scconf_find_list(b, "flags");
|
|
|
|
while (list != NULL) {
|
|
|
|
unsigned int flags;
|
|
|
|
|
|
|
|
if (!list->data) {
|
|
|
|
list = list->next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
flags = 0;
|
|
|
|
if (!strcmp(list->data, "keygen")) {
|
|
|
|
flags = SC_CARD_FLAG_ONBOARD_KEY_GEN;
|
|
|
|
} else if (!strcmp(list->data, "rng")) {
|
|
|
|
flags = SC_CARD_FLAG_RNG;
|
|
|
|
} else {
|
|
|
|
if (sscanf(list->data, "%x", &flags) != 1)
|
|
|
|
flags = 0;
|
|
|
|
}
|
|
|
|
t.flags |= flags;
|
|
|
|
list = list->next;
|
|
|
|
}
|
|
|
|
t.card_atr = b;
|
|
|
|
_sc_add_atr(ctx, driver, &t);
|
|
|
|
}
|
|
|
|
free(blocks);
|
|
|
|
}
|
|
|
|
return SC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
static void process_config_file(sc_context_t *ctx, struct _sc_ctx_options *opts)
|
2002-03-26 11:38:40 +00:00
|
|
|
{
|
|
|
|
int i, r, count = 0;
|
|
|
|
scconf_block **blocks;
|
2006-02-17 21:06:31 +00:00
|
|
|
const char *conf_path = NULL;
|
2003-04-23 11:46:07 +00:00
|
|
|
#ifdef _WIN32
|
2005-03-23 23:10:50 +00:00
|
|
|
char temp_path[PATH_MAX];
|
2008-03-06 16:06:59 +00:00
|
|
|
DWORD temp_len;
|
2005-03-07 14:00:31 +00:00
|
|
|
long rc;
|
|
|
|
HKEY hKey;
|
2003-04-23 11:46:07 +00:00
|
|
|
#endif
|
|
|
|
|
2002-12-21 14:10:36 +00:00
|
|
|
memset(ctx->conf_blocks, 0, sizeof(ctx->conf_blocks));
|
2003-01-20 10:12:28 +00:00
|
|
|
#ifdef _WIN32
|
2010-09-11 13:01:06 +00:00
|
|
|
conf_path = getenv("OPENSC_CONF");
|
|
|
|
if (!conf_path) {
|
|
|
|
rc = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\OpenSC", 0, KEY_QUERY_VALUE, &hKey);
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
temp_len = PATH_MAX;
|
|
|
|
rc = RegQueryValueEx( hKey, "ConfigFile", NULL, NULL, (LPBYTE) temp_path, &temp_len);
|
|
|
|
if ((rc == ERROR_SUCCESS) && (temp_len < PATH_MAX))
|
|
|
|
conf_path = temp_path;
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-06-26 21:03:11 +00:00
|
|
|
if (!conf_path) {
|
2010-09-11 13:01:06 +00:00
|
|
|
rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\OpenSC", 0, KEY_QUERY_VALUE, &hKey );
|
|
|
|
if (rc == ERROR_SUCCESS) {
|
|
|
|
temp_len = PATH_MAX;
|
|
|
|
rc = RegQueryValueEx( hKey, "ConfigFile", NULL, NULL, (LPBYTE) temp_path, &temp_len);
|
|
|
|
if ((rc == ERROR_SUCCESS) && (temp_len < PATH_MAX))
|
|
|
|
conf_path = temp_path;
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
}
|
2006-06-26 21:03:11 +00:00
|
|
|
}
|
2005-03-23 23:10:50 +00:00
|
|
|
|
2010-09-11 13:01:06 +00:00
|
|
|
if (!conf_path) {
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "process_config_file doesn't find opensc config file. Please set the registry key.");
|
2006-01-04 18:52:52 +00:00
|
|
|
return;
|
|
|
|
}
|
2005-03-07 14:00:31 +00:00
|
|
|
|
|
|
|
#else
|
2010-09-11 13:01:06 +00:00
|
|
|
conf_path = getenv("OPENSC_CONF");
|
|
|
|
if (!conf_path)
|
|
|
|
conf_path = OPENSC_CONF_PATH;
|
2003-01-20 10:12:28 +00:00
|
|
|
#endif
|
|
|
|
ctx->conf = scconf_new(conf_path);
|
2002-03-26 11:38:40 +00:00
|
|
|
if (ctx->conf == NULL)
|
|
|
|
return;
|
2003-12-03 14:09:15 +00:00
|
|
|
r = scconf_parse(ctx->conf);
|
2003-01-03 13:26:58 +00:00
|
|
|
#ifdef OPENSC_CONFIG_STRING
|
2003-12-03 12:07:01 +00:00
|
|
|
/* Parse the string if config file didn't exist */
|
|
|
|
if (r < 0)
|
2003-01-03 13:26:58 +00:00
|
|
|
r = scconf_parse_string(ctx->conf, OPENSC_CONFIG_STRING);
|
|
|
|
#endif
|
2002-03-26 11:38:40 +00:00
|
|
|
if (r < 1) {
|
2003-12-03 12:07:01 +00:00
|
|
|
/* A negative return value means the config file isn't
|
|
|
|
* there, which is not an error. Nevertheless log this
|
|
|
|
* fact. */
|
|
|
|
if (r < 0)
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "scconf_parse failed: %s", ctx->conf->errmsg);
|
2003-12-03 12:07:01 +00:00
|
|
|
else
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "scconf_parse failed: %s", ctx->conf->errmsg);
|
2002-03-26 20:56:13 +00:00
|
|
|
scconf_free(ctx->conf);
|
2002-03-26 11:38:40 +00:00
|
|
|
ctx->conf = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
blocks = scconf_find_blocks(ctx->conf, NULL, "app", ctx->app_name);
|
|
|
|
if (blocks[0])
|
|
|
|
ctx->conf_blocks[count++] = blocks[0];
|
|
|
|
free(blocks);
|
|
|
|
if (strcmp(ctx->app_name, "default") != 0) {
|
|
|
|
blocks = scconf_find_blocks(ctx->conf, NULL, "app", "default");
|
|
|
|
if (blocks[0])
|
|
|
|
ctx->conf_blocks[count++] = blocks[0];
|
|
|
|
free(blocks);
|
|
|
|
}
|
2002-12-21 14:10:36 +00:00
|
|
|
/* Above we add 2 blocks at most, but conf_blocks has 3 elements,
|
|
|
|
* so at least one is NULL */
|
|
|
|
for (i = 0; ctx->conf_blocks[i]; i++)
|
2002-03-26 11:38:40 +00:00
|
|
|
load_parameters(ctx, ctx->conf_blocks[i], opts);
|
|
|
|
}
|
|
|
|
|
2008-04-29 17:01:19 +00:00
|
|
|
int sc_ctx_detect_readers(sc_context_t *ctx)
|
|
|
|
{
|
2010-09-11 13:00:47 +00:00
|
|
|
int r;
|
|
|
|
const struct sc_reader_driver *drv = ctx->reader_driver;
|
2008-04-29 17:01:19 +00:00
|
|
|
|
|
|
|
sc_mutex_lock(ctx, ctx->mutex);
|
|
|
|
|
2010-09-11 13:00:47 +00:00
|
|
|
if (drv->ops->detect_readers != NULL)
|
|
|
|
r = drv->ops->detect_readers(ctx);
|
|
|
|
|
2008-04-29 17:01:19 +00:00
|
|
|
sc_mutex_unlock(ctx, ctx->mutex);
|
|
|
|
|
2010-09-11 13:00:47 +00:00
|
|
|
return r;
|
2008-04-29 17:01:19 +00:00
|
|
|
}
|
|
|
|
|
2005-09-16 10:18:55 +00:00
|
|
|
sc_reader_t *sc_ctx_get_reader(sc_context_t *ctx, unsigned int i)
|
|
|
|
{
|
2010-09-11 13:01:06 +00:00
|
|
|
return list_get_at(&ctx->readers, i);
|
2010-01-24 15:25:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sc_reader_t *sc_ctx_get_reader_by_id(sc_context_t *ctx, unsigned int id)
|
|
|
|
{
|
2010-09-11 13:01:06 +00:00
|
|
|
return list_get_at(&ctx->readers, id);
|
2010-01-24 15:25:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sc_reader_t *sc_ctx_get_reader_by_name(sc_context_t *ctx, const char * name)
|
|
|
|
{
|
2010-09-11 13:01:06 +00:00
|
|
|
return list_seek(&ctx->readers, name);
|
2005-09-16 10:18:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int sc_ctx_get_reader_count(sc_context_t *ctx)
|
|
|
|
{
|
2010-01-24 15:25:08 +00:00
|
|
|
return list_size(&ctx->readers);
|
2005-09-16 10:18:55 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_establish_context(sc_context_t **ctx_out, const char *app_name)
|
2002-03-24 22:47:35 +00:00
|
|
|
{
|
2006-02-01 22:59:42 +00:00
|
|
|
sc_context_param_t ctx_param;
|
2002-03-24 22:47:35 +00:00
|
|
|
|
2006-02-01 22:59:42 +00:00
|
|
|
memset(&ctx_param, 0, sizeof(sc_context_param_t));
|
|
|
|
ctx_param.ver = 0;
|
|
|
|
ctx_param.app_name = app_name;
|
|
|
|
return sc_context_create(ctx_out, &ctx_param);
|
|
|
|
}
|
|
|
|
|
|
|
|
int sc_context_create(sc_context_t **ctx_out, const sc_context_param_t *parm)
|
|
|
|
{
|
|
|
|
sc_context_t *ctx;
|
|
|
|
struct _sc_ctx_options opts;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (ctx_out == NULL)
|
|
|
|
return SC_ERROR_INVALID_ARGUMENTS;
|
|
|
|
|
|
|
|
ctx = calloc(1, sizeof(sc_context_t));
|
2002-03-24 22:47:35 +00:00
|
|
|
if (ctx == NULL)
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
memset(&opts, 0, sizeof(opts));
|
2006-02-01 22:59:42 +00:00
|
|
|
|
|
|
|
/* set the application name if set in the parameter options */
|
|
|
|
if (parm != NULL && parm->app_name != NULL)
|
|
|
|
ctx->app_name = strdup(parm->app_name);
|
|
|
|
else
|
|
|
|
ctx->app_name = strdup("default");
|
2005-01-03 17:20:17 +00:00
|
|
|
if (ctx->app_name == NULL) {
|
|
|
|
sc_release_context(ctx);
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2010-06-16 14:12:27 +00:00
|
|
|
|
|
|
|
set_defaults(ctx, &opts);
|
2010-01-24 15:25:08 +00:00
|
|
|
list_init(&ctx->readers);
|
|
|
|
list_attributes_seeker(&ctx->readers, reader_list_seeker);
|
2006-02-01 22:59:42 +00:00
|
|
|
/* set thread context and create mutex object (if specified) */
|
|
|
|
if (parm != NULL && parm->thread_ctx != NULL)
|
|
|
|
ctx->thread_ctx = parm->thread_ctx;
|
|
|
|
r = sc_mutex_create(ctx, &ctx->mutex);
|
|
|
|
if (r != SC_SUCCESS) {
|
|
|
|
sc_release_context(ctx);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2002-03-26 11:38:40 +00:00
|
|
|
process_config_file(ctx, &opts);
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "===================================\n"); /* first thing in the log */
|
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "opensc version: %s\n", sc_get_version());
|
2005-09-01 14:01:58 +00:00
|
|
|
|
2010-09-11 13:00:47 +00:00
|
|
|
/* initialize ltdl */
|
2005-09-01 14:01:58 +00:00
|
|
|
if (lt_dlinit() != 0) {
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "lt_dlinit failed\n");
|
2005-09-01 14:01:58 +00:00
|
|
|
sc_release_context(ctx);
|
|
|
|
return SC_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
2010-09-11 13:00:47 +00:00
|
|
|
#ifdef ENABLE_PCSC
|
|
|
|
ctx->reader_driver = sc_get_pcsc_driver();
|
2010-09-11 13:01:06 +00:00
|
|
|
#elif ENABLE_CTAPI
|
2010-09-11 13:00:47 +00:00
|
|
|
ctx->reader_driver = sc_get_ctapi_driver();
|
|
|
|
#elif ENABLE_OPENCT
|
|
|
|
ctx->reader_driver = sc_get_openct_driver();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
load_reader_driver_options(ctx);
|
|
|
|
ctx->reader_driver->ops->init(ctx);
|
|
|
|
|
2002-03-24 22:47:35 +00:00
|
|
|
load_card_drivers(ctx, &opts);
|
2010-09-11 13:01:00 +00:00
|
|
|
load_card_atrs(ctx);
|
2002-04-19 20:07:56 +00:00
|
|
|
if (opts.forced_card_driver) {
|
2006-04-26 10:05:21 +00:00
|
|
|
/* FIXME: check return value? */
|
2002-04-19 20:07:56 +00:00
|
|
|
sc_set_card_driver(ctx, opts.forced_card_driver);
|
|
|
|
free(opts.forced_card_driver);
|
2005-02-06 19:40:40 +00:00
|
|
|
}
|
2010-09-11 13:00:47 +00:00
|
|
|
del_drvs(&opts);
|
2008-04-29 17:01:19 +00:00
|
|
|
sc_ctx_detect_readers(ctx);
|
2002-03-24 22:47:35 +00:00
|
|
|
*ctx_out = ctx;
|
2005-02-20 08:26:27 +00:00
|
|
|
return SC_SUCCESS;
|
2002-03-24 22:47:35 +00:00
|
|
|
}
|
|
|
|
|
2010-01-24 15:25:08 +00:00
|
|
|
/* Following two are only implemented with internal PC/SC and don't consume a reader object */
|
|
|
|
int sc_cancel(sc_context_t *ctx)
|
|
|
|
{
|
2010-09-11 13:00:47 +00:00
|
|
|
SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL);
|
|
|
|
if (ctx->reader_driver->ops->cancel != NULL)
|
|
|
|
return ctx->reader_driver->ops->cancel(ctx);
|
|
|
|
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
2010-01-24 15:25:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-11 13:00:47 +00:00
|
|
|
int sc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_reader_t **event_reader, unsigned int *event, int timeout, void **reader_states)
|
2010-01-24 15:25:08 +00:00
|
|
|
{
|
2010-09-11 13:00:47 +00:00
|
|
|
SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL);
|
2010-09-11 13:01:06 +00:00
|
|
|
if (ctx->reader_driver->ops->wait_for_event != NULL)
|
2010-09-11 13:00:47 +00:00
|
|
|
return ctx->reader_driver->ops->wait_for_event(ctx, event_mask, event_reader, event, timeout, reader_states);
|
|
|
|
|
|
|
|
return SC_ERROR_NOT_SUPPORTED;
|
2010-01-24 15:25:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_release_context(sc_context_t *ctx)
|
2002-03-24 22:47:35 +00:00
|
|
|
{
|
2010-01-24 15:25:08 +00:00
|
|
|
unsigned int i;
|
2002-03-24 22:47:35 +00:00
|
|
|
|
|
|
|
assert(ctx != NULL);
|
2010-03-15 12:17:13 +00:00
|
|
|
SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
|
2010-01-24 15:25:08 +00:00
|
|
|
for (i=0; i<list_size(&ctx->readers); i++) {
|
2010-09-11 13:01:06 +00:00
|
|
|
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);
|
2002-03-24 22:47:35 +00:00
|
|
|
}
|
2010-01-24 15:25:08 +00:00
|
|
|
|
2010-09-11 13:00:47 +00:00
|
|
|
if (ctx->reader_driver->ops->finish != NULL)
|
|
|
|
ctx->reader_driver->ops->finish(ctx);
|
2005-02-06 19:40:40 +00:00
|
|
|
|
2004-10-18 08:24:12 +00:00
|
|
|
for (i = 0; ctx->card_drivers[i]; i++) {
|
|
|
|
struct sc_card_driver *drv = ctx->card_drivers[i];
|
2006-02-23 13:40:03 +00:00
|
|
|
|
2005-02-14 09:12:44 +00:00
|
|
|
if (drv->atr_map)
|
|
|
|
_sc_free_atr(ctx, drv);
|
2006-02-23 13:40:03 +00:00
|
|
|
if (drv->dll)
|
|
|
|
lt_dlclose(drv->dll);
|
2002-03-24 22:47:35 +00:00
|
|
|
}
|
2006-02-01 22:59:42 +00:00
|
|
|
if (ctx->preferred_language != NULL)
|
2003-10-22 18:16:21 +00:00
|
|
|
free(ctx->preferred_language);
|
2006-02-05 19:35:55 +00:00
|
|
|
if (ctx->mutex != NULL) {
|
|
|
|
int r = sc_mutex_destroy(ctx, ctx->mutex);
|
|
|
|
if (r != SC_SUCCESS) {
|
2010-03-15 12:17:13 +00:00
|
|
|
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "unable to destroy mutex\n");
|
2006-02-05 19:35:55 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
2006-02-01 22:59:42 +00:00
|
|
|
if (ctx->conf != NULL)
|
2002-03-26 20:56:13 +00:00
|
|
|
scconf_free(ctx->conf);
|
2009-09-14 08:46:59 +00:00
|
|
|
if (ctx->debug_file && (ctx->debug_file != stdout && ctx->debug_file != stderr))
|
2006-02-05 19:35:55 +00:00
|
|
|
fclose(ctx->debug_file);
|
2006-02-01 22:59:42 +00:00
|
|
|
if (ctx->app_name != NULL)
|
|
|
|
free(ctx->app_name);
|
2010-09-11 13:01:06 +00:00
|
|
|
list_destroy(&ctx->readers);
|
2005-09-17 10:44:45 +00:00
|
|
|
sc_mem_clear(ctx, sizeof(*ctx));
|
2002-03-24 22:47:35 +00:00
|
|
|
free(ctx);
|
2005-02-20 08:26:27 +00:00
|
|
|
return SC_SUCCESS;
|
2002-03-24 22:47:35 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_set_card_driver(sc_context_t *ctx, const char *short_name)
|
2002-03-24 22:47:35 +00:00
|
|
|
{
|
|
|
|
int i = 0, match = 0;
|
2005-02-06 19:40:40 +00:00
|
|
|
|
2006-02-01 22:59:42 +00:00
|
|
|
sc_mutex_lock(ctx, ctx->mutex);
|
2002-03-24 22:47:35 +00:00
|
|
|
if (short_name == NULL) {
|
|
|
|
ctx->forced_driver = NULL;
|
|
|
|
match = 1;
|
|
|
|
} else while (ctx->card_drivers[i] != NULL && i < SC_MAX_CARD_DRIVERS) {
|
2002-12-19 16:16:42 +00:00
|
|
|
struct sc_card_driver *drv = ctx->card_drivers[i];
|
2002-03-24 22:47:35 +00:00
|
|
|
|
|
|
|
if (strcmp(short_name, drv->short_name) == 0) {
|
|
|
|
ctx->forced_driver = drv;
|
|
|
|
match = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
2006-02-01 22:59:42 +00:00
|
|
|
sc_mutex_unlock(ctx, ctx->mutex);
|
2002-03-24 22:47:35 +00:00
|
|
|
if (match == 0)
|
|
|
|
return SC_ERROR_OBJECT_NOT_FOUND; /* FIXME: invent error */
|
2005-02-20 08:26:27 +00:00
|
|
|
return SC_SUCCESS;
|
2002-03-24 22:47:35 +00:00
|
|
|
}
|
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_get_cache_dir(sc_context_t *ctx, char *buf, size_t bufsize)
|
2002-03-24 22:47:35 +00:00
|
|
|
{
|
|
|
|
char *homedir;
|
2002-11-27 14:27:53 +00:00
|
|
|
const char *cache_dir;
|
2003-04-23 11:46:07 +00:00
|
|
|
#ifdef _WIN32
|
2005-03-23 23:10:50 +00:00
|
|
|
char temp_path[PATH_MAX];
|
2003-04-23 11:46:07 +00:00
|
|
|
#endif
|
2002-03-24 22:47:35 +00:00
|
|
|
|
2002-11-27 14:27:53 +00:00
|
|
|
#ifndef _WIN32
|
|
|
|
cache_dir = ".eid/cache";
|
2002-03-24 22:47:35 +00:00
|
|
|
homedir = getenv("HOME");
|
2002-11-27 14:27:53 +00:00
|
|
|
#else
|
|
|
|
cache_dir = "eid-cache";
|
|
|
|
homedir = getenv("USERPROFILE");
|
2003-04-23 11:46:07 +00:00
|
|
|
/* If USERPROFILE isn't defined, assume it's a single-user OS
|
|
|
|
* and put the cache dir in the Windows dir (usually C:\\WINDOWS) */
|
|
|
|
if (homedir == NULL || homedir[0] == '\0') {
|
2005-03-23 23:10:50 +00:00
|
|
|
GetWindowsDirectory(temp_path, sizeof(temp_path));
|
|
|
|
homedir = temp_path;
|
2003-04-23 11:46:07 +00:00
|
|
|
}
|
2002-11-27 14:27:53 +00:00
|
|
|
#endif
|
2002-03-24 22:47:35 +00:00
|
|
|
if (homedir == NULL)
|
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
if (snprintf(buf, bufsize, "%s/%s", homedir, cache_dir) < 0)
|
|
|
|
return SC_ERROR_BUFFER_TOO_SMALL;
|
2005-02-20 08:26:27 +00:00
|
|
|
return SC_SUCCESS;
|
2002-03-24 22:47:35 +00:00
|
|
|
}
|
2003-01-09 09:18:02 +00:00
|
|
|
|
2005-03-08 20:59:35 +00:00
|
|
|
int sc_make_cache_dir(sc_context_t *ctx)
|
2003-01-09 09:18:02 +00:00
|
|
|
{
|
|
|
|
char dirname[PATH_MAX], *sp;
|
2004-10-29 20:08:54 +00:00
|
|
|
int r;
|
|
|
|
size_t j, namelen;
|
2003-01-09 09:18:02 +00:00
|
|
|
|
|
|
|
if ((r = sc_get_cache_dir(ctx, dirname, sizeof(dirname))) < 0)
|
|
|
|
return r;
|
|
|
|
namelen = strlen(dirname);
|
|
|
|
|
|
|
|
while (1) {
|
2008-03-06 16:06:59 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
if (mkdir(dirname) >= 0)
|
|
|
|
#else
|
2003-01-09 09:18:02 +00:00
|
|
|
if (mkdir(dirname, 0700) >= 0)
|
2008-03-06 16:06:59 +00:00
|
|
|
#endif
|
2003-01-09 09:18:02 +00:00
|
|
|
break;
|
|
|
|
if (errno != ENOENT
|
|
|
|
|| (sp = strrchr(dirname, '/')) == NULL
|
|
|
|
|| sp == dirname)
|
|
|
|
goto failed;
|
|
|
|
*sp = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We may have stripped one or more path components from
|
|
|
|
* the directory name. Restore them */
|
|
|
|
while (1) {
|
|
|
|
j = strlen(dirname);
|
|
|
|
if (j >= namelen)
|
|
|
|
break;
|
|
|
|
dirname[j] = '/';
|
2008-03-06 16:06:59 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
if (mkdir(dirname) < 0)
|
|
|
|
#else
|
2003-01-09 09:18:02 +00:00
|
|
|
if (mkdir(dirname, 0700) < 0)
|
2008-03-06 16:06:59 +00:00
|
|
|
#endif
|
2003-01-09 09:18:02 +00:00
|
|
|
goto failed;
|
|
|
|
}
|
2005-02-20 08:26:27 +00:00
|
|
|
return SC_SUCCESS;
|
2003-01-09 09:18:02 +00:00
|
|
|
|
|
|
|
/* for lack of a better return code */
|
2010-03-15 12:17:13 +00:00
|
|
|
failed: sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "failed to create cache directory\n");
|
2003-01-09 09:18:02 +00:00
|
|
|
return SC_ERROR_INTERNAL;
|
|
|
|
}
|