pcsc-lite 2.3.0
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;
76int16_t ReaderEvents = 1;
77
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 /* we have one more reader */
404 ReaderEvents++;
405 /* wrap? */
406 if (ReaderEvents < 0)
407 ReaderEvents = 1;
408
409 /* Call on the driver to see if there are multiple slots */
410 dwGetSize = sizeof(ucGetData);
411 rv = IFDGetCapabilities((sReadersContexts[dwContext]),
412 TAG_IFD_SLOTS_NUMBER, &dwGetSize, ucGetData);
413
414 int nbSlots = ucGetData[0];
415 if (rv != IFD_SUCCESS || dwGetSize != 1 || nbSlots == 0)
416 /* Reader does not have this defined. Must be a single slot
417 * reader so we can just return SCARD_S_SUCCESS. */
418 return SCARD_S_SUCCESS;
419
420 if (1 == nbSlots)
421 /* Reader has only one slot */
422 return SCARD_S_SUCCESS;
423
424 /*
425 * Check the number of slots and create a different
426 * structure for each one accordingly
427 */
428
429 /* Initialize the rest of the slots */
430 for (j = 1; j < nbSlots; j++)
431 {
432 char *tmpReader = NULL;
433 DWORD dwContextB = 0;
434 RESPONSECODE (*fct)(DWORD, int) = NULL;
435
436 /* We must find an empty spot to put the reader structure */
437 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
438 {
439 if (sReadersContexts[i]->vHandle == 0)
440 {
441 dwContextB = i;
442 break;
443 }
444 }
445
447 {
448 /* No more slot left return */
449 RFRemoveReader(readerName, port, REMOVE_READER_NO_FLAG);
450 return SCARD_E_NO_MEMORY;
451 }
452
453 /* Copy the previous reader name and increment the slot number */
454 tmpReader = sReadersContexts[dwContextB]->readerState->readerName;
455 memcpy(tmpReader,
456 sReadersContexts[dwContext]->readerState->readerName,
457 sizeof(sReadersContexts[dwContextB]->readerState->readerName));
458 snprintf(tmpReader + strlen(tmpReader) - 2, 3, "%02X", j);
459
460 sReadersContexts[dwContextB]->library =
461 sReadersContexts[dwContext]->library;
462 sReadersContexts[dwContextB]->device =
463 sReadersContexts[dwContext]->device;
464 sReadersContexts[dwContextB]->version =
465 sReadersContexts[dwContext]->version;
466 sReadersContexts[dwContextB]->port =
467 sReadersContexts[dwContext]->port;
468 sReadersContexts[dwContextB]->vHandle =
469 sReadersContexts[dwContext]->vHandle;
470 sReadersContexts[dwContextB]->mMutex =
471 sReadersContexts[dwContext]->mMutex;
472 sReadersContexts[dwContextB]->pMutex =
473 sReadersContexts[dwContext]->pMutex;
474 sReadersContexts[dwContextB]->slot =
475 sReadersContexts[dwContext]->slot + j;
476 sReadersContexts[dwContextB]->pthCardEvent = NULL;
477
478 /*
479 * Added by Dave - slots did not have a pFeeds
480 * parameter so it was by luck they were working
481 */
482 sReadersContexts[dwContextB]->pFeeds =
483 sReadersContexts[dwContext]->pFeeds;
484
485 /* Added by Dave for multiple slots */
486 *(sReadersContexts[dwContextB])->pFeeds += 1;
487
488 sReadersContexts[dwContextB]->contexts = 0;
489 sReadersContexts[dwContextB]->hLockId = 0;
490 sReadersContexts[dwContextB]->LockCount = 0;
491
492 lrv = list_init(&sReadersContexts[dwContextB]->handlesList);
493 if (lrv < 0)
494 {
495 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
496 return SCARD_E_NO_MEMORY;
497 }
498
499 lrv = list_attributes_seeker(&sReadersContexts[dwContextB]->handlesList,
500 RDR_CLIHANDLES_seeker);
501 if (lrv < 0)
502 {
503 Log2(PCSC_LOG_CRITICAL,
504 "list_attributes_seeker failed with return value: %d", lrv);
505 return SCARD_E_NO_MEMORY;
506 }
507
508 (void)pthread_mutex_init(&sReadersContexts[dwContextB]->handlesList_lock, NULL);
509 (void)pthread_mutex_init(&sReadersContexts[dwContextB]->powerState_lock,
510 NULL);
511 sReadersContexts[dwContextB]->powerState = POWER_STATE_UNPOWERED;
512
513 /* reference count */
514 sReadersContexts[dwContextB]->reference = 1;
515
516 /* Call on the parent driver to see if the slots are thread safe */
517 dwGetSize = sizeof(ucThread);
518 rv = IFDGetCapabilities((sReadersContexts[dwContext]),
519 TAG_IFD_SLOT_THREAD_SAFE, &dwGetSize, ucThread);
520
521 if (rv == IFD_SUCCESS && dwGetSize == 1 && ucThread[0] == 1)
522 {
523 Log1(PCSC_LOG_INFO, "Driver is slot thread safe");
524
525 sReadersContexts[dwContextB]->library =
526 strdup(sReadersContexts[dwContext]->library);
527 sReadersContexts[dwContextB]->device =
528 strdup(sReadersContexts[dwContext]->device);
529 sReadersContexts[dwContextB]->mMutex =
530 malloc(sizeof(pthread_mutex_t));
531 (void)pthread_mutex_init(sReadersContexts[dwContextB]->mMutex,
532 NULL);
533
534 sReadersContexts[dwContextB]->pMutex = malloc(sizeof(int));
535 *(sReadersContexts[dwContextB])->pMutex = 1;
536 }
537 else
538 *(sReadersContexts[dwContextB])->pMutex += 1;
539
540 dwNumReadersContexts += 1;
541
542 rv = RFInitializeReader(sReadersContexts[dwContextB]);
543 if (rv != SCARD_S_SUCCESS)
544 {
545 /* Cannot connect to slot. Exit gracefully */
546 (void)RFRemoveReader(readerName, port, REMOVE_READER_NO_FLAG);
547 return rv;
548 }
549
550 /* asynchronous card movement? */
551 dwGetSize = sizeof(fct);
552
553 rv = IFDGetCapabilities((sReadersContexts[dwContextB]),
554 TAG_IFD_POLLING_THREAD_WITH_TIMEOUT, &dwGetSize, (PUCHAR)&fct);
555 if ((rv != SCARD_S_SUCCESS) || (dwGetSize != sizeof(fct)))
556 {
557 Log1(PCSC_LOG_INFO, "Using the pcscd polling thread");
558 }
559 else
560 {
561 sReadersContexts[dwContextB]->pthCardEvent = fct;
562 Log1(PCSC_LOG_INFO, "Using the reader polling thread");
563 }
564
565 rv = EHSpawnEventHandler(sReadersContexts[dwContextB]);
566 if (rv != SCARD_S_SUCCESS)
567 {
568 Log2(PCSC_LOG_ERROR, "%s init failed.", readerName);
569 (void)RFRemoveReader(readerName, port, REMOVE_READER_NO_FLAG);
570 return rv;
571 }
572 }
573
574 return SCARD_S_SUCCESS;
575}
576
577LONG RFRemoveReader(const char *readerName, int port, int flags)
578{
579 char lpcStripReader[MAX_READERNAME];
580 int i;
581#ifdef FILTER_NAMES
582 const char *extend;
583#endif
584 int extend_size = 0;
585
586 if (readerName == NULL)
588
589#ifdef FILTER_NAMES
590 extend = SYS_GetEnv("PCSCLITE_FILTER_EXTEND_READER_NAMES");
591 if (extend)
592 extend_size = strlen(extend);
593#endif
594
595 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
596 {
597 if (sReadersContexts[i] && (sReadersContexts[i]->vHandle != 0))
598 {
599 strncpy(lpcStripReader,
600 sReadersContexts[i]->readerState->readerName,
601 sizeof(lpcStripReader));
602 lpcStripReader[strlen(lpcStripReader) - 6 - extend_size] = 0;
603
604 /* Compare only the significant part of the reader name */
605 if ((strncmp(readerName, lpcStripReader, MAX_READERNAME - sizeof(" 00 00")) == 0)
606 && (port == sReadersContexts[i]->port))
607 {
608 if (flags & REMOVE_READER_FLAG_REMOVED)
609 {
610 UCHAR tagValue[1];
611 DWORD valueLength;
612 LONG ret;
613
614 /* signal to the driver that the reader has been removed */
615 valueLength = sizeof(tagValue);
616 ret = IFDGetCapabilities(sReadersContexts[i],
617 TAG_IFD_DEVICE_REMOVED, &valueLength, tagValue);
618 if ((IFD_SUCCESS) == ret && (1 == tagValue[0]))
619 {
620 tagValue[0] = 1;
621 IFDSetCapabilities(sReadersContexts[i],
622 TAG_IFD_DEVICE_REMOVED, sizeof tagValue, tagValue);
623 }
624 }
625
626 /* remove the reader */
627 UNREF_READER(sReadersContexts[i])
628 }
629 }
630 }
631
632 /* we have one less reader */
633 ReaderEvents++;
634 /* wrap? */
635 if (ReaderEvents < 0)
636 ReaderEvents = 1;
637
638 return SCARD_S_SUCCESS;
639}
640
641LONG removeReader(READER_CONTEXT * sContext)
642{
643 /* Try to destroy the thread */
644 if (sContext -> pthThread)
645 EHDestroyEventHandler(sContext);
646
647 if ((NULL == sContext->pMutex) || (NULL == sContext->pFeeds))
648 {
649 Log1(PCSC_LOG_ERROR,
650 "Trying to remove an already removed driver");
652 }
653
654 RFUnInitializeReader(sContext);
655
656 *sContext->pMutex -= 1;
657
658 /* free shared resources when the last slot is closed */
659 if (0 == *sContext->pMutex)
660 {
661 (void)pthread_mutex_destroy(sContext->mMutex);
662 free(sContext->mMutex);
663 sContext->mMutex = NULL;
664 free(sContext->library);
665 free(sContext->device);
666 free(sContext->pMutex);
667 sContext->pMutex = NULL;
668 }
669
670 *sContext->pFeeds -= 1;
671
672 /* Added by Dave to free the pFeeds variable */
673 if (*sContext->pFeeds == 0)
674 {
675 free(sContext->pFeeds);
676 sContext->pFeeds = NULL;
677 }
678
679 (void)pthread_mutex_destroy(&sContext->powerState_lock);
680 sContext->version = 0;
681 sContext->port = 0;
682 sContext->contexts = 0;
683 sContext->slot = 0;
684 sContext->hLockId = 0;
685 sContext->LockCount = 0;
686 sContext->vHandle = NULL;
687
688 (void)pthread_mutex_lock(&sContext->handlesList_lock);
689 while (list_size(&sContext->handlesList) != 0)
690 {
691 int lrv;
692 RDR_CLIHANDLES *currentHandle;
693
694 currentHandle = list_get_at(&sContext->handlesList, 0);
695 lrv = list_delete_at(&sContext->handlesList, 0);
696 if (lrv < 0)
697 Log2(PCSC_LOG_CRITICAL,
698 "list_delete_at failed with return value: %d", lrv);
699
700 free(currentHandle);
701 }
702 (void)pthread_mutex_unlock(&sContext->handlesList_lock);
703 (void)pthread_mutex_destroy(&sContext->handlesList_lock);
704 list_destroy(&sContext->handlesList);
705 dwNumReadersContexts -= 1;
706
707 /* signal an event to clients */
709
710 return SCARD_S_SUCCESS;
711}
712
713LONG RFSetReaderName(READER_CONTEXT * rContext, const char *readerName,
714 const char *libraryName, int port)
715{
716 LONG parent = -1; /* reader number of the parent of the clone */
717 DWORD valueLength;
718 int currentDigit = -1;
719 int supportedChannels = 0;
720 bool usedDigits[PCSCLITE_MAX_READERS_CONTEXTS];
721 int i;
722 const char *extend = "";
723
724 /* Clear the list */
725 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
726 usedDigits[i] = false;
727
728 if (dwNumReadersContexts != 0)
729 {
730 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
731 {
732 if (sReadersContexts[i]->vHandle != 0)
733 {
734 if (strcmp(sReadersContexts[i]->library, libraryName) == 0)
735 {
736 UCHAR tagValue[1];
737 LONG ret;
738
739 /* Ask the driver if it supports multiple channels */
740 valueLength = sizeof(tagValue);
741 ret = IFDGetCapabilities(sReadersContexts[i],
743 &valueLength, tagValue);
744
745 if ((ret == IFD_SUCCESS) && (valueLength == 1) &&
746 (tagValue[0] > 1))
747 {
748 supportedChannels = tagValue[0];
749 Log2(PCSC_LOG_INFO,
750 "Support %d simultaneous readers", tagValue[0]);
751 }
752 else
753 supportedChannels = 1;
754
755 /* Check to see if it is a hotplug reader and different */
756 if ((((sReadersContexts[i]->port & 0xFFFF0000) ==
757 PCSCLITE_HP_BASE_PORT)
758 && (sReadersContexts[i]->port != port))
759 || (supportedChannels > 1))
760 {
761 const char *reader = sReadersContexts[i]->readerState->readerName;
762
763 /*
764 * tells the caller who the parent of this
765 * clone is so it can use its shared
766 * resources like mutex/etc.
767 */
768 parent = i;
769
770 /*
771 * If the same reader already exists and it is
772 * hotplug then we must look for others and
773 * enumerate the readername
774 */
775 currentDigit = strtol(reader + strlen(reader) - 5, NULL, 16);
776
777 /* This spot is taken */
778 usedDigits[currentDigit] = true;
779 }
780 }
781 }
782 }
783 }
784
785 /* default value */
786 i = 0;
787
788 /* Other identical readers exist on the same bus */
789 if (currentDigit != -1)
790 {
791 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
792 {
793 /* get the first free digit */
794 if (usedDigits[i] == false)
795 break;
796 }
797
799 {
800 Log2(PCSC_LOG_ERROR, "Max number of readers reached: %d", PCSCLITE_MAX_READERS_CONTEXTS);
801 return -2;
802 }
803
804 if (i >= supportedChannels)
805 {
806 Log3(PCSC_LOG_ERROR, "Driver %s does not support more than "
807 "%d reader(s). Maybe the driver should support "
808 "TAG_IFD_SIMULTANEOUS_ACCESS", libraryName, supportedChannels);
809 return -2;
810 }
811 }
812
813#ifdef FILTER_NAMES
814 extend = SYS_GetEnv("PCSCLITE_FILTER_EXTEND_READER_NAMES");
815 if (NULL == extend)
816 extend = "";
817#endif
818
819 snprintf(rContext->readerState->readerName,
820 sizeof(rContext->readerState->readerName), "%s%s %02X 00",
821 readerName, extend, i);
822
823 /* Set the slot in 0xDDDDCCCC */
824 rContext->slot = i << 16;
825
826 return parent;
827}
828
829LONG RFReaderInfo(const char *readerName, READER_CONTEXT ** sReader)
830{
831 int i;
832
833 if (readerName == NULL)
835
836 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
837 {
838 if (sReadersContexts[i]->vHandle != 0)
839 {
840 if (strcmp(readerName,
841 sReadersContexts[i]->readerState->readerName) == 0)
842 {
843 /* Increase reference count */
844 REF_READER(sReadersContexts[i])
845
846 *sReader = sReadersContexts[i];
847 return SCARD_S_SUCCESS;
848 }
849 }
850 }
851
853}
854
855LONG RFReaderInfoById(SCARDHANDLE hCard, READER_CONTEXT * * sReader)
856{
857 int i;
858
859 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
860 {
861 if (sReadersContexts[i]->vHandle != 0)
862 {
863 RDR_CLIHANDLES * currentHandle;
864 (void)pthread_mutex_lock(&sReadersContexts[i]->handlesList_lock);
865 currentHandle = list_seek(&sReadersContexts[i]->handlesList,
866 &hCard);
867 (void)pthread_mutex_unlock(&sReadersContexts[i]->handlesList_lock);
868 if (currentHandle != NULL)
869 {
870 /* Increase reference count */
871 REF_READER(sReadersContexts[i])
872
873 *sReader = sReadersContexts[i];
874 return SCARD_S_SUCCESS;
875 }
876 }
877 }
878
880}
881
882LONG RFLoadReader(READER_CONTEXT * rContext)
883{
884 LONG ret = SCARD_S_SUCCESS;
885 if (rContext->vHandle != 0)
886 {
887 Log2(PCSC_LOG_INFO, "Reusing already loaded driver for %s",
888 rContext->library);
889 /* Another reader exists with this library loaded */
890 return SCARD_S_SUCCESS;
891 }
892
893 rContext->vHandle = DYN_LoadLibrary(rContext->library);
894 if (NULL == rContext->vHandle)
896 return ret;
897}
898
899LONG RFBindFunctions(READER_CONTEXT * rContext)
900{
901 int rv;
902 void *f;
903
904 rv = DYN_GetAddress(rContext->vHandle, &f, "IFDHCreateChannelByName", true);
905 if (SCARD_S_SUCCESS == rv)
906 {
907 /* Ifd Handler 3.0 found */
908 rContext->version = IFD_HVERSION_3_0;
909 }
910 else
911 {
912 rv = DYN_GetAddress(rContext->vHandle, &f, "IFDHCreateChannel", false);
913 if (SCARD_S_SUCCESS == rv)
914 {
915 /* Ifd Handler 2.0 found */
916 rContext->version = IFD_HVERSION_2_0;
917 }
918 else
919 {
920 /* Neither version of the IFD Handler was found - exit */
921 Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing");
923 }
924 }
925
926 if (rContext->version == IFD_HVERSION_2_0)
927 {
928 /* The following binds version 2.0 of the IFD Handler specs */
929#define GET_ADDRESS_OPTIONALv2(s, code) \
930{ \
931 void *f1 = NULL; \
932 int rvl = DYN_GetAddress(rContext->vHandle, &f1, "IFDH" #s, false); \
933 if (SCARD_S_SUCCESS != rvl) \
934 { \
935 code \
936 } \
937 rContext->psFunctions.psFunctions_v2.pvf ## s = f1; \
938}
939
940#define GET_ADDRESSv2(s) \
941 GET_ADDRESS_OPTIONALv2(s, \
942 Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing: " #s ); \
943 return(rv); )
944
945 Log1(PCSC_LOG_INFO, "Loading IFD Handler 2.0");
946
947 GET_ADDRESSv2(CreateChannel)
948 GET_ADDRESSv2(CloseChannel)
949 GET_ADDRESSv2(GetCapabilities)
950 GET_ADDRESSv2(SetCapabilities)
951 GET_ADDRESSv2(PowerICC)
952 GET_ADDRESSv2(TransmitToICC)
953 GET_ADDRESSv2(ICCPresence)
954 GET_ADDRESS_OPTIONALv2(SetProtocolParameters, )
955
956 GET_ADDRESSv2(Control)
957 }
958 else if (rContext->version == IFD_HVERSION_3_0)
959 {
960 /* The following binds version 3.0 of the IFD Handler specs */
961#define GET_ADDRESS_OPTIONALv3(s, code) \
962{ \
963 void *f1 = NULL; \
964 int rvl = DYN_GetAddress(rContext->vHandle, &f1, "IFDH" #s, false); \
965 if (SCARD_S_SUCCESS != rvl) \
966 { \
967 code \
968 } \
969 rContext->psFunctions.psFunctions_v3.pvf ## s = f1; \
970}
971
972#define GET_ADDRESSv3(s) \
973 GET_ADDRESS_OPTIONALv3(s, \
974 Log1(PCSC_LOG_CRITICAL, "IFDHandler functions missing: " #s ); \
975 return(rv); )
976
977 Log1(PCSC_LOG_INFO, "Loading IFD Handler 3.0");
978
979 GET_ADDRESSv2(CreateChannel)
980 GET_ADDRESSv2(CloseChannel)
981 GET_ADDRESSv2(GetCapabilities)
982 GET_ADDRESSv2(SetCapabilities)
983 GET_ADDRESSv2(PowerICC)
984 GET_ADDRESSv2(TransmitToICC)
985 GET_ADDRESSv2(ICCPresence)
986 GET_ADDRESS_OPTIONALv2(SetProtocolParameters, )
987
988 GET_ADDRESSv3(CreateChannelByName)
989 GET_ADDRESSv3(Control)
990 }
991 else
992 {
993 /* Who knows what could have happened for it to get here. */
994 Log1(PCSC_LOG_CRITICAL, "IFD Handler not 1.0/2.0 or 3.0");
996 }
997
998 return SCARD_S_SUCCESS;
999}
1000
1001LONG RFUnBindFunctions(READER_CONTEXT * rContext)
1002{
1003 /* Zero out everything */
1004 memset(&rContext->psFunctions, 0, sizeof(rContext->psFunctions));
1005
1006 return SCARD_S_SUCCESS;
1007}
1008
1009LONG RFUnloadReader(READER_CONTEXT * rContext)
1010{
1011 /* Make sure no one else is using this library */
1012 if (*rContext->pFeeds == 1)
1013 {
1014 Log1(PCSC_LOG_INFO, "Unloading reader driver.");
1015 (void)DYN_CloseLibrary(rContext->vHandle);
1016 rContext->vHandle = NULL;
1017 }
1018
1019 rContext->vHandle = NULL;
1020
1021 return SCARD_S_SUCCESS;
1022}
1023
1024LONG RFCheckSharing(SCARDHANDLE hCard, READER_CONTEXT * rContext)
1025{
1026 if (rContext->hLockId == 0 || rContext->hLockId == hCard)
1027 return SCARD_S_SUCCESS;
1028 else
1030}
1031
1032LONG RFLockSharing(SCARDHANDLE hCard, READER_CONTEXT * rContext)
1033{
1034 LONG rv;
1035
1036 (void)pthread_mutex_lock(&LockMutex);
1037 rv = RFCheckSharing(hCard, rContext);
1038 if (SCARD_S_SUCCESS == rv)
1039 {
1040 rContext->LockCount += 1;
1041 rContext->hLockId = hCard;
1042 }
1043 (void)pthread_mutex_unlock(&LockMutex);
1044
1045 return rv;
1046}
1047
1048LONG RFUnlockSharing(SCARDHANDLE hCard, READER_CONTEXT * rContext)
1049{
1050 LONG rv;
1051
1052 (void)pthread_mutex_lock(&LockMutex);
1053 rv = RFCheckSharing(hCard, rContext);
1054 if (SCARD_S_SUCCESS == rv)
1055 {
1057 {
1058 if (rContext->LockCount > 1)
1059 rContext->LockCount -= 1;
1060 else
1062 }
1063 else
1064 {
1065 if (rContext->LockCount > 0)
1066 {
1067 rContext->LockCount -= 1;
1068 if (0 == rContext->LockCount)
1069 rContext->hLockId = 0;
1070 }
1071 else
1072 /* rContext->LockCount == 0 */
1074 }
1075 }
1076 (void)pthread_mutex_unlock(&LockMutex);
1077
1078 return rv;
1079}
1080
1081LONG RFUnlockAllSharing(SCARDHANDLE hCard, READER_CONTEXT * rContext)
1082{
1083 LONG rv;
1084
1085 (void)pthread_mutex_lock(&LockMutex);
1086 rv = RFCheckSharing(hCard, rContext);
1087 if (SCARD_S_SUCCESS == rv)
1088 {
1089 rContext->LockCount = 0;
1090 rContext->hLockId = 0;
1091 }
1092 (void)pthread_mutex_unlock(&LockMutex);
1093
1094 return rv;
1095}
1096
1097LONG RFInitializeReader(READER_CONTEXT * rContext)
1098{
1099 LONG rv = SCARD_S_SUCCESS;
1100 RESPONSECODE rvd;
1101
1102 /* Spawn the event handler thread */
1103 Log3(PCSC_LOG_INFO, "Attempting startup of %s using %s",
1104 rContext->readerState->readerName, rContext->library);
1105
1106#ifndef PCSCLITE_STATIC_DRIVER
1107 /* loads the library */
1108 rv = RFLoadReader(rContext);
1109 if (rv != SCARD_S_SUCCESS)
1110 {
1111 Log2(PCSC_LOG_ERROR, "RFLoadReader failed: 0x%lX", rv);
1112 return rv;
1113 }
1114
1115 /* binds the functions */
1116 rv = RFBindFunctions(rContext);
1117
1118 if (rv != SCARD_S_SUCCESS)
1119 {
1120 Log2(PCSC_LOG_ERROR, "RFBindFunctions failed: 0x%lX", rv);
1121 (void)RFUnloadReader(rContext);
1122 return rv;
1123 }
1124#else
1125 /* define a fake vHandle. Can be any value except NULL */
1126 rContext->vHandle = RFInitializeReader;
1127#endif
1128
1129 /* tries to open the port */
1130 rvd = IFDOpenIFD(rContext);
1131
1132 if (rvd != IFD_SUCCESS)
1133 {
1134 int log_level = PCSC_LOG_CRITICAL;
1136
1137 if (IFD_NO_SUCH_DEVICE == rvd)
1138 {
1139 /* wrong interface on a composite device? */
1140 log_level = PCSC_LOG_INFO;
1142 }
1143
1144 Log3(log_level, "Open Port 0x%X Failed (%s)",
1145 rContext->port, rContext->device);
1146
1147 /* IFDOpenIFD() failed */
1148 /* the reader was not started correctly */
1149 rContext->slot = -1;
1150 }
1151
1152 return rv;
1153}
1154
1155void RFUnInitializeReader(READER_CONTEXT * rContext)
1156{
1157 Log2(PCSC_LOG_INFO, "Attempting shutdown of %s.",
1158 rContext->readerState->readerName);
1159
1160 /* Do not close a reader if IFDOpenIFD() failed in RFInitializeReader() */
1161 if (rContext->slot != -1)
1162 (void)IFDCloseIFD(rContext);
1163
1164 (void)RFUnBindFunctions(rContext);
1165 (void)RFUnloadReader(rContext);
1166
1167 /*
1168 * Zero out the public status struct to allow it to be recycled and
1169 * used again
1170 */
1171 memset(rContext->readerState->readerName, 0,
1172 sizeof(rContext->readerState->readerName));
1173 memset(rContext->readerState->cardAtr, 0,
1174 sizeof(rContext->readerState->cardAtr));
1175 rContext->readerState->readerState = 0;
1176 rContext->readerState->eventCounter = 0;
1177 rContext->readerState->readerSharing = 0;
1180
1181 return;
1182}
1183
1184SCARDHANDLE RFCreateReaderHandle(READER_CONTEXT * rContext)
1185{
1186 SCARDHANDLE randHandle;
1187 LONG ret;
1188
1189 (void)rContext;
1190
1191 do
1192 {
1193 READER_CONTEXT *dummy_reader;
1194
1195 /* Create a random handle with 32 bits check to see if it already is
1196 * used. */
1197 /* FIXME: THIS IS NOT STRONG ENOUGH: A 128-bit token should be
1198 * generated. The client and server would associate token and hCard
1199 * for authentication. */
1200 randHandle = SYS_RandomInt();
1201
1202 /* do we already use this hCard somewhere? */
1203 ret = RFReaderInfoById(randHandle, &dummy_reader);
1204 if (SCARD_S_SUCCESS == ret)
1205 UNREF_READER(dummy_reader)
1206 }
1207 while (SCARD_S_SUCCESS == ret);
1208
1209 /* Once the for loop is completed w/o restart a good handle was
1210 * found and the loop can be exited. */
1211 return randHandle;
1212}
1213
1214LONG RFAddReaderHandle(READER_CONTEXT * rContext, SCARDHANDLE hCard)
1215{
1216 int listLength, lrv;
1217 RDR_CLIHANDLES *newHandle;
1218 LONG rv = SCARD_S_SUCCESS;
1219
1220 (void)pthread_mutex_lock(&rContext->handlesList_lock);
1221 listLength = list_size(&rContext->handlesList);
1222
1223 /* Throttle the number of possible handles */
1224 if (listLength >= maxReaderHandles)
1225 {
1226 Log2(PCSC_LOG_CRITICAL,
1227 "Too many handles opened, exceeding configured max (%d)",
1228 maxReaderHandles);
1229 rv = SCARD_E_NO_MEMORY;
1230 goto end;
1231 }
1232
1233 newHandle = malloc(sizeof(RDR_CLIHANDLES));
1234 if (NULL == newHandle)
1235 {
1236 Log1(PCSC_LOG_CRITICAL, "malloc failed");
1237 rv = SCARD_E_NO_MEMORY;
1238 goto end;
1239 }
1240
1241 newHandle->hCard = hCard;
1242 atomic_init(&newHandle->dwEventStatus, 0);
1243
1244 lrv = list_append(&rContext->handlesList, newHandle);
1245 if (lrv < 0)
1246 {
1247 free(newHandle);
1248 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
1249 lrv);
1250 rv = SCARD_E_NO_MEMORY;
1251 }
1252end:
1253 (void)pthread_mutex_unlock(&rContext->handlesList_lock);
1254 return rv;
1255}
1256
1257LONG RFRemoveReaderHandle(READER_CONTEXT * rContext, SCARDHANDLE hCard)
1258{
1259 RDR_CLIHANDLES *currentHandle;
1260 int lrv;
1261 LONG rv = SCARD_S_SUCCESS;
1262
1263 (void)pthread_mutex_lock(&rContext->handlesList_lock);
1264 currentHandle = list_seek(&rContext->handlesList, &hCard);
1265 if (NULL == currentHandle)
1266 {
1267 Log2(PCSC_LOG_CRITICAL, "list_seek failed to locate hCard=%lX", hCard);
1269 goto end;
1270 }
1271
1272 lrv = list_delete(&rContext->handlesList, currentHandle);
1273 if (lrv < 0)
1274 Log2(PCSC_LOG_CRITICAL,
1275 "list_delete failed with return value: %d", lrv);
1276
1277 free(currentHandle);
1278
1279end:
1280 (void)pthread_mutex_unlock(&rContext->handlesList_lock);
1281
1282 /* Not Found */
1283 return rv;
1284}
1285
1286void RFSetReaderEventState(READER_CONTEXT * rContext, DWORD dwEvent)
1287{
1288 /* Set all the handles for that reader to the event */
1289 int list_index, listSize;
1290 RDR_CLIHANDLES *currentHandle;
1291
1292 (void)pthread_mutex_lock(&rContext->handlesList_lock);
1293 listSize = list_size(&rContext->handlesList);
1294
1295 for (list_index = 0; list_index < listSize; list_index++)
1296 {
1297 currentHandle = list_get_at(&rContext->handlesList, list_index);
1298 if (NULL == currentHandle)
1299 {
1300 Log2(PCSC_LOG_CRITICAL, "list_get_at failed at index %d",
1301 list_index);
1302 continue;
1303 }
1304
1305 currentHandle->dwEventStatus = dwEvent;
1306 }
1307 (void)pthread_mutex_unlock(&rContext->handlesList_lock);
1308
1309 if (SCARD_REMOVED == dwEvent)
1310 {
1311 /* unlock the card */
1312 rContext->hLockId = 0;
1313 rContext->LockCount = 0;
1314 }
1315
1316 return;
1317}
1318
1319LONG RFCheckReaderEventState(READER_CONTEXT * rContext, SCARDHANDLE hCard)
1320{
1321 LONG rv;
1322 RDR_CLIHANDLES *currentHandle;
1323 DWORD dwEventStatus;
1324
1325 (void)pthread_mutex_lock(&rContext->handlesList_lock);
1326 currentHandle = list_seek(&rContext->handlesList, &hCard);
1327 (void)pthread_mutex_unlock(&rContext->handlesList_lock);
1328 if (NULL == currentHandle)
1329 {
1330 /* Not Found */
1331 Log2(PCSC_LOG_CRITICAL, "list_seek failed for hCard 0x%lX", hCard);
1333 }
1334
1335 dwEventStatus = currentHandle->dwEventStatus;
1336 switch(dwEventStatus)
1337 {
1338 case 0:
1339 rv = SCARD_S_SUCCESS;
1340 break;
1341
1342 case SCARD_REMOVED:
1344 break;
1345
1346 case SCARD_RESET:
1347 rv = SCARD_W_RESET_CARD;
1348 break;
1349
1350 default:
1352 }
1353
1354 return rv;
1355}
1356
1357LONG RFClearReaderEventState(READER_CONTEXT * rContext, SCARDHANDLE hCard)
1358{
1359 RDR_CLIHANDLES *currentHandle;
1360
1361 (void)pthread_mutex_lock(&rContext->handlesList_lock);
1362 currentHandle = list_seek(&rContext->handlesList, &hCard);
1363 (void)pthread_mutex_unlock(&rContext->handlesList_lock);
1364 if (NULL == currentHandle)
1365 /* Not Found */
1367
1368 currentHandle->dwEventStatus = 0;
1369
1370 /* hCards should be unique so we
1371 * should be able to return
1372 * as soon as we have a hit */
1373 return SCARD_S_SUCCESS;
1374}
1375
1376LONG RFCheckReaderStatus(READER_CONTEXT * rContext)
1377{
1378 if (rContext->readerState->readerState & SCARD_UNKNOWN)
1380 else
1381 return SCARD_S_SUCCESS;
1382}
1383
1384void RFCleanupReaders(void)
1385{
1386 int i;
1387
1388 Log1(PCSC_LOG_INFO, "entering cleaning function");
1389 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1390 {
1391 if (sReadersContexts[i]->vHandle != 0)
1392 {
1393 LONG rv;
1394 char lpcStripReader[MAX_READERNAME];
1395
1396 Log2(PCSC_LOG_INFO, "Stopping reader: %s",
1397 sReadersContexts[i]->readerState->readerName);
1398
1399 strncpy(lpcStripReader,
1400 sReadersContexts[i]->readerState->readerName,
1401 sizeof(lpcStripReader));
1402 /* strip the 6 last char ' 00 00' */
1403 lpcStripReader[strlen(lpcStripReader) - 6] = '\0';
1404
1405 rv = RFRemoveReader(lpcStripReader, sReadersContexts[i]->port,
1406 REMOVE_READER_NO_FLAG);
1407
1408 if (rv != SCARD_S_SUCCESS)
1409 Log2(PCSC_LOG_ERROR, "RFRemoveReader error: %s", rv2text(rv));
1410 }
1411
1412 free(sReadersContexts[i]);
1413 sReadersContexts[i] = NULL;
1414 }
1415
1416#ifdef USE_SERIAL
1417 if (ConfigFile)
1418 {
1419 free(ConfigFile);
1420 ConfigFile = NULL;
1421 }
1422#endif
1423}
1424
1429#ifdef USE_USB
1430void RFWaitForReaderInit(void)
1431{
1432 bool need_to_wait;
1433
1434 do
1435 {
1436 need_to_wait = false;
1437 for (int i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1438 {
1439 /* reader is present */
1440 if (sReadersContexts[i] && sReadersContexts[i]->vHandle != NULL)
1441 {
1442 /* but card state is not yet available */
1444 == sReadersContexts[i]->readerState->cardAtrLength)
1445 {
1446 Log2(PCSC_LOG_DEBUG, "Waiting init for reader: %s",
1447 sReadersContexts[i]->readerState->readerName);
1448 need_to_wait = true;
1449 }
1450 }
1451 }
1452
1453 if (need_to_wait)
1454 SYS_USleep(10*1000); /* 10 ms */
1455 } while (need_to_wait);
1456}
1457#endif
1458
1459#ifdef USE_SERIAL
1460int RFStartSerialReaders(const char *readerconf)
1461{
1462 SerialReader *reader_list = NULL;
1463 int i, rv;
1464
1465 /* remember the configuration filename for RFReCheckReaderConf() */
1466 ConfigFile = strdup(readerconf);
1467
1468 rv = DBGetReaderListDir(readerconf, &reader_list);
1469
1470 /* the list is empty */
1471 if (NULL == reader_list)
1472 return rv;
1473
1474 for (i=0; reader_list[i].pcFriendlyname; i++)
1475 {
1476 int j;
1477
1478 (void)RFAddReader(reader_list[i].pcFriendlyname,
1479 reader_list[i].channelId,
1480 reader_list[i].pcLibpath, reader_list[i].pcDevicename);
1481
1482 /* update the ConfigFileCRC (this false "CRC" is very weak) */
1483 for (j=0; j<reader_list[i].pcFriendlyname[j]; j++)
1484 ConfigFileCRC += reader_list[i].pcFriendlyname[j];
1485 for (j=0; j<reader_list[i].pcLibpath[j]; j++)
1486 ConfigFileCRC += reader_list[i].pcLibpath[j];
1487 for (j=0; j<reader_list[i].pcDevicename[j]; j++)
1488 ConfigFileCRC += reader_list[i].pcDevicename[j];
1489
1490 /* free strings allocated by DBGetReaderListDir() */
1491 free(reader_list[i].pcFriendlyname);
1492 free(reader_list[i].pcLibpath);
1493 free(reader_list[i].pcDevicename);
1494 }
1495 free(reader_list);
1496
1497 return rv;
1498}
1499
1500void RFReCheckReaderConf(void)
1501{
1502 SerialReader *reader_list = NULL;
1503 int i, crc;
1504
1505 (void)DBGetReaderListDir(ConfigFile, &reader_list);
1506
1507 /* the list is empty */
1508 if (NULL == reader_list)
1509 return;
1510
1511 crc = 0;
1512 for (i=0; reader_list[i].pcFriendlyname; i++)
1513 {
1514 int j;
1515
1516 /* calculate a local crc */
1517 for (j=0; j<reader_list[i].pcFriendlyname[j]; j++)
1518 crc += reader_list[i].pcFriendlyname[j];
1519 for (j=0; j<reader_list[i].pcLibpath[j]; j++)
1520 crc += reader_list[i].pcLibpath[j];
1521 for (j=0; j<reader_list[i].pcDevicename[j]; j++)
1522 crc += reader_list[i].pcDevicename[j];
1523 }
1524
1525 /* cancel if the configuration file has been modified */
1526 if (crc != ConfigFileCRC)
1527 {
1528 Log2(PCSC_LOG_CRITICAL,
1529 "configuration file: %s has been modified. Recheck canceled",
1530 ConfigFile);
1531 return;
1532 }
1533
1534 for (i=0; reader_list[i].pcFriendlyname; i++)
1535 {
1536 int r;
1537 char present = false;
1538
1539 Log2(PCSC_LOG_DEBUG, "refresh reader: %s",
1540 reader_list[i].pcFriendlyname);
1541
1542 /* is the reader already present? */
1543 for (r = 0; r < PCSCLITE_MAX_READERS_CONTEXTS; r++)
1544 {
1545 if (sReadersContexts[r]->vHandle != 0)
1546 {
1547 char lpcStripReader[MAX_READERNAME];
1548 int tmplen;
1549
1550 /* get the reader name without the reader and slot numbers */
1551 strncpy(lpcStripReader,
1552 sReadersContexts[i]->readerState->readerName,
1553 sizeof(lpcStripReader));
1554 tmplen = strlen(lpcStripReader);
1555 lpcStripReader[tmplen - 6] = 0;
1556
1557 if ((strcmp(reader_list[i].pcFriendlyname, lpcStripReader) == 0)
1558 && (reader_list[r].channelId == sReadersContexts[i]->port))
1559 {
1560 DWORD dwStatus = 0;
1561
1562 /* the reader was already started */
1563 present = true;
1564
1565 /* verify the reader is still connected */
1566 if (IFDStatusICC(sReadersContexts[r], &dwStatus)
1567 != SCARD_S_SUCCESS)
1568 {
1569 Log2(PCSC_LOG_INFO, "Reader %s disappeared",
1570 reader_list[i].pcFriendlyname);
1571 (void)RFRemoveReader(reader_list[i].pcFriendlyname,
1572 reader_list[r].channelId, REMOVE_READER_NO_FLAG);
1573 }
1574 }
1575 }
1576 }
1577
1578 /* the reader was not present */
1579 if (!present)
1580 /* we try to add it */
1581 (void)RFAddReader(reader_list[i].pcFriendlyname,
1582 reader_list[i].channelId, reader_list[i].pcLibpath,
1583 reader_list[i].pcDevicename);
1584
1585 /* free strings allocated by DBGetReaderListDir() */
1586 free(reader_list[i].pcFriendlyname);
1587 free(reader_list[i].pcLibpath);
1588 free(reader_list[i].pcDevicename);
1589 }
1590 free(reader_list);
1591}
1592#endif
1593
1595{
1596 (void)pthread_mutex_lock(&rContext->powerState_lock);
1597 int result = rContext->powerState;
1598 (void)pthread_mutex_unlock(&rContext->powerState_lock);
1599 return result;
1600}
1601
1602void RFSetPowerState(READER_CONTEXT * rContext, int value)
1603{
1604 (void)pthread_mutex_lock(&rContext->powerState_lock);
1605 rContext->powerState = value;
1606 (void)pthread_mutex_unlock(&rContext->powerState_lock);
1607}
1608
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.
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.
union ReaderContext::@3 psFunctions
driver functions
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