/src/opensc/src/libopensc/ctx.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * ctx.c: Context related functions |
3 | | * |
4 | | * Copyright (C) 2002 Juha Yrjölä <juha.yrjola@iki.fi> |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * This library is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with this library; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | #ifdef HAVE_CONFIG_H |
22 | | #include "config.h" |
23 | | #endif |
24 | | |
25 | | #include <stdio.h> |
26 | | #include <stdlib.h> |
27 | | #include <string.h> |
28 | | #include <assert.h> |
29 | | #include <errno.h> |
30 | | #include <sys/stat.h> |
31 | | #include <limits.h> |
32 | | |
33 | | #ifdef _WIN32 |
34 | | #include <windows.h> |
35 | | #include <winreg.h> |
36 | | #include <direct.h> |
37 | | #include <io.h> |
38 | | #endif |
39 | | |
40 | | #ifdef __APPLE__ |
41 | | #include <libproc.h> |
42 | | #endif |
43 | | |
44 | | #include "common/libscdl.h" |
45 | | #include "common/compat_strlcpy.h" |
46 | | #include "internal.h" |
47 | | #ifdef ENABLE_OPENSSL |
48 | | #include <openssl/crypto.h> |
49 | | #include "sc-ossl-compat.h" |
50 | | #endif |
51 | | |
52 | | |
53 | | static int ignored_reader(sc_context_t *ctx, sc_reader_t *reader) |
54 | 0 | { |
55 | 0 | if (ctx != NULL && reader != NULL && reader->name != NULL) { |
56 | 0 | size_t i; |
57 | 0 | const scconf_list *list; |
58 | |
|
59 | 0 | for (i = 0; ctx->conf_blocks[i]; i++) { |
60 | 0 | list = scconf_find_list(ctx->conf_blocks[i], "ignored_readers"); |
61 | 0 | while (list != NULL) { |
62 | 0 | if (strstr(reader->name, list->data) != NULL) { |
63 | 0 | sc_log(ctx, "Ignoring reader \'%s\' because of \'%s\'\n", |
64 | 0 | reader->name, list->data); |
65 | 0 | return 1; |
66 | 0 | } |
67 | 0 | list = list->next; |
68 | 0 | } |
69 | 0 | } |
70 | 0 | } |
71 | | |
72 | 0 | return 0; |
73 | 0 | } |
74 | | |
75 | | int _sc_add_reader(sc_context_t *ctx, sc_reader_t *reader) |
76 | 0 | { |
77 | 0 | if (reader == NULL || ignored_reader(ctx, reader)) { |
78 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
79 | 0 | } |
80 | 0 | reader->ctx = ctx; |
81 | 0 | list_append(&ctx->readers, reader); |
82 | 0 | return SC_SUCCESS; |
83 | 0 | } |
84 | | |
85 | | int _sc_delete_reader(sc_context_t *ctx, sc_reader_t *reader) |
86 | 15.4k | { |
87 | 15.4k | if (reader == NULL) { |
88 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
89 | 0 | } |
90 | 15.4k | if (reader->ops->release) |
91 | 15.4k | reader->ops->release(reader); |
92 | 15.4k | free(reader->name); |
93 | 15.4k | free(reader->vendor); |
94 | 15.4k | list_delete(&ctx->readers, reader); |
95 | 15.4k | free(reader); |
96 | 15.4k | return SC_SUCCESS; |
97 | 15.4k | } |
98 | | |
99 | | struct _sc_driver_entry { |
100 | | const char *name; |
101 | | void *(*func)(void); |
102 | | }; |
103 | | |
104 | | // clang-format off |
105 | | static const struct _sc_driver_entry internal_card_drivers[] = { |
106 | | /* The card handled by skeid shares the ATR with other cards running CardOS 5.4. |
107 | | * In order to prevent the cardos driver from matching skeid cards, skeid driver |
108 | | * precedes cardos and matches no other CardOS 5.4 card. */ |
109 | | { "skeid", (void *(*)(void)) sc_get_skeid_driver }, |
110 | | /* The card handled by dtrust shares the ATR with other cards running CardOS 5.4. |
111 | | * In order to prevent the cardos driver from matching dtrust cards, dtrust driver |
112 | | * precedes cardos and matches no other CardOS 5.4 card. */ |
113 | | { "dtrust", (void *(*)(void)) sc_get_dtrust_driver }, |
114 | | { "cardos", (void *(*)(void)) sc_get_cardos_driver }, |
115 | | { "gemsafeV1", (void *(*)(void)) sc_get_gemsafeV1_driver }, |
116 | | { "starcos", (void *(*)(void)) sc_get_starcos_driver }, |
117 | | { "tcos", (void *(*)(void)) sc_get_tcos_driver }, |
118 | | #ifdef ENABLE_OPENSSL |
119 | | { "oberthur", (void *(*)(void)) sc_get_oberthur_driver }, |
120 | | { "authentic", (void *(*)(void)) sc_get_authentic_driver }, |
121 | | { "iasecc", (void *(*)(void)) sc_get_iasecc_driver }, |
122 | | #endif |
123 | | { "belpic", (void *(*)(void)) sc_get_belpic_driver }, |
124 | | #ifdef ENABLE_OPENSSL |
125 | | { "entersafe",(void *(*)(void)) sc_get_entersafe_driver }, |
126 | | #ifdef ENABLE_SM |
127 | | { "epass2003",(void *(*)(void)) sc_get_epass2003_driver }, |
128 | | #endif |
129 | | #endif |
130 | | { "rutoken", (void *(*)(void)) sc_get_rutoken_driver }, |
131 | | { "rutoken_ecp",(void *(*)(void)) sc_get_rtecp_driver }, |
132 | | { "myeid", (void *(*)(void)) sc_get_myeid_driver }, |
133 | | #if defined(ENABLE_OPENSSL) && defined(ENABLE_SM) |
134 | | { "dnie", (void *(*)(void)) sc_get_dnie_driver }, |
135 | | #endif |
136 | | { "masktech", (void *(*)(void)) sc_get_masktech_driver }, |
137 | | { "idprime", (void *(*)(void)) sc_get_idprime_driver }, |
138 | | #if defined(ENABLE_SM) && defined(ENABLE_OPENPACE) |
139 | | { "edo", (void *(*)(void)) sc_get_edo_driver }, |
140 | | #endif |
141 | | |
142 | | /* Here should be placed drivers that need some APDU transactions in the |
143 | | * driver's `match_card()` function. */ |
144 | | { "esteid2018", (void *(*)(void)) sc_get_esteid2018_driver }, |
145 | | { "esteid2025", (void *(*)(void)) sc_get_esteid2025_driver }, |
146 | | { "coolkey", (void *(*)(void)) sc_get_coolkey_driver }, |
147 | | /* MUSCLE card applet returns 9000 on whatever AID is selected, see |
148 | | * https://github.com/JavaCardOS/MuscleCard-Applet/blob/master/musclecard/src/com/musclecard/CardEdge/CardEdge.java#L326 |
149 | | * put the muscle driver first to cope with this bug. */ |
150 | | { "muscle", (void *(*)(void)) sc_get_muscle_driver }, |
151 | | { "sc-hsm", (void *(*)(void)) sc_get_sc_hsm_driver }, |
152 | | { "setcos", (void *(*)(void)) sc_get_setcos_driver }, |
153 | | { "PIV-II", (void *(*)(void)) sc_get_piv_driver }, |
154 | | { "cac", (void *(*)(void)) sc_get_cac_driver }, |
155 | | { "itacns", (void *(*)(void)) sc_get_itacns_driver }, |
156 | | { "isoApplet", (void *(*)(void)) sc_get_isoApplet_driver }, |
157 | | #ifdef ENABLE_ZLIB |
158 | | { "gids", (void *(*)(void)) sc_get_gids_driver }, |
159 | | #endif |
160 | | { "openpgp", (void *(*)(void)) sc_get_openpgp_driver }, |
161 | | { "jpki", (void *(*)(void)) sc_get_jpki_driver }, |
162 | | { "npa", (void *(*)(void)) sc_get_npa_driver }, |
163 | | { "cac1", (void *(*)(void)) sc_get_cac1_driver }, |
164 | | { "nqapplet", (void *(*)(void)) sc_get_nqApplet_driver }, |
165 | | #if defined(ENABLE_SM) && defined(ENABLE_OPENPACE) |
166 | | { "eOI", (void *(*)(void)) sc_get_eoi_driver }, |
167 | | #endif |
168 | | /* The default driver should be last, as it handles all the |
169 | | * unrecognized cards. */ |
170 | | { "default", (void *(*)(void)) sc_get_default_driver }, |
171 | | { NULL, NULL } |
172 | | }; |
173 | | |
174 | | static const struct _sc_driver_entry old_card_drivers[] = { |
175 | | { "asepcos", (void *(*)(void)) sc_get_asepcos_driver }, |
176 | | { "atrust-acos",(void *(*)(void)) sc_get_atrust_acos_driver }, |
177 | | { "cyberflex", (void *(*)(void)) sc_get_cyberflex_driver }, |
178 | | { "flex", (void *(*)(void)) sc_get_cryptoflex_driver }, |
179 | | { "mcrd", (void *(*)(void)) sc_get_mcrd_driver }, |
180 | | { NULL, NULL } |
181 | | }; |
182 | | // clang-format on |
183 | | |
184 | | struct _sc_ctx_options { |
185 | | struct _sc_driver_entry cdrv[SC_MAX_CARD_DRIVERS]; |
186 | | int ccount; |
187 | | }; |
188 | | |
189 | | |
190 | | int |
191 | | sc_ctx_win32_get_config_value(const char *name_env, |
192 | | const char *name_reg, const char *name_key, |
193 | | void *out, size_t *out_len) |
194 | 0 | { |
195 | | #ifdef _WIN32 |
196 | | long rc; |
197 | | HKEY hKey; |
198 | | |
199 | | if (!out || !out_len) |
200 | | return SC_ERROR_INVALID_ARGUMENTS; |
201 | | |
202 | | if (name_env) { |
203 | | char *value = getenv(name_env); |
204 | | if (value) { |
205 | | if (strlen(value) > *out_len) |
206 | | return SC_ERROR_NOT_ENOUGH_MEMORY; |
207 | | memcpy(out, value, strlen(value)); |
208 | | *out_len = strlen(value); |
209 | | return SC_SUCCESS; |
210 | | } |
211 | | } |
212 | | |
213 | | if (!name_reg) |
214 | | return SC_ERROR_INVALID_ARGUMENTS; |
215 | | |
216 | | if (!name_key) |
217 | | name_key = "Software\\OpenSC Project\\OpenSC"; |
218 | | |
219 | | rc = RegOpenKeyExA(HKEY_CURRENT_USER, name_key, 0, KEY_QUERY_VALUE, &hKey); |
220 | | if (rc == ERROR_SUCCESS) { |
221 | | DWORD len = *out_len; |
222 | | rc = RegQueryValueEx(hKey, name_reg, NULL, NULL, out, &len); |
223 | | RegCloseKey(hKey); |
224 | | if (rc == ERROR_SUCCESS) { |
225 | | *out_len = len; |
226 | | return SC_SUCCESS; |
227 | | } |
228 | | } |
229 | | |
230 | | rc = RegOpenKeyExA(HKEY_LOCAL_MACHINE, name_key, 0, KEY_QUERY_VALUE, &hKey); |
231 | | if (rc == ERROR_SUCCESS) { |
232 | | DWORD len = *out_len; |
233 | | rc = RegQueryValueEx(hKey, name_reg, NULL, NULL, out, &len); |
234 | | RegCloseKey(hKey); |
235 | | if (rc == ERROR_SUCCESS) { |
236 | | *out_len = len; |
237 | | return SC_SUCCESS; |
238 | | } |
239 | | } |
240 | | |
241 | | return SC_ERROR_OBJECT_NOT_FOUND; |
242 | | #else |
243 | 0 | return SC_ERROR_NOT_SUPPORTED; |
244 | 0 | #endif |
245 | 0 | } |
246 | | |
247 | | |
248 | | /* Simclist helper to locate readers by name */ |
249 | 0 | static int reader_list_seeker(const void *el, const void *key) { |
250 | 0 | const struct sc_reader *reader = (struct sc_reader *)el; |
251 | 0 | if ((el == NULL) || (key == NULL)) |
252 | 0 | return 0; |
253 | 0 | if (strcmp(reader->name, (char*)key) == 0) |
254 | 0 | return 1; |
255 | 0 | return 0; |
256 | 0 | } |
257 | | |
258 | | static void del_drvs(struct _sc_ctx_options *opts) |
259 | 15.4k | { |
260 | 15.4k | struct _sc_driver_entry *lst; |
261 | 15.4k | int *cp, i; |
262 | | |
263 | 15.4k | lst = opts->cdrv; |
264 | 15.4k | cp = &opts->ccount; |
265 | | |
266 | 556k | for (i = 0; i < *cp; i++) { |
267 | 541k | free((void *)lst[i].name); |
268 | 541k | } |
269 | 15.4k | *cp = 0; |
270 | 15.4k | } |
271 | | |
272 | | static void add_drv(struct _sc_ctx_options *opts, const char *name) |
273 | 541k | { |
274 | 541k | struct _sc_driver_entry *lst; |
275 | 541k | int *cp, max, i; |
276 | | |
277 | 541k | lst = opts->cdrv; |
278 | 541k | cp = &opts->ccount; |
279 | 541k | max = SC_MAX_CARD_DRIVERS; |
280 | 541k | if (*cp == max) /* No space for more drivers... */ |
281 | 0 | return; |
282 | 9.74M | for (i = 0; i < *cp; i++) |
283 | 9.20M | if (strcmp(name, lst[i].name) == 0) |
284 | 0 | return; |
285 | 541k | lst[*cp].name = strdup(name); |
286 | | |
287 | 541k | *cp = *cp + 1; |
288 | 541k | } |
289 | | |
290 | | static void add_internal_drvs(struct _sc_ctx_options *opts) |
291 | 15.4k | { |
292 | 15.4k | const struct _sc_driver_entry *lst; |
293 | 15.4k | int i; |
294 | | |
295 | 15.4k | lst = internal_card_drivers; |
296 | 15.4k | i = 0; |
297 | 556k | while (lst[i].name != NULL) { |
298 | 541k | add_drv(opts, lst[i].name); |
299 | 541k | i++; |
300 | 541k | } |
301 | 15.4k | } |
302 | | |
303 | | static void add_old_drvs(struct _sc_ctx_options *opts) |
304 | 0 | { |
305 | 0 | const struct _sc_driver_entry *lst; |
306 | 0 | int i; |
307 | |
|
308 | 0 | lst = old_card_drivers; |
309 | 0 | i = 0; |
310 | 0 | while (lst[i].name != NULL) { |
311 | 0 | add_drv(opts, lst[i].name); |
312 | 0 | i++; |
313 | 0 | } |
314 | 0 | } |
315 | | |
316 | | static void set_defaults(sc_context_t *ctx, struct _sc_ctx_options *opts) |
317 | 15.4k | { |
318 | 15.4k | ctx->debug = 0; |
319 | 15.4k | if (ctx->debug_file && (ctx->debug_file != stderr && ctx->debug_file != stdout)) |
320 | 0 | fclose(ctx->debug_file); |
321 | 15.4k | ctx->debug_file = stderr; |
322 | 15.4k | ctx->flags = 0; |
323 | 15.4k | ctx->forced_driver = NULL; |
324 | 15.4k | add_internal_drvs(opts); |
325 | 15.4k | } |
326 | | |
327 | | /* In Windows, file handles can not be shared between DLL-s, |
328 | | * each DLL has a separate file handle table. Thus tools and utilities |
329 | | * can not set the file handle themselves when -v is specified on command line. |
330 | | */ |
331 | | int sc_ctx_log_to_file(sc_context_t *ctx, const char* filename) |
332 | 0 | { |
333 | | /* Close any existing handles */ |
334 | 0 | if (ctx->debug_file && (ctx->debug_file != stderr && ctx->debug_file != stdout)) { |
335 | 0 | fclose(ctx->debug_file); |
336 | 0 | ctx->debug_file = NULL; |
337 | 0 | } |
338 | |
|
339 | 0 | if (!ctx->debug_filename) { |
340 | 0 | if (!filename) |
341 | 0 | filename = "stderr"; |
342 | 0 | ctx->debug_filename = strdup(filename); |
343 | 0 | } |
344 | |
|
345 | 0 | if (!filename) |
346 | 0 | return SC_SUCCESS; |
347 | | |
348 | | /* Handle special names */ |
349 | 0 | if (!strcmp(filename, "stdout")) |
350 | 0 | ctx->debug_file = stdout; |
351 | 0 | else if (!strcmp(filename, "stderr")) |
352 | 0 | ctx->debug_file = stderr; |
353 | 0 | else { |
354 | 0 | ctx->debug_file = fopen(filename, "a"); |
355 | 0 | if (ctx->debug_file == NULL) |
356 | 0 | return SC_ERROR_INTERNAL; |
357 | 0 | } |
358 | 0 | return SC_SUCCESS; |
359 | 0 | } |
360 | | |
361 | | static void |
362 | | set_drivers(struct _sc_ctx_options *opts, const scconf_list *list) |
363 | 0 | { |
364 | 0 | const char *s_internal = "internal", *s_old = "old"; |
365 | 0 | if (list != NULL) |
366 | 0 | del_drvs(opts); |
367 | 0 | while (list != NULL) { |
368 | 0 | if (strcmp(list->data, s_internal) == 0) |
369 | 0 | add_internal_drvs(opts); |
370 | 0 | else if (strcmp(list->data, s_old) == 0) |
371 | 0 | add_old_drvs(opts); |
372 | 0 | else |
373 | 0 | add_drv(opts, list->data); |
374 | 0 | list = list->next; |
375 | 0 | } |
376 | 0 | } |
377 | | |
378 | | static int |
379 | | load_parameters(sc_context_t *ctx, scconf_block *block, struct _sc_ctx_options *opts) |
380 | 0 | { |
381 | 0 | int err = 0; |
382 | 0 | const scconf_list *list; |
383 | 0 | const char *val; |
384 | 0 | int debug; |
385 | 0 | const char *disable_hw_pkcs1_padding; |
386 | | #ifdef _WIN32 |
387 | | char expanded_val[PATH_MAX]; |
388 | | DWORD expanded_len; |
389 | | #endif |
390 | |
|
391 | 0 | debug = scconf_get_int(block, "debug", ctx->debug); |
392 | 0 | if (debug > ctx->debug) |
393 | 0 | ctx->debug = debug; |
394 | |
|
395 | 0 | val = scconf_get_str(block, "debug_file", NULL); |
396 | 0 | if (val) { |
397 | | #ifdef _WIN32 |
398 | | expanded_len = PATH_MAX; |
399 | | expanded_len = ExpandEnvironmentStringsA(val, expanded_val, expanded_len); |
400 | | if (0 < expanded_len && expanded_len < sizeof expanded_val) |
401 | | val = expanded_val; |
402 | | #endif |
403 | 0 | sc_ctx_log_to_file(ctx, val); |
404 | 0 | } |
405 | 0 | else if (ctx->debug) { |
406 | 0 | sc_ctx_log_to_file(ctx, NULL); |
407 | 0 | } |
408 | |
|
409 | 0 | if (scconf_get_bool (block, "disable_popups", |
410 | 0 | ctx->flags & SC_CTX_FLAG_DISABLE_POPUPS)) |
411 | 0 | ctx->flags |= SC_CTX_FLAG_DISABLE_POPUPS; |
412 | |
|
413 | 0 | if (scconf_get_bool (block, "disable_colors", |
414 | 0 | ctx->flags & SC_CTX_FLAG_DISABLE_COLORS)) |
415 | 0 | ctx->flags |= SC_CTX_FLAG_DISABLE_COLORS; |
416 | |
|
417 | 0 | if (scconf_get_bool (block, "enable_default_driver", |
418 | 0 | ctx->flags & SC_CTX_FLAG_ENABLE_DEFAULT_DRIVER)) |
419 | 0 | ctx->flags |= SC_CTX_FLAG_ENABLE_DEFAULT_DRIVER; |
420 | |
|
421 | 0 | list = scconf_find_list(block, "card_drivers"); |
422 | 0 | set_drivers(opts, list); |
423 | | |
424 | | /* Disable PKCS#1 v1.5 type 2 (for decryption) depadding on card by default */ |
425 | 0 | disable_hw_pkcs1_padding = "decipher"; |
426 | 0 | ctx->disable_hw_pkcs1_padding = SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_02; |
427 | 0 | disable_hw_pkcs1_padding = scconf_get_str(block, "disable_hw_pkcs1_padding", disable_hw_pkcs1_padding); |
428 | 0 | if (0 == strcmp(disable_hw_pkcs1_padding, "no")) { |
429 | 0 | ctx->disable_hw_pkcs1_padding = 0; |
430 | 0 | } else if (0 == strcmp(disable_hw_pkcs1_padding, "sign")) { |
431 | 0 | ctx->disable_hw_pkcs1_padding = SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_01; |
432 | 0 | } else if (0 == strcmp(disable_hw_pkcs1_padding, "decipher")) { |
433 | 0 | ctx->disable_hw_pkcs1_padding = SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_02; |
434 | 0 | } else if (0 == strcmp(disable_hw_pkcs1_padding, "both")) { |
435 | 0 | ctx->disable_hw_pkcs1_padding = SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_01 | SC_ALGORITHM_RSA_PAD_PKCS1_TYPE_02; |
436 | 0 | } |
437 | |
|
438 | 0 | return err; |
439 | 0 | } |
440 | | |
441 | | |
442 | | /** |
443 | | * find library module for provided driver in configuration file |
444 | | * if not found assume library name equals to module name |
445 | | */ |
446 | | static const char *find_library(sc_context_t *ctx, const char *name) |
447 | 0 | { |
448 | 0 | int i, log_warning; |
449 | 0 | const char *libname = NULL; |
450 | 0 | scconf_block **blocks, *blk; |
451 | |
|
452 | 0 | for (i = 0; ctx->conf_blocks[i]; i++) { |
453 | 0 | blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i], "card_driver", name); |
454 | 0 | if (!blocks) |
455 | 0 | continue; |
456 | 0 | blk = blocks[0]; |
457 | 0 | free(blocks); |
458 | 0 | if (blk == NULL) |
459 | 0 | continue; |
460 | 0 | libname = scconf_get_str(blk, "module", name); |
461 | | #ifdef _WIN32 |
462 | | log_warning = libname && libname[0] != '\\'; |
463 | | #else |
464 | 0 | log_warning = libname && libname[0] != '/'; |
465 | 0 | #endif |
466 | 0 | if (log_warning) |
467 | 0 | sc_log(ctx, "warning: relative path to driver '%s' used", libname); |
468 | 0 | break; |
469 | 0 | } |
470 | |
|
471 | 0 | return libname; |
472 | 0 | } |
473 | | |
474 | | /** |
475 | | * load card/reader driver modules |
476 | | * Every module should contain a function " void * sc_module_init(char *) " |
477 | | * that returns a pointer to the function _sc_get_xxxx_driver() |
478 | | * used to initialize static modules |
479 | | * Also, an exported "char *sc_module_version" variable should exist in module |
480 | | */ |
481 | | static void *load_dynamic_driver(sc_context_t *ctx, void **dll, const char *name) |
482 | 0 | { |
483 | 0 | const char *version, *libname; |
484 | 0 | void *handle; |
485 | 0 | void *(*modinit)(const char *) = NULL; |
486 | 0 | void *(**tmodi)(const char *) = &modinit; |
487 | 0 | const char *(*modversion)(void) = NULL; |
488 | 0 | const char *(**tmodv)(void) = &modversion; |
489 | |
|
490 | 0 | if (dll == NULL) { |
491 | 0 | sc_log(ctx, "No dll parameter specified"); |
492 | 0 | return NULL; |
493 | 0 | } |
494 | 0 | if (name == NULL) { /* should not occur, but... */ |
495 | 0 | sc_log(ctx, "No module specified"); |
496 | 0 | return NULL; |
497 | 0 | } |
498 | 0 | libname = find_library(ctx, name); |
499 | 0 | if (libname == NULL) |
500 | 0 | return NULL; |
501 | 0 | handle = sc_dlopen(libname); |
502 | 0 | if (handle == NULL) { |
503 | 0 | sc_log(ctx, "Module %s: cannot load %s library: %s", name, libname, sc_dlerror()); |
504 | 0 | return NULL; |
505 | 0 | } |
506 | | |
507 | | /* verify correctness of module */ |
508 | 0 | *(void **)tmodi = sc_dlsym(handle, "sc_module_init"); |
509 | 0 | *(void **)tmodv = sc_dlsym(handle, "sc_driver_version"); |
510 | 0 | if (modinit == NULL || modversion == NULL) { |
511 | 0 | sc_log(ctx, "dynamic library '%s' is not a OpenSC module",libname); |
512 | 0 | sc_dlclose(handle); |
513 | 0 | return NULL; |
514 | 0 | } |
515 | | /* verify module version */ |
516 | 0 | version = modversion(); |
517 | | /* XXX: We really need to have ABI version for each interface */ |
518 | 0 | if (version == NULL || strncmp(version, PACKAGE_VERSION, strlen(PACKAGE_VERSION)) != 0) { |
519 | 0 | sc_log(ctx, "dynamic library '%s': invalid module version", libname); |
520 | 0 | sc_dlclose(handle); |
521 | 0 | return NULL; |
522 | 0 | } |
523 | | |
524 | 0 | *dll = handle; |
525 | 0 | sc_log(ctx, "successfully loaded card driver '%s'", name); |
526 | 0 | return modinit(name); |
527 | 0 | } |
528 | | |
529 | | static int load_card_driver_options(sc_context_t *ctx, |
530 | | struct sc_card_driver *driver) |
531 | 541k | { |
532 | 541k | scconf_block **blocks, *blk; |
533 | 541k | int i; |
534 | | |
535 | 541k | for (i = 0; ctx->conf_blocks[i]; i++) { |
536 | 0 | blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i], |
537 | 0 | "card_driver", driver->short_name); |
538 | 0 | if (!blocks) |
539 | 0 | continue; |
540 | 0 | blk = blocks[0]; |
541 | 0 | free(blocks); |
542 | |
|
543 | 0 | if (blk == NULL) |
544 | 0 | continue; |
545 | | |
546 | | /* no options at the moment */ |
547 | 0 | } |
548 | 541k | return SC_SUCCESS; |
549 | 541k | } |
550 | | |
551 | | static int load_card_drivers(sc_context_t *ctx, struct _sc_ctx_options *opts) |
552 | 15.4k | { |
553 | 15.4k | const struct _sc_driver_entry *ent; |
554 | 15.4k | int drv_count; |
555 | 15.4k | int i; |
556 | | |
557 | 15.4k | for (drv_count = 0; ctx->card_drivers[drv_count] != NULL; drv_count++) |
558 | 0 | ; |
559 | | |
560 | 556k | for (i = 0; i < opts->ccount; i++) { |
561 | 541k | struct sc_card_driver *(*func)(void) = NULL; |
562 | 541k | struct sc_card_driver *(**tfunc)(void) = &func; |
563 | 541k | void *dll = NULL; |
564 | 541k | int j; |
565 | | |
566 | 541k | if (drv_count >= SC_MAX_CARD_DRIVERS - 1) { |
567 | 0 | sc_log(ctx, "Not more then %i card drivers allowed.", SC_MAX_CARD_DRIVERS); |
568 | 0 | break; |
569 | 0 | } |
570 | | |
571 | 541k | ent = &opts->cdrv[i]; |
572 | 9.74M | for (j = 0; internal_card_drivers[j].name != NULL; j++) { |
573 | 9.74M | if (strcmp(ent->name, internal_card_drivers[j].name) == 0) { |
574 | 541k | func = (struct sc_card_driver *(*)(void)) internal_card_drivers[j].func; |
575 | 541k | break; |
576 | 541k | } |
577 | 9.74M | } |
578 | 541k | if (func == NULL) { |
579 | 0 | for (j = 0; old_card_drivers[j].name != NULL; j++) { |
580 | 0 | if (strcmp(ent->name, old_card_drivers[j].name) == 0) { |
581 | 0 | func = (struct sc_card_driver *(*)(void)) old_card_drivers[j].func; |
582 | 0 | break; |
583 | 0 | } |
584 | 0 | } |
585 | 0 | } |
586 | | /* if not initialized assume external module */ |
587 | 541k | if (func == NULL) |
588 | 0 | *(void **)(tfunc) = load_dynamic_driver(ctx, &dll, ent->name); |
589 | | /* if still null, assume driver not found */ |
590 | 541k | if (func == NULL) { |
591 | 0 | sc_log(ctx, "Unable to load '%s'.", ent->name); |
592 | 0 | if (dll) |
593 | 0 | sc_dlclose(dll); |
594 | 0 | continue; |
595 | 0 | } |
596 | | |
597 | 541k | ctx->card_drivers[drv_count] = func(); |
598 | 541k | if (ctx->card_drivers[drv_count] == NULL) { |
599 | 0 | sc_log(ctx, "Driver '%s' not available.", ent->name); |
600 | 0 | continue; |
601 | 0 | } |
602 | | |
603 | 541k | ctx->card_drivers[drv_count]->dll = dll; |
604 | 541k | ctx->card_drivers[drv_count]->atr_map = NULL; |
605 | 541k | ctx->card_drivers[drv_count]->natrs = 0; |
606 | | |
607 | 541k | load_card_driver_options(ctx, ctx->card_drivers[drv_count]); |
608 | | |
609 | | /* Ensure that the list is always terminated by NULL */ |
610 | 541k | ctx->card_drivers[drv_count + 1] = NULL; |
611 | | |
612 | 541k | drv_count++; |
613 | 541k | } |
614 | 15.4k | return SC_SUCCESS; |
615 | 15.4k | } |
616 | | |
617 | | static int load_card_atrs(sc_context_t *ctx) |
618 | 15.4k | { |
619 | 15.4k | struct sc_card_driver *driver; |
620 | 15.4k | scconf_block **blocks; |
621 | 15.4k | int i, j, k; |
622 | | |
623 | 15.4k | for (i = 0; ctx->conf_blocks[i] != NULL; i++) { |
624 | 0 | blocks = scconf_find_blocks(ctx->conf, ctx->conf_blocks[i], "card_atr", NULL); |
625 | 0 | if (!blocks) |
626 | 0 | continue; |
627 | 0 | for (j = 0; blocks[j] != NULL; j++) { |
628 | 0 | scconf_block *b = blocks[j]; |
629 | 0 | char *atr = b->name->data; |
630 | 0 | const scconf_list *list; |
631 | 0 | struct sc_atr_table t; |
632 | 0 | const char *dname; |
633 | |
|
634 | 0 | driver = NULL; |
635 | |
|
636 | 0 | if (strlen(atr) < 4) |
637 | 0 | continue; |
638 | | |
639 | | /* The interesting part. If there's no card |
640 | | * driver assigned for the ATR, add it to |
641 | | * the default driver. This will reduce the |
642 | | * amount of code required to process things |
643 | | * related to card_atr blocks in situations, |
644 | | * where the code is not exactly related to |
645 | | * card driver settings, but for example |
646 | | * forcing a protocol at the reader driver. |
647 | | */ |
648 | 0 | dname = scconf_get_str(b, "driver", "default"); |
649 | | |
650 | | /* Find the card driver structure according to dname */ |
651 | 0 | for (k = 0; ctx->card_drivers[k] != NULL; k++) { |
652 | 0 | driver = ctx->card_drivers[k]; |
653 | 0 | if (!strcmp(dname, driver->short_name)) |
654 | 0 | break; |
655 | 0 | driver = NULL; |
656 | 0 | } |
657 | |
|
658 | 0 | if (!driver) |
659 | 0 | continue; |
660 | | |
661 | 0 | memset(&t, 0, sizeof(struct sc_atr_table)); |
662 | 0 | t.atr = atr; |
663 | 0 | t.atrmask = (char *) scconf_get_str(b, "atrmask", NULL); |
664 | 0 | t.name = (char *) scconf_get_str(b, "name", NULL); |
665 | 0 | t.type = scconf_get_int(b, "type", SC_CARD_TYPE_UNKNOWN); |
666 | 0 | list = scconf_find_list(b, "flags"); |
667 | 0 | while (list != NULL) { |
668 | 0 | unsigned int flags = 0; |
669 | |
|
670 | 0 | if (!list->data) { |
671 | 0 | list = list->next; |
672 | 0 | continue; |
673 | 0 | } |
674 | | |
675 | 0 | if (!strcmp(list->data, "rng")) |
676 | 0 | flags = SC_CARD_FLAG_RNG; |
677 | 0 | else if (!strcmp(list->data, "keep_alive")) |
678 | 0 | flags = SC_CARD_FLAG_KEEP_ALIVE; |
679 | 0 | else if (sscanf(list->data, "%x", &flags) != 1) |
680 | 0 | flags = 0; |
681 | |
|
682 | 0 | t.flags |= flags; |
683 | 0 | list = list->next; |
684 | 0 | } |
685 | 0 | t.card_atr = b; |
686 | 0 | _sc_add_atr(ctx, driver, &t); |
687 | 0 | } |
688 | 0 | free(blocks); |
689 | 0 | } |
690 | 15.4k | return SC_SUCCESS; |
691 | 15.4k | } |
692 | | |
693 | | static void process_config_file(sc_context_t *ctx, struct _sc_ctx_options *opts) |
694 | 15.4k | { |
695 | 15.4k | int i, r, count = 0; |
696 | 15.4k | scconf_block **blocks; |
697 | 15.4k | const char *conf_path = NULL; |
698 | 15.4k | const char *debug = NULL; |
699 | | #ifdef _WIN32 |
700 | | char temp_path[PATH_MAX]; |
701 | | size_t temp_len; |
702 | | #endif |
703 | | |
704 | | /* Takes effect even when no config around */ |
705 | 15.4k | debug = getenv("OPENSC_DEBUG"); |
706 | 15.4k | if (debug) |
707 | 0 | ctx->debug = atoi(debug); |
708 | | |
709 | 15.4k | memset(ctx->conf_blocks, 0, sizeof(ctx->conf_blocks)); |
710 | | #ifdef _WIN32 |
711 | | temp_len = PATH_MAX-1; |
712 | | r = sc_ctx_win32_get_config_value("OPENSC_CONF", "ConfigFile", "Software\\OpenSC Project\\OpenSC", |
713 | | temp_path, &temp_len); |
714 | | if (r) { |
715 | | sc_log(ctx, "process_config_file doesn't find opensc config file. Please set the registry key."); |
716 | | return; |
717 | | } |
718 | | temp_path[temp_len] = '\0'; |
719 | | conf_path = temp_path; |
720 | | #else |
721 | 15.4k | conf_path = getenv("OPENSC_CONF"); |
722 | 15.4k | if (!conf_path) |
723 | 15.4k | conf_path = OPENSC_CONF_PATH; |
724 | 15.4k | #endif |
725 | 15.4k | ctx->conf = scconf_new(conf_path); |
726 | 15.4k | if (ctx->conf == NULL) |
727 | 0 | return; |
728 | 15.4k | r = scconf_parse(ctx->conf); |
729 | | #ifdef OPENSC_CONFIG_STRING |
730 | | /* Parse the string if config file didn't exist */ |
731 | | if (r < 0) |
732 | | r = scconf_parse_string(ctx->conf, OPENSC_CONFIG_STRING); |
733 | | #endif |
734 | 15.4k | if (r < 1) { |
735 | | /* A negative return value means the config file isn't |
736 | | * there, which is not an error. Nevertheless log this |
737 | | * fact. */ |
738 | 15.4k | if (r < 0) |
739 | 15.4k | sc_log(ctx, "scconf_parse failed: %s", ctx->conf->errmsg); |
740 | 0 | else |
741 | 0 | sc_log(ctx, "scconf_parse failed: %s", ctx->conf->errmsg); |
742 | 15.4k | scconf_free(ctx->conf); |
743 | 15.4k | ctx->conf = NULL; |
744 | 15.4k | return; |
745 | 15.4k | } |
746 | | /* needs to be after the log file is known */ |
747 | 0 | sc_log(ctx, "Used configuration file '%s'", conf_path); |
748 | 0 | blocks = scconf_find_blocks(ctx->conf, NULL, "app", ctx->exe_path); |
749 | 0 | if (blocks && blocks[0]) |
750 | 0 | ctx->conf_blocks[count++] = blocks[0]; |
751 | 0 | free(blocks); |
752 | 0 | blocks = scconf_find_blocks(ctx->conf, NULL, "app", ctx->app_name); |
753 | 0 | if (blocks && blocks[0]) |
754 | 0 | ctx->conf_blocks[count++] = blocks[0]; |
755 | 0 | free(blocks); |
756 | 0 | if (strcmp(ctx->app_name, "default") != 0) { |
757 | 0 | blocks = scconf_find_blocks(ctx->conf, NULL, "app", "default"); |
758 | 0 | if (blocks && blocks[0]) |
759 | 0 | ctx->conf_blocks[count] = blocks[0]; |
760 | 0 | free(blocks); |
761 | 0 | } |
762 | | /* Above we add 3 blocks at most, but conf_blocks has 4 elements, |
763 | | * so at least one is NULL */ |
764 | 0 | for (i = 0; ctx->conf_blocks[i]; i++) |
765 | 0 | load_parameters(ctx, ctx->conf_blocks[i], opts); |
766 | 0 | } |
767 | | |
768 | | int sc_ctx_detect_readers(sc_context_t *ctx) |
769 | 15.4k | { |
770 | 15.4k | int r = 0; |
771 | 15.4k | const struct sc_reader_driver *drv = ctx->reader_driver; |
772 | | |
773 | 15.4k | sc_mutex_lock(ctx, ctx->mutex); |
774 | | |
775 | 15.4k | if (drv->ops->detect_readers != NULL) |
776 | 0 | r = drv->ops->detect_readers(ctx); |
777 | | |
778 | 15.4k | sc_mutex_unlock(ctx, ctx->mutex); |
779 | | |
780 | 15.4k | return r; |
781 | 15.4k | } |
782 | | |
783 | | sc_reader_t *sc_ctx_get_reader(sc_context_t *ctx, unsigned int i) |
784 | 30.9k | { |
785 | 30.9k | return list_get_at(&ctx->readers, i); |
786 | 30.9k | } |
787 | | |
788 | | sc_reader_t *sc_ctx_get_reader_by_id(sc_context_t *ctx, unsigned int id) |
789 | 0 | { |
790 | 0 | return list_get_at(&ctx->readers, id); |
791 | 0 | } |
792 | | |
793 | | sc_reader_t *sc_ctx_get_reader_by_name(sc_context_t *ctx, const char * name) |
794 | 0 | { |
795 | 0 | return list_seek(&ctx->readers, name); |
796 | 0 | } |
797 | | |
798 | | unsigned int sc_ctx_get_reader_count(sc_context_t *ctx) |
799 | 46.4k | { |
800 | 46.4k | return list_size(&ctx->readers); |
801 | 46.4k | } |
802 | | |
803 | | int sc_establish_context(sc_context_t **ctx_out, const char *app_name) |
804 | 0 | { |
805 | 0 | sc_context_param_t ctx_param; |
806 | |
|
807 | 0 | memset(&ctx_param, 0, sizeof(sc_context_param_t)); |
808 | 0 | ctx_param.ver = 0; |
809 | 0 | ctx_param.app_name = app_name; |
810 | 0 | return sc_context_create(ctx_out, &ctx_param); |
811 | 0 | } |
812 | | |
813 | | /* For multithreaded issues */ |
814 | | int sc_context_repair(sc_context_t **ctx_out) |
815 | 0 | { |
816 | | /* Must already exist */ |
817 | 0 | if ((ctx_out == NULL) || (*ctx_out == NULL) || |
818 | 0 | ((*ctx_out)->app_name == NULL)) |
819 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
820 | | |
821 | | /* The only thing that should be shared across different contexts are the |
822 | | * card drivers - so rebuild the ATR's |
823 | | */ |
824 | 0 | load_card_atrs(*ctx_out); |
825 | | |
826 | | /* TODO: May need to re-open any card driver DLL's */ |
827 | |
|
828 | 0 | return SC_SUCCESS; |
829 | 0 | } |
830 | | |
831 | | #ifdef USE_OPENSSL3_LIBCTX |
832 | | static int sc_openssl3_init(sc_context_t *ctx) |
833 | | { |
834 | | ctx->ossl3ctx = calloc(1, sizeof(ossl3ctx_t)); |
835 | | if (ctx->ossl3ctx == NULL) |
836 | | return SC_ERROR_OUT_OF_MEMORY; |
837 | | ctx->ossl3ctx->libctx = OSSL_LIB_CTX_new(); |
838 | | if (ctx->ossl3ctx->libctx == NULL) { |
839 | | return SC_ERROR_INTERNAL; |
840 | | } |
841 | | ctx->ossl3ctx->defprov = OSSL_PROVIDER_load(ctx->ossl3ctx->libctx, |
842 | | "default"); |
843 | | if (ctx->ossl3ctx->defprov == NULL) { |
844 | | OSSL_LIB_CTX_free(ctx->ossl3ctx->libctx); |
845 | | free(ctx->ossl3ctx); |
846 | | ctx->ossl3ctx = NULL; |
847 | | return SC_ERROR_INTERNAL; |
848 | | } |
849 | | ctx->ossl3ctx->legacyprov = OSSL_PROVIDER_load(ctx->ossl3ctx->libctx, |
850 | | "legacy"); |
851 | | if (ctx->ossl3ctx->legacyprov == NULL) { |
852 | | sc_log(ctx, "Failed to load OpenSSL Legacy provider"); |
853 | | } |
854 | | return SC_SUCCESS; |
855 | | } |
856 | | |
857 | | static void sc_openssl3_deinit(sc_context_t *ctx) |
858 | | { |
859 | | if (ctx->ossl3ctx == NULL) |
860 | | return; |
861 | | if (ctx->ossl3ctx->legacyprov) |
862 | | OSSL_PROVIDER_unload(ctx->ossl3ctx->legacyprov); |
863 | | if (ctx->ossl3ctx->defprov) |
864 | | OSSL_PROVIDER_unload(ctx->ossl3ctx->defprov); |
865 | | if (ctx->ossl3ctx->libctx) |
866 | | OSSL_LIB_CTX_free(ctx->ossl3ctx->libctx); |
867 | | free(ctx->ossl3ctx); |
868 | | ctx->ossl3ctx = NULL; |
869 | | } |
870 | | #endif |
871 | | |
872 | | static char *get_exe_path() |
873 | 15.4k | { |
874 | | /* Find the executable's path which runs this code. |
875 | | * See https://github.com/gpakosz/whereami/ for |
876 | | * potentially more platforms */ |
877 | 15.4k | char exe_path[PATH_MAX] = "unknown executable path"; |
878 | 15.4k | int path_found = 0; |
879 | | |
880 | | #if defined(_WIN32) |
881 | | if (0 < GetModuleFileNameA(NULL, exe_path, sizeof exe_path)) |
882 | | path_found = 1; |
883 | | #elif defined(__APPLE__) |
884 | | if (0 < proc_pidpath(getpid(), exe_path, sizeof exe_path)) |
885 | | path_found = 1; |
886 | | #elif defined(__linux__) || defined(__CYGWIN__) |
887 | 15.4k | if (NULL != realpath("/proc/self/exe", exe_path)) |
888 | 15.4k | path_found = 1; |
889 | 15.4k | #endif |
890 | | |
891 | | #if defined(HAVE_GETPROGNAME) |
892 | | if (!path_found) { |
893 | | /* getprogname is unreliable and typically only returns the basename. |
894 | | * However, this should be enough for our purposes */ |
895 | | const char *prog = getprogname(); |
896 | | if (prog) |
897 | | strlcpy(exe_path, prog, sizeof exe_path); |
898 | | } |
899 | | #else |
900 | | /* avoid warning "set but not used" */ |
901 | 15.4k | (void) path_found; |
902 | 15.4k | #endif |
903 | | |
904 | 15.4k | return strdup(exe_path); |
905 | 15.4k | } |
906 | | |
907 | | int sc_context_create(sc_context_t **ctx_out, const sc_context_param_t *parm) |
908 | 15.4k | { |
909 | 15.4k | sc_context_t *ctx; |
910 | 15.4k | struct _sc_ctx_options opts; |
911 | 15.4k | int r; |
912 | 15.4k | char *driver; |
913 | | |
914 | 15.4k | if (ctx_out == NULL || parm == NULL) |
915 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
916 | | |
917 | 15.4k | ctx = calloc(1, sizeof(sc_context_t)); |
918 | 15.4k | if (ctx == NULL) |
919 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
920 | 15.4k | memset(&opts, 0, sizeof(opts)); |
921 | | |
922 | | /* set the application name if set in the parameter options */ |
923 | 15.4k | if (parm->app_name != NULL) |
924 | 15.4k | ctx->app_name = strdup(parm->app_name); |
925 | 0 | else |
926 | 0 | ctx->app_name = strdup("default"); |
927 | 15.4k | if (ctx->app_name == NULL) { |
928 | 0 | sc_release_context(ctx); |
929 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
930 | 0 | } |
931 | | |
932 | 15.4k | ctx->exe_path = get_exe_path(); |
933 | 15.4k | if (ctx->exe_path == NULL) { |
934 | 0 | sc_release_context(ctx); |
935 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
936 | 0 | } |
937 | | |
938 | 15.4k | ctx->flags = parm->flags; |
939 | 15.4k | set_defaults(ctx, &opts); |
940 | | |
941 | 15.4k | if (0 != list_init(&ctx->readers)) { |
942 | 0 | del_drvs(&opts); |
943 | 0 | sc_release_context(ctx); |
944 | 0 | return SC_ERROR_OUT_OF_MEMORY; |
945 | 0 | } |
946 | 15.4k | list_attributes_seeker(&ctx->readers, reader_list_seeker); |
947 | | /* set thread context and create mutex object (if specified) */ |
948 | 15.4k | if (parm->thread_ctx != NULL) |
949 | 15.4k | ctx->thread_ctx = parm->thread_ctx; |
950 | 15.4k | r = sc_mutex_create(ctx, &ctx->mutex); |
951 | 15.4k | if (r != SC_SUCCESS) { |
952 | 0 | del_drvs(&opts); |
953 | 0 | sc_release_context(ctx); |
954 | 0 | return r; |
955 | 0 | } |
956 | | |
957 | | #if defined(ENABLE_OPENSSL) && defined(OPENSSL_SECURE_MALLOC_SIZE) && !defined(LIBRESSL_VERSION_NUMBER) |
958 | | if (!CRYPTO_secure_malloc_initialized()) { |
959 | | CRYPTO_secure_malloc_init(OPENSSL_SECURE_MALLOC_SIZE, OPENSSL_SECURE_MALLOC_SIZE/8); |
960 | | } |
961 | | #endif |
962 | | |
963 | 15.4k | process_config_file(ctx, &opts); |
964 | | |
965 | | /* overwrite with caller's parameters if explicitly given */ |
966 | 15.4k | if (parm->debug) { |
967 | 0 | ctx->debug = parm->debug; |
968 | 0 | } |
969 | 15.4k | if (parm->debug_file) { |
970 | 0 | if (ctx->debug_file && (ctx->debug_file != stderr && ctx->debug_file != stdout)) |
971 | 0 | fclose(ctx->debug_file); |
972 | 0 | ctx->debug_file = parm->debug_file; |
973 | 0 | } |
974 | | |
975 | 15.4k | sc_log(ctx, "==================================="); /* first thing in the log */ |
976 | 15.4k | sc_log(ctx, "OpenSC version: %s", sc_get_version()); |
977 | 15.4k | sc_log(ctx, "Configured for %s (%s)", ctx->app_name, ctx->exe_path); |
978 | | |
979 | | #ifdef USE_OPENSSL3_LIBCTX |
980 | | r = sc_openssl3_init(ctx); |
981 | | if (r != SC_SUCCESS) { |
982 | | del_drvs(&opts); |
983 | | sc_release_context(ctx); |
984 | | return r; |
985 | | } |
986 | | #endif |
987 | | |
988 | | #ifdef ENABLE_PCSC |
989 | | ctx->reader_driver = sc_get_pcsc_driver(); |
990 | | #elif defined(ENABLE_CRYPTOTOKENKIT) |
991 | | ctx->reader_driver = sc_get_cryptotokenkit_driver(); |
992 | | #elif defined(ENABLE_CTAPI) |
993 | | ctx->reader_driver = sc_get_ctapi_driver(); |
994 | | #elif defined(ENABLE_OPENCT) |
995 | | ctx->reader_driver = sc_get_openct_driver(); |
996 | | #endif |
997 | | |
998 | 15.4k | r = ctx->reader_driver->ops->init(ctx); |
999 | 15.4k | if (r != SC_SUCCESS) { |
1000 | 0 | del_drvs(&opts); |
1001 | 0 | sc_release_context(ctx); |
1002 | 0 | return r; |
1003 | 0 | } |
1004 | | |
1005 | 15.4k | driver = getenv("OPENSC_DRIVER"); |
1006 | 15.4k | if (driver) { |
1007 | 0 | scconf_list *list = NULL; |
1008 | 0 | scconf_list_add(&list, driver); |
1009 | 0 | set_drivers(&opts, list); |
1010 | 0 | scconf_list_destroy(list); |
1011 | 0 | } |
1012 | | |
1013 | 15.4k | load_card_drivers(ctx, &opts); |
1014 | 15.4k | load_card_atrs(ctx); |
1015 | | |
1016 | 15.4k | del_drvs(&opts); |
1017 | 15.4k | sc_ctx_detect_readers(ctx); |
1018 | 15.4k | *ctx_out = ctx; |
1019 | | |
1020 | 15.4k | return SC_SUCCESS; |
1021 | 15.4k | } |
1022 | | |
1023 | | /* Used by minidriver to pass in provided handles to reader-pcsc */ |
1024 | | int sc_ctx_use_reader(sc_context_t *ctx, void *pcsc_context_handle, void *pcsc_card_handle) |
1025 | 0 | { |
1026 | 0 | LOG_FUNC_CALLED(ctx); |
1027 | 0 | if (ctx->reader_driver->ops->use_reader != NULL) |
1028 | 0 | return ctx->reader_driver->ops->use_reader(ctx, pcsc_context_handle, pcsc_card_handle); |
1029 | | |
1030 | 0 | return SC_ERROR_NOT_SUPPORTED; |
1031 | 0 | } |
1032 | | |
1033 | | /* Following two are only implemented with internal PC/SC and don't consume a reader object */ |
1034 | | int sc_cancel(sc_context_t *ctx) |
1035 | 15.4k | { |
1036 | 15.4k | LOG_FUNC_CALLED(ctx); |
1037 | 15.4k | if (ctx->reader_driver->ops->cancel != NULL) |
1038 | 0 | return ctx->reader_driver->ops->cancel(ctx); |
1039 | | |
1040 | 15.4k | return SC_ERROR_NOT_SUPPORTED; |
1041 | 15.4k | } |
1042 | | |
1043 | | |
1044 | | 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) |
1045 | 0 | { |
1046 | 0 | LOG_FUNC_CALLED(ctx); |
1047 | 0 | if (ctx->reader_driver->ops->wait_for_event != NULL) |
1048 | 0 | return ctx->reader_driver->ops->wait_for_event(ctx, event_mask, event_reader, event, timeout, reader_states); |
1049 | | |
1050 | 0 | return SC_ERROR_NOT_SUPPORTED; |
1051 | 0 | } |
1052 | | |
1053 | | int sc_release_context(sc_context_t *ctx) |
1054 | 15.4k | { |
1055 | 15.4k | unsigned int i; |
1056 | | |
1057 | 15.4k | if (ctx == NULL) { |
1058 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
1059 | 0 | } |
1060 | 15.4k | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); |
1061 | 30.9k | while (list_size(&ctx->readers)) { |
1062 | 15.4k | sc_reader_t *rdr = (sc_reader_t *) list_get_at(&ctx->readers, 0); |
1063 | 15.4k | _sc_delete_reader(ctx, rdr); |
1064 | 15.4k | } |
1065 | | |
1066 | 15.4k | if (ctx->reader_driver->ops->finish != NULL) |
1067 | 0 | ctx->reader_driver->ops->finish(ctx); |
1068 | | |
1069 | 556k | for (i = 0; ctx->card_drivers[i]; i++) { |
1070 | 541k | struct sc_card_driver *drv = ctx->card_drivers[i]; |
1071 | | |
1072 | 541k | if (drv->atr_map) |
1073 | 0 | _sc_free_atr(ctx, drv); |
1074 | 541k | if (drv->dll) |
1075 | 0 | sc_dlclose(drv->dll); |
1076 | 541k | } |
1077 | | #ifdef USE_OPENSSL3_LIBCTX |
1078 | | sc_openssl3_deinit(ctx); |
1079 | | #endif |
1080 | 15.4k | if (ctx->preferred_language != NULL) |
1081 | 0 | free(ctx->preferred_language); |
1082 | 15.4k | if (ctx->mutex != NULL) { |
1083 | 0 | int r = sc_mutex_destroy(ctx, ctx->mutex); |
1084 | 0 | if (r != SC_SUCCESS) { |
1085 | 0 | sc_log(ctx, "unable to destroy mutex"); |
1086 | 0 | return r; |
1087 | 0 | } |
1088 | 0 | } |
1089 | 15.4k | if (ctx->conf != NULL) |
1090 | 0 | scconf_free(ctx->conf); |
1091 | 15.4k | if (ctx->debug_file && (ctx->debug_file != stdout && ctx->debug_file != stderr)) |
1092 | 0 | fclose(ctx->debug_file); |
1093 | 15.4k | free(ctx->debug_filename); |
1094 | 15.4k | free(ctx->app_name); |
1095 | 15.4k | free(ctx->exe_path); |
1096 | 15.4k | list_destroy(&ctx->readers); |
1097 | 15.4k | sc_mem_clear(ctx, sizeof(*ctx)); |
1098 | 15.4k | free(ctx); |
1099 | 15.4k | return SC_SUCCESS; |
1100 | 15.4k | } |
1101 | | |
1102 | | int sc_set_card_driver(sc_context_t *ctx, const char *short_name) |
1103 | 0 | { |
1104 | 0 | int i = 0, match = 0; |
1105 | |
|
1106 | 0 | sc_mutex_lock(ctx, ctx->mutex); |
1107 | 0 | if (short_name == NULL) { |
1108 | 0 | ctx->forced_driver = NULL; |
1109 | 0 | match = 1; |
1110 | 0 | } else while (i < SC_MAX_CARD_DRIVERS && ctx->card_drivers[i] != NULL) { |
1111 | 0 | struct sc_card_driver *drv = ctx->card_drivers[i]; |
1112 | |
|
1113 | 0 | if (strcmp(short_name, drv->short_name) == 0) { |
1114 | 0 | ctx->forced_driver = drv; |
1115 | 0 | match = 1; |
1116 | 0 | break; |
1117 | 0 | } |
1118 | 0 | i++; |
1119 | 0 | } |
1120 | 0 | sc_mutex_unlock(ctx, ctx->mutex); |
1121 | 0 | if (match == 0) |
1122 | 0 | return SC_ERROR_OBJECT_NOT_FOUND; /* FIXME: invent error */ |
1123 | 0 | return SC_SUCCESS; |
1124 | 0 | } |
1125 | | |
1126 | | int sc_get_cache_dir(sc_context_t *ctx, char *buf, size_t bufsize) |
1127 | 2.27k | { |
1128 | 2.27k | char *homedir; |
1129 | 2.27k | const char *cache_dir; |
1130 | 2.27k | scconf_block *conf_block = NULL; |
1131 | | #ifdef _WIN32 |
1132 | | char temp_path[PATH_MAX]; |
1133 | | #endif |
1134 | 2.27k | conf_block = sc_get_conf_block(ctx, "framework", "pkcs15", 1); |
1135 | 2.27k | cache_dir = scconf_get_str(conf_block, "file_cache_dir", NULL); |
1136 | 2.27k | if (cache_dir != NULL) { |
1137 | 0 | strlcpy(buf, cache_dir, bufsize); |
1138 | 0 | return SC_SUCCESS; |
1139 | 0 | } |
1140 | | |
1141 | 2.27k | #ifndef _WIN32 |
1142 | | #ifdef __APPLE__ |
1143 | | cache_dir = getenv("Caches"); |
1144 | | #else |
1145 | 2.27k | cache_dir = getenv("XDG_CACHE_HOME"); |
1146 | 2.27k | #endif |
1147 | 2.27k | if (cache_dir != NULL && cache_dir[0] != '\0') { |
1148 | 0 | snprintf(buf, bufsize, "%s/%s", cache_dir, "opensc"); |
1149 | 0 | return SC_SUCCESS; |
1150 | 0 | } |
1151 | 2.27k | cache_dir = ".cache/opensc"; |
1152 | 2.27k | homedir = getenv("HOME"); |
1153 | | #else |
1154 | | cache_dir = "eid-cache"; |
1155 | | homedir = getenv("USERPROFILE"); |
1156 | | /* If USERPROFILE isn't defined, assume it's a single-user OS |
1157 | | * and put the cache dir in the Windows dir (usually C:\\WINDOWS) */ |
1158 | | if (homedir == NULL || homedir[0] == '\0') { |
1159 | | GetWindowsDirectoryA(temp_path, sizeof(temp_path)); |
1160 | | homedir = temp_path; |
1161 | | } |
1162 | | #endif |
1163 | 2.27k | if (homedir == NULL || homedir[0] == '\0') |
1164 | 0 | return SC_ERROR_INTERNAL; |
1165 | 2.27k | if (snprintf(buf, bufsize, "%s/%s", homedir, cache_dir) < 0) |
1166 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
1167 | 2.27k | return SC_SUCCESS; |
1168 | 2.27k | } |
1169 | | |
1170 | | int sc_make_cache_dir(sc_context_t *ctx) |
1171 | 52 | { |
1172 | 52 | char dirname[PATH_MAX], *sp; |
1173 | 52 | int r, mkdir_checker; |
1174 | 52 | size_t j, namelen; |
1175 | | |
1176 | 52 | if ((r = sc_get_cache_dir(ctx, dirname, sizeof(dirname))) < 0) |
1177 | 0 | return r; |
1178 | 52 | namelen = strlen(dirname); |
1179 | | |
1180 | 52 | while (1) { |
1181 | | #ifdef _WIN32 |
1182 | | mkdir_checker = mkdir(dirname) >= 0; |
1183 | | #else |
1184 | 52 | mkdir_checker = mkdir(dirname, 0700) >= 0; |
1185 | 52 | #endif |
1186 | 52 | if (mkdir_checker) |
1187 | 3 | break; |
1188 | | |
1189 | 49 | if (errno != ENOENT || (sp = strrchr(dirname, '/')) == NULL |
1190 | 49 | || sp == dirname) |
1191 | 49 | goto failed; |
1192 | 0 | *sp = '\0'; |
1193 | 0 | } |
1194 | | |
1195 | | /* We may have stripped one or more path components from |
1196 | | * the directory name. Restore them */ |
1197 | 3 | while (1) { |
1198 | 3 | j = strlen(dirname); |
1199 | 3 | if (j >= namelen) |
1200 | 3 | break; |
1201 | 0 | dirname[j] = '/'; |
1202 | | #ifdef _WIN32 |
1203 | | mkdir_checker = mkdir(dirname) < 0; |
1204 | | #else |
1205 | 0 | mkdir_checker = mkdir(dirname, 0700) < 0; |
1206 | 0 | #endif |
1207 | 0 | if (mkdir_checker) |
1208 | 0 | goto failed; |
1209 | 0 | } |
1210 | 3 | return SC_SUCCESS; |
1211 | | |
1212 | | /* for lack of a better return code */ |
1213 | 49 | failed: |
1214 | 49 | sc_log(ctx, "failed to create cache directory"); |
1215 | 49 | return SC_ERROR_INTERNAL; |
1216 | 3 | } |