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  coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard,
511  threadContext);
512 
513  WRITE_BODY(coStr);
514  }
515  break;
516 
517  case SCARD_RECONNECT:
518  {
519  struct reconnect_struct rcStr;
520  DWORD dwActiveProtocol;
521 
522  READ_BODY(rcStr);
523 
524  if (MSGCheckHandleAssociation(rcStr.hCard, threadContext))
525  goto exit;
526 
527  rcStr.rv = SCardReconnect(rcStr.hCard, rcStr.dwShareMode,
528  rcStr.dwPreferredProtocols, rcStr.dwInitialization,
529  &dwActiveProtocol);
530  rcStr.dwActiveProtocol = dwActiveProtocol;
531 
532  WRITE_BODY(rcStr);
533  }
534  break;
535 
536  case SCARD_DISCONNECT:
537  {
538  struct disconnect_struct diStr;
539 
540  READ_BODY(diStr);
541 
542  if (MSGCheckHandleAssociation(diStr.hCard, threadContext))
543  goto exit;
544 
545  diStr.rv = SCardDisconnect(diStr.hCard, diStr.dwDisposition);
546 
547  if (SCARD_S_SUCCESS == diStr.rv)
548  diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext);
549 
550  WRITE_BODY(diStr);
551  }
552  break;
553 
555  {
556  struct begin_struct beStr;
557 
558  READ_BODY(beStr);
559 
560  if (MSGCheckHandleAssociation(beStr.hCard, threadContext))
561  goto exit;
562 
563  beStr.rv = SCardBeginTransaction(beStr.hCard);
564 
565  WRITE_BODY(beStr);
566  }
567  break;
568 
570  {
571  struct end_struct enStr;
572 
573  READ_BODY(enStr);
574 
575  if (MSGCheckHandleAssociation(enStr.hCard, threadContext))
576  goto exit;
577 
578  enStr.rv = SCardEndTransaction(enStr.hCard,
579  enStr.dwDisposition);
580 
581  WRITE_BODY(enStr);
582  }
583  break;
584 
585  case SCARD_CANCEL:
586  {
587  struct cancel_struct caStr;
588  SCONTEXT * psTargetContext = NULL;
589 
590  READ_BODY(caStr);
591 
592  /* find the client */
593  (void)pthread_mutex_lock(&contextsList_lock);
594  psTargetContext = (SCONTEXT *) list_seek(&contextsList,
595  &caStr.hContext);
596  (void)pthread_mutex_unlock(&contextsList_lock);
597 
598  /* default value = error */
599  caStr.rv = SCARD_E_INVALID_HANDLE;
600 
601  if (psTargetContext != NULL)
602  {
603  uint32_t fd = psTargetContext->dwClientID;
604  LONG rv;
605 
606  /* the client should not receive the event
607  * notification now the waiting has been cancelled */
609 
610  /* signal the client only if it was still waiting */
611  if (SCARD_S_SUCCESS == rv)
612  caStr.rv = MSGSignalClient(fd, SCARD_E_CANCELLED);
613  }
614 
615  WRITE_BODY(caStr);
616  }
617  break;
618 
619  case SCARD_STATUS:
620  {
621  struct status_struct stStr;
622 
623  READ_BODY(stStr);
624 
625  if (MSGCheckHandleAssociation(stStr.hCard, threadContext))
626  goto exit;
627 
628  /* only hCard and return value are used by the client */
629  stStr.rv = SCardStatus(stStr.hCard, NULL, NULL, NULL,
630  NULL, 0, NULL);
631 
632  WRITE_BODY(stStr);
633  }
634  break;
635 
636  case SCARD_TRANSMIT:
637  {
638  struct transmit_struct trStr;
639  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
640  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
641  SCARD_IO_REQUEST ioSendPci;
642  SCARD_IO_REQUEST ioRecvPci;
643  DWORD cbRecvLength;
644 
645  READ_BODY(trStr);
646 
647  if (MSGCheckHandleAssociation(trStr.hCard, threadContext))
648  goto exit;
649 
650  /* avoids buffer overflow */
651  if ((trStr.pcbRecvLength > sizeof(pbRecvBuffer))
652  || (trStr.cbSendLength > sizeof(pbSendBuffer)))
653  goto buffer_overflow;
654 
655  /* read sent buffer */
656  ret = MessageReceive(pbSendBuffer, trStr.cbSendLength, filedes);
657  if (ret != SCARD_S_SUCCESS)
658  {
659  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
660  goto exit;
661  }
662 
663  ioSendPci.dwProtocol = trStr.ioSendPciProtocol;
664  ioSendPci.cbPciLength = trStr.ioSendPciLength;
665  ioRecvPci.dwProtocol = trStr.ioRecvPciProtocol;
666  ioRecvPci.cbPciLength = trStr.ioRecvPciLength;
667  cbRecvLength = sizeof pbRecvBuffer;
668 
669  trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci,
670  pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
671  pbRecvBuffer, &cbRecvLength);
672 
673  if (cbRecvLength > trStr.pcbRecvLength)
674  /* The client buffer is not large enough.
675  * The pbRecvBuffer buffer will NOT be sent a few
676  * lines bellow. So no buffer overflow is expected. */
677  trStr.rv = SCARD_E_INSUFFICIENT_BUFFER;
678 
679  trStr.ioSendPciProtocol = ioSendPci.dwProtocol;
680  trStr.ioSendPciLength = ioSendPci.cbPciLength;
681  trStr.ioRecvPciProtocol = ioRecvPci.dwProtocol;
682  trStr.ioRecvPciLength = ioRecvPci.cbPciLength;
683  trStr.pcbRecvLength = cbRecvLength;
684 
685  WRITE_BODY(trStr);
686 
687  /* write received buffer */
688  if (SCARD_S_SUCCESS == trStr.rv)
689  ret = MessageSend(pbRecvBuffer, cbRecvLength, filedes);
690  }
691  break;
692 
693  case SCARD_CONTROL:
694  {
695  struct control_struct ctStr;
696  unsigned char pbSendBuffer[MAX_BUFFER_SIZE_EXTENDED];
697  unsigned char pbRecvBuffer[MAX_BUFFER_SIZE_EXTENDED];
698  DWORD dwBytesReturned;
699 
700  READ_BODY(ctStr);
701 
702  if (MSGCheckHandleAssociation(ctStr.hCard, threadContext))
703  goto exit;
704 
705  /* avoids buffer overflow */
706  if ((ctStr.cbRecvLength > sizeof(pbRecvBuffer))
707  || (ctStr.cbSendLength > sizeof(pbSendBuffer)))
708  {
709  goto buffer_overflow;
710  }
711 
712  /* read sent buffer */
713  ret = MessageReceive(pbSendBuffer, ctStr.cbSendLength, filedes);
714  if (ret != SCARD_S_SUCCESS)
715  {
716  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
717  goto exit;
718  }
719 
720  dwBytesReturned = ctStr.dwBytesReturned;
721 
722  ctStr.rv = SCardControl(ctStr.hCard, ctStr.dwControlCode,
723  pbSendBuffer, ctStr.cbSendLength,
724  pbRecvBuffer, sizeof pbRecvBuffer,
725  &dwBytesReturned);
726 
727  if (dwBytesReturned > ctStr.cbRecvLength)
728  /* The client buffer is not large enough.
729  * The pbRecvBuffer buffer will NOT be sent a few
730  * lines bellow. So no buffer overflow is expected. */
731  ctStr.rv = SCARD_E_INSUFFICIENT_BUFFER;
732 
733  ctStr.dwBytesReturned = dwBytesReturned;
734 
735  WRITE_BODY(ctStr);
736 
737  /* write received buffer */
738  if (SCARD_S_SUCCESS == ctStr.rv)
739  ret = MessageSend(pbRecvBuffer, dwBytesReturned, filedes);
740  }
741  break;
742 
743  case SCARD_GET_ATTRIB:
744  {
745  struct getset_struct gsStr;
746  DWORD cbAttrLen;
747 
748  READ_BODY(gsStr);
749 
750  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
751  goto exit;
752 
753  /* avoids buffer overflow */
754  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
755  goto buffer_overflow;
756 
757  cbAttrLen = gsStr.cbAttrLen;
758 
759  gsStr.rv = SCardGetAttrib(gsStr.hCard, gsStr.dwAttrId,
760  gsStr.pbAttr, &cbAttrLen);
761 
762  gsStr.cbAttrLen = cbAttrLen;
763 
764  WRITE_BODY(gsStr);
765  }
766  break;
767 
768  case SCARD_SET_ATTRIB:
769  {
770  struct getset_struct gsStr;
771 
772  READ_BODY(gsStr);
773 
774  if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
775  goto exit;
776 
777  /* avoids buffer overflow */
778  if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
779  goto buffer_overflow;
780 
781  gsStr.rv = SCardSetAttrib(gsStr.hCard, gsStr.dwAttrId,
782  gsStr.pbAttr, gsStr.cbAttrLen);
783 
784  WRITE_BODY(gsStr);
785  }
786  break;
787 
788  default:
789  Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", header.command);
790  goto exit;
791  }
792 
793  /* MessageSend() failed */
794  if (ret != SCARD_S_SUCCESS)
795  {
796  /* Clean up the dead client */
797  Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes);
798  goto exit;
799  }
800  }
801 
802 buffer_overflow:
803  Log2(PCSC_LOG_DEBUG, "Buffer overflow detected: %d", filedes);
804  goto exit;
805 wrong_length:
806  Log2(PCSC_LOG_DEBUG, "Wrong length: %d", filedes);
807 exit:
808  (void)close(filedes);
809  MSGCleanupClient(threadContext);
810  (void)pthread_exit((LPVOID) NULL);
811 }
812 
813 LONG MSGSignalClient(uint32_t filedes, LONG rv)
814 {
815  uint32_t ret;
816  struct wait_reader_state_change waStr =
817  {
818  .timeOut = 0,
819  .rv = 0
820  };
821 
822  Log2(PCSC_LOG_DEBUG, "Signal client: %d", filedes);
823 
824  waStr.rv = rv;
825  WRITE_BODY_WITH_COMMAND("SIGNAL", waStr);
826 
827  return ret;
828 } /* MSGSignalClient */
829 
830 LONG MSGSendReaderStates(uint32_t filedes)
831 {
832  uint32_t ret;
833 
834  Log2(PCSC_LOG_DEBUG, "Send reader states: %d", filedes);
835 
836  /* dump the readers state */
837  ret = MessageSend(readerStates, sizeof(readerStates), filedes);
838 
839  return ret;
840 }
841 
842 static LONG MSGAddContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
843 {
844  threadContext->hContext = hContext;
845  return SCARD_S_SUCCESS;
846 }
847 
848 static LONG MSGRemoveContext(SCARDCONTEXT hContext, SCONTEXT * threadContext)
849 {
850  LONG rv;
851  int lrv;
852 
853  if (0 == threadContext->hContext)
854  {
855  Log1(PCSC_LOG_ERROR, "Invalidated handle");
856  return SCARD_E_INVALID_HANDLE;
857  }
858 
859  if (threadContext->hContext != hContext)
860  return SCARD_E_INVALID_VALUE;
861 
862  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
863  while (list_size(&threadContext->cardsList) != 0)
864  {
865  READER_CONTEXT * rContext = NULL;
866  SCARDHANDLE hCard;
867  void *ptr;
868 
869  /*
870  * Disconnect each of these just in case
871  */
872  ptr = list_get_at(&threadContext->cardsList, 0);
873  if (NULL == ptr)
874  {
875  Log1(PCSC_LOG_CRITICAL, "list_get_at failed");
876  continue;
877  }
878  hCard = *(int32_t *)ptr;
879 
880  /*
881  * Unlock the sharing
882  */
883  rv = RFReaderInfoById(hCard, &rContext);
884  if (rv != SCARD_S_SUCCESS)
885  {
886  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
887  return rv;
888  }
889 
890  if (0 == rContext->hLockId)
891  {
892  /* no lock. Just leave the card */
893  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
894  }
895  else
896  {
897  if (hCard != rContext->hLockId)
898  {
899  /*
900  * if the card is locked by someone else we do not reset it
901  */
902 
903  /* decrement card use */
904  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
905  }
906  else
907  {
908  /* release the lock */
909  rContext->hLockId = 0;
910 
911  /*
912  * We will use SCardStatus to see if the card has been
913  * reset there is no need to reset each time
914  * Disconnect is called
915  */
916  rv = SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL);
917 
918  if (rv == SCARD_W_RESET_CARD || rv == SCARD_W_REMOVED_CARD)
919  (void)SCardDisconnect(hCard, SCARD_LEAVE_CARD);
920  else
921  (void)SCardDisconnect(hCard, SCARD_RESET_CARD);
922  }
923  }
924 
925  /* Remove entry from the list */
926  lrv = list_delete_at(&threadContext->cardsList, 0);
927  if (lrv < 0)
928  Log2(PCSC_LOG_CRITICAL,
929  "list_delete_at failed with return value: %d", lrv);
930 
931  UNREF_READER(rContext)
932  }
933  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
934 
935  /* We only mark the context as no longer in use.
936  * The memory is freed in MSGCleanupCLient() */
937  threadContext->hContext = 0;
938 
939  return SCARD_S_SUCCESS;
940 }
941 
942 static LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard,
943  SCONTEXT * threadContext)
944 {
945  LONG retval = SCARD_E_INVALID_VALUE;
946 
947  if (0 == threadContext->hContext)
948  {
949  Log1(PCSC_LOG_ERROR, "Invalidated handle");
950  return SCARD_E_INVALID_HANDLE;
951  }
952 
953  if (threadContext->hContext == hContext)
954  {
955  /*
956  * Find an empty spot to put the hCard value
957  */
958  int listLength;
959 
960  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
961 
962  listLength = list_size(&threadContext->cardsList);
963  if (listLength >= contextMaxCardHandles)
964  {
965  Log4(PCSC_LOG_DEBUG,
966  "Too many card handles for thread context @%p: %d (max is %d)"
967  "Restart pcscd with --max-card-handle-per-thread value",
968  threadContext, listLength, contextMaxCardHandles);
969  retval = SCARD_E_NO_MEMORY;
970  }
971  else
972  {
973  int lrv;
974 
975  lrv = list_append(&threadContext->cardsList, &hCard);
976  if (lrv < 0)
977  {
978  Log2(PCSC_LOG_CRITICAL,
979  "list_append failed with return value: %d", lrv);
980  retval = SCARD_E_NO_MEMORY;
981  }
982  else
983  retval = SCARD_S_SUCCESS;
984  }
985 
986  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
987  }
988 
989  return retval;
990 }
991 
992 /* Pre-condition: MSGCheckHandleAssociation must succeed. */
993 static LONG MSGRemoveHandle(SCARDHANDLE hCard, SCONTEXT * threadContext)
994 {
995  int lrv;
996 
997  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
998  lrv = list_delete(&threadContext->cardsList, &hCard);
999  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1000  if (lrv < 0)
1001  {
1002  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %d", lrv);
1003  return SCARD_E_INVALID_VALUE;
1004  }
1005 
1006  return SCARD_S_SUCCESS;
1007 }
1008 
1009 
1010 static LONG MSGCheckHandleAssociation(SCARDHANDLE hCard,
1011  SCONTEXT * threadContext)
1012 {
1013  int list_index = 0;
1014 
1015  if (0 == threadContext->hContext)
1016  {
1017  /* the handle is no more valid. After SCardReleaseContext() for
1018  * example */
1019  Log1(PCSC_LOG_CRITICAL, "Invalidated handle");
1020  return -1;
1021  }
1022 
1023  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
1024  list_index = list_locate(&threadContext->cardsList, &hCard);
1025  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1026  if (list_index >= 0)
1027  return 0;
1028 
1029  /* Must be a rogue client, debug log and sleep a couple of seconds */
1030  Log1(PCSC_LOG_ERROR, "Client failed to authenticate");
1031  (void)SYS_Sleep(2);
1032 
1033  return -1;
1034 }
1035 
1036 
1037 /* Should be called just prior to exiting the thread as it de-allocates
1038  * the thread memory strucutres
1039  */
1040 static void MSGCleanupClient(SCONTEXT * threadContext)
1041 {
1042  int lrv;
1043  int listSize;
1044 
1045  if (threadContext->hContext != 0)
1046  {
1047  (void)SCardReleaseContext(threadContext->hContext);
1048  (void)MSGRemoveContext(threadContext->hContext, threadContext);
1049  }
1050 
1051  (void)pthread_mutex_lock(&threadContext->cardsList_lock);
1052  list_destroy(&threadContext->cardsList);
1053  (void)pthread_mutex_unlock(&threadContext->cardsList_lock);
1054 
1055  Log3(PCSC_LOG_DEBUG,
1056  "Thread is stopping: dwClientID=%d, threadContext @%p",
1057  threadContext->dwClientID, threadContext);
1058 
1059  /* Clear the struct to ensure that we detect
1060  * access to de-allocated memory
1061  * Hopefully the compiler won't optimise it out */
1062  memset((void*) threadContext, 0, sizeof(SCONTEXT));
1063  Log2(PCSC_LOG_DEBUG, "Freeing SCONTEXT @%p", threadContext);
1064 
1065  (void)pthread_mutex_lock(&contextsList_lock);
1066  lrv = list_delete(&contextsList, threadContext);
1067  listSize = list_size(&contextsList);
1068  (void)pthread_mutex_unlock(&contextsList_lock);
1069  if (lrv < 0)
1070  Log2(PCSC_LOG_CRITICAL, "list_delete failed with error %x", lrv);
1071 
1072  free(threadContext);
1073 
1074  /* start a suicide alarm */
1075  if (AutoExit && (listSize < 1))
1076  {
1077  Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds",
1078  TIME_BEFORE_SUICIDE);
1079  alarm(TIME_BEFORE_SUICIDE);
1080  }
1081 
1082  return;
1083 }
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:119
wait_reader_state_change
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
Definition: winscard_msg.h:108
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:49
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:173
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:65
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:208
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:247
connect_struct
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:142
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:219
getset_struct
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:262
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:107
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:185
version_struct
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:55
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:196
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:82
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:158
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:80
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:230
_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:131
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