pcsc-lite  1.9.0
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  *
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions
15 are met:
16 
17 1. Redistributions of source code must retain the above copyright
18  notice, this list of conditions and the following disclaimer.
19 2. 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.
22 3. 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 
25 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 THIS 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 
74 extern char AutoExit;
75 static int contextMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
76 static int contextMaxCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
77 
79 pthread_mutex_t contextsList_lock;
81 struct _psContext
82 {
83  int32_t hContext;
84  list_t cardsList;
85  pthread_mutex_t cardsList_lock;
86  uint32_t dwClientID;
87  pthread_t pthThread;
88 };
89 typedef struct _psContext SCONTEXT;
90 
91 static LONG MSGCheckHandleAssociation(SCARDHANDLE, SCONTEXT *);
92 static LONG MSGAddContext(SCARDCONTEXT, SCONTEXT *);
93 static LONG MSGRemoveContext(SCARDCONTEXT, SCONTEXT *);
94 static LONG MSGAddHandle(SCARDCONTEXT, SCARDHANDLE, SCONTEXT *);
95 static LONG MSGRemoveHandle(SCARDHANDLE, SCONTEXT *);
96 static void MSGCleanupClient(SCONTEXT *);
97 
98 static void * ContextThread(LPVOID pdwIndex);
99 
101 
102 static 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 
118 LONG 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 
148 void 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 
171 LONG 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 
256 out:
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
283 static 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 
328 static 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 
436  /* remove the client fd from the list */
437  waStr.rv = EHUnregisterClientForEvent(filedes);
438 
439  /* send the response only if the client was still in the
440  * list */
441  if (waStr.rv != SCARD_F_INTERNAL_ERROR)
442  WRITE_BODY(waStr);
443  }
444  break;
445 
447  {
448  struct establish_struct esStr;
449  SCARDCONTEXT hContext;
450 
451  READ_BODY(esStr);
452 
453  hContext = esStr.hContext;
454  esStr.rv = SCardEstablishContext(esStr.dwScope, 0, 0,
455  &hContext);
456  esStr.hContext = hContext;
457 
458  if (esStr.rv == SCARD_S_SUCCESS)
459  esStr.rv = MSGAddContext(esStr.hContext, threadContext);
460 
461  WRITE_BODY(esStr);
462  }
463  break;
464 
466  {
467  struct release_struct reStr;
468 
469  READ_BODY(reStr);
470 
471  reStr.rv = SCardReleaseContext(reStr.hContext);
472 
473  if (reStr.rv == SCARD_S_SUCCESS)
474  reStr.rv = MSGRemoveContext(reStr.hContext, threadContext);
475 
476  WRITE_BODY(reStr);
477  }
478  break;
479 
480  case SCARD_CONNECT:
481  {
482  struct connect_struct coStr;
483  SCARDHANDLE hCard;
484  DWORD dwActiveProtocol;
485 
486  READ_BODY(coStr);
487 
488  coStr.szReader[sizeof(coStr.szReader)-1] = 0;
489  hCard = coStr.hCard;
490  dwActiveProtocol = coStr.dwActiveProtocol;
491 
492  if (IsClientAuthorized(filedes, "access_card", coStr.szReader) == 0)
493  {
494  Log2(PCSC_LOG_CRITICAL, "Rejected unauthorized client for '%s'", coStr.szReader);
495  goto exit;
496  }
497  else
498  {
499  Log2(PCSC_LOG_DEBUG, "Authorized client for '%s'", coStr.szReader);
500  }
501 
502  coStr.rv = SCardConnect(coStr.hContext, coStr.szReader,
503  coStr.dwShareMode, coStr.dwPreferredProtocols,
504  &hCard, &dwActiveProtocol);
505 
506  coStr.hCard = hCard;
507  coStr.dwActiveProtocol = dwActiveProtocol;
508 
509  if (coStr.rv == SCARD_S_SUCCESS)
510  {
511  coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard,
512  threadContext);
513 
514  /* if storing the hCard fails we disconnect */
515  if (coStr.rv != SCARD_S_SUCCESS)
516  SCardDisconnect(coStr.hCard, SCARD_LEAVE_CARD);
517  }
518 
519  WRITE_BODY(coStr);
520  }
521  break;
522 
523  case SCARD_RECONNECT:
524  {
525  struct reconnect_struct rcStr;
526  DWORD dwActiveProtocol;
527 
528  READ_BODY(rcStr);
529 
530  if (MSGCheckHandleAssociation(rcStr.hCard, threadContext))
531  goto exit;
532 
533  rcStr.rv = SCardReconnect(rcStr.hCard, rcStr.dwShareMode,
534  rcStr.dwPreferredProtocols, rcStr.dwInitialization,
535  &dwActiveProtocol);
536  rcStr.dwActiveProtocol = dwActiveProtocol;
537 
538  WRITE_BODY(rcStr);
539  }
540  break;
541 
542  case SCARD_DISCONNECT:
543  {
544  struct disconnect_struct diStr;
545 
546  READ_BODY(diStr);
547 
548  if (MSGCheckHandleAssociation(diStr.hCard, threadContext))
549  goto exit;
550 
551  diStr.rv = SCardDisconnect(diStr.hCard, diStr.dwDisposition);
552 
553  if (SCARD_S_SUCCESS == diStr.rv)
554  diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext);
555 
556  WRITE_BODY(diStr);
557  }
558  break;
559 
561  {
562  struct begin_struct beStr;
563 
564  READ_BODY(beStr);
565 
566  if (MSGCheckHandleAssociation(beStr.hCard, threadContext))
567  goto exit;
568 
569  beStr.rv = SCardBeginTransaction(beStr.hCard);
570 
571  WRITE_BODY(beStr);
572  }
573  break;
574 
576  {
577  struct end_struct enStr;
578 
579  READ_BODY(enStr);
580 
581  if (MSGCheckHandleAssociation(enStr.hCard, threadContext))
582  goto exit;
583 
584  enStr.rv = SCardEndTransaction(enStr.hCard,
585  enStr.dwDisposition);
586 
587  WRITE_BODY(enStr);
588  }
589  break;
590 
591  case SCARD_CANCEL:
592  {
593  struct cancel_struct caStr;
594  SCONTEXT * psTargetContext = NULL;
595 
596  READ_BODY(caStr);
597 
598  /* find the client */
599  (void)pthread_mutex_lock(&contextsList_lock);
600  psTargetContext = (SCONTEXT *) list_seek(&contextsList,
601  &caStr.hContext);
602  (void)pthread_mutex_unlock(&contextsList_lock);
603 
604  /* default value = error */
605  caStr.rv = SCARD_E_INVALID_HANDLE;
606 
607  if (psTargetContext != NULL)
608  {
609  uint32_t fd = psTargetContext->dwClientID;
610  LONG rv;
611 
612  /* the client should not receive the event
613  * notification now the waiting has been cancelled */
615 
616  /* signal the client only if it was still waiting */
617  if (SCARD_S_SUCCESS == rv)
618  caStr.rv = MSGSignalClient(fd, SCARD_E_CANCELLED);
619  }
620 
621  WRITE_BODY(caStr);
622  }
623  break;
624 
625  case SCARD_STATUS:
626  {
627  struct status_struct stStr;
628 
629  READ_BODY(stStr);
630 
631  if (MSGCheckHandleAssociation(stStr.hCard, threadContext))
632  goto exit;
633 
634  /* only hCard and return value are used by the client */
635  stStr.rv = SCardStatus(stStr.hCard, NULL, NULL, NULL,
636  NULL, 0, NULL);
637 
638  WRITE_BODY(stStr);
639  }
640  break;
641 
642  case SCARD_TRANSMIT:
643  {
644  struct transmit_struct trStr;
645  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
646  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
647  SCARD_IO_REQUEST ioSendPci;
648  SCARD_IO_REQUEST ioRecvPci;
649  DWORD cbRecvLength;
650 
651  READ_BODY(trStr);
652 
653  if (MSGCheckHandleAssociation(trStr.hCard, threadContext))
654  goto exit;
655 
656  /* avoids buffer overflow */
657  if ((trStr.pcbRecvLength > sizeof(pbRecvBuffer))
658  || (trStr.cbSendLength > sizeof(pbSendBuffer)))
659  goto buffer_overflow;
660 
661  /* read sent buffer */
662  ret = MessageReceive(pbSendBuffer, trStr.cbSendLength, filedes);
663  if (ret != SCARD_S_SUCCESS)
664  {
665  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
666  goto exit;
667  }
668 
669  ioSendPci.dwProtocol = trStr.ioSendPciProtocol;
670  ioSendPci.cbPciLength = trStr.ioSendPciLength;
671  ioRecvPci.dwProtocol = trStr.ioRecvPciProtocol;
672  ioRecvPci.cbPciLength = trStr.ioRecvPciLength;
673  cbRecvLength = sizeof pbRecvBuffer;
674 
675  trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci,
676  pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
677  pbRecvBuffer, &cbRecvLength);
678 
679  if (cbRecvLength > trStr.pcbRecvLength)
680  /* The client buffer is not large enough.
681  * The pbRecvBuffer buffer will NOT be sent a few
682  * lines bellow. So no buffer overflow is expected. */
683  trStr.rv = SCARD_E_INSUFFICIENT_BUFFER;
684 
685  trStr.ioSendPciProtocol = ioSendPci.dwProtocol;
686  trStr.ioSendPciLength = ioSendPci.cbPciLength;
687  trStr.ioRecvPciProtocol = ioRecvPci.dwProtocol;
688  trStr.ioRecvPciLength = ioRecvPci.cbPciLength;
689  trStr.pcbRecvLength = cbRecvLength;
690 
691  WRITE_BODY(trStr);
692 
693  /* write received buffer */
694  if (SCARD_S_SUCCESS == trStr.rv)
695  ret = MessageSend(pbRecvBuffer, cbRecvLength, filedes);
696  }
697  break;
698 
699  case SCARD_CONTROL:
700  {
701  struct control_struct ctStr;
702  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
703  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
704  DWORD dwBytesReturned;
705 
706  READ_BODY(ctStr);
707 
708  if (MSGCheckHandleAssociation(ctStr.hCard, threadContext))
709  goto exit;
710 
711  /* avoids buffer overflow */
712  if ((ctStr.cbRecvLength > sizeof(pbRecvBuffer))
713  || (ctStr.cbSendLength > sizeof(pbSendBuffer)))
714  {
715  goto buffer_overflow;
716  }
717 
718  /* read sent buffer */
719  ret = MessageReceive(pbSendBuffer, ctStr.cbSendLength, filedes);
720  if (ret != SCARD_S_SUCCESS)
721  {
722  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
723  goto exit;
724  }
725 
726  dwBytesReturned = ctStr.dwBytesReturned;
727 
728  ctStr.rv = SCardControl(ctStr.hCard, ctStr.dwControlCode,
729  pbSendBuffer, ctStr.cbSendLength,
730  pbRecvBuffer, sizeof pbRecvBuffer,
731  &dwBytesReturned);
732 
733  if (dwBytesReturned > ctStr.cbRecvLength)
734  /* The client buffer is not large enough.
735  * The pbRecvBuffer buffer will NOT be sent a few
736  * lines bellow. So no buffer overflow is expected. */
737  ctStr.rv = SCARD_E_INSUFFICIENT_BUFFER;
738 
739  ctStr.dwBytesReturned = dwBytesReturned;
740 
741  WRITE_BODY(ctStr);
742 
743  /* write received buffer */
744  if (SCARD_S_SUCCESS == ctStr.rv)
745  ret = MessageSend(pbRecvBuffer, dwBytesReturned, filedes);
746  }
747  break;
748 
749  case SCARD_GET_ATTRIB:
750  {
751  struct getset_struct gsStr;
752  DWORD cbAttrLen;
753 
754  READ_BODY(gsStr);
755 
756  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
757  goto exit;
758 
759  /* avoids buffer overflow */
760  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
761  goto buffer_overflow;
762 
763  cbAttrLen = gsStr.cbAttrLen;
764 
765  gsStr.rv = SCardGetAttrib(gsStr.hCard, gsStr.dwAttrId,
766  gsStr.pbAttr, &cbAttrLen);
767 
768  gsStr.cbAttrLen = cbAttrLen;
769 
770  WRITE_BODY(gsStr);
771  }
772  break;
773 
774  case SCARD_SET_ATTRIB:
775  {
776  struct getset_struct gsStr;
777 
778  READ_BODY(gsStr);
779 
780  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
781  goto exit;
782 
783  /* avoids buffer overflow */
784  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
785  goto buffer_overflow;
786 
787  gsStr.rv = SCardSetAttrib(gsStr.hCard, gsStr.dwAttrId,
788  gsStr.pbAttr, gsStr.cbAttrLen);
789 
790  WRITE_BODY(gsStr);
791  }
792  break;
793 
794  default:
795  Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", header.command);
796  goto exit;
797  }
798 
799  /* MessageSend() failed */
800  if (ret != SCARD_S_SUCCESS)
801  {
802  /* Clean up the dead client */
803  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
804  goto exit;
805  }
806  }
807 
808 buffer_overflow:
809  Log2(PCSC_LOG_DEBUG, "Buffer overflow detected: %d", filedes);
810  goto exit;
811 wrong_length:
812  Log2(PCSC_LOG_DEBUG, "Wrong length: %d", filedes);
813 exit:
814  (void)close(filedes);
815  MSGCleanupClient(threadContext);
816  (void)pthread_exit((LPVOID) NULL);
817 }
818 
819 LONG MSGSignalClient(uint32_t filedes, LONG rv)
820 {
821  uint32_t ret;
822  struct wait_reader_state_change waStr =
823  {
824  .timeOut = 0,
825  .rv = 0
826  };
827 
828  Log2(PCSC_LOG_DEBUG, "Signal client: %d", filedes);
829 
830  waStr.rv = rv;
831  WRITE_BODY_WITH_COMMAND("SIGNAL", waStr);
832 
833  return ret;
834 } /* MSGSignalClient */
835 
836 LONG MSGSendReaderStates(uint32_t filedes)
837 {
838  uint32_t ret;
839 
840  Log2(PCSC_LOG_DEBUG, "Send reader states: %d", filedes);
841 
842  /* dump the readers state */
843  ret = MessageSend(readerStates, sizeof(readerStates), filedes);
844 
845  return ret;
846 }
847 
848 static LONG MSGAddContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
849 {
850  threadContext->hContext = hContext;
851  return SCARD_S_SUCCESS;
852 }
853 
854 static LONG MSGRemoveContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
855 {
856  LONG rv;
857  int lrv;
858 
859  if (0 == threadContext->hContext)
860  {
861  Log1(PCSC_LOG_ERROR, "Invalidated handle");
862  return SCARD_E_INVALID_HANDLE;
863  }
864 
865  if (threadContext->hContext != hContext)
866  return SCARD_E_INVALID_VALUE;
867 
868  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
869  while (list_size(&threadContext->cardsList) != 0)
870  {
871  READER_CONTEXT * rContext = NULL;
872  SCARDHANDLE hCard;
873  void *ptr;
874 
875  /*
876  * Disconnect each of these just in case
877  */
878  ptr = list_get_at(&threadContext->cardsList, 0);
879  if (NULL == ptr)
880  {
881  Log1(PCSC_LOG_CRITICAL, "list_get_at failed");
882  continue;
883  }
884  hCard = *(int32_t *)ptr;
885 
886  /*
887  * Unlock the sharing
888  */
889  rv = RFReaderInfoById(hCard, &rContext);
890  if (rv != SCARD_S_SUCCESS)
891  {
892  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
893  return rv;
894  }
895 
896  if (0 == rContext->hLockId)
897  {
898  /* no lock. Just leave the card */
899  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
900  }
901  else
902  {
903  if (hCard != rContext->hLockId)
904  {
905  /*
906  * if the card is locked by someone else we do not reset it
907  */
908 
909  /* decrement card use */
910  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
911  }
912  else
913  {
914  /* release the lock */
915  rContext->hLockId = 0;
916 
917  /*
918  * We will use SCardStatus to see if the card has been
919  * reset there is no need to reset each time
920  * Disconnect is called
921  */
922  rv = SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL);
923 
924  if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD)
925  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
926  else
927  (void)SCardDisconnect(hCard, SCARD_RESET_CARD);
928  }
929  }
930 
931  /* Remove entry from the list */
932  lrv = list_delete_at(&threadContext->cardsList, 0);
933  if (lrv < 0)
934  Log2(PCSC_LOG_CRITICAL,
935  "list_delete_at failed with return value: %d", lrv);
936 
937  UNREF_READER(rContext)
938  }
939  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
940 
941  /* We only mark the context as no longer in use.
942  * The memory is freed in MSGCleanupCLient() */
943  threadContext->hContext = 0;
944 
945  return SCARD_S_SUCCESS;
946 }
947 
948 static LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard,
949  SCONTEXT * threadContext)
950 {
951  LONG retval = SCARD_E_INVALID_VALUE;
952 
953  if (0 == threadContext->hContext)
954  {
955  Log1(PCSC_LOG_ERROR, "Invalidated handle");
956  return SCARD_E_INVALID_HANDLE;
957  }
958 
959  if (threadContext->hContext == hContext)
960  {
961  /*
962  * Find an empty spot to put the hCard value
963  */
964  int listLength;
965 
966  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
967 
968  listLength = list_size(&threadContext->cardsList);
969  if (listLength >= contextMaxCardHandles)
970  {
971  Log4(PCSC_LOG_DEBUG,
972  "Too many card handles for thread context @%p: %d (max is %d). "
973  "Restart pcscd with --max-card-handle-per-thread value",
974  threadContext, listLength, contextMaxCardHandles);
975  retval = SCARD_E_NO_MEMORY;
976  }
977  else
978  {
979  int lrv;
980 
981  lrv = list_append(&threadContext->cardsList, &hCard);
982  if (lrv < 0)
983  {
984  Log2(PCSC_LOG_CRITICAL,
985  "list_append failed with return value: %d", lrv);
986  retval = SCARD_E_NO_MEMORY;
987  }
988  else
989  retval = SCARD_S_SUCCESS;
990  }
991 
992  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
993  }
994 
995  return retval;
996 }
997 
998 /* Pre-condition: MSGCheckHandleAssociation must succeed. */
999 static LONG MSGRemoveHandle(SCARDHANDLE hCard, SCONTEXT * threadContext)
1000 {
1001  int lrv;
1002 
1003  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
1004  lrv = list_delete(&threadContext->cardsList, &hCard);
1005  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1006  if (lrv < 0)
1007  {
1008  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv);
1009  return SCARD_E_INVALID_VALUE;
1010  }
1011 
1012  return SCARD_S_SUCCESS;
1013 }
1014 
1015 
1016 static LONG MSGCheckHandleAssociation(SCARDHANDLE hCard,
1017  SCONTEXT * threadContext)
1018 {
1019  int list_index = 0;
1020 
1021  if (0 == threadContext->hContext)
1022  {
1023  /* the handle is no more valid. After SCardReleaseContext() for
1024  * example */
1025  Log1(PCSC_LOG_CRITICAL, "Invalidated handle");
1026  return -1;
1027  }
1028 
1029  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
1030  list_index = list_locate(&threadContext->cardsList, &hCard);
1031  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1032  if (list_index >= 0)
1033  return 0;
1034 
1035  /* Must be a rogue client, debug log and sleep a couple of seconds */
1036  Log1(PCSC_LOG_ERROR, "Client failed to authenticate");
1037  (void)SYS_Sleep(2);
1038 
1039  return -1;
1040 }
1041 
1042 
1043 /* Should be called just prior to exiting the thread as it de-allocates
1044  * the thread memory strucutres
1045  */
1046 static void MSGCleanupClient(SCONTEXT * threadContext)
1047 {
1048  int lrv;
1049  int listSize;
1050 
1051  if (threadContext->hContext != 0)
1052  {
1053  (void)SCardReleaseContext(threadContext->hContext);
1054  (void)MSGRemoveContext(threadContext->hContext, threadContext);
1055  }
1056 
1057  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
1058  list_destroy(&threadContext->cardsList);
1059  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1060 
1061  Log3(PCSC_LOG_DEBUG,
1062  "Thread is stopping: dwClientID=%d, threadContext @%p",
1063  threadContext->dwClientID, threadContext);
1064 
1065  /* Clear the struct to ensure that we detect
1066  * access to de-allocated memory
1067  * Hopefully the compiler won't optimise it out */
1068  memset((void*) threadContext, 0, sizeof(SCONTEXT));
1069  Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXT @%p", threadContext);
1070 
1071  (void)pthread_mutex_lock(&contextsList_lock);
1072  lrv = list_delete(&contextsList, threadContext);
1073  listSize = list_size(&contextsList);
1074  (void)pthread_mutex_unlock(&contextsList_lock);
1075  if (lrv < 0)
1076  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %x", lrv);
1077 
1078  free(threadContext);
1079 
1080  /* start a suicide alarm */
1081  if (AutoExit && (listSize < 1))
1082  {
1083  Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds",
1084  TIME_BEFORE_SUICIDE);
1085  alarm(TIME_BEFORE_SUICIDE);
1086  }
1087 
1088  return;
1089 }
EHUnregisterClientForEvent
LONG EHUnregisterClientForEvent(int32_t filedes)
Unregister a client and log an error if the client is not found.
Definition: eventhandler.c:103
SCardReleaseContext
PCSC_API LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.
Definition: winscard.c:220
SCardDisconnect
PCSC_API LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
Definition: winscard.c:829
debuglog.h
This handles debugging.
SCardGetAttrib
PCSC_API LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
Definition: winscard.c:1364
SCARD_RESET_CARD
#define SCARD_RESET_CARD
Reset on close.
Definition: pcsclite.h:253
establish_struct
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
Definition: winscard_msg.h:118
wait_reader_state_change
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
Definition: winscard_msg.h:107
CreateContextThread
LONG CreateContextThread(uint32_t *pdwClientID)
Creates threads to handle messages received from Clients.
Definition: winscard_svc.c:171
SCARD_S_SUCCESS
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
pubReaderStatesList
Define an exported public reader state structure so each application gets instant notification of cha...
Definition: eventhandler.h:48
SCARD_W_REMOVED_CARD
#define SCARD_W_REMOVED_CARD
The smart card has been removed, so further communication is not possible.
Definition: pcsclite.h:218
PROTOCOL_VERSION_MAJOR
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
Definition: winscard_msg.h:47
disconnect_struct
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:172
SCARD_CONTROL
@ SCARD_CONTROL
used by SCardControl()
Definition: winscard_msg.h:85
SCARD_IO_REQUEST::cbPciLength
unsigned long cbPciLength
Protocol Control Inf Length.
Definition: pcsclite.h:82
CMD_STOP_WAITING_READER_STATE_CHANGE
@ CMD_STOP_WAITING_READER_STATE_CHANGE
stop waiting for a reader state change
Definition: winscard_msg.h:95
SCardEstablishContext
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
SCARD_CONNECT
@ SCARD_CONNECT
used by SCardConnect()
Definition: winscard_msg.h:79
sys_generic.h
This handles abstract system level calls.
readerfactory.h
This keeps track of a list of currently available reader structures.
rxHeader
header structure for client/server message data exchange.
Definition: winscard_msg.h:64
SYS_Sleep
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
Definition: sys_unix.c:53
eventhandler.h
This handles card insertion/removal events, updates ATR, protocol, and status information.
winscard_svc.h
This demarshalls functions over the message queue and keeps track of clients and their handles.
cancel_struct
contained in SCARD_CANCEL Messages.
Definition: winscard_msg.h:207
wait_reader_state_change::timeOut
uint32_t timeOut
timeout in ms
Definition: winscard_msg.h:109
SCARD_CANCEL
@ SCARD_CANCEL
used by SCardCancel()
Definition: winscard_msg.h:88
SCARDHANDLE
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition: pcsclite.h:55
contextsList
static list_t contextsList
Context tracking list.
Definition: winscard_svc.c:78
MAX_BUFFER_SIZE_EXTENDED
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition: pcsclite.h:298
SCARD_E_CANCELLED
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition: pcsclite.h:111
list_t
list object
Definition: simclist.h:181
control_struct
contained in SCARD_CONTROL Messages.
Definition: winscard_msg.h:246
connect_struct
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:141
CMD_WAIT_READER_STATE_CHANGE
@ CMD_WAIT_READER_STATE_CHANGE
wait for a reader state change
Definition: winscard_msg.h:94
status_struct
contained in SCARD_STATUS Messages.
Definition: winscard_msg.h:218
getset_struct
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:261
SCARD_E_INSUFFICIENT_BUFFER
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition: pcsclite.h:123
ReaderContext
Definition: readerfactory.h:106
SCARD_GET_ATTRIB
@ SCARD_GET_ATTRIB
used by SCardGetAttrib()
Definition: winscard_msg.h:90
SCARD_END_TRANSACTION
@ SCARD_END_TRANSACTION
used by SCardEndTransaction()
Definition: winscard_msg.h:83
SCardBeginTransaction
PCSC_API LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a serie of commands in a transaction.
Definition: winscard.c:1048
_psContext::cardsList_lock
pthread_mutex_t cardsList_lock
lock for the above list
Definition: winscard_svc.c:85
SCARD_W_RESET_CARD
#define SCARD_W_RESET_CARD
The smart card has been reset, so any shared state information is invalid.
Definition: pcsclite.h:216
SCARD_RECONNECT
@ SCARD_RECONNECT
used by SCardReconnect()
Definition: winscard_msg.h:80
begin_struct
contained in SCARD_BEGIN_TRANSACTION Messages.
Definition: winscard_msg.h:184
version_struct
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:54
CMD_GET_READERS_STATE
@ CMD_GET_READERS_STATE
get the readers state
Definition: winscard_msg.h:93
end_struct
contained in SCARD_END_TRANSACTION Messages.
Definition: winscard_msg.h:195
winscard_msg.h
This defines some structures and #defines to be used over the transport layer.
SCARD_ESTABLISH_CONTEXT
@ SCARD_ESTABLISH_CONTEXT
used by SCardEstablishContext()
Definition: winscard_msg.h:76
SCARD_SET_ATTRIB
@ SCARD_SET_ATTRIB
used by SCardSetAttrib()
Definition: winscard_msg.h:91
pcscd.h
This keeps a list of defines for pcsc-lite.
SCARD_E_NO_MEMORY
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:119
PCSCLITE_MAX_READERS_CONTEXTS
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:284
MessageReceive
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
_psContext::dwClientID
uint32_t dwClientID
Connection ID used to reference the Client.
Definition: winscard_svc.c:86
SCARD_IO_REQUEST::dwProtocol
unsigned long dwProtocol
Protocol identifier.
Definition: pcsclite.h:81
winscard.h
This handles smart card reader communications.
MessageSend
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
AutoExit
char AutoExit
Represents an Application Context on the Server side.
Definition: pcscdaemon.c:80
SCardReconnect
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
SCARDCONTEXT
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition: pcsclite.h:52
SCARD_LEAVE_CARD
#define SCARD_LEAVE_CARD
Do nothing on close.
Definition: pcsclite.h:252
SCARD_BEGIN_TRANSACTION
@ SCARD_BEGIN_TRANSACTION
used by SCardBeginTransaction()
Definition: winscard_msg.h:82
_psContext
Definition: winscard_svc.c:81
PROTOCOL_VERSION_MINOR
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
Definition: winscard_msg.h:49
reconnect_struct
contained in SCARD_RECONNECT Messages.
Definition: winscard_msg.h:157
contextsList_lock
pthread_mutex_t contextsList_lock
lock for the above list
Definition: winscard_svc.c:79
SCARD_IO_REQUEST
Protocol Control Information (PCI)
Definition: pcsclite.h:79
SCARD_E_INVALID_VALUE
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition: pcsclite.h:141
SCARD_RELEASE_CONTEXT
@ SCARD_RELEASE_CONTEXT
used by SCardReleaseContext()
Definition: winscard_msg.h:77
CommandsText
static const char * CommandsText[]
Handles messages received from Clients.
Definition: winscard_svc.c:283
SCardStatus
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:1242
SCARD_TRANSMIT
@ SCARD_TRANSMIT
used by SCardTransmit()
Definition: winscard_msg.h:84
SCARD_DISCONNECT
@ SCARD_DISCONNECT
used by SCardDisconnect()
Definition: winscard_msg.h:81
SCardControl
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:1305
ReaderContext::hLockId
volatile SCARDHANDLE hLockId
Lock Id.
Definition: readerfactory.h:126
SCARD_STATUS
@ SCARD_STATUS
used by SCardStatus()
Definition: winscard_msg.h:86
SCARD_E_SERVICE_STOPPED
#define SCARD_E_SERVICE_STOPPED
The Smart card resource manager has shut down.
Definition: pcsclite.h:167
SCARD_F_INTERNAL_ERROR
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:109
SCARD_E_INVALID_HANDLE
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition: pcsclite.h:113
transmit_struct
contained in SCARD_TRANSMIT Messages.
Definition: winscard_msg.h:229
_psContext::pthThread
pthread_t pthThread
Event polling thread's ID.
Definition: winscard_svc.c:87
SCardEndTransaction
PCSC_API LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
Definition: winscard.c:1090
CMD_VERSION
@ CMD_VERSION
get the client/server protocol version
Definition: winscard_msg.h:92
EHTryToUnregisterClientForEvent
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
readerStates
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
Definition: winscard_clnt.c:364
SCardConnect
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
release_struct
Information contained in SCARD_RELEASE_CONTEXT Messages.
Definition: winscard_msg.h:130
SCardSetAttrib
PCSC_API LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
Definition: winscard.c:1439
SCardTransmit
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:1489