pcsc-lite 2.2.3
readerfactory.c
Go to the documentation of this file.
1/*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3 *
4 * Copyright (C) 1999-2004
5 * David Corcoran <corcoran@musclecard.com>
6 * Copyright (C) 2003-2004
7 * Damien Sauveron <damien.sauveron@labri.fr>
8 * Copyright (C) 2002-2024
9 * Ludovic Rousseau <ludovic.rousseau@free.fr>
10 * Copyright (C) 2009
11 * Jean-Luc Giraud <jlgiraud@googlemail.com>
12 *
13Redistribution and use in source and binary forms, with or without
14modification, are permitted provided that the following conditions
15are met:
16
171. Redistributions of source code must retain the above copyright
18 notice, this list of conditions and the following disclaimer.
192. Redistributions in binary form must reproduce the above copyright
20 notice, this list of conditions and the following disclaimer in the
21 documentation and/or other materials provided with the distribution.
223. The name of the author may not be used to endorse or promote products
23 derived from this software without specific prior written permission.
24
25THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
42#include "config.h"
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <unistd.h>
47#include <sys/types.h>
48#include <sys/stat.h>
49#include <errno.h>
50#include <fcntl.h>
51#include <pthread.h>
52#include <stdatomic.h>
53#include <stdbool.h>
54
55#include "misc.h"
56#include "pcscd.h"
57#include "debuglog.h"
58#include "readerfactory.h"
59#include "dyn_generic.h"
60#include "sys_generic.h"
61#include "eventhandler.h"
62#include "ifdwrapper.h"
63#include "hotplug.h"
64#include "configfile.h"
65#include "utils.h"
66
67static READER_CONTEXT * sReadersContexts[PCSCLITE_MAX_READERS_CONTEXTS];
69static int maxReaderHandles = PCSC_MAX_READER_HANDLES;
70static DWORD dwNumReadersContexts = 0;
71#ifdef USE_SERIAL
72static char *ConfigFile = NULL;
73static int ConfigFileCRC = 0;
74#endif
75static pthread_mutex_t LockMutex = PTHREAD_MUTEX_INITIALIZER;
76
77#define IDENTITY_SHIFT 16
78static LONG removeReader(READER_CONTEXT * sReader);
79
80static int RDR_CLIHANDLES_seeker(const void *el, const void *key)
81{
82 const RDR_CLIHANDLES *rdrCliHandles = el;
83
84 if ((el == NULL) || (key == NULL))
85 {
86 Log3(PCSC_LOG_CRITICAL,
87 "RDR_CLIHANDLES_seeker called with NULL pointer: el=%p, key=%p",
88 el, key);
89 return 0;
90 }
91
92 if (rdrCliHandles->hCard == *(SCARDHANDLE *)key)
93 return 1;
94
95 return 0;
96}
97
98
99LONG _RefReader(READER_CONTEXT * sReader)
100{
101 if (0 == sReader->reference)
103
104 sReader->reference += 1;
105
106 return SCARD_S_SUCCESS;
107}
108
109LONG _UnrefReader(READER_CONTEXT * sReader)
110{
111 if (0 == sReader->reference)
113
114 sReader->reference -= 1;
115
116 if (0 == sReader->reference)
117 removeReader(sReader);
118
119 return SCARD_S_SUCCESS;
120}
121
122LONG RFAllocateReaderSpace(unsigned int customMaxReaderHandles)
123{
124 int i; /* Counter */
125
126 if (customMaxReaderHandles != 0)
127 maxReaderHandles = customMaxReaderHandles;
128
129 /* Allocate each reader structure */
130 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
131 {
132 sReadersContexts[i] = malloc(sizeof(READER_CONTEXT));
133 sReadersContexts[i]->vHandle = NULL;
134 atomic_init(&sReadersContexts[i]->hLockId, 0);
135 atomic_init(&sReadersContexts[i]->contexts, 0);
136 atomic_init(&sReadersContexts[i]->reference, 0);
137
138 /* Zero out each value in the struct */
139 memset(readerStates[i].readerName, 0, MAX_READERNAME);
140 memset(readerStates[i].cardAtr, 0, MAX_ATR_SIZE);
141 readerStates[i].eventCounter = 0;
142 readerStates[i].readerState = 0;
143 readerStates[i].readerSharing = 0;
144 readerStates[i].cardAtrLength = READER_NOT_INITIALIZED;
145 readerStates[i].cardProtocol = SCARD_PROTOCOL_UNDEFINED;
146
147 sReadersContexts[i]->readerState = &readerStates[i];
148 }
149
150 /* Create public event structures */
151 return EHInitializeEventStructures();
152}
153
154LONG RFAddReader(const char *readerNameLong, int port, const char *library,
155 const char *device)
156{
157 DWORD dwContext = 0, dwGetSize;
158 UCHAR ucGetData[1], ucThread[1];
159 LONG rv, parentNode;
160 int i, j;
161 int lrv = 0;
162 char *readerName = NULL;
163
164 if ((readerNameLong == NULL) || (library == NULL) || (device == NULL))
166
167#ifdef FILTER_NAMES
168 const char *ro_filter = SYS_GetEnv("PCSCLITE_FILTER_IGNORE_READER_NAMES");
169 if (ro_filter)
170 {
171 char *filter, *next;
172
173 /* get a RW copy of the env string */
174 filter = alloca(strlen(ro_filter)+1);
175 strcpy(filter, ro_filter);
176
177 while (filter)
178 {
179 /* ':' is the separator */
180 next = strchr(filter, ':');
181 if (next)
182 {
183 /* NUL terminate the current pattern */
184 *next = '\0';
185 }
186
187 /* if filter is non empty and found in the reader name */
188 if (*filter && strstr(readerNameLong, filter))
189 {
190 Log3(PCSC_LOG_ERROR,
191 "Reader name \"%s\" contains \"%s\": ignored",
192 readerNameLong, filter);
194 }
195
196 if (next)
197 /* next pattern */
198 filter = next+1;
199 else
200 /* end */
201 filter = NULL;
202 }
203 }
204#endif
205
206 /* allocate memory that is automatically freed */
207 readerName = alloca(strlen(readerNameLong)+1);
208 strcpy(readerName, readerNameLong);
209
210 /* Reader name too long? also count " 00 00"*/
211 if (strlen(readerName) > MAX_READERNAME - sizeof(" 00 00"))
212 {
213 Log3(PCSC_LOG_ERROR,
214 "Reader name too long: %zd chars instead of max %zd. Truncating!",
215 strlen(readerName), MAX_READERNAME - sizeof(" 00 00"));
216 readerName[MAX_READERNAME - sizeof(" 00 00")] = '\0';
217 }
218
219 /* Same name, same port, same device - duplicate reader cannot be used */
220 if (dwNumReadersContexts != 0)
221 {
222 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
223 {
224 if (sReadersContexts[i]->vHandle != 0)
225 {
226 char lpcStripReader[MAX_READERNAME];
227 int tmplen;
228
229 /* get the reader name without the reader and slot numbers */
230 strncpy(lpcStripReader,
231 sReadersContexts[i]->readerState->readerName,
232 sizeof(lpcStripReader));
233 tmplen = strlen(lpcStripReader);
234 lpcStripReader[tmplen - 6] = 0;
235
236 if ((strcmp(readerName, lpcStripReader) == 0)
237 && (port == sReadersContexts[i]->port)
238 && (strcmp(device, sReadersContexts[i]->device) == 0))
239 {
240 Log1(PCSC_LOG_ERROR, "Duplicate reader found.");
242 }
243 }
244 }
245 }
246
247 /* We must find an empty slot to put the reader structure */
248 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
249 {
250 if (sReadersContexts[i]->vHandle == 0)
251 {
252 dwContext = i;
253 break;
254 }
255 }
256
258 {
259 /* No more spots left return */
260 return SCARD_E_NO_MEMORY;
261 }
262
263 /* Check and set the readername to see if it must be enumerated */
264 parentNode = RFSetReaderName(sReadersContexts[dwContext], readerName,
265 library, port);
266 if (parentNode < -1)
267 return SCARD_E_NO_MEMORY;
268
269 sReadersContexts[dwContext]->library = strdup(library);
270 sReadersContexts[dwContext]->device = strdup(device);
271 sReadersContexts[dwContext]->version = 0;
272 sReadersContexts[dwContext]->port = port;
273 sReadersContexts[dwContext]->mMutex = NULL;
274 sReadersContexts[dwContext]->contexts = 0;
275 sReadersContexts[dwContext]->pthThread = 0;
276 sReadersContexts[dwContext]->hLockId = 0;
277 sReadersContexts[dwContext]->LockCount = 0;
278 sReadersContexts[dwContext]->vHandle = NULL;
279 sReadersContexts[dwContext]->pFeeds = NULL;
280 sReadersContexts[dwContext]->pMutex = NULL;
281 sReadersContexts[dwContext]->pthCardEvent = NULL;
282
283 lrv = list_init(&sReadersContexts[dwContext]->handlesList);
284 if (lrv < 0)
285 {
286 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
287 return SCARD_E_NO_MEMORY;
288 }
289
290 lrv = list_attributes_seeker(&sReadersContexts[dwContext]->handlesList,
291 RDR_CLIHANDLES_seeker);
292 if (lrv < 0)
293 {
294 Log2(PCSC_LOG_CRITICAL,
295 "list_attributes_seeker failed with return value: %d", lrv);
296 return SCARD_E_NO_MEMORY;
297 }
298
299 (void)pthread_mutex_init(&sReadersContexts[dwContext]->handlesList_lock,
300 NULL);
301
302 (void)pthread_mutex_init(&sReadersContexts[dwContext]->powerState_lock,
303 NULL);
304 sReadersContexts[dwContext]->powerState = POWER_STATE_UNPOWERED;
305
306 /* reference count */
307 sReadersContexts[dwContext]->reference = 1;
308
309 /* If a clone to this reader exists take some values from that clone */
310 if (parentNode >= 0 && parentNode < PCSCLITE_MAX_READERS_CONTEXTS)
311 {
312 sReadersContexts[dwContext]->pFeeds =
313 sReadersContexts[parentNode]->pFeeds;
314 *(sReadersContexts[dwContext])->pFeeds += 1;
315 sReadersContexts[dwContext]->vHandle =
316 sReadersContexts[parentNode]->vHandle;
317 sReadersContexts[dwContext]->mMutex =
318 sReadersContexts[parentNode]->mMutex;
319 sReadersContexts[dwContext]->pMutex =
320 sReadersContexts[parentNode]->pMutex;
321
322 /* Call on the parent driver to see if it is thread safe */
323 dwGetSize = sizeof(ucThread);
324 rv = IFDGetCapabilities(sReadersContexts[parentNode],
325 TAG_IFD_THREAD_SAFE, &dwGetSize, ucThread);
326
327 if (rv == IFD_SUCCESS && dwGetSize == 1 && ucThread[0] == 1)
328 {
329 Log1(PCSC_LOG_INFO, "Driver is thread safe");
330 sReadersContexts[dwContext]->mMutex = NULL;
331 sReadersContexts[dwContext]->pMutex = NULL;
332 }
333 else
334 *(sReadersContexts[dwContext])->pMutex += 1;
335 }
336
337 if (sReadersContexts[dwContext]->pFeeds == NULL)
338 {
339 sReadersContexts[dwContext]->pFeeds = malloc(sizeof(int));
340
341 /* Initialize pFeeds to 1, otherwise multiple
342 cloned readers will cause pcscd to crash when
343 RFUnloadReader unloads the driver library
344 and there are still devices attached using it --mikeg*/
345 *(sReadersContexts[dwContext])->pFeeds = 1;
346 }
347
348 if (sReadersContexts[dwContext]->mMutex == 0)
349 {
350 sReadersContexts[dwContext]->mMutex =
351 malloc(sizeof(pthread_mutex_t));
352 (void)pthread_mutex_init(sReadersContexts[dwContext]->mMutex, NULL);
353 }
354
355 if (sReadersContexts[dwContext]->pMutex == NULL)
356 {
357 sReadersContexts[dwContext]->pMutex = malloc(sizeof(int));
358 *(sReadersContexts[dwContext])->pMutex = 1;
359 }
360
361 dwNumReadersContexts += 1;
362
363 rv = RFInitializeReader(sReadersContexts[dwContext]);
364 if (rv != SCARD_S_SUCCESS)
365 {
366 int log_level = PCSC_LOG_ERROR;
367 if (SCARD_E_UNKNOWN_READER == rv)
368 log_level = PCSC_LOG_INFO;
369
370 /* Cannot connect to reader. Exit gracefully */
371 Log2(log_level, "%s init failed.", readerName);
372 (void)RFRemoveReader(readerName, port, REMOVE_READER_NO_FLAG);
373 return rv;
374 }
375
376 /* asynchronous card movement? */
377 {
378 RESPONSECODE (*fct)(DWORD, int) = NULL;
379
380 dwGetSize = sizeof(fct);
381
382 rv = IFDGetCapabilities(sReadersContexts[dwContext],
383 TAG_IFD_POLLING_THREAD_WITH_TIMEOUT, &dwGetSize, (PUCHAR)&fct);
384 if ((rv != SCARD_S_SUCCESS) || (dwGetSize != sizeof(fct)))
385 {
386 Log1(PCSC_LOG_INFO, "Using the pcscd polling thread");
387 }
388 else
389 {
390 sReadersContexts[dwContext]->pthCardEvent = fct;
391 Log1(PCSC_LOG_INFO, "Using the reader polling thread");
392 }
393
394 rv = EHSpawnEventHandler(sReadersContexts[dwContext]);
395 if (rv != SCARD_S_SUCCESS)
396 {
397 Log2(PCSC_LOG_ERROR, "%s init failed.", readerName);
398 (void)RFRemoveReader(readerName, port, REMOVE_READER_NO_FLAG);
399 return rv;
400 }
401 }
402
403 /* Call on the driver to see if there are multiple slots */
404 dwGetSize = sizeof(ucGetData);
405 rv = IFDGetCapabilities((sReadersContexts[dwContext]),
406 TAG_IFD_SLOTS_NUMBER, &dwGetSize, ucGetData);
407
408 int nbSlots = ucGetData[0];
409 if (rv != IFD_SUCCESS || dwGetSize != 1 || nbSlots == 0)
410 /* Reader does not have this defined. Must be a single slot
411 * reader so we can just return SCARD_S_SUCCESS. */
412 return SCARD_S_SUCCESS;
413
414 if (1 == nbSlots)
415 /* Reader has only one slot */
416 return SCARD_S_SUCCESS;
417
418 /*
419 * Check the number of slots and create a different
420 * structure for each one accordingly
421 */
422
423 /* Initialize the rest of the slots */
424 for (j = 1; j < nbSlots; j++)
425 {
426 char *tmpReader = NULL;
427 DWORD dwContextB = 0;
428 RESPONSECODE (*fct)(DWORD, int) = NULL;
429
430 /* We must find an empty spot to put the reader structure */
431 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
432 {
433 if (sReadersContexts[i]->vHandle == 0)
434 {
435 dwContextB = i;
436 break;
437 }
438 }
439
441 {
442 /* No more slot left return */
443 RFRemoveReader(readerName, port, REMOVE_READER_NO_FLAG);
444 return SCARD_E_NO_MEMORY;
445 }
446
447 /* Copy the previous reader name and increment the slot number */
448 tmpReader = sReadersContexts[dwContextB]->readerState->readerName;
449 memcpy(tmpReader,
450 sReadersContexts[dwContext]->readerState->readerName,
451 sizeof(sReadersContexts[dwContextB]->readerState->readerName));
452 snprintf(tmpReader + strlen(tmpReader) - 2, 3, "%02X", j);
453
454 sReadersContexts[dwContextB]->library =
455 sReadersContexts[dwContext]->library;
456 sReadersContexts[dwContextB]->device =
457 sReadersContexts[dwContext]->device;
458 sReadersContexts[dwContextB]->version =
459 sReadersContexts[dwContext]->version;
460 sReadersContexts[dwContextB]->port =
461 sReadersContexts[dwContext]->port;
462 sReadersContexts[dwContextB]->vHandle =
463 sReadersContexts[dwContext]->vHandle;
464 sReadersContexts[dwContextB]->mMutex =
465 sReadersContexts[dwContext]->mMutex;
466 sReadersContexts[dwContextB]->pMutex =
467 sReadersContexts[dwContext]->pMutex;
468 sReadersContexts[dwContextB]->slot =
469 sReadersContexts[dwContext]->slot + j;
470 sReadersContexts[dwContextB]->pthCardEvent = NULL;
471
472 /*
473 * Added by Dave - slots did not have a pFeeds
474 * parameter so it was by luck they were working
475 */
476 sReadersContexts[dwContextB]->pFeeds =
477 sReadersContexts[dwContext]->pFeeds;
478
479 /* Added by Dave for multiple slots */
480 *(sReadersContexts[dwContextB])->pFeeds += 1;
481
482 sReadersContexts[dwContextB]->contexts = 0;
483 sReadersContexts[dwContextB]->hLockId = 0;
484 sReadersContexts[dwContextB]->LockCount = 0;
485
486 lrv = list_init(&sReadersContexts[dwContextB]->handlesList);
487 if (lrv < 0)
488 {
489 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
490 return SCARD_E_NO_MEMORY;
491 }
492
493 lrv = list_attributes_seeker(&sReadersContexts[dwContextB]->handlesList,
494 RDR_CLIHANDLES_seeker);
495 if (lrv < 0)
496 {
497 Log2(PCSC_LOG_CRITICAL,
498 "list_attributes_seeker failed with return value: %d", lrv);
499 return SCARD_E_NO_MEMORY;
500 }
501
502 (void)pthread_mutex_init(&sReadersContexts[dwContextB]->handlesList_lock, NULL);
503 (void)pthread_mutex_init(&sReadersContexts[dwContextB]->powerState_lock,
504 NULL);
505 sReadersContexts[dwContextB]->powerState = POWER_STATE_UNPOWERED;
506
507 /* reference count */
508 sReadersContexts[dwContextB]->reference = 1;
509
510 /* Call on the parent driver to see if the slots are thread safe */
511 dwGetSize = sizeof(ucThread);
512 rv = IFDGetCapabilities((sReadersContexts[dwContext]),
513 TAG_IFD_SLOT_THREAD_SAFE, &dwGetSize, ucThread);
514
515 if (rv == IFD_SUCCESS && dwGetSize == 1 && ucThread[0] == 1)
516 {
517 Log1(PCSC_LOG_INFO, "Driver is slot thread safe");
518
519 sReadersContexts[dwContextB]->library =
520 strdup(sReadersContexts[dwContext]->library);
521 sReadersContexts[dwContextB]->device =
522 strdup(sReadersContexts[dwContext]->device);
523 sReadersContexts[dwContextB]->mMutex =
524 malloc(sizeof(pthread_mutex_t));
525 (void)pthread_mutex_init(sReadersContexts[dwContextB]->mMutex,
526 NULL);
527
528 sReadersContexts[dwContextB]->pMutex = malloc(sizeof(int));
529 *(sReadersContexts[dwContextB])->pMutex = 1;
530 }
531 else
532 *(sReadersContexts[dwContextB])->pMutex += 1;
533
534 dwNumReadersContexts += 1;
535
536 rv = RFInitializeReader(sReadersContexts[dwContextB]);
537 if (rv != SCARD_S_SUCCESS)
538 {
539 /* Cannot connect to slot. Exit gracefully */
540 (void)RFRemoveReader(readerName, port, REMOVE_READER_NO_FLAG);
541 return rv;
542 }
543
544 /* asynchronous card movement? */
545 dwGetSize = sizeof(fct);
546
547 rv = IFDGetCapabilities((sReadersContexts[dwContextB]),
548 TAG_IFD_POLLING_THREAD_WITH_TIMEOUT, &dwGetSize, (PUCHAR)&fct);
549 if ((rv != SCARD_S_SUCCESS) || (dwGetSize != sizeof(fct)))
550 {
551 Log1(PCSC_LOG_INFO, "Using the pcscd polling thread");
552 }
553 else
554 {
555 sReadersContexts[dwContextB]->pthCardEvent = fct;
556 Log1(PCSC_LOG_INFO, "Using the reader polling thread");
557 }
558
559 rv = EHSpawnEventHandler(sReadersContexts[dwContextB]);
560 if (rv != SCARD_S_SUCCESS)
561 {
562 Log2(PCSC_LOG_ERROR, "%s init failed.", readerName);
563 (void)RFRemoveReader(readerName, port, REMOVE_READER_NO_FLAG);
564 return rv;
565 }
566 }
567
568 return SCARD_S_SUCCESS;
569}
570
571LONG RFRemoveReader(const char *readerName, int port, int flags)
572{
573 char lpcStripReader[MAX_READERNAME];
574 int i;
575#ifdef FILTER_NAMES
576 const char *extend;
577#endif
578 int extend_size = 0;
579
580 if (readerName == NULL)
582
583#ifdef FILTER_NAMES
584 extend = SYS_GetEnv("PCSCLITE_FILTER_EXTEND_READER_NAMES");
585 if (extend)
586 extend_size = strlen(extend);
587#endif
588
589 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
590 {
591 if (sReadersContexts[i] && (sReadersContexts[i]->vHandle != 0))
592 {
593 strncpy(lpcStripReader,
594 sReadersContexts[i]->readerState->readerName,
595 sizeof(lpcStripReader));
596 lpcStripReader[strlen(lpcStripReader) - 6 - extend_size] = 0;
597
598 /* Compare only the significant part of the reader name */
599 if ((strncmp(readerName, lpcStripReader, MAX_READERNAME - sizeof(" 00 00")) == 0)
600 && (port == sReadersContexts[i]->port))
601 {
602 if (flags & REMOVE_READER_FLAG_REMOVED)
603 {
604 UCHAR tagValue[1];
605 DWORD valueLength;
606 LONG ret;
607
608 /* signal to the driver that the reader has been removed */
609 valueLength = sizeof(tagValue);
610 ret = IFDGetCapabilities(sReadersContexts[i],
611 TAG_IFD_DEVICE_REMOVED, &valueLength, tagValue);
612 if ((IFD_SUCCESS) == ret && (1 == tagValue[0]))
613 {
614 tagValue[0] = 1;
615 IFDSetCapabilities(sReadersContexts[i],
616 TAG_IFD_DEVICE_REMOVED, sizeof tagValue, tagValue);
617 }
618 }
619
620 /* remove the reader */
621 UNREF_READER(sReadersContexts[i])
622 }
623 }
624 }
625
626 return SCARD_S_SUCCESS;
627}
628
629LONG removeReader(READER_CONTEXT * sContext)
630{
631 /* Try to destroy the thread */
632 if (sContext -> pthThread)
633 EHDestroyEventHandler(sContext);
634
635 if ((NULL == sContext->pMutex) || (NULL == sContext->pFeeds))
636 {
637 Log1(PCSC_LOG_ERROR,
638 "Trying to remove an already removed driver");
640 }
641
642 RFUnInitializeReader(sContext);
643
644 *sContext->pMutex -= 1;
645
646 /* free shared resources when the last slot is closed */
647 if (0 == *sContext->pMutex)
648 {
649 (void)pthread_mutex_destroy(sContext->mMutex);
650 free(sContext->mMutex);
651 sContext->mMutex = NULL;
652 free(sContext->library);
653 free(sContext->device);
654 free(sContext->pMutex);
655 sContext->pMutex = NULL;
656 }
657
658 *sContext->pFeeds -= 1;
659
660 /* Added by Dave to free the pFeeds variable */
661 if (*sContext->pFeeds == 0)
662 {
663 free(sContext->pFeeds);
664 sContext->pFeeds = NULL;
665 }
666
667 (void)pthread_mutex_destroy(&sContext->powerState_lock);
668 sContext->version = 0;
669 sContext->port = 0;
670 sContext->contexts = 0;
671 sContext->slot = 0;
672 sContext->hLockId = 0;
673 sContext->LockCount = 0;
674 sContext->vHandle = NULL;
675
676 (void)pthread_mutex_lock(&sContext->handlesList_lock);
677 while (list_size(&sContext->handlesList) != 0)
678 {
679 int lrv;
680 RDR_CLIHANDLES *currentHandle;
681
682 currentHandle = list_get_at(&sContext->handlesList, 0);
683 lrv = list_delete_at(&sContext->handlesList, 0);
684 if (lrv < 0)
685 Log2(PCSC_LOG_CRITICAL,
686 "list_delete_at failed with return value: %d", lrv);
687
688 free(currentHandle);
689 }
690 (void)pthread_mutex_unlock(&sContext->handlesList_lock);
691 (void)pthread_mutex_destroy(&sContext->handlesList_lock);
692 list_destroy(&sContext->handlesList);
693 dwNumReadersContexts -= 1;
694
695 /* signal an event to clients */
697
698 return SCARD_S_SUCCESS;
699}
700
701LONG RFSetReaderName(READER_CONTEXT * rContext, const char *readerName,
702 const char *libraryName, int port)
703{
704 LONG parent = -1; /* reader number of the parent of the clone */
705 DWORD valueLength;
706 int currentDigit = -1;
707 int supportedChannels = 0;
708 bool usedDigits[PCSCLITE_MAX_READERS_CONTEXTS];
709 int i;
710 const char *extend = "";
711
712 /* Clear the list */
713 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
714 usedDigits[i] = false;
715
716 if (dwNumReadersContexts != 0)
717 {
718 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
719 {
720 if (sReadersContexts[i]->vHandle != 0)
721 {
722 if (strcmp(sReadersContexts[i]->library, libraryName) == 0)
723 {
724 UCHAR tagValue[1];
725 LONG ret;
726
727 /* Ask the driver if it supports multiple channels */
728 valueLength = sizeof(tagValue);
729 ret = IFDGetCapabilities(sReadersContexts[i],
731 &valueLength, tagValue);
732
733 if ((ret == IFD_SUCCESS) && (valueLength == 1) &&
734 (tagValue[0] > 1))
735 {
736 supportedChannels = tagValue[0];
737 Log2(PCSC_LOG_INFO,
738 "Support %d simultaneous readers", tagValue[0]);
739 }
740 else
741 supportedChannels = 1;
742
743 /* Check to see if it is a hotplug reader and different */
744 if ((((sReadersContexts[i]->port & 0xFFFF0000) ==
745 PCSCLITE_HP_BASE_PORT)
746 && (sReadersContexts[i]->port != port))
747 || (supportedChannels > 1))
748 {
749 const char *reader = sReadersContexts[i]->readerState->readerName;
750
751 /*
752 * tells the caller who the parent of this
753 * clone is so it can use its shared
754 * resources like mutex/etc.
755 */
756 parent = i;
757
758 /*
759 * If the same reader already exists and it is
760 * hotplug then we must look for others and
761 * enumerate the readername
762 */
763 currentDigit = strtol(reader + strlen(reader) - 5, NULL, 16);
764
765 /* This spot is taken */
766 usedDigits[currentDigit] = true;
767 }
768 }
769 }
770 }
771 }
772
773 /* default value */
774 i = 0;
775
776 /* Other identical readers exist on the same bus */
777 if (currentDigit != -1)
778 {
779 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
780 {
781 /* get the first free digit */
782 if (usedDigits[i] == false)
783 break;
784 }
785
787 {
788 Log2(PCSC_LOG_ERROR, "Max number of readers reached: %d", PCSCLITE_MAX_READERS_CONTEXTS);
789 return -2;
790 }
791
792 if (i >= supportedChannels)
793 {
794 Log3(PCSC_LOG_ERROR, "Driver %s does not support more than "
795 "%d reader(s). Maybe the driver should support "
796 "TAG_IFD_SIMULTANEOUS_ACCESS", libraryName, supportedChannels);
797 return -2;
798 }
799 }
800
801#ifdef FILTER_NAMES
802 extend = SYS_GetEnv("PCSCLITE_FILTER_EXTEND_READER_NAMES");
803 if (NULL == extend)
804 extend = "";
805#endif
806
807 snprintf(rContext->readerState->readerName,
808 sizeof(rContext->readerState->readerName), "%s%s %02X 00",
809 readerName, extend, i);
810
811 /* Set the slot in 0xDDDDCCCC */
812 rContext->slot = i << 16;
813
814 return parent;
815}
816
817LONG RFReaderInfo(const char *readerName, READER_CONTEXT ** sReader)
818{
819 int i;
820
821 if (readerName == NULL)
823
824 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
825 {
826 if (sReadersContexts[i]->vHandle != 0)
827 {
828 if (strcmp(readerName,
829 sReadersContexts[i]->readerState->readerName) == 0)
830 {
831 /* Increase reference count */
832 REF_READER(sReadersContexts[i])
833
834 *sReader = sReadersContexts[i];
835 return SCARD_S_SUCCESS;
836 }
837 }
838 }
839
841}
842
843LONG RFReaderInfoById(SCARDHANDLE hCard, READER_CONTEXT * * sReader)
844{
845 int i;
846
847 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
848 {
849 if (sReadersContexts[i]->vHandle != 0)
850 {
851 RDR_CLIHANDLES * currentHandle;
852 (void)pthread_mutex_lock(&sReadersContexts[i]->handlesList_lock);
853 currentHandle = list_seek(&sReadersContexts[i]->handlesList,
854 &hCard);
855 (void)pthread_mutex_unlock(&sReadersContexts[i]->handlesList_lock);
856 if (currentHandle != NULL)
857 {
858 /* Increase reference count */
859 REF_READER(sReadersContexts[i])
860
861 *sReader = sReadersContexts[i];
862 return SCARD_S_SUCCESS;
863 }
864 }
865 }
866
868}
869
870LONG RFLoadReader(READER_CONTEXT * rContext)
871{
872 LONG ret = SCARD_S_SUCCESS;
873 if (rContext->vHandle != 0)
874 {
875 Log2(PCSC_LOG_INFO, "Reusing already loaded driver for %s",
876 rContext->library);
877 /* Another reader exists with this library loaded */
878 return SCARD_S_SUCCESS;
879 }
880
881 rContext->vHandle = DYN_LoadLibrary(rContext->library);
882 if (NULL == rContext->vHandle)
884 return ret;
885}
886
887LONG RFBindFunctions(READER_CONTEXT * rContext)
888{
889 int rv;
890 void *f;
891
892 rv = DYN_GetAddress(rContext->vHandle, &f, "IFDHCreateChannelByName", true);
893 if (SCARD_S_SUCCESS == rv)
894 {
895 /* Ifd Handler 3.0 found */
896 rContext->version = IFD_HVERSION_3_0;
897 }
898 else
899 {
900 rv = DYN_GetAddress(rContext->vHandle, &f, "IFDHCreateChannel", false);
901 if (SCARD_S_SUCCESS == rv)
902 {
903 /* Ifd Handler 2.0 found */
904 rContext->version = IFD_HVERSION_2_0;
905 }
906 else
907 {
908 /* Neither version of the IFD Handler was found - exit */
909 Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing");
911 }
912 }
913
914 if (rContext->version == IFD_HVERSION_2_0)
915 {
916 /* The following binds version 2.0 of the IFD Handler specs */
917#define GET_ADDRESS_OPTIONALv2(s, code) \
918{ \
919 void *f1 = NULL; \
920 int rvl = DYN_GetAddress(rContext->vHandle, &f1, "IFDH" #s, false); \
921 if (SCARD_S_SUCCESS != rvl) \
922 { \
923 code \
924 } \
925 rContext->psFunctions.psFunctions_v2.pvf ## s = f1; \
926}
927
928#define GET_ADDRESSv2(s) \
929 GET_ADDRESS_OPTIONALv2(s, \
930 Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing: " #s ); \
931 return(rv); )
932
933 Log1(PCSC_LOG_INFO, "Loading IFD Handler 2.0");
934
935 GET_ADDRESSv2(CreateChannel)
936 GET_ADDRESSv2(CloseChannel)
937 GET_ADDRESSv2(GetCapabilities)
938 GET_ADDRESSv2(SetCapabilities)
939 GET_ADDRESSv2(PowerICC)
940 GET_ADDRESSv2(TransmitToICC)
941 GET_ADDRESSv2(ICCPresence)
942 GET_ADDRESS_OPTIONALv2(SetProtocolParameters, )
943
944 GET_ADDRESSv2(Control)
945 }
946 else if (rContext->version == IFD_HVERSION_3_0)
947 {
948 /* The following binds version 3.0 of the IFD Handler specs */
949#define GET_ADDRESS_OPTIONALv3(s, code) \
950{ \
951 void *f1 = NULL; \
952 int rvl = DYN_GetAddress(rContext->vHandle, &f1, "IFDH" #s, false); \
953 if (SCARD_S_SUCCESS != rvl) \
954 { \
955 code \
956 } \
957 rContext->psFunctions.psFunctions_v3.pvf ## s = f1; \
958}
959
960#define GET_ADDRESSv3(s) \
961 GET_ADDRESS_OPTIONALv3(s, \
962 Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing: " #s ); \
963 return(rv); )
964
965 Log1(PCSC_LOG_INFO, "Loading IFD Handler 3.0");
966
967 GET_ADDRESSv2(CreateChannel)
968 GET_ADDRESSv2(CloseChannel)
969 GET_ADDRESSv2(GetCapabilities)
970 GET_ADDRESSv2(SetCapabilities)
971 GET_ADDRESSv2(PowerICC)
972 GET_ADDRESSv2(TransmitToICC)
973 GET_ADDRESSv2(ICCPresence)
974 GET_ADDRESS_OPTIONALv2(SetProtocolParameters, )
975
976 GET_ADDRESSv3(CreateChannelByName)
977 GET_ADDRESSv3(Control)
978 }
979 else
980 {
981 /* Who knows what could have happened for it to get here. */
982 Log1(PCSC_LOG_CRITICAL, "IFD Handler not 1.0/2.0 or 3.0");
984 }
985
986 return SCARD_S_SUCCESS;
987}
988
989LONG RFUnBindFunctions(READER_CONTEXT * rContext)
990{
991 /* Zero out everything */
992 memset(&rContext->psFunctions, 0, sizeof(rContext->psFunctions));
993
994 return SCARD_S_SUCCESS;
995}
996
997LONG RFUnloadReader(READER_CONTEXT * rContext)
998{
999 /* Make sure no one else is using this library */
1000 if (*rContext->pFeeds == 1)
1001 {
1002 Log1(PCSC_LOG_INFO, "Unloading reader driver.");
1003 (void)DYN_CloseLibrary(rContext->vHandle);
1004 rContext->vHandle = NULL;
1005 }
1006
1007 rContext->vHandle = NULL;
1008
1009 return SCARD_S_SUCCESS;
1010}
1011
1012LONG RFCheckSharing(SCARDHANDLE hCard, READER_CONTEXT * rContext)
1013{
1014 if (rContext->hLockId == 0 || rContext->hLockId == hCard)
1015 return SCARD_S_SUCCESS;
1016 else
1018}
1019
1020LONG RFLockSharing(SCARDHANDLE hCard, READER_CONTEXT * rContext)
1021{
1022 LONG rv;
1023
1024 (void)pthread_mutex_lock(&LockMutex);
1025 rv = RFCheckSharing(hCard, rContext);
1026 if (SCARD_S_SUCCESS == rv)
1027 {
1028 rContext->LockCount += 1;
1029 rContext->hLockId = hCard;
1030 }
1031 (void)pthread_mutex_unlock(&LockMutex);
1032
1033 return rv;
1034}
1035
1036LONG RFUnlockSharing(SCARDHANDLE hCard, READER_CONTEXT * rContext)
1037{
1038 LONG rv;
1039
1040 (void)pthread_mutex_lock(&LockMutex);
1041 rv = RFCheckSharing(hCard, rContext);
1042 if (SCARD_S_SUCCESS == rv)
1043 {
1045 {
1046 if (rContext->LockCount > 1)
1047 rContext->LockCount -= 1;
1048 else
1050 }
1051 else
1052 {
1053 if (rContext->LockCount > 0)
1054 {
1055 rContext->LockCount -= 1;
1056 if (0 == rContext->LockCount)
1057 rContext->hLockId = 0;
1058 }
1059 else
1060 /* rContext->LockCount == 0 */
1062 }
1063 }
1064 (void)pthread_mutex_unlock(&LockMutex);
1065
1066 return rv;
1067}
1068
1069LONG RFUnlockAllSharing(SCARDHANDLE hCard, READER_CONTEXT * rContext)
1070{
1071 LONG rv;
1072
1073 (void)pthread_mutex_lock(&LockMutex);
1074 rv = RFCheckSharing(hCard, rContext);
1075 if (SCARD_S_SUCCESS == rv)
1076 {
1077 rContext->LockCount = 0;
1078 rContext->hLockId = 0;
1079 }
1080 (void)pthread_mutex_unlock(&LockMutex);
1081
1082 return rv;
1083}
1084
1085LONG RFInitializeReader(READER_CONTEXT * rContext)
1086{
1087 LONG rv = SCARD_S_SUCCESS;
1088 RESPONSECODE rvd;
1089
1090 /* Spawn the event handler thread */
1091 Log3(PCSC_LOG_INFO, "Attempting startup of %s using %s",
1092 rContext->readerState->readerName, rContext->library);
1093
1094#ifndef PCSCLITE_STATIC_DRIVER
1095 /* loads the library */
1096 rv = RFLoadReader(rContext);
1097 if (rv != SCARD_S_SUCCESS)
1098 {
1099 Log2(PCSC_LOG_ERROR, "RFLoadReader failed: 0x%lX", rv);
1100 return rv;
1101 }
1102
1103 /* binds the functions */
1104 rv = RFBindFunctions(rContext);
1105
1106 if (rv != SCARD_S_SUCCESS)
1107 {
1108 Log2(PCSC_LOG_ERROR, "RFBindFunctions failed: 0x%lX", rv);
1109 (void)RFUnloadReader(rContext);
1110 return rv;
1111 }
1112#else
1113 /* define a fake vHandle. Can be any value except NULL */
1114 rContext->vHandle = RFInitializeReader;
1115#endif
1116
1117 /* tries to open the port */
1118 rvd = IFDOpenIFD(rContext);
1119
1120 if (rvd != IFD_SUCCESS)
1121 {
1122 int log_level = PCSC_LOG_CRITICAL;
1124
1125 if (IFD_NO_SUCH_DEVICE == rvd)
1126 {
1127 /* wrong interface on a composite device? */
1128 log_level = PCSC_LOG_INFO;
1130 }
1131
1132 Log3(log_level, "Open Port 0x%X Failed (%s)",
1133 rContext->port, rContext->device);
1134
1135 /* IFDOpenIFD() failed */
1136 /* the reader was not started correctly */
1137 rContext->slot = -1;
1138 }
1139
1140 return rv;
1141}
1142
1143void RFUnInitializeReader(READER_CONTEXT * rContext)
1144{
1145 Log2(PCSC_LOG_INFO, "Attempting shutdown of %s.",
1146 rContext->readerState->readerName);
1147
1148 /* Do not close a reader if IFDOpenIFD() failed in RFInitializeReader() */
1149 if (rContext->slot != -1)
1150 (void)IFDCloseIFD(rContext);
1151
1152 (void)RFUnBindFunctions(rContext);
1153 (void)RFUnloadReader(rContext);
1154
1155 /*
1156 * Zero out the public status struct to allow it to be recycled and
1157 * used again
1158 */
1159 memset(rContext->readerState->readerName, 0,
1160 sizeof(rContext->readerState->readerName));
1161 memset(rContext->readerState->cardAtr, 0,
1162 sizeof(rContext->readerState->cardAtr));
1163 rContext->readerState->readerState = 0;
1164 rContext->readerState->eventCounter = 0;
1165 rContext->readerState->readerSharing = 0;
1168
1169 return;
1170}
1171
1172SCARDHANDLE RFCreateReaderHandle(READER_CONTEXT * rContext)
1173{
1174 SCARDHANDLE randHandle;
1175 LONG ret;
1176
1177 (void)rContext;
1178
1179 do
1180 {
1181 READER_CONTEXT *dummy_reader;
1182
1183 /* Create a random handle with 32 bits check to see if it already is
1184 * used. */
1185 /* FIXME: THIS IS NOT STRONG ENOUGH: A 128-bit token should be
1186 * generated. The client and server would associate token and hCard
1187 * for authentication. */
1188 randHandle = SYS_RandomInt();
1189
1190 /* do we already use this hCard somewhere? */
1191 ret = RFReaderInfoById(randHandle, &dummy_reader);
1192 if (SCARD_S_SUCCESS == ret)
1193 UNREF_READER(dummy_reader)
1194 }
1195 while (SCARD_S_SUCCESS == ret);
1196
1197 /* Once the for loop is completed w/o restart a good handle was
1198 * found and the loop can be exited. */
1199 return randHandle;
1200}
1201
1202LONG RFAddReaderHandle(READER_CONTEXT * rContext, SCARDHANDLE hCard)
1203{
1204 int listLength, lrv;
1205 RDR_CLIHANDLES *newHandle;
1206 LONG rv = SCARD_S_SUCCESS;
1207
1208 (void)pthread_mutex_lock(&rContext->handlesList_lock);
1209 listLength = list_size(&rContext->handlesList);
1210
1211 /* Throttle the number of possible handles */
1212 if (listLength >= maxReaderHandles)
1213 {
1214 Log2(PCSC_LOG_CRITICAL,
1215 "Too many handles opened, exceeding configured max (%d)",
1216 maxReaderHandles);
1217 rv = SCARD_E_NO_MEMORY;
1218 goto end;
1219 }
1220
1221 newHandle = malloc(sizeof(RDR_CLIHANDLES));
1222 if (NULL == newHandle)
1223 {
1224 Log1(PCSC_LOG_CRITICAL, "malloc failed");
1225 rv = SCARD_E_NO_MEMORY;
1226 goto end;
1227 }
1228
1229 newHandle->hCard = hCard;
1230 atomic_init(&newHandle->dwEventStatus, 0);
1231
1232 lrv = list_append(&rContext->handlesList, newHandle);
1233 if (lrv < 0)
1234 {
1235 free(newHandle);
1236 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
1237 lrv);
1238 rv = SCARD_E_NO_MEMORY;
1239 }
1240end:
1241 (void)pthread_mutex_unlock(&rContext->handlesList_lock);
1242 return rv;
1243}
1244
1245LONG RFRemoveReaderHandle(READER_CONTEXT * rContext, SCARDHANDLE hCard)
1246{
1247 RDR_CLIHANDLES *currentHandle;
1248 int lrv;
1249 LONG rv = SCARD_S_SUCCESS;
1250
1251 (void)pthread_mutex_lock(&rContext->handlesList_lock);
1252 currentHandle = list_seek(&rContext->handlesList, &hCard);
1253 if (NULL == currentHandle)
1254 {
1255 Log2(PCSC_LOG_CRITICAL, "list_seek failed to locate hCard=%lX", hCard);
1257 goto end;
1258 }
1259
1260 lrv = list_delete(&rContext->handlesList, currentHandle);
1261 if (lrv < 0)
1262 Log2(PCSC_LOG_CRITICAL,
1263 "list_delete failed with return value: %d", lrv);
1264
1265 free(currentHandle);
1266
1267end:
1268 (void)pthread_mutex_unlock(&rContext->handlesList_lock);
1269
1270 /* Not Found */
1271 return rv;
1272}
1273
1274void RFSetReaderEventState(READER_CONTEXT * rContext, DWORD dwEvent)
1275{
1276 /* Set all the handles for that reader to the event */
1277 int list_index, listSize;
1278 RDR_CLIHANDLES *currentHandle;
1279
1280 (void)pthread_mutex_lock(&rContext->handlesList_lock);
1281 listSize = list_size(&rContext->handlesList);
1282
1283 for (list_index = 0; list_index < listSize; list_index++)
1284 {
1285 currentHandle = list_get_at(&rContext->handlesList, list_index);
1286 if (NULL == currentHandle)
1287 {
1288 Log2(PCSC_LOG_CRITICAL, "list_get_at failed at index %d",
1289 list_index);
1290 continue;
1291 }
1292
1293 currentHandle->dwEventStatus = dwEvent;
1294 }
1295 (void)pthread_mutex_unlock(&rContext->handlesList_lock);
1296
1297 if (SCARD_REMOVED == dwEvent)
1298 {
1299 /* unlock the card */
1300 rContext->hLockId = 0;
1301 rContext->LockCount = 0;
1302 }
1303
1304 return;
1305}
1306
1307LONG RFCheckReaderEventState(READER_CONTEXT * rContext, SCARDHANDLE hCard)
1308{
1309 LONG rv;
1310 RDR_CLIHANDLES *currentHandle;
1311 DWORD dwEventStatus;
1312
1313 (void)pthread_mutex_lock(&rContext->handlesList_lock);
1314 currentHandle = list_seek(&rContext->handlesList, &hCard);
1315 (void)pthread_mutex_unlock(&rContext->handlesList_lock);
1316 if (NULL == currentHandle)
1317 {
1318 /* Not Found */
1319 Log2(PCSC_LOG_CRITICAL, "list_seek failed for hCard 0x%lX", hCard);
1321 }
1322
1323 dwEventStatus = currentHandle->dwEventStatus;
1324 switch(dwEventStatus)
1325 {
1326 case 0:
1327 rv = SCARD_S_SUCCESS;
1328 break;
1329
1330 case SCARD_REMOVED:
1332 break;
1333
1334 case SCARD_RESET:
1335 rv = SCARD_W_RESET_CARD;
1336 break;
1337
1338 default:
1340 }
1341
1342 return rv;
1343}
1344
1345LONG RFClearReaderEventState(READER_CONTEXT * rContext, SCARDHANDLE hCard)
1346{
1347 RDR_CLIHANDLES *currentHandle;
1348
1349 (void)pthread_mutex_lock(&rContext->handlesList_lock);
1350 currentHandle = list_seek(&rContext->handlesList, &hCard);
1351 (void)pthread_mutex_unlock(&rContext->handlesList_lock);
1352 if (NULL == currentHandle)
1353 /* Not Found */
1355
1356 currentHandle->dwEventStatus = 0;
1357
1358 /* hCards should be unique so we
1359 * should be able to return
1360 * as soon as we have a hit */
1361 return SCARD_S_SUCCESS;
1362}
1363
1364LONG RFCheckReaderStatus(READER_CONTEXT * rContext)
1365{
1366 if (rContext->readerState->readerState & SCARD_UNKNOWN)
1368 else
1369 return SCARD_S_SUCCESS;
1370}
1371
1372void RFCleanupReaders(void)
1373{
1374 int i;
1375
1376 Log1(PCSC_LOG_INFO, "entering cleaning function");
1377 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1378 {
1379 if (sReadersContexts[i]->vHandle != 0)
1380 {
1381 LONG rv;
1382 char lpcStripReader[MAX_READERNAME];
1383
1384 Log2(PCSC_LOG_INFO, "Stopping reader: %s",
1385 sReadersContexts[i]->readerState->readerName);
1386
1387 strncpy(lpcStripReader,
1388 sReadersContexts[i]->readerState->readerName,
1389 sizeof(lpcStripReader));
1390 /* strip the 6 last char ' 00 00' */
1391 lpcStripReader[strlen(lpcStripReader) - 6] = '\0';
1392
1393 rv = RFRemoveReader(lpcStripReader, sReadersContexts[i]->port,
1394 REMOVE_READER_NO_FLAG);
1395
1396 if (rv != SCARD_S_SUCCESS)
1397 Log2(PCSC_LOG_ERROR, "RFRemoveReader error: %s", rv2text(rv));
1398 }
1399
1400 free(sReadersContexts[i]);
1401 sReadersContexts[i] = NULL;
1402 }
1403
1404#ifdef USE_SERIAL
1405 if (ConfigFile)
1406 {
1407 free(ConfigFile);
1408 ConfigFile = NULL;
1409 }
1410#endif
1411}
1412
1417#ifdef USE_USB
1418void RFWaitForReaderInit(void)
1419{
1420 bool need_to_wait;
1421
1422 do
1423 {
1424 need_to_wait = false;
1425 for (int i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1426 {
1427 /* reader is present */
1428 if (sReadersContexts[i] && sReadersContexts[i]->vHandle != NULL)
1429 {
1430 /* but card state is not yet available */
1432 == sReadersContexts[i]->readerState->cardAtrLength)
1433 {
1434 Log2(PCSC_LOG_DEBUG, "Waiting init for reader: %s",
1435 sReadersContexts[i]->readerState->readerName);
1436 need_to_wait = true;
1437 }
1438 }
1439 }
1440
1441 if (need_to_wait)
1442 SYS_USleep(10*1000); /* 10 ms */
1443 } while (need_to_wait);
1444}
1445#endif
1446
1447#ifdef USE_SERIAL
1448int RFStartSerialReaders(const char *readerconf)
1449{
1450 SerialReader *reader_list = NULL;
1451 int i, rv;
1452
1453 /* remember the configuration filename for RFReCheckReaderConf() */
1454 ConfigFile = strdup(readerconf);
1455
1456 rv = DBGetReaderListDir(readerconf, &reader_list);
1457
1458 /* the list is empty */
1459 if (NULL == reader_list)
1460 return rv;
1461
1462 for (i=0; reader_list[i].pcFriendlyname; i++)
1463 {
1464 int j;
1465
1466 (void)RFAddReader(reader_list[i].pcFriendlyname,
1467 reader_list[i].channelId,
1468 reader_list[i].pcLibpath, reader_list[i].pcDevicename);
1469
1470 /* update the ConfigFileCRC (this false "CRC" is very weak) */
1471 for (j=0; j<reader_list[i].pcFriendlyname[j]; j++)
1472 ConfigFileCRC += reader_list[i].pcFriendlyname[j];
1473 for (j=0; j<reader_list[i].pcLibpath[j]; j++)
1474 ConfigFileCRC += reader_list[i].pcLibpath[j];
1475 for (j=0; j<reader_list[i].pcDevicename[j]; j++)
1476 ConfigFileCRC += reader_list[i].pcDevicename[j];
1477
1478 /* free strings allocated by DBGetReaderListDir() */
1479 free(reader_list[i].pcFriendlyname);
1480 free(reader_list[i].pcLibpath);
1481 free(reader_list[i].pcDevicename);
1482 }
1483 free(reader_list);
1484
1485 return rv;
1486}
1487
1488void RFReCheckReaderConf(void)
1489{
1490 SerialReader *reader_list = NULL;
1491 int i, crc;
1492
1493 (void)DBGetReaderListDir(ConfigFile, &reader_list);
1494
1495 /* the list is empty */
1496 if (NULL == reader_list)
1497 return;
1498
1499 crc = 0;
1500 for (i=0; reader_list[i].pcFriendlyname; i++)
1501 {
1502 int j;
1503
1504 /* calculate a local crc */
1505 for (j=0; j<reader_list[i].pcFriendlyname[j]; j++)
1506 crc += reader_list[i].pcFriendlyname[j];
1507 for (j=0; j<reader_list[i].pcLibpath[j]; j++)
1508 crc += reader_list[i].pcLibpath[j];
1509 for (j=0; j<reader_list[i].pcDevicename[j]; j++)
1510 crc += reader_list[i].pcDevicename[j];
1511 }
1512
1513 /* cancel if the configuration file has been modified */
1514 if (crc != ConfigFileCRC)
1515 {
1516 Log2(PCSC_LOG_CRITICAL,
1517 "configuration file: %s has been modified. Recheck canceled",
1518 ConfigFile);
1519 return;
1520 }
1521
1522 for (i=0; reader_list[i].pcFriendlyname; i++)
1523 {
1524 int r;
1525 char present = false;
1526
1527 Log2(PCSC_LOG_DEBUG, "refresh reader: %s",
1528 reader_list[i].pcFriendlyname);
1529
1530 /* is the reader already present? */
1531 for (r = 0; r < PCSCLITE_MAX_READERS_CONTEXTS; r++)
1532 {
1533 if (sReadersContexts[r]->vHandle != 0)
1534 {
1535 char lpcStripReader[MAX_READERNAME];
1536 int tmplen;
1537
1538 /* get the reader name without the reader and slot numbers */
1539 strncpy(lpcStripReader,
1540 sReadersContexts[i]->readerState->readerName,
1541 sizeof(lpcStripReader));
1542 tmplen = strlen(lpcStripReader);
1543 lpcStripReader[tmplen - 6] = 0;
1544
1545 if ((strcmp(reader_list[i].pcFriendlyname, lpcStripReader) == 0)
1546 && (reader_list[r].channelId == sReadersContexts[i]->port))
1547 {
1548 DWORD dwStatus = 0;
1549
1550 /* the reader was already started */
1551 present = true;
1552
1553 /* verify the reader is still connected */
1554 if (IFDStatusICC(sReadersContexts[r], &dwStatus)
1555 != SCARD_S_SUCCESS)
1556 {
1557 Log2(PCSC_LOG_INFO, "Reader %s disappeared",
1558 reader_list[i].pcFriendlyname);
1559 (void)RFRemoveReader(reader_list[i].pcFriendlyname,
1560 reader_list[r].channelId, REMOVE_READER_NO_FLAG);
1561 }
1562 }
1563 }
1564 }
1565
1566 /* the reader was not present */
1567 if (!present)
1568 /* we try to add it */
1569 (void)RFAddReader(reader_list[i].pcFriendlyname,
1570 reader_list[i].channelId, reader_list[i].pcLibpath,
1571 reader_list[i].pcDevicename);
1572
1573 /* free strings allocated by DBGetReaderListDir() */
1574 free(reader_list[i].pcFriendlyname);
1575 free(reader_list[i].pcLibpath);
1576 free(reader_list[i].pcDevicename);
1577 }
1578 free(reader_list);
1579}
1580#endif
1581
1583{
1584 (void)pthread_mutex_lock(&rContext->powerState_lock);
1585 int result = rContext->powerState;
1586 (void)pthread_mutex_unlock(&rContext->powerState_lock);
1587 return result;
1588}
1589
1590void RFSetPowerState(READER_CONTEXT * rContext, int value)
1591{
1592 (void)pthread_mutex_lock(&rContext->powerState_lock);
1593 rContext->powerState = value;
1594 (void)pthread_mutex_unlock(&rContext->powerState_lock);
1595}
1596
This handles debugging.
This abstracts dynamic library loading functions.
void EHSignalEventToClients(void)
Sends an asynchronous event to any waiting client.
This handles card insertion/removal events, updates ATR, protocol, and status information.
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
#define READER_NOT_INITIALIZED
Special value to indicate that power up has not yet happen This is used to auto start mode to wait un...
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition pcsclite.h:113
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition pcsclite.h:125
#define SCARD_W_RESET_CARD
The smart card has been reset, so any shared state information is invalid.
Definition pcsclite.h:217
#define SCARD_F_UNKNOWN_ERROR
An internal error has been detected, but the source is unknown.
Definition pcsclite.h:147
#define SCARD_E_INVALID_TARGET
Registry startup information is missing or invalid.
Definition pcsclite.h:117
#define SCARD_S_SUCCESS
No error was encountered.
Definition pcsclite.h:107
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition pcsclite.h:119
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
Definition pcsclite.h:129
#define SCARD_E_DUPLICATE_READER
The reader driver did not produce a unique reader name.
Definition pcsclite.h:161
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition pcsclite.h:141
#define SCARD_W_REMOVED_CARD
The smart card has been removed, so further communication is not possible.
Definition pcsclite.h:219
#define SCARD_E_NOT_TRANSACTED
An attempt was made to end a non-existent transaction.
Definition pcsclite.h:151
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition pcsclite.h:153
This provides a search API for hot pluggble devices.
#define IFD_NO_SUCH_DEVICE
The IFD_NO_SUCH_DEVICE error must be returned by the driver when it detects the reader is no more pre...
Definition ifdhandler.h:372
#define TAG_IFD_SIMULTANEOUS_ACCESS
number of reader the driver can manage
Definition ifdhandler.h:326
#define TAG_IFD_THREAD_SAFE
driver is thread safe
Definition ifdhandler.h:324
#define TAG_IFD_SLOTS_NUMBER
number of slots of the reader
Definition ifdhandler.h:325
#define TAG_IFD_POLLING_THREAD_WITH_TIMEOUT
driver uses a polling thread with a timeout parameter
Definition ifdhandler.h:330
#define TAG_IFD_SLOT_THREAD_SAFE
support access to different slots of the reader
Definition ifdhandler.h:323
#define IFD_SUCCESS
no error
Definition ifdhandler.h:351
#define TAG_IFD_DEVICE_REMOVED
signals the reader has been removed
Definition ifdhandler.h:331
RESPONSECODE IFDCloseIFD(READER_CONTEXT *rContext)
Close a communication channel to the IFD.
Definition ifdwrapper.c:163
RESPONSECODE IFDOpenIFD(READER_CONTEXT *rContext)
Open a communication channel to the IFD.
Definition ifdwrapper.c:105
RESPONSECODE IFDGetCapabilities(READER_CONTEXT *rContext, DWORD dwTag, PDWORD pdwLength, PUCHAR pucValue)
Gets capabilities in the reader.
Definition ifdwrapper.c:240
LONG IFDStatusICC(READER_CONTEXT *rContext, PDWORD pdwStatus)
Provide statistical information about the IFD and ICC including insertions, atr, powering status/etc.
Definition ifdwrapper.c:339
RESPONSECODE IFDSetCapabilities(READER_CONTEXT *rContext, DWORD dwTag, DWORD dwLength, PUCHAR pucValue)
Set capabilities in the reader.
Definition ifdwrapper.c:209
This wraps the dynamic ifdhandler functions.
#define SCARD_PROTOCOL_UNDEFINED
protocol not set
Definition pcsclite.h:240
#define MAX_ATR_SIZE
Maximum ATR size.
Definition pcsclite.h:59
#define SCARD_UNKNOWN
Unknown state.
Definition pcsclite.h:258
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition pcsclite.h:55
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition pcsclite.h:285
int RFGetPowerState(READER_CONTEXT *rContext)
Wait until all connected readers have a chance to power up a possibly inserted card.
This keeps track of a list of currently available reader structures.
SCARDHANDLE hCard
hCard for this connection
_Atomic DWORD dwEventStatus
Recent event that must be sent.
union ReaderContext::@111161344206126344220174204324120377211343341035 psFunctions
driver functions
RESPONSECODE(* pthCardEvent)(DWORD, int)
Card Event sync.
pthread_mutex_t * mMutex
Mutex for this connection.
pthread_mutex_t powerState_lock
powerState mutex
int port
Port ID.
pthread_t pthThread
Event polling thread.
_Atomic int32_t contexts
Number of open contexts.
int slot
Current Reader Slot.
int * pFeeds
Number of shared client to lib.
_Atomic SCARDHANDLE hLockId
Lock Id.
int * pMutex
Number of client to mutex.
int version
IFD Handler version number.
pthread_mutex_t handlesList_lock
lock for the above list
_Atomic int LockCount
number of recursive locks
char * library
Library Path.
struct pubReaderStatesList * readerState
link to the reader state
_Atomic int reference
number of users of the structure
int powerState
auto power off state
char * device
Device Name.
_Atomic LPVOID vHandle
Dlopen handle.
char * pcFriendlyname
FRIENDLYNAME.
char * pcLibpath
LIBPATH.
char * pcDevicename
DEVICENAME.
Define an exported public reader state structure so each application gets instant notification of cha...
_Atomic int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
char readerName[MAX_READERNAME]
reader name
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
uint32_t eventCounter
number of card events
_Atomic uint32_t cardAtrLength
ATR length.
uint32_t readerState
SCARD_* bit field.
This handles abstract system level calls.
const char * SYS_GetEnv(const char *name)
(More) secure version of getenv(3)
Definition sys_unix.c:168
int SYS_RandomInt(void)
Generate a pseudo random number.
Definition sys_unix.c:108
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition sys_unix.c:80