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