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