diff --git a/etc/opensc.conf.example b/etc/opensc.conf.example index ef54cfc8..148fa509 100644 --- a/etc/opensc.conf.example +++ b/etc/opensc.conf.example @@ -1,17 +1,77 @@ # Configuration file for OpenSC # Example configuration file -# Default values for any application -# These can be overrided by the application -# specific configuration block. +# NOTE: All key-value pairs must be terminated by a semicolon. +# Default values for any application +# These can be overrided by an application +# specific configuration block. app default { + # Amount of debug info to print + # + # A greater value means more debug info. + # Default: 0 + # debug = 0; - #debug_file = "/tmp/opensc-debug.log"; - #error_file = "/tmp/opensc-errors.log"; + + # The file to which debug output will be written + # + # A special value of 'stdout' is recognized. + # Default: stdout + # + # debug_file = /tmp/opensc-debug.log; + + # The file to which errors will be written + # + # A special value of 'stderr' is recognized. + # Default: stderr + # + # error_file = /tmp/opensc-errors.log; + + # What reader drivers to load at start-up + # + # A special value of 'internal' will load all + # statically linked drivers. If an unknown (ie. not + # internal) driver is supplied, a separate configuration + # configuration block has to be written for the driver. + # Default: internal + # + # reader_drivers = pcsc, ctapi; + + # What reader drivers to load at start-up + # + # A special value of 'internal' will load all + # statically linked drivers. If an unknown (ie. not + # internal) driver is supplied, a separate configuration + # configuration block has to be written for the driver. + # Default: internal + # + # card_drivers = internal, customcos; + + # card_driver customcos { + # The location of the driver library + # + # module = /usr/lib/opensc/drivers/card_customcos.so + # } + + # Below are the framework specific configuration blocks. + + # PKCS #15 + framework pkcs15 { + # Whether to use the cache files in the user's + # home directory. + + # WARNING: This shouldn't be used in setuid root + # applications. + # Default: false + # + use_caching = true; + } } # For applications that use SCAM (pam_opensc, sia_opensc) app scam { - use_cache = false; + framework pkcs15 { + use_caching = false; + } } diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am index 2e01371c..379ab72a 100644 --- a/src/libopensc/Makefile.am +++ b/src/libopensc/Makefile.am @@ -17,8 +17,9 @@ INCLUDES = $(PCSC_FLAGS) bin_SCRIPTS = opensc-config lib_LTLIBRARIES = libopensc.la -libopensc_la_SOURCES = asn1.c base64.c sec.c log.c sc.c card.c iso7816.c \ - dir.c pkcs15.c pkcs15-cert.c pkcs15-pin.c \ +libopensc_la_SOURCES = sc.c ctx.c asn1.c base64.c sec.c log.c \ + card.c iso7816.c dir.c \ + pkcs15.c pkcs15-cert.c pkcs15-pin.c \ pkcs15-prkey.c pkcs15-pubkey.c pkcs15-sec.c \ pkcs15-cache.c $(PCSC_SRC) \ card-setcos.c card-miocos.c card-flex.c card-gpk.c \ diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c new file mode 100644 index 00000000..e81ab542 --- /dev/null +++ b/src/libopensc/ctx.c @@ -0,0 +1,390 @@ +/* + * ctx.c: Context related functions + * + * Copyright (C) 2002 Juha Yrjölä + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "sc-internal.h" +#include "sc-log.h" +#include +#include +#include +#include + +int _sc_add_reader(struct sc_context *ctx, struct sc_reader *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++; + + return 0; +} + +struct _sc_driver_entry { + char *name; + void *func; + char *libpath; +}; + +static const struct _sc_driver_entry internal_card_drivers[] = { + { "setcos", sc_get_setcos_driver }, + { "miocos", sc_get_miocos_driver }, + { "flex", sc_get_flex_driver }, + { "tcos", sc_get_tcos_driver }, + { "emv", sc_get_emv_driver }, +#ifdef HAVE_OPENSSL + { "gpk", sc_get_gpk_driver }, +#endif + /* The default driver should be last, as it handles all the + * unrecognized cards. */ + { "default", sc_get_default_driver }, + { NULL } +}; + +static const struct _sc_driver_entry internal_reader_drivers[] = { +#ifdef HAVE_LIBPCSCLITE + { "pcsc", sc_get_pcsc_driver }, +#endif + { NULL } +}; + +struct _sc_ctx_options { + struct _sc_driver_entry rdrv[16]; + int rcount; + struct _sc_driver_entry cdrv[16]; + int ccount; +}; + +static void set_defaults(struct sc_context *ctx, struct _sc_ctx_options *opts) +{ + ctx->debug = 0; + if (ctx->debug_file) + fclose(ctx->debug_file); + ctx->debug_file = NULL; + ctx->log_errors = 1; + ctx->error_file = stderr; + ctx->forced_driver = NULL; +} + +static void del_drvs(struct _sc_ctx_options *opts, int type) +{ + struct _sc_driver_entry *lst; + int *cp, i; + + if (type == 0) { + lst = opts->rdrv; + cp = &opts->rcount; + } else { + lst = opts->cdrv; + cp = &opts->ccount; + } + for (i = 0; i < *cp; i++) { + free(lst[i].name); + if (lst[i].libpath) + free(lst[i].libpath); + } + *cp = 0; +} + +static void add_drv(struct _sc_ctx_options *opts, int type, const char *name) +{ + struct _sc_driver_entry *lst; + int *cp, i; + + if (type == 0) { + lst = opts->rdrv; + cp = &opts->rcount; + } else { + lst = opts->cdrv; + cp = &opts->ccount; + } + if (*cp == 16) /* No space for more drivers... */ + return; + for (i = 0; i < *cp; i++) + if (strcmp(name, lst[i].name) == 0) + return; + lst[*cp].name = strdup(name); + + *cp = *cp + 1; +} + +static void add_internal_drvs(struct _sc_ctx_options *opts, int type) +{ + const struct _sc_driver_entry *lst; + int i; + + if (type == 0) + lst = internal_reader_drivers; + else + lst = internal_card_drivers; + i = 0; + while (lst[i].name != NULL) { + add_drv(opts, type, lst[i].name); + i++; + } +} + +static int load_parameters(struct sc_context *ctx, const char *app, + struct _sc_ctx_options *opts) +{ + scconf_block **blocks = NULL; + int i, err = 0; + + blocks = scconf_find_blocks(ctx->conf, NULL, "app"); + for (i = 0; blocks[i]; i++) { + scconf_block *block = blocks[i]; + const scconf_list *list; + const char *val; + const char *s_internal = "internal"; + + if (!block->name && strcmp(block->name->data, app)) + continue; + val = scconf_find_value_first(block, "debug"); + if (val) + sscanf(val, "%d", &ctx->debug); + val = scconf_find_value_first(block, "debug_file"); + if (val) { + if (ctx->debug_file && ctx->debug_file != stdout) + fclose(ctx->debug_file); + if (strcmp(val, "stdout") == 0) + ctx->debug_file = fopen(val, "a"); + else + ctx->debug_file = stdout; + } + val = scconf_find_value_first(block, "error_file"); + if (val) { + if (ctx->error_file && ctx->error_file != stderr) + fclose(ctx->error_file); + if (strcmp(val, "stderr") != 0) + ctx->error_file = fopen(val, "a"); + else + ctx->error_file = stderr; + } + + list = scconf_find_value(block, "reader_drivers"); + if (list == NULL) { + if (opts->rcount == 0) /* Add the internal drivers */ + add_internal_drvs(opts, 0); + } else + del_drvs(opts, 0); + while (list != NULL) { + if (strcmp(list->data, s_internal) == 0) + add_internal_drvs(opts, 1); + else + add_drv(opts, 0, list->data); + list = list->next; + } + if (err) + break; + + list = scconf_find_value(block, "card_drivers"); + if (list == NULL) { + if (opts->ccount == 0) /* Add the internal drivers */ + add_internal_drvs(opts, 1); + } else + del_drvs(opts, 1); + while (list != NULL) { + if (strcmp(list->data, s_internal) == 0) + add_internal_drvs(opts, 1); + else + add_drv(opts, 1, list->data); + list = list->next; + } + if (err) + break; + } + free(blocks); + return err; +} + +static int load_reader_drivers(struct sc_context *ctx, + struct _sc_ctx_options *opts) +{ + const struct _sc_driver_entry *ent; + int drv_count; + int i; + + for (drv_count = 0; ctx->reader_drivers[drv_count] != NULL; drv_count++); + + for (i = 0; i < opts->rcount; i++) { + const struct sc_reader_driver * (* func)(void) = NULL; + int j; + + ent = &opts->rdrv[i]; + for (j = 0; internal_reader_drivers[j].name != NULL; j++) + if (strcmp(ent->name, internal_reader_drivers[j].name) == 0) { + func = internal_reader_drivers[j].func; + break; + } + if (func == NULL) { + /* External driver */ + /* FIXME: Load shared library */ + error(ctx, "Unable to load '%s'. External drivers not supported yet.\n", + ent->name); + continue; + } + ctx->reader_drivers[drv_count] = func(); + ctx->reader_drivers[drv_count]->ops->init(ctx, &ctx->reader_drv_data[i]); + drv_count++; + } + return 0; +} + +static int load_card_drivers(struct sc_context *ctx, + 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++) { + const struct sc_card_driver * (* func)(void) = NULL; + int j; + + ent = &opts->cdrv[i]; + for (j = 0; internal_card_drivers[j].name != NULL; j++) + if (strcmp(ent->name, internal_card_drivers[j].name) == 0) { + func = internal_card_drivers[j].func; + break; + } + if (func == NULL) { + /* External driver */ + /* FIXME: Load shared library */ + error(ctx, "Unable to load '%s'. External drivers not supported yet.\n", + ent->name); + continue; + } + ctx->card_drivers[drv_count] = func(); + drv_count++; + } + return 0; +} + +int sc_establish_context(struct sc_context **ctx_out, const char *app_name) +{ + const char *default_app = "default"; + struct sc_context *ctx; + struct _sc_ctx_options opts; + int r; + + assert(ctx_out != NULL); + ctx = malloc(sizeof(struct sc_context)); + if (ctx == NULL) + return SC_ERROR_OUT_OF_MEMORY; + memset(ctx, 0, sizeof(struct sc_context)); + memset(&opts, 0, sizeof(opts)); + set_defaults(ctx, &opts); + ctx->app_name = app_name ? strdup(app_name) : strdup(default_app); + ctx->conf = scconf_init(OPENSC_CONF_PATH); + if (ctx->conf) { + r = scconf_parse(ctx->conf); + if (r < 1) { + scconf_deinit(ctx->conf); + ctx->conf = NULL; + } else { + load_parameters(ctx, default_app, &opts); + if (strcmp(default_app, ctx->app_name)) { + load_parameters(ctx, ctx->app_name, &opts); + } + } + } +#ifdef HAVE_PTHREAD + pthread_mutex_init(&ctx->mutex, NULL); +#endif + load_reader_drivers(ctx, &opts); + load_card_drivers(ctx, &opts); + + *ctx_out = ctx; + return 0; +} + +int sc_release_context(struct sc_context *ctx) +{ + int i; + + assert(ctx != NULL); + SC_FUNC_CALLED(ctx, 1); + for (i = 0; i < ctx->reader_count; i++) { + struct sc_reader *rdr = ctx->reader[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]; + + if (drv->ops->finish != NULL) + drv->ops->finish(ctx->reader_drv_data[i]); + } + ctx->debug_file = ctx->error_file = NULL; + if (ctx->conf) + scconf_deinit(ctx->conf); + free(ctx->app_name); + free(ctx); + return 0; +} + +int sc_set_card_driver(struct sc_context *ctx, const char *short_name) +{ + int i = 0, match = 0; + +#ifdef HAVE_PTHREAD + pthread_mutex_lock(&ctx->mutex); +#endif + if (short_name == NULL) { + ctx->forced_driver = NULL; + match = 1; + } else while (ctx->card_drivers[i] != NULL && i < SC_MAX_CARD_DRIVERS) { + const struct sc_card_driver *drv = ctx->card_drivers[i]; + + if (strcmp(short_name, drv->short_name) == 0) { + ctx->forced_driver = drv; + match = 1; + break; + } + i++; + } +#ifdef HAVE_PTHREAD + pthread_mutex_unlock(&ctx->mutex); +#endif + if (match == 0) + return SC_ERROR_OBJECT_NOT_FOUND; /* FIXME: invent error */ + return 0; +} + +int sc_get_cache_dir(struct sc_context *ctx, char *buf, size_t bufsize) +{ + char *homedir; + const char *cache_dir = ".eid/cache"; + + homedir = getenv("HOME"); + if (homedir == NULL) + return SC_ERROR_INTERNAL; + if (snprintf(buf, bufsize, "%s/%s", homedir, cache_dir) < 0) + return SC_ERROR_BUFFER_TOO_SMALL; + return 0; +} diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index 66e47960..279f507a 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -331,6 +331,8 @@ static int pcsc_init(struct sc_context *ctx, void **reader_data) reader->driver = &pcsc_drv; reader->slot_count = 1; reader->name = strdup(p); + priv->pcsc_ctx = pcsc_ctx; + priv->reader_name = strdup(p); r = _sc_add_reader(ctx, reader); if (r) { free(priv->reader_name); @@ -345,8 +347,6 @@ static int pcsc_init(struct sc_context *ctx, void **reader_data) slot->atr_len = 0; slot->drv_data = NULL; - priv->pcsc_ctx = pcsc_ctx; - priv->reader_name = strdup(p); while (*p++ != 0); } while (p < (reader_buf + reader_buf_size - 1)); free(reader_buf); diff --git a/src/libopensc/sc.c b/src/libopensc/sc.c index 7311bdd8..a56f22ec 100644 --- a/src/libopensc/sc.c +++ b/src/libopensc/sc.c @@ -28,7 +28,6 @@ #include #include #include -#include #ifdef VERSION const char *sc_version = VERSION; @@ -67,18 +66,6 @@ int sc_hex_to_bin(const char *in, u8 *out, size_t *outlen) return err; } -int _sc_add_reader(struct sc_context *ctx, struct sc_reader *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++; - - return 0; -} - struct sc_slot_info * _sc_get_slot_info(struct sc_reader *reader, int slot_id) { assert(reader != NULL); @@ -142,173 +129,6 @@ int sc_wait_for_card(struct sc_context *ctx, int reader, int timeout) } #endif -static void set_defaults(struct sc_context *ctx) -{ - ctx->debug = 0; - if (ctx->debug_file) - fclose(ctx->debug_file); - ctx->debug_file = NULL; - ctx->log_errors = 1; - ctx->error_file = stderr; -} - -static int load_parameters(struct sc_context *ctx, const char *app) -{ - scconf_block **blocks = NULL; - const char *val; - unsigned int i; - - blocks = scconf_find_blocks(ctx->conf, NULL, "app"); - for (i = 0; blocks[i]; i++) { - scconf_block *block = blocks[i]; - - if (!block->name && strcmp(block->name->data, app)) - continue; - val = scconf_find_value_first(block, "debug"); - sscanf(val, "%d", &ctx->debug); - val = scconf_find_value_first(block, "debug_file"); - if (ctx->debug_file) - fclose(ctx->debug_file); - if (strcmp(val, "stdout") == 0) - ctx->debug_file = fopen(val, "a"); - val = scconf_find_value_first(block, "error_file"); - if (ctx->error_file) - fclose(ctx->error_file); - if (strcmp(val, "stderr") != 0) - ctx->error_file = fopen(val, "a"); - } - free(blocks); - return 0; -} - -int sc_establish_context(struct sc_context **ctx_out, const char *app_name) -{ - const char *default_app = "default"; - struct sc_context *ctx; - int i, r; - - assert(ctx_out != NULL); - ctx = malloc(sizeof(struct sc_context)); - if (ctx == NULL) - return SC_ERROR_OUT_OF_MEMORY; - memset(ctx, 0, sizeof(struct sc_context)); - set_defaults(ctx); - ctx->app_name = app_name ? strdup(app_name) : strdup(default_app); - ctx->conf = scconf_init(OPENSC_CONF_PATH); - if (ctx->conf) { - r = scconf_parse(ctx->conf); - if (r < 1) { - scconf_deinit(ctx->conf); - ctx->conf = NULL; - } else { - load_parameters(ctx, default_app); - if (strcmp(default_app, ctx->app_name)) { - load_parameters(ctx, ctx->app_name); - } - } - } -#ifdef HAVE_PTHREAD - pthread_mutex_init(&ctx->mutex, NULL); -#endif - for (i = 0; i < SC_MAX_READER_DRIVERS+1; i++) - ctx->reader_drivers[i] = NULL; - i = 0; -#if 1 && defined(HAVE_LIBPCSCLITE) - ctx->reader_drivers[i++] = sc_get_pcsc_driver(); -#endif - i = 0; - while (ctx->reader_drivers[i] != NULL) { - ctx->reader_drivers[i]->ops->init(ctx, &ctx->reader_drv_data[i]); - i++; - } - - ctx->forced_driver = NULL; - for (i = 0; i < SC_MAX_CARD_DRIVERS+1; i++) - ctx->card_drivers[i] = NULL; - i = 0; -#if 1 - ctx->card_drivers[i++] = sc_get_setcos_driver(); -#endif -#if 1 - ctx->card_drivers[i++] = sc_get_miocos_driver(); -#endif -#if 1 - ctx->card_drivers[i++] = sc_get_flex_driver(); -#endif -#if 1 - ctx->card_drivers[i++] = sc_get_emv_driver(); -#endif -#if 1 - ctx->card_drivers[i++] = sc_get_tcos_driver(); -#endif -#if defined(HAVE_OPENSSL) - ctx->card_drivers[i++] = sc_get_gpk_driver(); -#endif -#if 1 - /* this should be last in line */ - ctx->card_drivers[i++] = sc_get_default_driver(); -#endif - - *ctx_out = ctx; - return 0; -} - -int sc_release_context(struct sc_context *ctx) -{ - int i; - - assert(ctx != NULL); - SC_FUNC_CALLED(ctx, 1); - for (i = 0; i < ctx->reader_count; i++) { - struct sc_reader *rdr = ctx->reader[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]; - - if (drv->ops->finish != NULL) - drv->ops->finish(ctx->reader_drv_data[i]); - } - ctx->debug_file = ctx->error_file = NULL; - if (ctx->conf) - scconf_deinit(ctx->conf); - free(ctx->app_name); - free(ctx); - return 0; -} - -int sc_set_card_driver(struct sc_context *ctx, const char *short_name) -{ - int i = 0, match = 0; - -#ifdef HAVE_PTHREAD - pthread_mutex_lock(&ctx->mutex); -#endif - if (short_name == NULL) { - ctx->forced_driver = NULL; - match = 1; - } else while (ctx->card_drivers[i] != NULL && i < SC_MAX_CARD_DRIVERS) { - const struct sc_card_driver *drv = ctx->card_drivers[i]; - - if (strcmp(short_name, drv->short_name) == 0) { - ctx->forced_driver = drv; - match = 1; - break; - } - i++; - } -#ifdef HAVE_PTHREAD - pthread_mutex_unlock(&ctx->mutex); -#endif - if (match == 0) - return SC_ERROR_OBJECT_NOT_FOUND; /* FIXME: invent error */ - return 0; -} - void sc_format_path(const char *str, struct sc_path *path) { int len = 0; @@ -353,19 +173,6 @@ int sc_append_path_id(struct sc_path *dest, const u8 *id, size_t idlen) return 0; } -int sc_get_cache_dir(struct sc_context *ctx, char *buf, size_t bufsize) -{ - char *homedir; - const char *cache_dir = ".eid/cache"; - - homedir = getenv("HOME"); - if (homedir == NULL) - return SC_ERROR_INTERNAL; - if (snprintf(buf, bufsize, "%s/%s", homedir, cache_dir) < 0) - return SC_ERROR_BUFFER_TOO_SMALL; - return 0; -} - const char *sc_strerror(int error) { const char *errors[] = {