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