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