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