pcsc-lite 1.9.7
winscard_svc.c
Go to the documentation of this file.
1/*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3 *
4 * Copyright (C) 2001-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
47#include "config.h"
48#include <time.h>
49#include <stdio.h>
50#include <string.h>
51#include <stddef.h>
52#include <stdlib.h>
53#include <unistd.h>
54#include <pthread.h>
55
56#include "pcscd.h"
57#include "winscard.h"
58#include "debuglog.h"
59#include "winscard_msg.h"
60#include "winscard_svc.h"
61#include "sys_generic.h"
62#include "utils.h"
63#include "readerfactory.h"
64#include "eventhandler.h"
65#include "simclist.h"
66#include "auth.h"
67
74extern char AutoExit;
75static int contextMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
76static int contextMaxCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
77
79pthread_mutex_t contextsList_lock;
82{
83 int32_t hContext;
84 list_t cardsList;
85 pthread_mutex_t cardsList_lock;
86 uint32_t dwClientID;
87 pthread_t pthThread;
88};
89typedef struct _psContext SCONTEXT;
90
91static LONG MSGCheckHandleAssociation(SCARDHANDLE, SCONTEXT *);
92static LONG MSGAddContext(SCARDCONTEXT, SCONTEXT *);
93static LONG MSGRemoveContext(SCARDCONTEXT, SCONTEXT *);
94static LONG MSGAddHandle(SCARDCONTEXT, SCARDHANDLE, SCONTEXT *);
95static LONG MSGRemoveHandle(SCARDHANDLE, SCONTEXT *);
96static void MSGCleanupClient(SCONTEXT *);
97
98static void * ContextThread(LPVOID pdwIndex);
99
101
102static int contextsListhContext_seeker(const void *el, const void *key)
103{
104 const SCONTEXT * currentContext = (SCONTEXT *)el;
105
106 if ((el == NULL) || (key == NULL))
107 {
108 Log3(PCSC_LOG_CRITICAL, "called with NULL pointer: el=%p, key=%p",
109 el, key);
110 return 0;
111 }
112
113 if (currentContext->hContext == *(int32_t *)key)
114 return 1;
115 return 0;
116}
117
118LONG ContextsInitialize(int customMaxThreadCounter,
119 int customMaxThreadCardHandles)
120{
121 int lrv = 0;
122
123 if (customMaxThreadCounter != 0)
124 contextMaxThreadCounter = customMaxThreadCounter;
125
126 if (customMaxThreadCardHandles != 0)
127 contextMaxCardHandles = customMaxThreadCardHandles;
128
129 lrv = list_init(&contextsList);
130 if (lrv < 0)
131 {
132 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
133 return -1;
134 }
135 lrv = list_attributes_seeker(& contextsList, contextsListhContext_seeker);
136 if (lrv < 0)
137 {
138 Log2(PCSC_LOG_CRITICAL,
139 "list_attributes_seeker failed with return value: %d", lrv);
140 return -1;
141 }
142
143 (void)pthread_mutex_init(&contextsList_lock, NULL);
144
145 return 1;
146}
147
148void ContextsDeinitialize(void)
149{
150 int listSize;
151 listSize = list_size(&contextsList);
152#ifdef NO_LOG
153 (void)listSize;
154#endif
155 Log2(PCSC_LOG_DEBUG, "remaining threads: %d", listSize);
156 /* This is currently a no-op. It should terminate the threads properly. */
157
158 list_destroy(&contextsList);
159}
160
171LONG CreateContextThread(uint32_t *pdwClientID)
172{
173 int rv;
174 int lrv;
175 int listSize;
176 SCONTEXT * newContext = NULL;
177 LONG retval = SCARD_E_NO_MEMORY;
178
179 (void)pthread_mutex_lock(&contextsList_lock);
180
181 listSize = list_size(&contextsList);
182 if (listSize >= contextMaxThreadCounter)
183 {
184 Log2(PCSC_LOG_CRITICAL, "Too many context running: %d", listSize);
185 goto out;
186 }
187
188 /* Create the context for this thread. */
189 newContext = malloc(sizeof(*newContext));
190 if (NULL == newContext)
191 {
192 Log1(PCSC_LOG_CRITICAL, "Could not allocate new context");
193 goto out;
194 }
195 memset(newContext, 0, sizeof(*newContext));
196
197 newContext->dwClientID = *pdwClientID;
198
199 /* Initialise the list of card contexts */
200 lrv = list_init(&newContext->cardsList);
201 if (lrv < 0)
202 {
203 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
204 goto out;
205 }
206
207 /* request to store copies, and provide the metric function */
208 list_attributes_copy(&newContext->cardsList, list_meter_int32_t, 1);
209
210 /* Adding a comparator
211 * The stored type is SCARDHANDLE (long) but has only 32 bits
212 * usefull even on a 64-bit CPU since the API between pcscd and
213 * libpcscliter uses "int32_t hCard;"
214 */
215 lrv = list_attributes_comparator(&newContext->cardsList,
216 list_comparator_int32_t);
217 if (lrv != 0)
218 {
219 Log2(PCSC_LOG_CRITICAL,
220 "list_attributes_comparator failed with return value: %d", lrv);
221 list_destroy(&newContext->cardsList);
222 goto out;
223 }
224
225 (void)pthread_mutex_init(&newContext->cardsList_lock, NULL);
226
227 lrv = list_append(&contextsList, newContext);
228 if (lrv < 0)
229 {
230 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
231 lrv);
232 list_destroy(&newContext->cardsList);
233 goto out;
234 }
235
236 rv = ThreadCreate(&newContext->pthThread, THREAD_ATTR_DETACHED,
237 (PCSCLITE_THREAD_FUNCTION( )) ContextThread, (LPVOID) newContext);
238 if (rv)
239 {
240 int lrv2;
241
242 Log2(PCSC_LOG_CRITICAL, "ThreadCreate failed: %s", strerror(rv));
243 lrv2 = list_delete(&contextsList, newContext);
244 if (lrv2 < 0)
245 Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv2);
246 list_destroy(&newContext->cardsList);
247 goto out;
248 }
249
250 /* disable any suicide alarm */
251 if (AutoExit)
252 alarm(0);
253
254 retval = SCARD_S_SUCCESS;
255
256out:
257 (void)pthread_mutex_unlock(&contextsList_lock);
258
259 if (retval != SCARD_S_SUCCESS)
260 {
261 if (newContext)
262 free(newContext);
263 (void)close(*pdwClientID);
264 }
265
266 return retval;
267}
268
269/*
270 * A list of local functions used to keep track of clients and their
271 * connections
272 */
273
282#ifndef NO_LOG
283static const char *CommandsText[] = {
284 "NULL",
285 "ESTABLISH_CONTEXT", /* 0x01 */
286 "RELEASE_CONTEXT",
287 "LIST_READERS",
288 "CONNECT",
289 "RECONNECT", /* 0x05 */
290 "DISCONNECT",
291 "BEGIN_TRANSACTION",
292 "END_TRANSACTION",
293 "TRANSMIT",
294 "CONTROL", /* 0x0A */
295 "STATUS",
296 "GET_STATUS_CHANGE",
297 "CANCEL",
298 "CANCEL_TRANSACTION",
299 "GET_ATTRIB", /* 0x0F */
300 "SET_ATTRIB",
301 "CMD_VERSION",
302 "CMD_GET_READERS_STATE",
303 "CMD_WAIT_READER_STATE_CHANGE",
304 "CMD_STOP_WAITING_READER_STATE_CHANGE", /* 0x14 */
305 "NULL"
306};
307#endif
308
309#define READ_BODY(v) \
310 do { \
311 if (header.size != sizeof(v)) \
312 goto wrong_length; \
313 ret = MessageReceive(&v, sizeof(v), filedes); \
314 if (ret != SCARD_S_SUCCESS) { \
315 Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); \
316 goto exit; \
317 } \
318 } while (0)
319
320#define WRITE_BODY(v) \
321 WRITE_BODY_WITH_COMMAND(CommandsText[header.command], v)
322#define WRITE_BODY_WITH_COMMAND(command, v) \
323 do { \
324 Log4(PCSC_LOG_DEBUG, "%s rv=0x%X for client %d", command, v.rv, filedes); \
325 ret = MessageSend(&v, sizeof(v), filedes); \
326 } while (0)
327
328static void * ContextThread(LPVOID newContext)
329{
330 SCONTEXT * threadContext = (SCONTEXT *) newContext;
331 int32_t filedes = threadContext->dwClientID;
332
333 if (IsClientAuthorized(filedes, "access_pcsc", NULL) == 0)
334 {
335 Log1(PCSC_LOG_CRITICAL, "Rejected unauthorized PC/SC client");
336 goto exit;
337 }
338 else
339 {
340 Log1(PCSC_LOG_DEBUG, "Authorized PC/SC client");
341 }
342
343 Log3(PCSC_LOG_DEBUG, "Thread is started: dwClientID=%d, threadContext @%p",
344 threadContext->dwClientID, threadContext);
345
346 while (1)
347 {
348 struct rxHeader header;
349 int32_t ret = MessageReceive(&header, sizeof(header), filedes);
350
351 if (ret != SCARD_S_SUCCESS)
352 {
353 /* Clean up the dead client */
354 Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
356 goto exit;
357 }
358
359 if ((header.command > CMD_ENUM_FIRST)
360 && (header.command < CMD_ENUM_LAST))
361 Log3(PCSC_LOG_DEBUG, "Received command: %s from client %d",
362 CommandsText[header.command], filedes);
363
364 switch (header.command)
365 {
366 /* pcsc-lite client/server protocol version */
367 case CMD_VERSION:
368 {
369 struct version_struct veStr;
370
371 READ_BODY(veStr);
372
373 Log3(PCSC_LOG_DEBUG, "Client is protocol version %d:%d",
374 veStr.major, veStr.minor);
375
376 veStr.rv = SCARD_S_SUCCESS;
377
378 /* client and server use different protocol */
379 if ((veStr.major != PROTOCOL_VERSION_MAJOR)
380 || (veStr.minor != PROTOCOL_VERSION_MINOR))
381 {
382 Log1(PCSC_LOG_CRITICAL,
383 "Communication protocol mismatch!");
384 Log3(PCSC_LOG_ERROR, "Client protocol is %d:%d",
385 veStr.major, veStr.minor);
386 Log3(PCSC_LOG_ERROR, "Server protocol is %d:%d",
388 veStr.rv = SCARD_E_SERVICE_STOPPED;
389 }
390
391 /* set the server protocol version */
392 veStr.major = PROTOCOL_VERSION_MAJOR;
393 veStr.minor = PROTOCOL_VERSION_MINOR;
394
395 /* send back the response */
396 WRITE_BODY(veStr);
397 }
398 break;
399
401 {
402 /* nothing to read */
403
404#ifdef USE_USB
405 /* wait until all readers are ready */
406 RFWaitForReaderInit();
407#endif
408
409 /* dump the readers state */
410 ret = MessageSend(readerStates, sizeof(readerStates), filedes);
411 }
412 break;
413
415 {
416 /* nothing to read */
417
418#ifdef USE_USB
419 /* wait until all readers are ready */
420 RFWaitForReaderInit();
421#endif
422
423 /* add the client fd to the list and dump the readers state */
424 EHRegisterClientForEvent(filedes);
425 }
426 break;
427
429 {
430 struct wait_reader_state_change waStr =
431 {
432 .timeOut = 0,
433 .rv = 0
434 };
435 LONG rv;
436
437 /* remove the client fd from the list */
438 rv = EHUnregisterClientForEvent(filedes);
439
440 /* send the response only if the client was still in the
441 * list */
442 if (rv != SCARD_F_INTERNAL_ERROR)
443 {
444 waStr.rv = rv;
445 WRITE_BODY(waStr);
446 }
447 }
448 break;
449
451 {
452 struct establish_struct esStr;
453 SCARDCONTEXT hContext;
454
455 READ_BODY(esStr);
456
457 hContext = esStr.hContext;
458 esStr.rv = SCardEstablishContext(esStr.dwScope, 0, 0,
459 &hContext);
460 esStr.hContext = hContext;
461
462 if (esStr.rv == SCARD_S_SUCCESS)
463 esStr.rv = MSGAddContext(esStr.hContext, threadContext);
464
465 WRITE_BODY(esStr);
466 }
467 break;
468
470 {
471 struct release_struct reStr;
472
473 READ_BODY(reStr);
474
475 reStr.rv = SCardReleaseContext(reStr.hContext);
476
477 if (reStr.rv == SCARD_S_SUCCESS)
478 reStr.rv = MSGRemoveContext(reStr.hContext, threadContext);
479
480 WRITE_BODY(reStr);
481 }
482 break;
483
484 case SCARD_CONNECT:
485 {
486 struct connect_struct coStr;
487 SCARDHANDLE hCard;
488 DWORD dwActiveProtocol;
489
490 READ_BODY(coStr);
491
492 coStr.szReader[sizeof(coStr.szReader)-1] = 0;
493 hCard = coStr.hCard;
494 dwActiveProtocol = coStr.dwActiveProtocol;
495
496 if (IsClientAuthorized(filedes, "access_card", coStr.szReader) == 0)
497 {
498 Log2(PCSC_LOG_CRITICAL, "Rejected unauthorized client for '%s'", coStr.szReader);
499 goto exit;
500 }
501 else
502 {
503 Log2(PCSC_LOG_DEBUG, "Authorized client for '%s'", coStr.szReader);
504 }
505
506 coStr.rv = SCardConnect(coStr.hContext, coStr.szReader,
507 coStr.dwShareMode, coStr.dwPreferredProtocols,
508 &hCard, &dwActiveProtocol);
509
510 coStr.hCard = hCard;
511 coStr.dwActiveProtocol = dwActiveProtocol;
512
513 if (coStr.rv == SCARD_S_SUCCESS)
514 {
515 coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard,
516 threadContext);
517
518 /* if storing the hCard fails we disconnect */
519 if (coStr.rv != SCARD_S_SUCCESS)
520 SCardDisconnect(coStr.hCard, SCARD_LEAVE_CARD);
521 }
522
523 WRITE_BODY(coStr);
524 }
525 break;
526
527 case SCARD_RECONNECT:
528 {
529 struct reconnect_struct rcStr;
530 DWORD dwActiveProtocol = SCARD_PROTOCOL_UNDEFINED;
531
532 READ_BODY(rcStr);
533
534 if (MSGCheckHandleAssociation(rcStr.hCard, threadContext))
535 goto exit;
536
537 rcStr.rv = SCardReconnect(rcStr.hCard, rcStr.dwShareMode,
538 rcStr.dwPreferredProtocols, rcStr.dwInitialization,
539 &dwActiveProtocol);
540 rcStr.dwActiveProtocol = dwActiveProtocol;
541
542 WRITE_BODY(rcStr);
543 }
544 break;
545
546 case SCARD_DISCONNECT:
547 {
548 struct disconnect_struct diStr;
549
550 READ_BODY(diStr);
551
552 if (MSGCheckHandleAssociation(diStr.hCard, threadContext))
553 goto exit;
554
555 diStr.rv = SCardDisconnect(diStr.hCard, diStr.dwDisposition);
556
557 if (SCARD_S_SUCCESS == diStr.rv)
558 diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext);
559
560 WRITE_BODY(diStr);
561 }
562 break;
563
565 {
566 struct begin_struct beStr;
567
568 READ_BODY(beStr);
569
570 if (MSGCheckHandleAssociation(beStr.hCard, threadContext))
571 goto exit;
572
573 beStr.rv = SCardBeginTransaction(beStr.hCard);
574
575 WRITE_BODY(beStr);
576 }
577 break;
578
580 {
581 struct end_struct enStr;
582
583 READ_BODY(enStr);
584
585 if (MSGCheckHandleAssociation(enStr.hCard, threadContext))
586 goto exit;
587
588 enStr.rv = SCardEndTransaction(enStr.hCard,
589 enStr.dwDisposition);
590
591 WRITE_BODY(enStr);
592 }
593 break;
594
595 case SCARD_CANCEL:
596 {
597 struct cancel_struct caStr;
598 SCONTEXT * psTargetContext = NULL;
599
600 READ_BODY(caStr);
601
602 /* find the client */
603 (void)pthread_mutex_lock(&contextsList_lock);
604 psTargetContext = (SCONTEXT *) list_seek(&contextsList,
605 &caStr.hContext);
606 (void)pthread_mutex_unlock(&contextsList_lock);
607
608 /* default value = error */
609 caStr.rv = SCARD_E_INVALID_HANDLE;
610
611 if (psTargetContext != NULL)
612 {
613 uint32_t fd = psTargetContext->dwClientID;
614 LONG rv;
615
616 /* the client should not receive the event
617 * notification now the waiting has been cancelled */
619
620 /* signal the client only if it was still waiting */
621 if (SCARD_S_SUCCESS == rv)
622 caStr.rv = MSGSignalClient(fd, SCARD_E_CANCELLED);
623 }
624
625 WRITE_BODY(caStr);
626 }
627 break;
628
629 case SCARD_STATUS:
630 {
631 struct status_struct stStr;
632
633 READ_BODY(stStr);
634
635 if (MSGCheckHandleAssociation(stStr.hCard, threadContext))
636 goto exit;
637
638 /* only hCard and return value are used by the client */
639 stStr.rv = SCardStatus(stStr.hCard, NULL, NULL, NULL,
640 NULL, 0, NULL);
641
642 WRITE_BODY(stStr);
643 }
644 break;
645
646 case SCARD_TRANSMIT:
647 {
648 struct transmit_struct trStr;
649 unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
650 unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
651 SCARD_IO_REQUEST ioSendPci;
652 SCARD_IO_REQUEST ioRecvPci;
653 DWORD cbRecvLength;
654
655 READ_BODY(trStr);
656
657 if (MSGCheckHandleAssociation(trStr.hCard, threadContext))
658 goto exit;
659
660 /* avoids buffer overflow */
661 if ((trStr.pcbRecvLength > sizeof(pbRecvBuffer))
662 || (trStr.cbSendLength > sizeof(pbSendBuffer)))
663 goto buffer_overflow;
664
665 /* read sent buffer */
666 ret = MessageReceive(pbSendBuffer, trStr.cbSendLength, filedes);
667 if (ret != SCARD_S_SUCCESS)
668 {
669 Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
670 goto exit;
671 }
672
673 ioSendPci.dwProtocol = trStr.ioSendPciProtocol;
674 ioSendPci.cbPciLength = trStr.ioSendPciLength;
675 ioRecvPci.dwProtocol = trStr.ioRecvPciProtocol;
676 ioRecvPci.cbPciLength = trStr.ioRecvPciLength;
677 cbRecvLength = sizeof pbRecvBuffer;
678
679 trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci,
680 pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
681 pbRecvBuffer, &cbRecvLength);
682
683 if (cbRecvLength > trStr.pcbRecvLength)
684 /* The client buffer is not large enough.
685 * The pbRecvBuffer buffer will NOT be sent a few
686 * lines bellow. So no buffer overflow is expected. */
688
689 trStr.ioSendPciProtocol = ioSendPci.dwProtocol;
690 trStr.ioSendPciLength = ioSendPci.cbPciLength;
691 trStr.ioRecvPciProtocol = ioRecvPci.dwProtocol;
692 trStr.ioRecvPciLength = ioRecvPci.cbPciLength;
693 trStr.pcbRecvLength = cbRecvLength;
694
695 WRITE_BODY(trStr);
696
697 /* write received buffer */
698 if (SCARD_S_SUCCESS == trStr.rv)
699 ret = MessageSend(pbRecvBuffer, cbRecvLength, filedes);
700 }
701 break;
702
703 case SCARD_CONTROL:
704 {
705 struct control_struct ctStr;
706 unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
707 unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
708 DWORD dwBytesReturned;
709
710 READ_BODY(ctStr);
711
712 if (MSGCheckHandleAssociation(ctStr.hCard, threadContext))
713 goto exit;
714
715 /* avoids buffer overflow */
716 if ((ctStr.cbRecvLength > sizeof(pbRecvBuffer))
717 || (ctStr.cbSendLength > sizeof(pbSendBuffer)))
718 {
719 goto buffer_overflow;
720 }
721
722 /* read sent buffer */
723 ret = MessageReceive(pbSendBuffer, ctStr.cbSendLength, filedes);
724 if (ret != SCARD_S_SUCCESS)
725 {
726 Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
727 goto exit;
728 }
729
730 dwBytesReturned = ctStr.dwBytesReturned;
731
732 ctStr.rv = SCardControl(ctStr.hCard, ctStr.dwControlCode,
733 pbSendBuffer, ctStr.cbSendLength,
734 pbRecvBuffer, sizeof pbRecvBuffer,
735 &dwBytesReturned);
736
737 if (dwBytesReturned > ctStr.cbRecvLength)
738 /* The client buffer is not large enough.
739 * The pbRecvBuffer buffer will NOT be sent a few
740 * lines bellow. So no buffer overflow is expected. */
742
743 ctStr.dwBytesReturned = dwBytesReturned;
744
745 WRITE_BODY(ctStr);
746
747 /* write received buffer */
748 if (SCARD_S_SUCCESS == ctStr.rv)
749 ret = MessageSend(pbRecvBuffer, dwBytesReturned, filedes);
750 }
751 break;
752
753 case SCARD_GET_ATTRIB:
754 {
755 struct getset_struct gsStr;
756 DWORD cbAttrLen;
757
758 READ_BODY(gsStr);
759
760 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
761 goto exit;
762
763 /* avoids buffer overflow */
764 if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
765 goto buffer_overflow;
766
767 cbAttrLen = gsStr.cbAttrLen;
768
769 gsStr.rv = SCardGetAttrib(gsStr.hCard, gsStr.dwAttrId,
770 gsStr.pbAttr, &cbAttrLen);
771
772 gsStr.cbAttrLen = cbAttrLen;
773
774 WRITE_BODY(gsStr);
775 }
776 break;
777
778 case SCARD_SET_ATTRIB:
779 {
780 struct getset_struct gsStr;
781
782 READ_BODY(gsStr);
783
784 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
785 goto exit;
786
787 /* avoids buffer overflow */
788 if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
789 goto buffer_overflow;
790
791 gsStr.rv = SCardSetAttrib(gsStr.hCard, gsStr.dwAttrId,
792 gsStr.pbAttr, gsStr.cbAttrLen);
793
794 WRITE_BODY(gsStr);
795 }
796 break;
797
798 default:
799 Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", header.command);
800 goto exit;
801 }
802
803 /* MessageSend() failed */
804 if (ret != SCARD_S_SUCCESS)
805 {
806 /* Clean up the dead client */
807 Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
808 goto exit;
809 }
810 }
811
812buffer_overflow:
813 Log2(PCSC_LOG_DEBUG, "Buffer overflow detected: %d", filedes);
814 goto exit;
815wrong_length:
816 Log2(PCSC_LOG_DEBUG, "Wrong length: %d", filedes);
817exit:
818 (void)close(filedes);
819 MSGCleanupClient(threadContext);
820 (void)pthread_exit((LPVOID) NULL);
821}
822
823LONG MSGSignalClient(uint32_t filedes, LONG rv)
824{
825 uint32_t ret;
826 struct wait_reader_state_change waStr =
827 {
828 .timeOut = 0,
829 .rv = 0
830 };
831
832 Log2(PCSC_LOG_DEBUG, "Signal client: %d", filedes);
833
834 waStr.rv = rv;
835 WRITE_BODY_WITH_COMMAND("SIGNAL", waStr);
836
837 return ret;
838} /* MSGSignalClient */
839
840LONG MSGSendReaderStates(uint32_t filedes)
841{
842 uint32_t ret;
843
844 Log2(PCSC_LOG_DEBUG, "Send reader states: %d", filedes);
845
846 /* dump the readers state */
847 ret = MessageSend(readerStates, sizeof(readerStates), filedes);
848
849 return ret;
850}
851
852static LONG MSGAddContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
853{
854 threadContext->hContext = hContext;
855 return SCARD_S_SUCCESS;
856}
857
858static LONG MSGRemoveContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
859{
860 LONG rv;
861 int lrv;
862
863 if (0 == threadContext->hContext)
864 {
865 Log1(PCSC_LOG_ERROR, "Invalidated handle");
867 }
868
869 if (threadContext->hContext != hContext)
871
872 (void)pthread_mutex_lock(&threadContext->cardsList_lock);
873 while (list_size(&threadContext->cardsList) != 0)
874 {
875 READER_CONTEXT * rContext = NULL;
876 SCARDHANDLE hCard;
877 void *ptr;
878
879 /*
880 * Disconnect each of these just in case
881 */
882 ptr = list_get_at(&threadContext->cardsList, 0);
883 if (NULL == ptr)
884 {
885 Log1(PCSC_LOG_CRITICAL, "list_get_at failed");
886 continue;
887 }
888 hCard = *(int32_t *)ptr;
889
890 /*
891 * Unlock the sharing
892 */
893 rv = RFReaderInfoById(hCard, &rContext);
894 if (rv != SCARD_S_SUCCESS)
895 {
896 (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
897 return rv;
898 }
899
900 if (0 == rContext->hLockId)
901 {
902 /* no lock. Just leave the card */
903 (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
904 }
905 else
906 {
907 if (hCard != rContext->hLockId)
908 {
909 /*
910 * if the card is locked by someone else we do not reset it
911 */
912
913 /* decrement card use */
914 (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
915 }
916 else
917 {
918 /* release the lock */
919 rContext->hLockId = 0;
920
921 /*
922 * We will use SCardStatus to see if the card has been
923 * reset there is no need to reset each time
924 * Disconnect is called
925 */
926 rv = SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL);
927
928 if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD)
929 (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
930 else
931 (void)SCardDisconnect(hCard, SCARD_RESET_CARD);
932 }
933 }
934
935 /* Remove entry from the list */
936 lrv = list_delete_at(&threadContext->cardsList, 0);
937 if (lrv < 0)
938 Log2(PCSC_LOG_CRITICAL,
939 "list_delete_at failed with return value: %d", lrv);
940
941 UNREF_READER(rContext)
942 }
943 (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
944
945 /* We only mark the context as no longer in use.
946 * The memory is freed in MSGCleanupCLient() */
947 threadContext->hContext = 0;
948
949 return SCARD_S_SUCCESS;
950}
951
952static LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard,
953 SCONTEXT * threadContext)
954{
955 LONG retval = SCARD_E_INVALID_VALUE;
956
957 if (0 == threadContext->hContext)
958 {
959 Log1(PCSC_LOG_ERROR, "Invalidated handle");
961 }
962
963 if (threadContext->hContext == hContext)
964 {
965 /*
966 * Find an empty spot to put the hCard value
967 */
968 int listLength;
969
970 (void)pthread_mutex_lock(&threadContext->cardsList_lock);
971
972 listLength = list_size(&threadContext->cardsList);
973 if (listLength >= contextMaxCardHandles)
974 {
975 Log4(PCSC_LOG_DEBUG,
976 "Too many card handles for thread context @%p: %d (max is %d). "
977 "Restart pcscd with --max-card-handle-per-thread value",
978 threadContext, listLength, contextMaxCardHandles);
979 retval = SCARD_E_NO_MEMORY;
980 }
981 else
982 {
983 int lrv;
984
985 lrv = list_append(&threadContext->cardsList, &hCard);
986 if (lrv < 0)
987 {
988 Log2(PCSC_LOG_CRITICAL,
989 "list_append failed with return value: %d", lrv);
990 retval = SCARD_E_NO_MEMORY;
991 }
992 else
993 retval = SCARD_S_SUCCESS;
994 }
995
996 (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
997 }
998
999 return retval;
1000}
1001
1002/* Pre-condition: MSGCheckHandleAssociation must succeed. */
1003static LONG MSGRemoveHandle(SCARDHANDLE hCard, SCONTEXT * threadContext)
1004{
1005 int lrv;
1006
1007 (void)pthread_mutex_lock(&threadContext->cardsList_lock);
1008 lrv = list_delete(&threadContext->cardsList, &hCard);
1009 (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1010 if (lrv < 0)
1011 {
1012 Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv);
1013 return SCARD_E_INVALID_VALUE;
1014 }
1015
1016 return SCARD_S_SUCCESS;
1017}
1018
1019
1020static LONG MSGCheckHandleAssociation(SCARDHANDLE hCard,
1021 SCONTEXT * threadContext)
1022{
1023 int list_index = 0;
1024
1025 if (0 == threadContext->hContext)
1026 {
1027 /* the handle is no more valid. After SCardReleaseContext() for
1028 * example */
1029 Log1(PCSC_LOG_CRITICAL, "Invalidated handle");
1030 return -1;
1031 }
1032
1033 (void)pthread_mutex_lock(&threadContext->cardsList_lock);
1034 list_index = list_locate(&threadContext->cardsList, &hCard);
1035 (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1036 if (list_index >= 0)
1037 return 0;
1038
1039 /* Must be a rogue client, debug log and sleep a couple of seconds */
1040 Log1(PCSC_LOG_ERROR, "Client failed to authenticate");
1041 (void)SYS_Sleep(2);
1042
1043 return -1;
1044}
1045
1046
1047/* Should be called just prior to exiting the thread as it de-allocates
1048 * the thread memory strucutres
1049 */
1050static void MSGCleanupClient(SCONTEXT * threadContext)
1051{
1052 int lrv;
1053 int listSize;
1054
1055 if (threadContext->hContext != 0)
1056 {
1057 (void)SCardReleaseContext(threadContext->hContext);
1058 (void)MSGRemoveContext(threadContext->hContext, threadContext);
1059 }
1060
1061 (void)pthread_mutex_lock(&threadContext->cardsList_lock);
1062 list_destroy(&threadContext->cardsList);
1063 (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1064
1065 Log3(PCSC_LOG_DEBUG,
1066 "Thread is stopping: dwClientID=%d, threadContext @%p",
1067 threadContext->dwClientID, threadContext);
1068
1069 /* Clear the struct to ensure that we detect
1070 * access to de-allocated memory
1071 * Hopefully the compiler won't optimise it out */
1072 memset((void*) threadContext, 0, sizeof(SCONTEXT));
1073 Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXT @%p", threadContext);
1074
1075 (void)pthread_mutex_lock(&contextsList_lock);
1076 lrv = list_delete(&contextsList, threadContext);
1077 listSize = list_size(&contextsList);
1078 (void)pthread_mutex_unlock(&contextsList_lock);
1079 if (lrv < 0)
1080 Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %x", lrv);
1081
1082 free(threadContext);
1083
1084 /* start a suicide alarm */
1085 if (AutoExit && (listSize < 1))
1086 {
1087 Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds",
1088 TIME_BEFORE_SUICIDE);
1089 alarm(TIME_BEFORE_SUICIDE);
1090 }
1091
1092 return;
1093}
This handles debugging.
LONG EHTryToUnregisterClientForEvent(int32_t filedes)
Try to unregisted a client If no client is found then do not log an error.
Definition: eventhandler.c:83
LONG EHUnregisterClientForEvent(int32_t filedes)
Unregister a client and log an error if the client is not found.
Definition: eventhandler.c:103
This handles card insertion/removal events, updates ATR, protocol, and status information.
PCSC_API LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
Definition: winscard.c:1437
PCSC_API LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
Definition: winscard.c:827
PCSC_API LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
Establishes a connection to the reader specified in * szReader.
Definition: winscard.c:234
PCSC_API LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.
Definition: winscard.c:220
PCSC_API LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength, SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength)
Sends an APDU to the smart card contained in the reader connected to by SCardConnect().
Definition: winscard.c:1487
PCSC_API LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
Creates an Application Context to the PC/SC Resource Manager.
Definition: winscard.c:195
PCSC_API LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
Definition: winscard.c:1362
PCSC_API LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, LPDWORD lpBytesReturned)
Sends a command directly to the IFD Handler (reader driver) to be processed by the reader.
Definition: winscard.c:1303
PCSC_API LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode, DWORD dwPreferredProtocols, DWORD dwInitialization, LPDWORD pdwActiveProtocol)
Reestablishes a connection to a reader that was previously connected to using SCardConnect().
Definition: winscard.c:525
PCSC_API LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a serie of commands in a transaction.
Definition: winscard.c:1046
PCSC_API LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
Returns the current status of the reader connected to by hCard.
Definition: winscard.c:1240
PCSC_API LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
Definition: winscard.c:1088
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition: pcsclite.h:113
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:109
#define SCARD_W_RESET_CARD
The smart card has been reset, so any shared state information is invalid.
Definition: pcsclite.h:216
#define SCARD_E_SERVICE_STOPPED
The Smart card resource manager has shut down.
Definition: pcsclite.h:167
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition: pcsclite.h:111
#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_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_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition: pcsclite.h:123
This keeps a list of defines for pcsc-lite.
#define SCARD_RESET_CARD
Reset on close.
Definition: pcsclite.h:253
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition: pcsclite.h:52
#define SCARD_PROTOCOL_UNDEFINED
protocol not set
Definition: pcsclite.h:239
#define SCARD_LEAVE_CARD
Do nothing on close.
Definition: pcsclite.h:252
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition: pcsclite.h:298
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
This keeps track of a list of currently available reader structures.
_Atomic SCARDHANDLE hLockId
Lock Id.
Protocol Control Information (PCI)
Definition: pcsclite.h:80
unsigned long dwProtocol
Protocol identifier.
Definition: pcsclite.h:81
unsigned long cbPciLength
Protocol Control Inf Length.
Definition: pcsclite.h:82
pthread_mutex_t cardsList_lock
lock for the above list
Definition: winscard_svc.c:85
pthread_t pthThread
Event polling thread's ID.
Definition: winscard_svc.c:87
uint32_t dwClientID
Connection ID used to reference the Client.
Definition: winscard_svc.c:86
contained in SCARD_BEGIN_TRANSACTION Messages.
Definition: winscard_msg.h:188
contained in SCARD_CANCEL Messages.
Definition: winscard_msg.h:211
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:145
contained in SCARD_CONTROL Messages.
Definition: winscard_msg.h:250
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:176
contained in SCARD_END_TRANSACTION Messages.
Definition: winscard_msg.h:199
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
Definition: winscard_msg.h:122
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:265
list object
Definition: simclist.h:181
Define an exported public reader state structure so each application gets instant notification of cha...
Definition: eventhandler.h:53
contained in SCARD_RECONNECT Messages.
Definition: winscard_msg.h:161
Information contained in SCARD_RELEASE_CONTEXT Messages.
Definition: winscard_msg.h:134
header structure for client/server message data exchange.
Definition: winscard_msg.h:68
contained in SCARD_STATUS Messages.
Definition: winscard_msg.h:222
contained in SCARD_TRANSMIT Messages.
Definition: winscard_msg.h:233
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:58
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
Definition: winscard_msg.h:111
uint32_t timeOut
timeout in ms
Definition: winscard_msg.h:112
This handles abstract system level calls.
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
Definition: sys_unix.c:53
This handles smart card reader communications.
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Sends a menssage from client to server or vice-versa.
Definition: winscard_msg.c:357
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the reponse from the server or vice-versa.
Definition: winscard_msg.c:457
This defines some structures and #defines to be used over the transport layer.
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
Definition: winscard_msg.h:50
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
Definition: winscard_msg.h:52
@ SCARD_DISCONNECT
used by SCardDisconnect()
Definition: winscard_msg.h:84
@ SCARD_SET_ATTRIB
used by SCardSetAttrib()
Definition: winscard_msg.h:94
@ SCARD_RELEASE_CONTEXT
used by SCardReleaseContext()
Definition: winscard_msg.h:80
@ CMD_STOP_WAITING_READER_STATE_CHANGE
stop waiting for a reader state change
Definition: winscard_msg.h:98
@ CMD_GET_READERS_STATE
get the readers state
Definition: winscard_msg.h:96
@ SCARD_CONTROL
used by SCardControl()
Definition: winscard_msg.h:88
@ CMD_VERSION
get the client/server protocol version
Definition: winscard_msg.h:95
@ CMD_WAIT_READER_STATE_CHANGE
wait for a reader state change
Definition: winscard_msg.h:97
@ SCARD_RECONNECT
used by SCardReconnect()
Definition: winscard_msg.h:83
@ SCARD_STATUS
used by SCardStatus()
Definition: winscard_msg.h:89
@ SCARD_GET_ATTRIB
used by SCardGetAttrib()
Definition: winscard_msg.h:93
@ SCARD_BEGIN_TRANSACTION
used by SCardBeginTransaction()
Definition: winscard_msg.h:85
@ SCARD_TRANSMIT
used by SCardTransmit()
Definition: winscard_msg.h:87
@ SCARD_END_TRANSACTION
used by SCardEndTransaction()
Definition: winscard_msg.h:86
@ SCARD_CANCEL
used by SCardCancel()
Definition: winscard_msg.h:91
@ SCARD_CONNECT
used by SCardConnect()
Definition: winscard_msg.h:82
@ SCARD_ESTABLISH_CONTEXT
used by SCardEstablishContext()
Definition: winscard_msg.h:79
LONG CreateContextThread(uint32_t *pdwClientID)
Creates threads to handle messages received from Clients.
Definition: winscard_svc.c:171
static const char * CommandsText[]
Handles messages received from Clients.
Definition: winscard_svc.c:283
static list_t contextsList
Context tracking list.
Definition: winscard_svc.c:78
pthread_mutex_t contextsList_lock
lock for the above list
Definition: winscard_svc.c:79
char AutoExit
Represents an Application Context on the Server side.
Definition: pcscdaemon.c:80
This demarshalls functions over the message queue and keeps track of clients and their handles.