/* * 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", NULL); for (i = 0; blocks[i]; i++) { const scconf_block *block = blocks[i]; const scconf_list *list; const char *s_internal = "internal", *val; if (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); del_drvs(&opts, 0); del_drvs(&opts, 1); *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; }