pcsc-lite  2.5.0
eventhandler.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3  *
4  * Copyright (C) 2000-2002
5  * David Corcoran <corcoran@musclecard.com>
6  * Copyright (C) 2002-2023
7  * Ludovic Rousseau <ludovic.rousseau@free.fr>
8  *
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12 
13 1. Redistributions of source code must retain the above copyright
14  notice, this list of conditions and the following disclaimer.
15 2. Redistributions in binary form must reproduce the above copyright
16  notice, this list of conditions and the following disclaimer in the
17  documentation and/or other materials provided with the distribution.
18 3. The name of the author may not be used to endorse or promote products
19  derived from this software without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
39 #include "config.h"
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <string.h>
45 #include <stdlib.h>
46 #include <pthread.h>
47 
48 #include "misc.h"
49 #include "pcscd.h"
50 #include "debuglog.h"
51 #include "readerfactory.h"
52 #include "eventhandler.h"
53 #include "dyn_generic.h"
54 #include "sys_generic.h"
55 #include "ifdwrapper.h"
56 #include "prothandler.h"
57 #include "utils.h"
58 #include "winscard_svc.h"
59 #include "simclist.h"
60 
62 pthread_mutex_t ClientsWaitingForEvent_lock;
64 static void * EHStatusHandlerThread(READER_CONTEXT *);
65 
66 LONG EHRegisterClientForEvent(int32_t filedes)
67 {
68  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
69 
70  (void)list_append(&ClientsWaitingForEvent, &filedes);
71 
72  (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
73 
74  return SCARD_S_SUCCESS;
75 } /* EHRegisterClientForEvent */
76 
81 LONG EHTryToUnregisterClientForEvent(int32_t filedes)
82 {
83  LONG rv = SCARD_S_SUCCESS;
84  int ret;
85 
86  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
87 
88  ret = list_delete(&ClientsWaitingForEvent, &filedes);
89 
90  (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
91 
92  if (ret < 0)
94 
95  return rv;
96 } /* EHTryToUnregisterClientForEvent */
97 
101 LONG EHUnregisterClientForEvent(int32_t filedes)
102 {
103  LONG rv = EHTryToUnregisterClientForEvent(filedes);
104 
105  if (rv != SCARD_S_SUCCESS)
106  Log2(PCSC_LOG_ERROR, "Can't remove client: %d", filedes);
107 
108  return rv;
109 } /* EHUnregisterClientForEvent */
110 
115 {
116  int32_t filedes;
117 
118  (void)pthread_mutex_lock(&ClientsWaitingForEvent_lock);
119 
120  (void)list_iterator_start(&ClientsWaitingForEvent);
121  while (list_iterator_hasnext(&ClientsWaitingForEvent))
122  {
123  filedes = *(int32_t *)list_iterator_next(&ClientsWaitingForEvent);
124  MSGSignalClient(filedes, SCARD_S_SUCCESS);
125  }
126  (void)list_iterator_stop(&ClientsWaitingForEvent);
127 
128  (void)list_clear(&ClientsWaitingForEvent);
129 
130  (void)pthread_mutex_unlock(&ClientsWaitingForEvent_lock);
131 } /* EHSignalEventToClients */
132 
133 LONG EHInitializeEventStructures(void)
134 {
135  (void)list_init(&ClientsWaitingForEvent);
136 
137  /* request to store copies, and provide the metric function */
138  (void)list_attributes_copy(&ClientsWaitingForEvent, list_meter_int32_t, 1);
139 
140  /* setting the comparator, so the list can sort, find the min, max etc */
141  (void)list_attributes_comparator(&ClientsWaitingForEvent, list_comparator_int32_t);
142 
143  (void)pthread_mutex_init(&ClientsWaitingForEvent_lock, NULL);
144 
145  return SCARD_S_SUCCESS;
146 }
147 
148 LONG EHDeinitializeEventStructures(void)
149 {
150  list_destroy(&ClientsWaitingForEvent);
151  pthread_mutex_destroy(&ClientsWaitingForEvent_lock);
152 
153  return SCARD_S_SUCCESS;
154 }
155 
156 void EHDestroyEventHandler(READER_CONTEXT * rContext)
157 {
158  int rv;
159  DWORD dwGetSize;
160  UCHAR ucGetData[1];
161 
162  if ('\0' == rContext->readerState.readerName[0])
163  {
164  Log1(PCSC_LOG_INFO, "Thread already stomped.");
165  return;
166  }
167 
168  /*
169  * Set the thread to 0 to exit thread
170  */
171  rContext->hLockId = 0xFFFF;
172 
173  Log1(PCSC_LOG_INFO, "Stomping thread.");
174 
175  /* kill the "polling" thread */
176  dwGetSize = sizeof(ucGetData);
178  &dwGetSize, ucGetData);
179 
180  if ((IFD_SUCCESS == rv) && (1 == dwGetSize) && ucGetData[0])
181  {
182  Log1(PCSC_LOG_INFO, "Killing polling thread");
183  (void)pthread_cancel(rContext->pthThread);
184  }
185  else
186  {
187  /* ask to stop the "polling" thread */
188  RESPONSECODE (*fct)(DWORD) = NULL;
189 
190  dwGetSize = sizeof(fct);
192  &dwGetSize, (PUCHAR)&fct);
193 
194  if ((IFD_SUCCESS == rv) && (dwGetSize == sizeof(fct)))
195  {
196  Log1(PCSC_LOG_INFO, "Request stopping of polling thread");
197  fct(rContext->slot);
198  }
199  else
200  Log1(PCSC_LOG_INFO, "Waiting polling thread");
201  }
202 
203  /* wait for the thread to finish */
204  rv = pthread_join(rContext->pthThread, NULL);
205  if (rv)
206  Log2(PCSC_LOG_ERROR, "pthread_join failed: %s", strerror(rv));
207 
208  /* Zero the thread */
209  rContext->pthThread = 0;
210 
211  Log1(PCSC_LOG_INFO, "Thread stomped.");
212 
213  return;
214 }
215 
216 LONG EHSpawnEventHandler(READER_CONTEXT * rContext)
217 {
218  LONG rv;
219  DWORD dwStatus = 0;
220 
221  rv = IFDStatusICC(rContext, &dwStatus);
222  if (rv != SCARD_S_SUCCESS)
223  {
224  Log2(PCSC_LOG_ERROR, "Initial Check Failed on %s",
225  rContext->readerState.readerName);
226  return SCARD_F_UNKNOWN_ERROR;
227  }
228 
229  rv = ThreadCreate(&rContext->pthThread, 0,
230  (PCSCLITE_THREAD_FUNCTION( ))EHStatusHandlerThread, (LPVOID) rContext);
231  if (rv)
232  {
233  Log2(PCSC_LOG_ERROR, "ThreadCreate failed: %s", strerror(rv));
234  return SCARD_E_NO_MEMORY;
235  }
236  else
237  return SCARD_S_SUCCESS;
238 }
239 
240 static void * EHStatusHandlerThread(READER_CONTEXT * rContext)
241 {
242  LONG rv;
243 #ifndef NO_LOG
244  const char *readerName;
245 #endif
246  DWORD dwStatus;
247  uint32_t readerState;
248  int32_t readerSharing;
249  DWORD dwCurrentState;
250 #ifndef DISABLE_AUTO_POWER_ON
251  DWORD dwAtrLen;
252 #endif
253 
254  /*
255  * Zero out everything
256  */
257  dwStatus = 0;
258 
259 #ifndef NO_LOG
260  readerName = rContext->readerState.readerName;
261 #endif
262 
263  rv = IFDStatusICC(rContext, &dwStatus);
264 
265  if ((SCARD_S_SUCCESS == rv) && (dwStatus & SCARD_PRESENT))
266  {
267 #ifdef DISABLE_AUTO_POWER_ON
268  rContext->readerState.cardAtrLength = 0;
270  readerState = SCARD_PRESENT;
271  Log1(PCSC_LOG_INFO, "Skip card power on");
272 #else
273  dwAtrLen = sizeof(rContext->readerState.cardAtr);
274  rv = IFDPowerICC(rContext, IFD_POWER_UP,
275  rContext->readerState.cardAtr, &dwAtrLen);
276  rContext->readerState.cardAtrLength = dwAtrLen;
277 
278  /* the protocol is unset after a power on */
280 
281  if (rv == IFD_SUCCESS)
282  {
283  readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
284  RFSetPowerState(rContext, POWER_STATE_POWERED);
285  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
286 
287  if (rContext->readerState.cardAtrLength > 0)
288  {
289  LogXxd(PCSC_LOG_INFO, "Card ATR: ",
290  rContext->readerState.cardAtr,
291  rContext->readerState.cardAtrLength);
292  }
293  else
294  Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
295  }
296  else
297  {
298  readerState = SCARD_PRESENT | SCARD_SWALLOWED;
299  RFSetPowerState(rContext, POWER_STATE_UNPOWERED);
300  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
301  Log2(PCSC_LOG_ERROR, "Error powering up card: %s", rv2text(rv));
302  }
303 #endif
304 
305  dwCurrentState = SCARD_PRESENT;
306  }
307  else
308  {
309  readerState = SCARD_ABSENT;
310  rContext->readerState.cardAtrLength = 0;
312 
313  dwCurrentState = SCARD_ABSENT;
314  }
315 
316  /*
317  * Set all the public attributes to this reader
318  */
319  rContext->readerState.readerState = readerState;
320  rContext->readerState.readerSharing = readerSharing = rContext->contexts;
321 
323 
324  while (1)
325  {
326  dwStatus = 0;
327 
328  rv = IFDStatusICC(rContext, &dwStatus);
329 
330  if (rv != SCARD_S_SUCCESS)
331  {
332  Log2(PCSC_LOG_ERROR, "Error communicating to: %s", readerName);
333 
334  /*
335  * Set error status on this reader while errors occur
336  */
338  rContext->readerState.cardAtrLength = 0;
340 
341  dwCurrentState = SCARD_UNKNOWN;
342 
344  }
345 
346  if (dwStatus & SCARD_ABSENT)
347  {
348  if (dwCurrentState == SCARD_PRESENT ||
349  dwCurrentState == SCARD_UNKNOWN)
350  {
351  /*
352  * Change the status structure
353  */
354  Log2(PCSC_LOG_INFO, "Card Removed From %s", readerName);
355  /*
356  * Notify the card has been removed
357  */
358  (void)RFSetReaderEventState(rContext, SCARD_REMOVED);
359 
360  rContext->readerState.cardAtrLength = 0;
363  dwCurrentState = SCARD_ABSENT;
364 
365  rContext->readerState.eventCounter++;
366  if (rContext->readerState.eventCounter > 0xFFFF)
367  rContext->readerState.eventCounter = 0;
368 
370  }
371 
372  }
373  else if (dwStatus & SCARD_PRESENT)
374  {
375  if (dwCurrentState == SCARD_ABSENT ||
376  dwCurrentState == SCARD_UNKNOWN)
377  {
378 #ifdef DISABLE_AUTO_POWER_ON
379  rContext->readerState.cardAtrLength = 0;
382  RFSetPowerState(rContext, POWER_STATE_UNPOWERED);
383  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
384  rv = IFD_SUCCESS;
385  Log1(PCSC_LOG_INFO, "Skip card power on");
386 #else
387  /*
388  * Power and reset the card
389  */
390  dwAtrLen = sizeof(rContext->readerState.cardAtr);
391  rv = IFDPowerICC(rContext, IFD_POWER_UP,
392  rContext->readerState.cardAtr, &dwAtrLen);
393  rContext->readerState.cardAtrLength = dwAtrLen;
394 
395  /* the protocol is unset after a power on */
397 
398  if (rv == IFD_SUCCESS)
399  {
400  rContext->readerState.readerState = SCARD_PRESENT | SCARD_POWERED | SCARD_NEGOTIABLE;
401  RFSetPowerState(rContext, POWER_STATE_POWERED);
402  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
403  }
404  else
405  {
406  rContext->readerState.readerState = SCARD_PRESENT | SCARD_SWALLOWED;
407  RFSetPowerState(rContext, POWER_STATE_UNPOWERED);
408  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
409  rContext->readerState.cardAtrLength = 0;
410  }
411 #endif
412 
413  dwCurrentState = SCARD_PRESENT;
414 
415  rContext->readerState.eventCounter++;
416  if (rContext->readerState.eventCounter > 0xFFFF)
417  rContext->readerState.eventCounter = 0;
418 
419  Log2(PCSC_LOG_INFO, "Card inserted into %s", readerName);
420 
422 
423  if (rv == IFD_SUCCESS)
424  {
425  if (rContext->readerState.cardAtrLength > 0)
426  {
427  LogXxd(PCSC_LOG_INFO, "Card ATR: ",
428  rContext->readerState.cardAtr,
429  rContext->readerState.cardAtrLength);
430  }
431  else
432  Log1(PCSC_LOG_INFO, "Card ATR: (NULL)");
433  }
434  else
435  Log1(PCSC_LOG_ERROR,"Error powering up card.");
436  }
437  }
438 
439  /*
440  * Sharing may change w/o an event pass it on
441  */
442  if (readerSharing != rContext->contexts)
443  {
444  readerSharing = rContext->contexts;
445  rContext->readerState.readerSharing = readerSharing;
447  }
448 
449  if (rContext->pthCardEvent)
450  {
451  int ret;
452  int timeout;
453 
454 #ifndef DISABLE_ON_DEMAND_POWER_ON
455  if (POWER_STATE_POWERED == RFGetPowerState(rContext))
456  /* The card is powered but not yet used */
457  timeout = PCSCLITE_POWER_OFF_GRACE_PERIOD;
458  else
459  /* The card is already in use or not used at all */
460 #endif
461  timeout = PCSCLITE_STATUS_EVENT_TIMEOUT;
462 
463  ret = rContext->pthCardEvent(rContext->slot, timeout);
464  if (IFD_SUCCESS != ret)
465  (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
466  }
467  else
468  (void)SYS_USleep(PCSCLITE_STATUS_POLL_RATE);
469 
470 #ifndef DISABLE_ON_DEMAND_POWER_ON
471  /* the card is powered but not used */
472  (void)pthread_mutex_lock(&rContext->powerState_lock);
473  if (POWER_STATE_POWERED == rContext->powerState)
474  {
475  /* power down */
476  IFDPowerICC(rContext, IFD_POWER_DOWN, NULL, NULL);
477  rContext->powerState = POWER_STATE_UNPOWERED;
478  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_UNPOWERED");
479 
480  /* the protocol is unset after a power down */
482  }
483 
484  /* the card was in use */
485  if (POWER_STATE_GRACE_PERIOD == rContext->powerState)
486  {
487  /* the next state should be UNPOWERED unless the
488  * card is used again */
489  rContext->powerState = POWER_STATE_POWERED;
490  Log1(PCSC_LOG_DEBUG, "powerState: POWER_STATE_POWERED");
491  }
492  (void)pthread_mutex_unlock(&rContext->powerState_lock);
493 #endif
494 
495  if (rContext->hLockId == 0xFFFF)
496  {
497  /*
498  * Exit and notify the caller
499  */
500  Log1(PCSC_LOG_INFO, "Die");
501  rContext->hLockId = 0;
502  (void)pthread_exit(NULL);
503  }
504  }
505 }
506 
LONG EHUnregisterClientForEvent(int32_t filedes)
Unregister a client and log an error if the client is not found.
Definition: eventhandler.c:101
LONG IFDStatusICC(READER_CONTEXT *rContext, PDWORD pdwStatus)
Provide statistical information about the IFD and ICC including insertions, atr, powering status/etc...
Definition: ifdwrapper.c:337
This abstracts dynamic library loading functions.
list object
Definition: simclist.h:181
#define TAG_IFD_STOP_POLLING_THREAD
method used to stop the polling thread (instead of just pthread_kill())
Definition: ifdhandler.h:329
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
void EHSignalEventToClients(void)
Sends an asynchronous event to any waiting client.
Definition: eventhandler.c:114
pthread_t pthThread
Event polling thread.
Definition: readers.h:108
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition: readers.h:56
#define SCARD_UNKNOWN
Unknown state.
Definition: pcsclite.h:258
RESPONSECODE(* pthCardEvent)(DWORD, int)
Card Event sync.
Definition: readers.h:109
This handles protocol defaults, PTS, etc.
This handles abstract system level calls.
int slot
Current Reader Slot.
Definition: readers.h:123
This wraps the dynamic ifdhandler functions.
This demarshalls functions over the message queue and keeps track of clients and their handles...
#define SCARD_PRESENT
Card is present.
Definition: pcsclite.h:260
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:80
RESPONSECODE IFDGetCapabilities(READER_CONTEXT *rContext, DWORD dwTag, PDWORD pdwLength, PUCHAR pucValue)
Gets capabilities in the reader.
Definition: ifdwrapper.c:238
#define SCARD_NEGOTIABLE
Ready for PTS.
Definition: pcsclite.h:263
_Atomic SCARDHANDLE hLockId
Lock Id.
Definition: readers.h:124
#define SCARD_F_UNKNOWN_ERROR
An internal error has been detected, but the source is unknown.
Definition: pcsclite.h:147
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:119
#define IFD_POWER_DOWN
power down the card
Definition: ifdhandler.h:344
static list_t ClientsWaitingForEvent
list of client file descriptors
Definition: eventhandler.c:61
LONG EHTryToUnregisterClientForEvent(int32_t filedes)
Try to unregister a client If no client is found then do not log an error.
Definition: eventhandler.c:81
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition: readers.h:58
This handles card insertion/removal events, updates ATR, protocol, and status information.
RESPONSECODE IFDPowerICC(READER_CONTEXT *rContext, DWORD dwAction, PUCHAR pucAtr, PDWORD pdwAtrLen)
Power up/down or reset's an ICC located in the IFD.
Definition: ifdwrapper.c:268
READER_STATE readerState
reader state
Definition: readers.h:133
pthread_mutex_t ClientsWaitingForEvent_lock
lock for the above list
Definition: eventhandler.c:62
uint32_t readerState
SCARD_* bit field.
Definition: readers.h:53
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:261
int powerState
auto power off state
Definition: readers.h:129
#define SCARD_PROTOCOL_UNDEFINED
protocol not set
Definition: pcsclite.h:240
#define SCARD_POWERED
Card is powered.
Definition: pcsclite.h:262
_Atomic uint32_t cardAtrLength
ATR length.
Definition: readers.h:57
_Atomic int32_t contexts
Number of open contexts.
Definition: readers.h:126
#define SCARD_ABSENT
Card is absent.
Definition: pcsclite.h:259
This keeps track of a list of currently available reader structures.
char readerName[MAX_READERNAME]
reader name
Definition: readers.h:51
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:109
int RFGetPowerState(READER_CONTEXT *rContext)
Wait until all connected readers have a chance to power up a possibly inserted card.
pthread_mutex_t powerState_lock
powerState mutex
Definition: readers.h:130
_Atomic int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: readers.h:54
uint32_t eventCounter
number of card events
Definition: readers.h:52
#define IFD_POWER_UP
power up the card
Definition: ifdhandler.h:343
#define TAG_IFD_POLLING_THREAD_KILLABLE
the polling thread can be killed
Definition: ifdhandler.h:328
This handles debugging.
#define IFD_SUCCESS
no error
Definition: ifdhandler.h:351