/* * Load a module - this will load the shared object, call * C_Initialize, and get the list of function pointers */ void * C_LoadModule(const char *mspec, CK_FUNCTION_LIST_PTR_PTR funcs) { sc_pkcs11_module_t *mod; CK_RV rv, (*c_get_function_list)(CK_FUNCTION_LIST_PTR_PTR); mod = calloc(1, sizeof(*mod)); mod->_magic = MAGIC; if (mspec == NULL) { free(mod); return NULL; } mod->handle = sc_dlopen(mspec); if (mod->handle == NULL) { fprintf(stderr, "sc_dlopen failed: %s\n", sc_dlerror()); goto failed; } /* Get the list of function pointers */ c_get_function_list = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) sc_dlsym(mod->handle, "C_GetFunctionList"); if (!c_get_function_list) goto failed; rv = c_get_function_list(funcs); if (rv == CKR_OK) return (void *) mod; else fprintf(stderr, "C_GetFunctionList failed %lx", rv); failed: C_UnloadModule((void *) mod); free(mod); return NULL; }
/** * 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 */ static void *load_dynamic_driver(sc_context_t *ctx, void **dll, const char *name) { const char *version, *libname; void *handle; void *(*modinit)(const char *) = NULL; void *(**tmodi)(const char *) = &modinit; const char *(*modversion)(void) = NULL; const char *(**tmodv)(void) = &modversion; if (dll == NULL) { sc_log(ctx, "No dll parameter specified"); return NULL; } if (name == NULL) { /* should not occur, but... */ sc_log(ctx, "No module specified"); return NULL; } libname = find_library(ctx, name); if (libname == NULL) return NULL; handle = sc_dlopen(libname); if (handle == NULL) { sc_log(ctx, "Module %s: cannot load %s library: %s", name, libname, sc_dlerror()); return NULL; } /* verify correctness of module */ *(void **)tmodi = sc_dlsym(handle, "sc_module_init"); *(void **)tmodv = sc_dlsym(handle, "sc_driver_version"); if (modinit == NULL || modversion == NULL) { sc_log(ctx, "dynamic library '%s' is not a OpenSC module",libname); sc_dlclose(handle); return NULL; } /* verify module version */ version = modversion(); /* XXX: We really need to have ABI version for each interface */ if (version == NULL || strncmp(version, PACKAGE_VERSION, strlen(PACKAGE_VERSION)) != 0) { sc_log(ctx, "dynamic library '%s': invalid module version", libname); sc_dlclose(handle); return NULL; } *dll = handle; sc_log(ctx, "successfully loaded card driver '%s'", name); return modinit(name); }
static int ctapi_load_module(sc_context_t *ctx, struct ctapi_global_private_data *gpriv, scconf_block *conf) { const char *val; struct ctapi_functions funcs; struct ctapi_module *mod; const scconf_list *list; void *dlh; int r, i, NumUnits; u8 cmd[5], rbuf[256], sad, dad; unsigned short lr; list = scconf_find_list(conf, "ports"); if (list == NULL) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "No ports configured.\n"); return -1; } val = conf->name->data; dlh = sc_dlopen(val); if (!dlh) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Unable to open shared library '%s': %s\n", val, sc_dlerror()); return -1; } funcs.CT_init = (CT_INIT_TYPE *) sc_dlsym(dlh, "CT_init"); if (!funcs.CT_init) goto symerr; funcs.CT_close = (CT_CLOSE_TYPE *) sc_dlsym(dlh, "CT_close"); if (!funcs.CT_close) goto symerr; funcs.CT_data = (CT_DATA_TYPE *) sc_dlsym(dlh, "CT_data"); if (!funcs.CT_data) goto symerr; mod = add_module(gpriv, val, dlh); for (; list != NULL; list = list->next) { int port; char namebuf[128]; char rv; sc_reader_t *reader; struct ctapi_private_data *priv; if (sscanf(list->data, "%d", &port) != 1) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Port '%s' is not a number.\n", list->data); continue; } rv = funcs.CT_init((unsigned short)mod->ctn_count, (unsigned short)port); if (rv) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "CT_init() failed with %d\n", rv); continue; } reader = calloc(1, sizeof(sc_reader_t)); priv = calloc(1, sizeof(struct ctapi_private_data)); if (!priv || !reader) { free(reader); free(priv); return SC_ERROR_OUT_OF_MEMORY; } reader->drv_data = priv; reader->ops = &ctapi_ops; reader->driver = &ctapi_drv; snprintf(namebuf, sizeof(namebuf), "CT-API %s, port %d", mod->name, port); reader->name = strdup(namebuf); priv->funcs = funcs; priv->ctn = mod->ctn_count; r = _sc_add_reader(ctx, reader); if (r) { funcs.CT_close((unsigned short)mod->ctn_count); free(priv); free(reader->name); free(reader); break; } /* Detect functional units of the reader according to CT-BCS spec version 1.0 (14.04.2004, http://www.teletrust.de/down/mct1-0_t4.zip) */ cmd[0] = CTBCS_CLA; cmd[1] = CTBCS_INS_STATUS; cmd[2] = CTBCS_P1_CT_KERNEL; cmd[3] = CTBCS_P2_STATUS_TFU; cmd[4] = 0x00; dad = 1; sad = 2; lr = 256; rv = priv->funcs.CT_data(priv->ctn, &dad, &sad, 5, cmd, &lr, rbuf); if (rv || (lr < 4) || (rbuf[lr-2] != 0x90)) { sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "Error getting status of terminal: %d, using defaults\n", rv); } if (rbuf[0] != CTBCS_P2_STATUS_TFU) { /* Number of slots might also detected by using CTBCS_P2_STATUS_ICC. If you think that's important please do it... ;) */ sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "Invalid data object returnd on CTBCS_P2_STATUS_TFU: 0x%x\n", rbuf[0]); } NumUnits = rbuf[1]; if (NumUnits + 4 > lr) { sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "Invalid data returnd: %d functional units, size %d\n", NumUnits, rv); } priv->ctapi_functional_units = 0; for(i = 0; i < NumUnits; i++) { switch(rbuf[i+2]) { case CTBCS_P1_INTERFACE1: case CTBCS_P1_INTERFACE2: case CTBCS_P1_INTERFACE3: case CTBCS_P1_INTERFACE4: case CTBCS_P1_INTERFACE5: case CTBCS_P1_INTERFACE6: case CTBCS_P1_INTERFACE7: case CTBCS_P1_INTERFACE8: case CTBCS_P1_INTERFACE9: case CTBCS_P1_INTERFACE10: case CTBCS_P1_INTERFACE11: case CTBCS_P1_INTERFACE12: case CTBCS_P1_INTERFACE13: case CTBCS_P1_INTERFACE14: /* Maybe a weak point here if multiple interfaces are present and not returned in the "canonical" order. This is not forbidden by the specs, but why should anyone want to do that? */ sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "Found slot id 0x%x\n", rbuf[i+2]); break; case CTBCS_P1_DISPLAY: priv->ctapi_functional_units |= CTAPI_FU_DISPLAY; sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "Display detected\n"); break; case CTBCS_P1_KEYPAD: priv->ctapi_functional_units |= CTAPI_FU_KEYBOARD; sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "Keypad detected\n"); break; case CTBCS_P1_PRINTER: priv->ctapi_functional_units |= CTAPI_FU_PRINTER; sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "Printer detected\n"); break; case CTBCS_P1_FINGERPRINT: case CTBCS_P1_VOICEPRINT: case CTBCS_P1_DSV: case CTBCS_P1_FACE_RECOGNITION: case CTBCS_P1_IRISSCAN: priv->ctapi_functional_units |= CTAPI_FU_BIOMETRIC; sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "Biometric sensor detected\n"); break; default: sc_debug(reader->ctx, SC_LOG_DEBUG_NORMAL, "Unknown functional unit 0x%x\n", rbuf[i+2]); } } /* CT-BCS does not define Keyboard/Display for each slot, so I assume those additional units can be used for each slot */ if (priv->ctapi_functional_units) { if (priv->ctapi_functional_units & CTAPI_FU_KEYBOARD) reader->capabilities |= SC_READER_CAP_PIN_PAD; if (priv->ctapi_functional_units & CTAPI_FU_DISPLAY) reader->capabilities |= SC_READER_CAP_DISPLAY; } ctapi_reset(reader); refresh_attributes(reader); mod->ctn_count++; } return 0; symerr: sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Unable to resolve CT-API symbols.\n"); sc_dlclose(dlh); return -1; }
static int sc_card_sm_load(struct sc_card *card, const char *module_path, const char *in_module) { struct sc_context *ctx = NULL; int rv = SC_ERROR_INTERNAL; char *module = NULL; #ifdef _WIN32 char temp_path[PATH_MAX]; size_t temp_len; const char path_delim = '\\'; char expanded_val[PATH_MAX]; DWORD expanded_len; #else const char path_delim = '/'; #endif if (card == NULL) { return SC_ERROR_INVALID_ARGUMENTS; } ctx = card->ctx; LOG_FUNC_CALLED(ctx); if (!in_module) return sc_card_sm_unload(card); #ifdef _WIN32 if (!module_path || strlen(module_path) == 0) { temp_len = PATH_MAX-1; rv = sc_ctx_win32_get_config_value(NULL, "SmDir", "Software\\OpenSC Project\\OpenSC", temp_path, &temp_len); if (rv == SC_SUCCESS) { temp_path[temp_len] = '\0'; module_path = temp_path; } } expanded_len = PATH_MAX; expanded_len = ExpandEnvironmentStringsA(module_path, expanded_val, expanded_len); if (0 < expanded_len && expanded_len < sizeof expanded_val) module_path = expanded_val; #endif sc_log(ctx, "SM module '%s' located in '%s'", in_module, module_path); if (module_path && strlen(module_path) > 0) { int sz = strlen(in_module) + strlen(module_path) + 3; module = malloc(sz); if (module) snprintf(module, sz, "%s%c%s", module_path, path_delim, in_module); } else { module = strdup(in_module); } if (!module) return SC_ERROR_OUT_OF_MEMORY; sc_log(ctx, "try to load SM module '%s'", module); do { struct sm_module_operations *mod_ops = &card->sm_ctx.module.ops; void *mod_handle; card->sm_ctx.module.handle = sc_dlopen(module); if (!card->sm_ctx.module.handle) { sc_log(ctx, "cannot open dynamic library '%s': %s", module, sc_dlerror()); break; } mod_handle = card->sm_ctx.module.handle; mod_ops->initialize = sc_dlsym(mod_handle, "initialize"); if (!mod_ops->initialize) { sc_log(ctx, "SM handler 'initialize' not exported: %s", sc_dlerror()); break; } mod_ops->get_apdus = sc_dlsym(mod_handle, "get_apdus"); if (!mod_ops->get_apdus) { sc_log(ctx, "SM handler 'get_apdus' not exported: %s", sc_dlerror()); break; } mod_ops->finalize = sc_dlsym(mod_handle, "finalize"); if (!mod_ops->finalize) sc_log(ctx, "SM handler 'finalize' not exported -- ignored"); mod_ops->module_init = sc_dlsym(mod_handle, "module_init"); if (!mod_ops->module_init) sc_log(ctx, "SM handler 'module_init' not exported -- ignored"); mod_ops->module_cleanup = sc_dlsym(mod_handle, "module_cleanup"); if (!mod_ops->module_cleanup) sc_log(ctx, "SM handler 'module_cleanup' not exported -- ignored"); mod_ops->test = sc_dlsym(mod_handle, "test"); if (mod_ops->test) sc_log(ctx, "SM handler 'test' not exported -- ignored"); rv = 0; break; } while(0); if (rv) sc_card_sm_unload(card); card->sm_ctx.sm_mode = SM_MODE_ACL; if (module) free(module); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, rv); }
/** * find library module for provided driver in configuration file * if not found assume library name equals to module name */ static const char *find_library(sc_context_t *ctx, const char *name) { 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], "card_driver", name); if (!blocks) continue; 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, SC_LOG_DEBUG_NORMAL, "warning: relative path to driver '%s' used", 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 */ static void *load_dynamic_driver(sc_context_t *ctx, void **dll, const char *name) { const char *version, *libname; void *handle; void *(*modinit)(const char *) = NULL; void *(**tmodi)(const char *) = &modinit; const char *(*modversion)(void) = NULL; const char *(**tmodv)(void) = &modversion; if (name == NULL) { /* should not occurr, but... */ sc_debug(ctx, SC_LOG_DEBUG_NORMAL,"No module specified",name); return NULL; } libname = find_library(ctx, name); if (libname == NULL) return NULL; handle = sc_dlopen(libname); if (handle == NULL) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Module %s: cannot load %s library: %s", name, libname, sc_dlerror()); return NULL; } /* verify correctness of module */ *(void **)tmodi = sc_dlsym(handle, "sc_module_init"); *(void **)tmodv = sc_dlsym(handle, "sc_driver_version"); if (modinit == NULL || modversion == NULL) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "dynamic library '%s' is not a OpenSC module",libname); sc_dlclose(handle); return NULL; } /* verify module version */ version = modversion(); /* XXX: We really need to have ABI version for each interface */ if (version == NULL || strncmp(version, PACKAGE_VERSION, strlen(PACKAGE_VERSION)) != 0) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL,"dynamic library '%s': invalid module version",libname); sc_dlclose(handle); return NULL; } *dll = handle; sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "successfully loaded card driver '%s'", name); return modinit(name); } static int load_card_driver_options(sc_context_t *ctx, struct sc_card_driver *driver) { scconf_block **blocks, *blk; int i; for (i = 0; ctx->conf_blocks[i]; i++) { blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i], "card_driver", driver->short_name); if (!blocks) continue; blk = blocks[0]; free(blocks); if (blk == NULL) continue; /* no options at the moment */ } return SC_SUCCESS; }
static int parse_emu_block(sc_pkcs15_card_t *p15card, scconf_block *conf) { sc_card_t *card = p15card->card; sc_context_t *ctx = card->ctx; sc_pkcs15emu_opt_t opts; void *handle = NULL; int (*init_func)(sc_pkcs15_card_t *); int (*init_func_ex)(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *); int r, force = 0; const char *driver, *module_name; driver = conf->name->data; init_func = NULL; init_func_ex = NULL; memset(&opts, 0, sizeof(opts)); opts.blk = conf; if (force != 0) opts.flags = SC_PKCS15EMU_FLAGS_NO_CHECK; module_name = scconf_get_str(conf, "module", builtin_name); if (!strcmp(module_name, "builtin")) { int i; /* This function is built into libopensc itself. * Look it up in the table of emulators */ module_name = driver; for (i = 0; builtin_emulators[i].name; i++) { if (!strcmp(builtin_emulators[i].name, module_name)) { init_func_ex = builtin_emulators[i].handler; break; } } } else { const char *(*get_version)(void); const char *name = NULL; void *address; sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Loading %s\n", module_name); /* try to open dynamic library */ handle = sc_dlopen(module_name); if (!handle) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "unable to open dynamic library '%s': %s\n", module_name, sc_dlerror()); return SC_ERROR_INTERNAL; } /* try to get version of the driver/api */ get_version = (const char *(*)(void)) sc_dlsym(handle, "sc_driver_version"); if (!get_version || strcmp(get_version(), "0.9.3") < 0) { /* no sc_driver_version function => assume old style * init function (note: this should later give an error */ /* get the init function name */ name = scconf_get_str(conf, "function", func_name); address = sc_dlsym(handle, name); if (address) init_func = (int (*)(sc_pkcs15_card_t *)) address; } else { name = scconf_get_str(conf, "function", exfunc_name); address = sc_dlsym(handle, name); if (address) init_func_ex = (int (*)(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *)) address; } } /* try to initialize the pkcs15 structures */ if (init_func_ex) r = init_func_ex(p15card, &opts); else if (init_func) r = init_func(p15card); else r = SC_ERROR_WRONG_CARD; if (r >= 0) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "%s succeeded, card bound\n", module_name); p15card->dll_handle = handle; } else { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "%s failed: %s\n", module_name, sc_strerror(r)); /* clear pkcs15 card */ sc_pkcs15_card_clear(p15card); if (handle) sc_dlclose(handle); } return r; }
static int sc_card_sm_load(struct sc_card *card, const char *module_path, const char *in_module) { struct sc_context *ctx = NULL; int rv = SC_ERROR_INTERNAL; char *module = NULL; #ifdef _WIN32 char temp_path[PATH_MAX]; int temp_len; long rc; HKEY hKey; const char path_delim = '\\'; #else const char path_delim = '/'; #endif assert(card != NULL); ctx = card->ctx; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); if (!in_module) return sc_card_sm_unload(card); #ifdef _WIN32 if (!module_path) { rc = RegOpenKeyExA( HKEY_CURRENT_USER, "Software\\OpenSC Project\\OpenSC", 0, KEY_QUERY_VALUE, &hKey ); if( rc == ERROR_SUCCESS ) { temp_len = PATH_MAX; rc = RegQueryValueExA( hKey, "SmDir", NULL, NULL, (LPBYTE) temp_path, &temp_len); if( (rc == ERROR_SUCCESS) && (temp_len < PATH_MAX) ) module_path = temp_path; RegCloseKey( hKey ); } } if (!module_path) { rc = RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\OpenSC Project\\OpenSC", 0, KEY_QUERY_VALUE, &hKey ); if( rc == ERROR_SUCCESS ) { temp_len = PATH_MAX; rc = RegQueryValueExA( hKey, "SmDir", NULL, NULL, (LPBYTE) temp_path, &temp_len); if(rc == ERROR_SUCCESS && temp_len < PATH_MAX) module_path = temp_path; RegCloseKey( hKey ); } } #endif sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "SM module '%s' located in '%s'", in_module, module_path); if (module_path) { int sz = strlen(in_module) + strlen(module_path) + 3; module = malloc(sz); if (module) snprintf(module, sz, "%s%c%s", module_path, path_delim, in_module); } else { module = strdup(in_module); } if (!module) return SC_ERROR_OUT_OF_MEMORY; sc_log(ctx, "try to load SM module '%s'", module); do { struct sm_module_operations *mod_ops = &card->sm_ctx.module.ops; void *mod_handle; card->sm_ctx.module.handle = sc_dlopen(module); if (!card->sm_ctx.module.handle) { sc_log(ctx, "cannot open dynamic library '%s': %s", module, sc_dlerror()); break; } mod_handle = card->sm_ctx.module.handle; mod_ops->initialize = sc_dlsym(mod_handle, "initialize"); if (!mod_ops->initialize) { sc_log(ctx, "SM handler 'initialize' not exported: %s", sc_dlerror()); break; } mod_ops->get_apdus = sc_dlsym(mod_handle, "get_apdus"); if (!mod_ops->get_apdus) { sc_log(ctx, "SM handler 'get_apdus' not exported: %s", sc_dlerror()); break; } mod_ops->finalize = sc_dlsym(mod_handle, "finalize"); if (!mod_ops->finalize) sc_log(ctx, "SM handler 'finalize' not exported -- ignored"); mod_ops->module_init = sc_dlsym(mod_handle, "module_init"); if (!mod_ops->module_init) sc_log(ctx, "SM handler 'module_init' not exported -- ignored"); mod_ops->module_cleanup = sc_dlsym(mod_handle, "module_cleanup"); if (!mod_ops->module_cleanup) sc_log(ctx, "SM handler 'module_cleanup' not exported -- ignored"); mod_ops->test = sc_dlsym(mod_handle, "test"); if (mod_ops->test) sc_log(ctx, "SM handler 'test' not exported -- ignored"); rv = 0; break; } while(0); if (rv) sc_card_sm_unload(card); card->sm_ctx.sm_mode = SM_MODE_ACL; if (module) free(module); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, rv); }