pcsc-lite 1.9.9
winscard_clnt.c
Go to the documentation of this file.
1/*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3 *
4 * Copyright (C) 1999-2004
5 * David Corcoran <corcoran@musclecard.com>
6 * Copyright (C) 2003-2004
7 * Damien Sauveron <damien.sauveron@labri.fr>
8 * Copyright (C) 2005
9 * Martin Paljak <martin@paljak.pri.ee>
10 * Copyright (C) 2002-2011
11 * Ludovic Rousseau <ludovic.rousseau@free.fr>
12 * Copyright (C) 2009
13 * Jean-Luc Giraud <jlgiraud@googlemail.com>
14 *
15Redistribution and use in source and binary forms, with or without
16modification, are permitted provided that the following conditions
17are met:
18
191. Redistributions of source code must retain the above copyright
20 notice, this list of conditions and the following disclaimer.
212. Redistributions in binary form must reproduce the above copyright
22 notice, this list of conditions and the following disclaimer in the
23 documentation and/or other materials provided with the distribution.
243. The name of the author may not be used to endorse or promote products
25 derived from this software without specific prior written permission.
26
27THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38
105#include "config.h"
106#include <stdlib.h>
107#include <string.h>
108#include <sys/types.h>
109#include <fcntl.h>
110#include <unistd.h>
111#include <sys/un.h>
112#include <errno.h>
113#include <stddef.h>
114#include <sys/time.h>
115#include <pthread.h>
116#include <sys/wait.h>
117
118#include "misc.h"
119#include "pcscd.h"
120#include "winscard.h"
121#include "debuglog.h"
122
123#include "readerfactory.h"
124#include "eventhandler.h"
125#include "sys_generic.h"
126#include "winscard_msg.h"
127#include "utils.h"
128
129/* Display, on stderr, a trace of the WinSCard calls with arguments and
130 * results */
131//#define DO_TRACE
132
133/* Profile the execution time of WinSCard calls */
134//#define DO_PROFILE
135
136
137#ifndef TRUE
138#define TRUE 1
139#define FALSE 0
140#endif
141
142static char sharing_shall_block = TRUE;
143
144#define COLOR_RED "\33[01;31m"
145#define COLOR_GREEN "\33[32m"
146#define COLOR_BLUE "\33[34m"
147#define COLOR_MAGENTA "\33[35m"
148#define COLOR_NORMAL "\33[0m"
149
150#ifdef DO_TRACE
151
152#include <stdio.h>
153#include <stdarg.h>
154
155static void trace(const char *func, const char direction, const char *fmt, ...)
156{
157 va_list args;
158
159 fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
160 direction, pthread_self(), func);
161
162 fprintf(stderr, COLOR_MAGENTA);
163 va_start(args, fmt);
164 vfprintf(stderr, fmt, args);
165 va_end(args);
166
167 fprintf(stderr, COLOR_NORMAL "\n");
168}
169
170#define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
171#define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
172#else
173#define API_TRACE_IN(...)
174#define API_TRACE_OUT(...)
175#endif
176
177#ifdef DO_PROFILE
178
179#define PROFILE_FILE "/tmp/pcsc_profile"
180#include <stdio.h>
181#include <sys/time.h>
182
183/* we can profile a maximum of 5 simultaneous calls */
184#define MAX_THREADS 5
185pthread_t threads[MAX_THREADS];
186struct timeval profile_time_start[MAX_THREADS];
187FILE *profile_fd;
188char profile_tty;
189
190#define PROFILE_START profile_start();
191#define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
192
193static void profile_start(void)
194{
195 static char initialized = FALSE;
196 pthread_t t;
197 int i;
198
199 if (!initialized)
200 {
201 char filename[80];
202
203 initialized = TRUE;
204 sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
205 profile_fd = fopen(filename, "a+");
206 if (NULL == profile_fd)
207 {
208 fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
209 PROFILE_FILE, strerror(errno));
210 exit(-1);
211 }
212 fprintf(profile_fd, "\nStart a new profile\n");
213
214 if (isatty(fileno(stderr)))
215 profile_tty = TRUE;
216 else
217 profile_tty = FALSE;
218 }
219
220 t = pthread_self();
221 for (i=0; i<MAX_THREADS; i++)
222 if (pthread_equal(0, threads[i]))
223 {
224 threads[i] = t;
225 break;
226 }
227
228 gettimeofday(&profile_time_start[i], NULL);
229} /* profile_start */
230
231static void profile_end(const char *f, LONG rv)
232{
233 struct timeval profile_time_end;
234 long d;
235 pthread_t t;
236 int i;
237
238 gettimeofday(&profile_time_end, NULL);
239
240 t = pthread_self();
241 for (i=0; i<MAX_THREADS; i++)
242 if (pthread_equal(t, threads[i]))
243 break;
244
245 if (i>=MAX_THREADS)
246 {
247 fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
248 return;
249 }
250
251 d = time_sub(&profile_time_end, &profile_time_start[i]);
252
253 /* free this entry */
254 threads[i] = 0;
255
256 if (profile_tty)
257 {
258 if (rv != SCARD_S_SUCCESS)
259 fprintf(stderr,
260 COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
261 COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n",
262 f, d, rv, pcsc_stringify_error(rv));
263 else
264 fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld"
265 COLOR_NORMAL "\n", f, d);
266 }
267 fprintf(profile_fd, "%s %ld\n", f, d);
268 fflush(profile_fd);
269} /* profile_end */
270
271#else
272#define PROFILE_START
273#define PROFILE_END(rv)
274#endif
275
281{
282 SCARDHANDLE hCard;
283 LPSTR readerName;
284};
285
286typedef struct _psChannelMap CHANNEL_MAP;
287
288static int CHANNEL_MAP_seeker(const void *el, const void *key)
289{
290 const CHANNEL_MAP * channelMap = el;
291
292 if ((el == NULL) || (key == NULL))
293 {
294 Log3(PCSC_LOG_CRITICAL,
295 "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
296 el, key);
297 return 0;
298 }
299
300 if (channelMap->hCard == *(SCARDHANDLE *)key)
301 return 1;
302
303 return 0;
304}
305
312{
315 pthread_mutex_t mMutex;
316 list_t channelMapList;
318};
325
326static list_t contextMapList;
327
328static int SCONTEXTMAP_seeker(const void *el, const void *key)
329{
330 const SCONTEXTMAP * contextMap = el;
331
332 if ((el == NULL) || (key == NULL))
333 {
334 Log3(PCSC_LOG_CRITICAL,
335 "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
336 el, key);
337 return 0;
338 }
339
340 if (contextMap->hContext == *(SCARDCONTEXT *) key)
341 return 1;
342
343 return 0;
344}
345
349static short isExecuted = 0;
350
351
356static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
357
362
369
370
371static LONG SCardAddContext(SCARDCONTEXT, DWORD);
375static void SCardCleanContext(SCONTEXTMAP *);
376
377static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
378static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
379 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
380static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
381 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
382static void SCardRemoveHandle(SCARDHANDLE);
383
384static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
385 LPBYTE pbAttr, LPDWORD pcbAttrLen);
386
387static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
388static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap);
389static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap);
390
391/*
392 * Thread safety functions
393 */
400inline static void SCardLockThread(void)
401{
402 pthread_mutex_lock(&clientMutex);
403}
404
410inline static void SCardUnlockThread(void)
411{
412 pthread_mutex_unlock(&clientMutex);
413}
414
425{
426 SCONTEXTMAP * currentContextMap;
427
429 currentContextMap = SCardGetContextTH(hContext);
431
432 return currentContextMap != NULL;
433}
434
435static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
436 /*@out@*/ LPSCARDCONTEXT);
437
473LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
474 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
475{
476 LONG rv;
477
478 API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
479 PROFILE_START
480
481 /* Check if the server is running */
483 if (rv != SCARD_S_SUCCESS)
484 goto end;
485
487 rv = SCardEstablishContextTH(dwScope, pvReserved1,
488 pvReserved2, phContext);
490
491end:
492 PROFILE_END(rv)
493 API_TRACE_OUT("%ld", *phContext)
494
495 return rv;
496}
497
498#ifdef DESTRUCTOR
499DESTRUCTOR static void destructor(void)
500{
501 list_destroy(&contextMapList);
502}
503#endif
504
532static LONG SCardEstablishContextTH(DWORD dwScope,
533 /*@unused@*/ LPCVOID pvReserved1,
534 /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
535{
536 LONG rv;
537 struct establish_struct scEstablishStruct;
538 uint32_t dwClientID = 0;
539
540 (void)pvReserved1;
541 (void)pvReserved2;
542 if (phContext == NULL)
544 else
545 *phContext = 0;
546
547 /*
548 * Do this only once:
549 * - Initialize context list.
550 */
551 if (isExecuted == 0)
552 {
553 int lrv;
554
555 /* NOTE: The list will be freed only if DESTRUCTOR is defined.
556 * Applications which load and unload the library may leak
557 * the list's internal structures. */
558 lrv = list_init(&contextMapList);
559 if (lrv < 0)
560 {
561 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
562 lrv);
563 return SCARD_E_NO_MEMORY;
564 }
565
566 lrv = list_attributes_seeker(&contextMapList,
567 SCONTEXTMAP_seeker);
568 if (lrv <0)
569 {
570 Log2(PCSC_LOG_CRITICAL,
571 "list_attributes_seeker failed with return value: %d", lrv);
572 list_destroy(&contextMapList);
573 return SCARD_E_NO_MEMORY;
574 }
575
576 if (getenv("PCSCLITE_NO_BLOCKING"))
577 {
578 Log1(PCSC_LOG_INFO, "Disable shared blocking");
579 sharing_shall_block = FALSE;
580 }
581
582 isExecuted = 1;
583 }
584
585
586 /* Establishes a connection to the server */
587 if (ClientSetupSession(&dwClientID) != 0)
588 {
589 return SCARD_E_NO_SERVICE;
590 }
591
592 { /* exchange client/server protocol versions */
593 struct version_struct veStr;
594
597 veStr.rv = SCARD_S_SUCCESS;
598
599 rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
600 &veStr);
601 if (rv != SCARD_S_SUCCESS)
602 goto cleanup;
603
604 /* Read a message from the server */
605 rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
606 if (rv != SCARD_S_SUCCESS)
607 {
608 Log1(PCSC_LOG_CRITICAL,
609 "Your pcscd is too old and does not support CMD_VERSION");
610 goto cleanup;
611 }
612
613 Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
614 veStr.major, veStr.minor);
615
616 if (veStr.rv != SCARD_S_SUCCESS)
617 {
618 rv = veStr.rv;
619 goto cleanup;
620 }
621 }
622
623again:
624 /*
625 * Try to establish an Application Context with the server
626 */
627 scEstablishStruct.dwScope = dwScope;
628 scEstablishStruct.hContext = 0;
629 scEstablishStruct.rv = SCARD_S_SUCCESS;
630
632 sizeof(scEstablishStruct), (void *) &scEstablishStruct);
633
634 if (rv != SCARD_S_SUCCESS)
635 goto cleanup;
636
637 /*
638 * Read the response from the server
639 */
640 rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
641 dwClientID);
642
643 if (rv != SCARD_S_SUCCESS)
644 goto cleanup;
645
646 if (scEstablishStruct.rv != SCARD_S_SUCCESS)
647 {
648 rv = scEstablishStruct.rv;
649 goto cleanup;
650 }
651
652 /* check we do not reuse an existing hContext */
653 if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
654 /* we do not need to release the allocated context since
655 * SCardReleaseContext() does nothing on the server side */
656 goto again;
657
658 *phContext = scEstablishStruct.hContext;
659
660 /*
661 * Allocate the new hContext - if allocator full return an error
662 */
663 rv = SCardAddContext(*phContext, dwClientID);
664
665 return rv;
666
667cleanup:
668 ClientCloseSession(dwClientID);
669
670 return rv;
671}
672
694LONG SCardReleaseContext(SCARDCONTEXT hContext)
695{
696 LONG rv;
697 struct release_struct scReleaseStruct;
698 SCONTEXTMAP * currentContextMap;
699
700 API_TRACE_IN("%ld", hContext)
701 PROFILE_START
702
703 /*
704 * Make sure this context has been opened
705 * and get currentContextMap
706 */
707 currentContextMap = SCardGetAndLockContext(hContext);
708 if (NULL == currentContextMap)
709 {
711 goto error;
712 }
713
714 scReleaseStruct.hContext = hContext;
715 scReleaseStruct.rv = SCARD_S_SUCCESS;
716
718 currentContextMap->dwClientID,
719 sizeof(scReleaseStruct), (void *) &scReleaseStruct);
720
721 if (rv != SCARD_S_SUCCESS)
722 goto end;
723
724 /*
725 * Read a message from the server
726 */
727 rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
728 currentContextMap->dwClientID);
729
730 if (rv != SCARD_S_SUCCESS)
731 goto end;
732
733 rv = scReleaseStruct.rv;
734end:
735 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
736
737 /*
738 * Remove the local context from the stack
739 */
741 SCardRemoveContext(hContext);
743
744error:
745 PROFILE_END(rv)
746 API_TRACE_OUT("")
747
748 return rv;
749}
750
806LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
807 DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
808 LPDWORD pdwActiveProtocol)
809{
810 LONG rv;
811 struct connect_struct scConnectStruct;
812 SCONTEXTMAP * currentContextMap;
813
814 PROFILE_START
815 API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
816
817 /*
818 * Check for NULL parameters
819 */
820 if (phCard == NULL || pdwActiveProtocol == NULL)
822 else
823 *phCard = 0;
824
825 if (szReader == NULL)
827
828 /*
829 * Check for uninitialized strings
830 */
831 if (strlen(szReader) > MAX_READERNAME)
833
834 /*
835 * Make sure this context has been opened
836 */
837 currentContextMap = SCardGetAndLockContext(hContext);
838 if (NULL == currentContextMap)
840
841 memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
842 strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
843 scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
844
845 scConnectStruct.hContext = hContext;
846 scConnectStruct.dwShareMode = dwShareMode;
847 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
848 scConnectStruct.hCard = 0;
849 scConnectStruct.dwActiveProtocol = 0;
850 scConnectStruct.rv = SCARD_S_SUCCESS;
851
852 rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
853 sizeof(scConnectStruct), (void *) &scConnectStruct);
854
855 if (rv != SCARD_S_SUCCESS)
856 goto end;
857
858 /*
859 * Read a message from the server
860 */
861 rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
862 currentContextMap->dwClientID);
863
864 if (rv != SCARD_S_SUCCESS)
865 goto end;
866
867 *phCard = scConnectStruct.hCard;
868 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
869
870 if (scConnectStruct.rv == SCARD_S_SUCCESS)
871 {
872 /*
873 * Keep track of the handle locally
874 */
875 rv = SCardAddHandle(*phCard, currentContextMap, szReader);
876 }
877 else
878 rv = scConnectStruct.rv;
879
880end:
881 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
882
883 PROFILE_END(rv)
884 API_TRACE_OUT("%d", *pdwActiveProtocol)
885
886 return rv;
887}
888
961LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
962 DWORD dwPreferredProtocols, DWORD dwInitialization,
963 LPDWORD pdwActiveProtocol)
964{
965 LONG rv;
966 struct reconnect_struct scReconnectStruct;
967 SCONTEXTMAP * currentContextMap;
968 CHANNEL_MAP * pChannelMap;
969
970 PROFILE_START
971 API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
972
973 if (pdwActiveProtocol == NULL)
975
976 /* Retry loop for blocking behaviour */
977retry:
978
979 /*
980 * Make sure this handle has been opened
981 */
982 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
983 &pChannelMap);
984 if (rv == -1)
986
987 scReconnectStruct.hCard = hCard;
988 scReconnectStruct.dwShareMode = dwShareMode;
989 scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
990 scReconnectStruct.dwInitialization = dwInitialization;
991 scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
992 scReconnectStruct.rv = SCARD_S_SUCCESS;
993
994 rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
995 sizeof(scReconnectStruct), (void *) &scReconnectStruct);
996
997 if (rv != SCARD_S_SUCCESS)
998 goto end;
999
1000 /*
1001 * Read a message from the server
1002 */
1003 rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
1004 currentContextMap->dwClientID);
1005
1006 if (rv != SCARD_S_SUCCESS)
1007 goto end;
1008
1009 rv = scReconnectStruct.rv;
1010
1011 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1012 {
1013 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1015 goto retry;
1016 }
1017
1018 *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1019
1020end:
1021 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1022
1023 PROFILE_END(rv)
1024 API_TRACE_OUT("%ld", *pdwActiveProtocol)
1025
1026 return rv;
1027}
1028
1060LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1061{
1062 LONG rv;
1063 struct disconnect_struct scDisconnectStruct;
1064 SCONTEXTMAP * currentContextMap;
1065 CHANNEL_MAP * pChannelMap;
1066
1067 PROFILE_START
1068 API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1069
1070 /*
1071 * Make sure this handle has been opened
1072 */
1073 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1074 &pChannelMap);
1075 if (rv == -1)
1076 {
1078 goto error;
1079 }
1080
1081 scDisconnectStruct.hCard = hCard;
1082 scDisconnectStruct.dwDisposition = dwDisposition;
1083 scDisconnectStruct.rv = SCARD_S_SUCCESS;
1084
1085 rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1086 sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1087
1088 if (rv != SCARD_S_SUCCESS)
1089 goto end;
1090
1091 /*
1092 * Read a message from the server
1093 */
1094 rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1095 currentContextMap->dwClientID);
1096
1097 if (rv != SCARD_S_SUCCESS)
1098 goto end;
1099
1100 if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1101 SCardRemoveHandle(hCard);
1102 rv = scDisconnectStruct.rv;
1103
1104end:
1105 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1106
1107error:
1108 PROFILE_END(rv)
1109 API_TRACE_OUT("")
1110
1111 return rv;
1112}
1113
1149LONG SCardBeginTransaction(SCARDHANDLE hCard)
1150{
1151
1152 LONG rv;
1153 struct begin_struct scBeginStruct;
1154 SCONTEXTMAP * currentContextMap;
1155 CHANNEL_MAP * pChannelMap;
1156
1157 PROFILE_START
1158 API_TRACE_IN("%ld", hCard)
1159
1160 /*
1161 * Query the server every so often until the sharing violation ends
1162 * and then hold the lock for yourself.
1163 */
1164
1165 for(;;)
1166 {
1167 /*
1168 * Make sure this handle has been opened
1169 */
1170 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1171 &pChannelMap);
1172 if (rv == -1)
1174
1175 scBeginStruct.hCard = hCard;
1176 scBeginStruct.rv = SCARD_S_SUCCESS;
1177
1179 currentContextMap->dwClientID,
1180 sizeof(scBeginStruct), (void *) &scBeginStruct);
1181
1182 if (rv != SCARD_S_SUCCESS)
1183 break;
1184
1185 /*
1186 * Read a message from the server
1187 */
1188 rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1189 currentContextMap->dwClientID);
1190
1191 if (rv != SCARD_S_SUCCESS)
1192 break;
1193
1194 rv = scBeginStruct.rv;
1195
1196 if (SCARD_E_SHARING_VIOLATION != rv)
1197 break;
1198
1199 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1201 }
1202
1203 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1204
1205 PROFILE_END(rv)
1206 API_TRACE_OUT("")
1207
1208 return rv;
1209}
1210
1250LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1251{
1252 LONG rv;
1253 struct end_struct scEndStruct;
1254 SCONTEXTMAP * currentContextMap;
1255 CHANNEL_MAP * pChannelMap;
1256
1257 PROFILE_START
1258 API_TRACE_IN("%ld", hCard)
1259
1260 /*
1261 * Make sure this handle has been opened
1262 */
1263 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1264 &pChannelMap);
1265 if (rv == -1)
1267
1268 scEndStruct.hCard = hCard;
1269 scEndStruct.dwDisposition = dwDisposition;
1270 scEndStruct.rv = SCARD_S_SUCCESS;
1271
1273 currentContextMap->dwClientID,
1274 sizeof(scEndStruct), (void *) &scEndStruct);
1275
1276 if (rv != SCARD_S_SUCCESS)
1277 goto end;
1278
1279 /*
1280 * Read a message from the server
1281 */
1282 rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1283 currentContextMap->dwClientID);
1284
1285 if (rv != SCARD_S_SUCCESS)
1286 goto end;
1287
1288 rv = scEndStruct.rv;
1289
1290end:
1291 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1292
1293 PROFILE_END(rv)
1294 API_TRACE_OUT("")
1295
1296 return rv;
1297}
1298
1394LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1395 LPDWORD pcchReaderLen, LPDWORD pdwState,
1396 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1397{
1398 DWORD dwReaderLen, dwAtrLen;
1399 LONG rv;
1400 int i;
1401 struct status_struct scStatusStruct;
1402 SCONTEXTMAP * currentContextMap;
1403 CHANNEL_MAP * pChannelMap;
1404 char *r;
1405 char *bufReader = NULL;
1406 LPBYTE bufAtr = NULL;
1407 DWORD dummy = 0;
1408
1409 PROFILE_START
1410
1411 /* default output values */
1412 if (pdwState)
1413 *pdwState = 0;
1414
1415 if (pdwProtocol)
1416 *pdwProtocol = 0;
1417
1418 /* Check for NULL parameters */
1419 if (pcchReaderLen == NULL)
1420 pcchReaderLen = &dummy;
1421
1422 if (pcbAtrLen == NULL)
1423 pcbAtrLen = &dummy;
1424
1425 /* length passed from caller */
1426 dwReaderLen = *pcchReaderLen;
1427 dwAtrLen = *pcbAtrLen;
1428
1429 *pcchReaderLen = 0;
1430 *pcbAtrLen = 0;
1431
1432 /* Retry loop for blocking behaviour */
1433retry:
1434
1435 /*
1436 * Make sure this handle has been opened
1437 */
1438 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1439 &pChannelMap);
1440 if (rv == -1)
1442
1443 /* synchronize reader states with daemon */
1444 rv = getReaderStates(currentContextMap);
1445 if (rv != SCARD_S_SUCCESS)
1446 goto end;
1447
1448 r = pChannelMap->readerName;
1449 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1450 {
1451 /* by default r == NULL */
1452 if (r && strcmp(r, readerStates[i].readerName) == 0)
1453 break;
1454 }
1455
1457 {
1459 goto end;
1460 }
1461
1462 /* initialise the structure */
1463 memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1464 scStatusStruct.hCard = hCard;
1465
1466 rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1467 sizeof(scStatusStruct), (void *) &scStatusStruct);
1468
1469 if (rv != SCARD_S_SUCCESS)
1470 goto end;
1471
1472 /*
1473 * Read a message from the server
1474 */
1475 rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1476 currentContextMap->dwClientID);
1477
1478 if (rv != SCARD_S_SUCCESS)
1479 goto end;
1480
1481 rv = scStatusStruct.rv;
1482
1483 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1484 {
1485 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1487 goto retry;
1488 }
1489
1491 {
1492 /*
1493 * An event must have occurred
1494 */
1495 goto end;
1496 }
1497
1498 /*
1499 * Now continue with the client side SCardStatus
1500 */
1501
1502 *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1503 *pcbAtrLen = readerStates[i].cardAtrLength;
1504
1505 if (pdwState)
1506 *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1507
1508 if (pdwProtocol)
1509 *pdwProtocol = readerStates[i].cardProtocol;
1510
1511 if (SCARD_AUTOALLOCATE == dwReaderLen)
1512 {
1513 dwReaderLen = *pcchReaderLen;
1514 if (NULL == szReaderName)
1515 {
1517 goto end;
1518 }
1519 bufReader = malloc(dwReaderLen);
1520 if (NULL == bufReader)
1521 {
1522 rv = SCARD_E_NO_MEMORY;
1523 goto end;
1524 }
1525 *(char **)szReaderName = bufReader;
1526 }
1527 else
1528 bufReader = szReaderName;
1529
1530 /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1531 if (bufReader)
1532 {
1533 if (*pcchReaderLen > dwReaderLen)
1535
1536 strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1537 }
1538
1539 if (SCARD_AUTOALLOCATE == dwAtrLen)
1540 {
1541 dwAtrLen = *pcbAtrLen;
1542 if (NULL == pbAtr)
1543 {
1545 goto end;
1546 }
1547 bufAtr = malloc(dwAtrLen);
1548 if (NULL == bufAtr)
1549 {
1550 rv = SCARD_E_NO_MEMORY;
1551 goto end;
1552 }
1553 *(LPBYTE *)pbAtr = bufAtr;
1554 }
1555 else
1556 bufAtr = pbAtr;
1557
1558 if (bufAtr)
1559 {
1560 if (*pcbAtrLen > dwAtrLen)
1562
1563 memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1564 }
1565
1566end:
1567 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1568
1569 PROFILE_END(rv)
1570
1571 return rv;
1572}
1573
1681LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1682 SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1683{
1684 SCARD_READERSTATE *currReader;
1685 READER_STATE *rContext;
1686 long dwTime;
1687 DWORD dwBreakFlag = 0;
1688 unsigned int j;
1689 SCONTEXTMAP * currentContextMap;
1690 int currentReaderCount = 0;
1691 LONG rv = SCARD_S_SUCCESS;
1692
1693 PROFILE_START
1694 API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1695#ifdef DO_TRACE
1696 for (j=0; j<cReaders; j++)
1697 {
1698 API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1699 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1700 }
1701#endif
1702
1703 if ((rgReaderStates == NULL && cReaders > 0)
1704 || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1705 {
1707 goto error;
1708 }
1709
1710 /* Check the integrity of the reader states structures */
1711 for (j = 0; j < cReaders; j++)
1712 {
1713 if (rgReaderStates[j].szReader == NULL)
1714 return SCARD_E_INVALID_VALUE;
1715 }
1716
1717 /* return if all readers are SCARD_STATE_IGNORE */
1718 if (cReaders > 0)
1719 {
1720 int nbNonIgnoredReaders = cReaders;
1721
1722 for (j=0; j<cReaders; j++)
1723 if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1724 nbNonIgnoredReaders--;
1725
1726 if (0 == nbNonIgnoredReaders)
1727 {
1728 rv = SCARD_S_SUCCESS;
1729 goto error;
1730 }
1731 }
1732 else
1733 {
1734 /* reader list is empty */
1735 rv = SCARD_S_SUCCESS;
1736 goto error;
1737 }
1738
1739 /*
1740 * Make sure this context has been opened
1741 */
1742 currentContextMap = SCardGetAndLockContext(hContext);
1743 if (NULL == currentContextMap)
1744 {
1746 goto error;
1747 }
1748
1749 /* synchronize reader states with daemon */
1750 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1751 if (rv != SCARD_S_SUCCESS)
1752 goto end;
1753
1754 /* check all the readers are already known */
1755 for (j=0; j<cReaders; j++)
1756 {
1757 const char *readerName;
1758 int i;
1759
1760 readerName = rgReaderStates[j].szReader;
1761 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1762 {
1763 if (strcmp(readerName, readerStates[i].readerName) == 0)
1764 break;
1765 }
1766
1767 /* The requested reader name is not recognized */
1769 {
1770 /* PnP special reader? */
1771 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1772 {
1774 goto end;
1775 }
1776 }
1777 }
1778
1779 /* Clear the event state for all readers */
1780 for (j = 0; j < cReaders; j++)
1781 rgReaderStates[j].dwEventState = 0;
1782
1783 /* Now is where we start our event checking loop */
1784 Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1785
1786 /* Get the initial reader count on the system */
1787 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1788 if (readerStates[j].readerName[0] != '\0')
1789 currentReaderCount++;
1790
1791 /* catch possible sign extension problems from 32 to 64-bits integers */
1792 if ((DWORD)-1 == dwTimeout)
1793 dwTimeout = INFINITE;
1794 if (INFINITE == dwTimeout)
1795 dwTime = 60*1000; /* "infinite" timeout */
1796 else
1797 dwTime = dwTimeout;
1798
1799 j = 0;
1800 do
1801 {
1802 currReader = &rgReaderStates[j];
1803
1804 /* Ignore for IGNORED readers */
1805 if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1806 {
1807 const char *readerName;
1808 int i;
1809
1810 /* Looks for correct readernames */
1811 readerName = currReader->szReader;
1812 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1813 {
1814 if (strcmp(readerName, readerStates[i].readerName) == 0)
1815 break;
1816 }
1817
1818 /* The requested reader name is not recognized */
1820 {
1821 /* PnP special reader? */
1822 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1823 {
1824 int k, newReaderCount = 0;
1825
1826 for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1827 if (readerStates[k].readerName[0] != '\0')
1828 newReaderCount++;
1829
1830 if (newReaderCount != currentReaderCount)
1831 {
1832 Log1(PCSC_LOG_INFO, "Reader list changed");
1833 currentReaderCount = newReaderCount;
1834
1835 currReader->dwEventState |= SCARD_STATE_CHANGED;
1836 dwBreakFlag = 1;
1837 }
1838 }
1839 else
1840 {
1841 currReader->dwEventState =
1843 if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1844 {
1845 currReader->dwEventState |= SCARD_STATE_CHANGED;
1846 /*
1847 * Spec says use SCARD_STATE_IGNORE but a removed USB
1848 * reader with eventState fed into currentState will
1849 * be ignored forever
1850 */
1851 dwBreakFlag = 1;
1852 }
1853 }
1854 }
1855 else
1856 {
1857 uint32_t readerState;
1858
1859 /* The reader has come back after being away */
1860 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1861 {
1862 currReader->dwEventState |= SCARD_STATE_CHANGED;
1863 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1864 Log0(PCSC_LOG_DEBUG);
1865 dwBreakFlag = 1;
1866 }
1867
1868 /* Set the reader status structure */
1869 rContext = &readerStates[i];
1870
1871 /* Now we check all the Reader States */
1872 readerState = rContext->readerState;
1873
1874 /* only if current state has an non null event counter */
1875 if (currReader->dwCurrentState & 0xFFFF0000)
1876 {
1877 unsigned int currentCounter;
1878
1879 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1880
1881 /* has the event counter changed since the last call? */
1882 if (rContext->eventCounter != currentCounter)
1883 {
1884 currReader->dwEventState |= SCARD_STATE_CHANGED;
1885 Log0(PCSC_LOG_DEBUG);
1886 dwBreakFlag = 1;
1887 }
1888 }
1889
1890 /* add an event counter in the upper word of dwEventState */
1891 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1892 | (rContext->eventCounter << 16));
1893
1894 /* Check if the reader is in the correct state */
1895 if (readerState & SCARD_UNKNOWN)
1896 {
1897 /* reader is in bad state */
1898 currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1899 if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1900 {
1901 /* App thinks reader is in good state and it is not */
1902 currReader->dwEventState |= SCARD_STATE_CHANGED;
1903 Log0(PCSC_LOG_DEBUG);
1904 dwBreakFlag = 1;
1905 }
1906 }
1907 else
1908 {
1909 /* App thinks reader in bad state but it is not */
1910 if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1911 {
1912 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1913 currReader->dwEventState |= SCARD_STATE_CHANGED;
1914 Log0(PCSC_LOG_DEBUG);
1915 dwBreakFlag = 1;
1916 }
1917 }
1918
1919 /* Check for card presence in the reader */
1920 if (readerState & SCARD_PRESENT)
1921 {
1922#ifndef DISABLE_AUTO_POWER_ON
1923 /* card present but not yet powered up */
1924 if (0 == rContext->cardAtrLength)
1925 /* Allow the status thread to convey information */
1927#endif
1928
1929 currReader->cbAtr = rContext->cardAtrLength;
1930 memcpy(currReader->rgbAtr, rContext->cardAtr,
1931 currReader->cbAtr);
1932 }
1933 else
1934 currReader->cbAtr = 0;
1935
1936 /* Card is now absent */
1937 if (readerState & SCARD_ABSENT)
1938 {
1939 currReader->dwEventState |= SCARD_STATE_EMPTY;
1940 currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1941 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1942 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1943 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1944 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1945 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1946 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1947 currReader->dwEventState &= ~SCARD_STATE_INUSE;
1948
1949 /* After present the rest are assumed */
1950 if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1951 {
1952 currReader->dwEventState |= SCARD_STATE_CHANGED;
1953 Log0(PCSC_LOG_DEBUG);
1954 dwBreakFlag = 1;
1955 }
1956 }
1957 /* Card is now present */
1958 else if (readerState & SCARD_PRESENT)
1959 {
1960 currReader->dwEventState |= SCARD_STATE_PRESENT;
1961 currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1962 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1963 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1964 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1965 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1966 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1967
1968 if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1969 {
1970 currReader->dwEventState |= SCARD_STATE_CHANGED;
1971 Log0(PCSC_LOG_DEBUG);
1972 dwBreakFlag = 1;
1973 }
1974
1975 if (readerState & SCARD_SWALLOWED)
1976 {
1977 currReader->dwEventState |= SCARD_STATE_MUTE;
1978 if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1979 {
1980 currReader->dwEventState |= SCARD_STATE_CHANGED;
1981 Log0(PCSC_LOG_DEBUG);
1982 dwBreakFlag = 1;
1983 }
1984 }
1985 else
1986 {
1987 /* App thinks card is mute but it is not */
1988 if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1989 {
1990 currReader->dwEventState |= SCARD_STATE_CHANGED;
1991 Log0(PCSC_LOG_DEBUG);
1992 dwBreakFlag = 1;
1993 }
1994 }
1995 }
1996
1997 /* Now figure out sharing modes */
1999 {
2000 currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
2001 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2002 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2003 {
2004 currReader->dwEventState |= SCARD_STATE_CHANGED;
2005 Log0(PCSC_LOG_DEBUG);
2006 dwBreakFlag = 1;
2007 }
2008 }
2009 else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2010 {
2011 /* A card must be inserted for it to be INUSE */
2012 if (readerState & SCARD_PRESENT)
2013 {
2014 currReader->dwEventState |= SCARD_STATE_INUSE;
2015 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2016 if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2017 {
2018 currReader->dwEventState |= SCARD_STATE_CHANGED;
2019 Log0(PCSC_LOG_DEBUG);
2020 dwBreakFlag = 1;
2021 }
2022 }
2023 }
2024 else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2025 {
2026 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2027 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2028
2029 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2030 {
2031 currReader->dwEventState |= SCARD_STATE_CHANGED;
2032 Log0(PCSC_LOG_DEBUG);
2033 dwBreakFlag = 1;
2034 }
2035 else if (currReader-> dwCurrentState
2037 {
2038 currReader->dwEventState |= SCARD_STATE_CHANGED;
2039 Log0(PCSC_LOG_DEBUG);
2040 dwBreakFlag = 1;
2041 }
2042 }
2043
2044 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2045 {
2046 /*
2047 * Break out of the while .. loop and return status
2048 * once all the status's for all readers is met
2049 */
2050 currReader->dwEventState |= SCARD_STATE_CHANGED;
2051 Log0(PCSC_LOG_DEBUG);
2052 dwBreakFlag = 1;
2053 }
2054 } /* End of SCARD_STATE_UNKNOWN */
2055 } /* End of SCARD_STATE_IGNORE */
2056
2057 /* Counter and resetter */
2058 j++;
2059 if (j == cReaders)
2060 {
2061 /* go back to the first reader */
2062 j = 0;
2063
2064 /* Declare all the break conditions */
2065
2066 /* Break if UNAWARE is set and all readers have been checked */
2067 if (dwBreakFlag == 1)
2068 break;
2069
2070 /* Only sleep once for each cycle of reader checks. */
2071 {
2072 struct wait_reader_state_change waitStatusStruct = {0};
2073 struct timeval before, after;
2074
2075 gettimeofday(&before, NULL);
2076
2077 waitStatusStruct.rv = SCARD_S_SUCCESS;
2078
2079 /* another thread can do SCardCancel() */
2080 currentContextMap->cancellable = TRUE;
2081
2082 /*
2083 * Read a message from the server
2084 */
2086 &waitStatusStruct, sizeof(waitStatusStruct),
2087 currentContextMap->dwClientID, dwTime);
2088
2089 /* SCardCancel() will return immediatly with success
2090 * because something changed on the daemon side. */
2091 currentContextMap->cancellable = FALSE;
2092
2093 /* timeout */
2094 if (SCARD_E_TIMEOUT == rv)
2095 {
2096 /* ask server to remove us from the event list */
2097 rv = unregisterFromEvents(currentContextMap);
2098 }
2099
2100 if (rv != SCARD_S_SUCCESS)
2101 goto end;
2102
2103 /* an event occurs or SCardCancel() was called */
2104 if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2105 {
2106 rv = waitStatusStruct.rv;
2107 goto end;
2108 }
2109
2110 /* synchronize reader states with daemon */
2111 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2112 if (rv != SCARD_S_SUCCESS)
2113 goto end;
2114
2115 if (INFINITE != dwTimeout)
2116 {
2117 long int diff;
2118
2119 gettimeofday(&after, NULL);
2120 diff = time_sub(&after, &before);
2121 dwTime -= diff/1000;
2122 }
2123 }
2124
2125 if (dwTimeout != INFINITE)
2126 {
2127 /* If time is greater than timeout and all readers have been
2128 * checked
2129 */
2130 if (dwTime <= 0)
2131 {
2132 rv = SCARD_E_TIMEOUT;
2133 goto end;
2134 }
2135 }
2136 }
2137 }
2138 while (1);
2139
2140end:
2141 Log1(PCSC_LOG_DEBUG, "Event Loop End");
2142
2143 /* if SCardCancel() has been used then the client is already
2144 * unregistered */
2145 if (SCARD_E_CANCELLED != rv)
2146 (void)unregisterFromEvents(currentContextMap);
2147
2148 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2149
2150error:
2151 PROFILE_END(rv)
2152#ifdef DO_TRACE
2153 for (j=0; j<cReaders; j++)
2154 {
2155 API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2156 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2157 }
2158#endif
2159
2160 return rv;
2161}
2162
2213LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2214 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2215 LPDWORD lpBytesReturned)
2216{
2217 LONG rv;
2218 struct control_struct scControlStruct;
2219 SCONTEXTMAP * currentContextMap;
2220 CHANNEL_MAP * pChannelMap;
2221
2222 PROFILE_START
2223
2224 /* 0 bytes received by default */
2225 if (NULL != lpBytesReturned)
2226 *lpBytesReturned = 0;
2227
2228 /*
2229 * Make sure this handle has been opened
2230 */
2231 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2232 &pChannelMap);
2233 if (rv == -1)
2234 {
2235 PROFILE_END(SCARD_E_INVALID_HANDLE)
2237 }
2238
2239 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2240 {
2242 goto end;
2243 }
2244
2245 scControlStruct.hCard = hCard;
2246 scControlStruct.dwControlCode = dwControlCode;
2247 scControlStruct.cbSendLength = cbSendLength;
2248 scControlStruct.cbRecvLength = cbRecvLength;
2249 scControlStruct.dwBytesReturned = 0;
2250 scControlStruct.rv = 0;
2251
2252 rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2253 sizeof(scControlStruct), &scControlStruct);
2254
2255 if (rv != SCARD_S_SUCCESS)
2256 goto end;
2257
2258 /* write the sent buffer */
2259 rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2260 currentContextMap->dwClientID);
2261
2262 if (rv != SCARD_S_SUCCESS)
2263 goto end;
2264
2265 /*
2266 * Read a message from the server
2267 */
2268 rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2269 currentContextMap->dwClientID);
2270
2271 if (rv != SCARD_S_SUCCESS)
2272 goto end;
2273
2274 if (SCARD_S_SUCCESS == scControlStruct.rv)
2275 {
2276 if (scControlStruct.dwBytesReturned > cbRecvLength)
2277 {
2278 if (NULL != lpBytesReturned)
2279 *lpBytesReturned = scControlStruct.dwBytesReturned;
2281 goto end;
2282 }
2283
2284 /* read the received buffer */
2285 rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2286 currentContextMap->dwClientID);
2287
2288 if (rv != SCARD_S_SUCCESS)
2289 goto end;
2290
2291 }
2292
2293 if (NULL != lpBytesReturned)
2294 *lpBytesReturned = scControlStruct.dwBytesReturned;
2295
2296 rv = scControlStruct.rv;
2297
2298end:
2299 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2300
2301 PROFILE_END(rv)
2302
2303 return rv;
2304}
2305
2423LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2424 LPDWORD pcbAttrLen)
2425{
2426 LONG ret;
2427 unsigned char *buf = NULL;
2428
2429 PROFILE_START
2430
2431 if (NULL == pcbAttrLen)
2432 {
2434 goto end;
2435 }
2436
2437 if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2438 {
2439 if (NULL == pbAttr)
2441
2442 *pcbAttrLen = MAX_BUFFER_SIZE;
2443 buf = malloc(*pcbAttrLen);
2444 if (NULL == buf)
2445 {
2446 ret = SCARD_E_NO_MEMORY;
2447 goto end;
2448 }
2449
2450 *(unsigned char **)pbAttr = buf;
2451 }
2452 else
2453 {
2454 buf = pbAttr;
2455
2456 /* if only get the length */
2457 if (NULL == pbAttr)
2458 /* use a reasonable size */
2459 *pcbAttrLen = MAX_BUFFER_SIZE;
2460 }
2461
2462 ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2463 pcbAttrLen);
2464
2465end:
2466 PROFILE_END(ret)
2467
2468 return ret;
2469}
2470
2506LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2507 DWORD cbAttrLen)
2508{
2509 LONG ret;
2510
2511 PROFILE_START
2512
2513 if (NULL == pbAttr || 0 == cbAttrLen)
2515
2516 ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2517 &cbAttrLen);
2518
2519 PROFILE_END(ret)
2520
2521 return ret;
2522}
2523
2524static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2525 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2526{
2527 LONG rv;
2528 struct getset_struct scGetSetStruct;
2529 SCONTEXTMAP * currentContextMap;
2530 CHANNEL_MAP * pChannelMap;
2531
2532 /*
2533 * Make sure this handle has been opened
2534 */
2535 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2536 &pChannelMap);
2537 if (rv == -1)
2539
2540 if (*pcbAttrLen > MAX_BUFFER_SIZE)
2541 {
2543 goto end;
2544 }
2545
2546 scGetSetStruct.hCard = hCard;
2547 scGetSetStruct.dwAttrId = dwAttrId;
2548 scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2549 memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2550 if (SCARD_SET_ATTRIB == command)
2551 {
2552 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2553 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2554 }
2555 else
2556 /* we can get up to the communication buffer size */
2557 scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2558
2559 rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2560 sizeof(scGetSetStruct), &scGetSetStruct);
2561
2562 if (rv != SCARD_S_SUCCESS)
2563 goto end;
2564
2565 /*
2566 * Read a message from the server
2567 */
2568 rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2569 currentContextMap->dwClientID);
2570
2571 if (rv != SCARD_S_SUCCESS)
2572 goto end;
2573
2574 if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2575 {
2576 /*
2577 * Copy and zero it so any secret information is not leaked
2578 */
2579 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2580 {
2581 /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2582 * buffer overflow in the memcpy() bellow */
2583 DWORD correct_value = scGetSetStruct.cbAttrLen;
2584 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2585 *pcbAttrLen = correct_value;
2586
2587 scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2588 }
2589 else
2590 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2591
2592 if (pbAttr)
2593 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2594
2595 memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2596 }
2597 rv = scGetSetStruct.rv;
2598
2599end:
2600 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2601
2602 return rv;
2603}
2604
2663LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2664 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2665 SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2666 LPDWORD pcbRecvLength)
2667{
2668 LONG rv;
2669 SCONTEXTMAP * currentContextMap;
2670 CHANNEL_MAP * pChannelMap;
2671 struct transmit_struct scTransmitStruct;
2672
2673 PROFILE_START
2674
2675 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2676 pcbRecvLength == NULL || pioSendPci == NULL)
2678
2679 /* Retry loop for blocking behaviour */
2680retry:
2681
2682 /*
2683 * Make sure this handle has been opened
2684 */
2685 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2686 &pChannelMap);
2687 if (rv == -1)
2688 {
2689 *pcbRecvLength = 0;
2690 PROFILE_END(SCARD_E_INVALID_HANDLE)
2692 }
2693
2694 if (cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2695 {
2697 goto end;
2698 }
2699
2700 scTransmitStruct.hCard = hCard;
2701 scTransmitStruct.cbSendLength = cbSendLength;
2702 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2703 scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2704 scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2705 scTransmitStruct.rv = SCARD_S_SUCCESS;
2706
2707 if (pioRecvPci)
2708 {
2709 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2710 scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2711 }
2712 else
2713 {
2714 scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2715 scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2716 }
2717
2718 rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2719 sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2720
2721 if (rv != SCARD_S_SUCCESS)
2722 goto end;
2723
2724 /* write the sent buffer */
2725 rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2726 currentContextMap->dwClientID);
2727
2728 if (rv != SCARD_S_SUCCESS)
2729 goto end;
2730
2731 /*
2732 * Read a message from the server
2733 */
2734 rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2735 currentContextMap->dwClientID);
2736
2737 if (rv != SCARD_S_SUCCESS)
2738 goto end;
2739
2740 if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2741 {
2742 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2743 {
2744 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2746 goto end;
2747 }
2748
2749 /* read the received buffer */
2750 rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2751 currentContextMap->dwClientID);
2752
2753 if (rv != SCARD_S_SUCCESS)
2754 goto end;
2755
2756 if (pioRecvPci)
2757 {
2758 pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2759 pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2760 }
2761 }
2762
2763 rv = scTransmitStruct.rv;
2764
2765 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2766 {
2767 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2769 goto retry;
2770 }
2771
2772 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2773
2774end:
2775 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2776
2777 PROFILE_END(rv)
2778
2779 return rv;
2780}
2781
2844LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2845 LPSTR mszReaders, LPDWORD pcchReaders)
2846{
2847 DWORD dwReadersLen = 0;
2848 int i;
2849 SCONTEXTMAP * currentContextMap;
2850 LONG rv = SCARD_S_SUCCESS;
2851 char *buf = NULL;
2852
2853 (void)mszGroups;
2854 PROFILE_START
2855 API_TRACE_IN("%ld", hContext)
2856
2857 /*
2858 * Check for NULL parameters
2859 */
2860 if (pcchReaders == NULL)
2862
2863 /*
2864 * Make sure this context has been opened
2865 */
2866 currentContextMap = SCardGetAndLockContext(hContext);
2867 if (NULL == currentContextMap)
2868 {
2869 PROFILE_END(SCARD_E_INVALID_HANDLE)
2871 }
2872
2873 /* synchronize reader states with daemon */
2874 rv = getReaderStates(currentContextMap);
2875 if (rv != SCARD_S_SUCCESS)
2876 goto end;
2877
2878 dwReadersLen = 0;
2879 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2880 if (readerStates[i].readerName[0] != '\0')
2881 dwReadersLen += strlen(readerStates[i].readerName) + 1;
2882
2883 /* for the last NULL byte */
2884 dwReadersLen += 1;
2885
2886 if (1 == dwReadersLen)
2887 {
2889 goto end;
2890 }
2891
2892 if (SCARD_AUTOALLOCATE == *pcchReaders)
2893 {
2894 if (NULL == mszReaders)
2895 {
2897 goto end;
2898 }
2899 buf = malloc(dwReadersLen);
2900 if (NULL == buf)
2901 {
2902 rv = SCARD_E_NO_MEMORY;
2903 goto end;
2904 }
2905 *(char **)mszReaders = buf;
2906 }
2907 else
2908 {
2909 buf = mszReaders;
2910
2911 /* not enough place to store the reader names */
2912 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2913 {
2915 goto end;
2916 }
2917 }
2918
2919 if (mszReaders == NULL) /* text array not allocated */
2920 goto end;
2921
2922 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2923 {
2924 if (readerStates[i].readerName[0] != '\0')
2925 {
2926 /*
2927 * Build the multi-string
2928 */
2929 strcpy(buf, readerStates[i].readerName);
2930 buf += strlen(readerStates[i].readerName)+1;
2931 }
2932 }
2933 *buf = '\0'; /* Add the last null */
2934
2935end:
2936 /* set the reader names length */
2937 *pcchReaders = dwReadersLen;
2938
2939 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2940
2941 PROFILE_END(rv)
2942 API_TRACE_OUT("%d", *pcchReaders)
2943
2944 return rv;
2945}
2946
2960LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2961{
2962 LONG rv = SCARD_S_SUCCESS;
2963
2964 PROFILE_START
2965
2966 /*
2967 * Make sure this context has been opened
2968 */
2969 if (! SCardGetContextValidity(hContext))
2971
2972 free((void *)pvMem);
2973
2974 PROFILE_END(rv)
2975
2976 return rv;
2977}
2978
3030LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3031 LPDWORD pcchGroups)
3032{
3033 LONG rv = SCARD_S_SUCCESS;
3034 SCONTEXTMAP * currentContextMap;
3035 char *buf = NULL;
3036
3037 PROFILE_START
3038
3039 /* Multi-string with two trailing \0 */
3040 const char ReaderGroup[] = "SCard$DefaultReaders\0";
3041 const unsigned int dwGroups = sizeof(ReaderGroup);
3042
3043 /*
3044 * Make sure this context has been opened
3045 */
3046 currentContextMap = SCardGetAndLockContext(hContext);
3047 if (NULL == currentContextMap)
3049
3050 if (SCARD_AUTOALLOCATE == *pcchGroups)
3051 {
3052 if (NULL == mszGroups)
3053 {
3055 goto end;
3056 }
3057 buf = malloc(dwGroups);
3058 if (NULL == buf)
3059 {
3060 rv = SCARD_E_NO_MEMORY;
3061 goto end;
3062 }
3063 *(char **)mszGroups = buf;
3064 }
3065 else
3066 {
3067 buf = mszGroups;
3068
3069 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3070 {
3072 goto end;
3073 }
3074 }
3075
3076 if (buf)
3077 memcpy(buf, ReaderGroup, dwGroups);
3078
3079end:
3080 *pcchGroups = dwGroups;
3081
3082 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3083
3084 PROFILE_END(rv)
3085
3086 return rv;
3087}
3088
3120LONG SCardCancel(SCARDCONTEXT hContext)
3121{
3122 SCONTEXTMAP * currentContextMap;
3123 LONG rv = SCARD_S_SUCCESS;
3124 uint32_t dwClientID = 0;
3125 struct cancel_struct scCancelStruct;
3126 char cancellable;
3127
3128 PROFILE_START
3129 API_TRACE_IN("%ld", hContext)
3130
3131 /*
3132 * Make sure this context has been opened
3133 */
3134 (void)SCardLockThread();
3135 currentContextMap = SCardGetContextTH(hContext);
3136
3137 if (NULL == currentContextMap)
3138 {
3139 (void)SCardUnlockThread();
3141 goto error;
3142 }
3143 cancellable = currentContextMap->cancellable;
3144 (void)SCardUnlockThread();
3145
3146 if (! cancellable)
3147 {
3148 rv = SCARD_S_SUCCESS;
3149 goto error;
3150 }
3151
3152 /* create a new connection to the server */
3153 if (ClientSetupSession(&dwClientID) != 0)
3154 {
3155 rv = SCARD_E_NO_SERVICE;
3156 goto error;
3157 }
3158
3159 scCancelStruct.hContext = hContext;
3160 scCancelStruct.rv = SCARD_S_SUCCESS;
3161
3162 rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3163 sizeof(scCancelStruct), (void *) &scCancelStruct);
3164
3165 if (rv != SCARD_S_SUCCESS)
3166 goto end;
3167
3168 /*
3169 * Read a message from the server
3170 */
3171 rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3172
3173 if (rv != SCARD_S_SUCCESS)
3174 goto end;
3175
3176 rv = scCancelStruct.rv;
3177end:
3178 ClientCloseSession(dwClientID);
3179
3180error:
3181 PROFILE_END(rv)
3182 API_TRACE_OUT("")
3183
3184 return rv;
3185}
3186
3210LONG SCardIsValidContext(SCARDCONTEXT hContext)
3211{
3212 LONG rv;
3213
3214 PROFILE_START
3215 API_TRACE_IN("%ld", hContext)
3216
3217 rv = SCARD_S_SUCCESS;
3218
3219 /*
3220 * Make sure this context has been opened
3221 */
3222 if (! SCardGetContextValidity(hContext))
3224
3225 PROFILE_END(rv)
3226 API_TRACE_OUT("")
3227
3228 return rv;
3229}
3230
3247static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3248{
3249 int lrv;
3250 SCONTEXTMAP * newContextMap;
3251
3252 newContextMap = malloc(sizeof(SCONTEXTMAP));
3253 if (NULL == newContextMap)
3254 return SCARD_E_NO_MEMORY;
3255
3256 Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3257 newContextMap->hContext = hContext;
3258 newContextMap->dwClientID = dwClientID;
3259 newContextMap->cancellable = FALSE;
3260
3261 (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3262
3263 lrv = list_init(&newContextMap->channelMapList);
3264 if (lrv < 0)
3265 {
3266 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3267 goto error;
3268 }
3269
3270 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3271 CHANNEL_MAP_seeker);
3272 if (lrv <0)
3273 {
3274 Log2(PCSC_LOG_CRITICAL,
3275 "list_attributes_seeker failed with return value: %d", lrv);
3276 list_destroy(&newContextMap->channelMapList);
3277 goto error;
3278 }
3279
3280 lrv = list_append(&contextMapList, newContextMap);
3281 if (lrv < 0)
3282 {
3283 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3284 lrv);
3285 list_destroy(&newContextMap->channelMapList);
3286 goto error;
3287 }
3288
3289 return SCARD_S_SUCCESS;
3290
3291error:
3292
3293 (void)pthread_mutex_destroy(&newContextMap->mMutex);
3294 free(newContextMap);
3295
3296 return SCARD_E_NO_MEMORY;
3297}
3298
3316{
3317 SCONTEXTMAP * currentContextMap;
3318
3320 currentContextMap = SCardGetContextTH(hContext);
3321
3322 /* lock the context (if available) */
3323 if (NULL != currentContextMap)
3324 (void)pthread_mutex_lock(&currentContextMap->mMutex);
3325
3327
3328 return currentContextMap;
3329}
3330
3344{
3345 return list_seek(&contextMapList, &hContext);
3346}
3347
3355{
3356 SCONTEXTMAP * currentContextMap;
3357 currentContextMap = SCardGetContextTH(hContext);
3358
3359 if (NULL != currentContextMap)
3360 SCardCleanContext(currentContextMap);
3361}
3362
3363static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3364{
3365 int list_index, lrv;
3366 int listSize;
3367 CHANNEL_MAP * currentChannelMap;
3368
3369 targetContextMap->hContext = 0;
3370 ClientCloseSession(targetContextMap->dwClientID);
3371 targetContextMap->dwClientID = 0;
3372 (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3373
3374 listSize = list_size(&targetContextMap->channelMapList);
3375 for (list_index = 0; list_index < listSize; list_index++)
3376 {
3377 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3378 list_index);
3379 if (NULL == currentChannelMap)
3380 {
3381 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3382 list_index);
3383 continue;
3384 }
3385 else
3386 {
3387 free(currentChannelMap->readerName);
3388 free(currentChannelMap);
3389 }
3390
3391 }
3392 list_destroy(&targetContextMap->channelMapList);
3393
3394 lrv = list_delete(&contextMapList, targetContextMap);
3395 if (lrv < 0)
3396 {
3397 Log2(PCSC_LOG_CRITICAL,
3398 "list_delete failed with return value: %d", lrv);
3399 }
3400
3401 free(targetContextMap);
3402
3403 return;
3404}
3405
3406/*
3407 * Functions for managing hCard values returned from SCardConnect.
3408 */
3409
3410static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3411 LPCSTR readerName)
3412{
3413 CHANNEL_MAP * newChannelMap;
3414 int lrv = -1;
3415
3416 newChannelMap = malloc(sizeof(CHANNEL_MAP));
3417 if (NULL == newChannelMap)
3418 return SCARD_E_NO_MEMORY;
3419
3420 newChannelMap->hCard = hCard;
3421 newChannelMap->readerName = strdup(readerName);
3422
3423 lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3424 if (lrv < 0)
3425 {
3426 free(newChannelMap->readerName);
3427 free(newChannelMap);
3428 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3429 lrv);
3430 return SCARD_E_NO_MEMORY;
3431 }
3432
3433 return SCARD_S_SUCCESS;
3434}
3435
3436static void SCardRemoveHandle(SCARDHANDLE hCard)
3437{
3438 SCONTEXTMAP * currentContextMap;
3439 CHANNEL_MAP * currentChannelMap;
3440 int lrv;
3441 LONG rv;
3442
3443 rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3444 &currentChannelMap);
3445 if (rv == -1)
3446 return;
3447
3448 free(currentChannelMap->readerName);
3449
3450 lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3451 if (lrv < 0)
3452 {
3453 Log2(PCSC_LOG_CRITICAL,
3454 "list_delete failed with return value: %d", lrv);
3455 }
3456
3457 free(currentChannelMap);
3458
3459 return;
3460}
3461
3462static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3463 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3464{
3465 LONG rv;
3466
3467 if (0 == hCard)
3468 return -1;
3469
3471 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3472 targetChannelMap);
3473
3474 if (SCARD_S_SUCCESS == rv)
3475 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3476
3478
3479 return rv;
3480}
3481
3482static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3483 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3484{
3485 int listSize;
3486 int list_index;
3487 SCONTEXTMAP * currentContextMap;
3488 CHANNEL_MAP * currentChannelMap;
3489
3490 /* Best to get the caller a crash early if we fail unsafely */
3491 *targetContextMap = NULL;
3492 *targetChannelMap = NULL;
3493
3494 listSize = list_size(&contextMapList);
3495
3496 for (list_index = 0; list_index < listSize; list_index++)
3497 {
3498 currentContextMap = list_get_at(&contextMapList, list_index);
3499 if (currentContextMap == NULL)
3500 {
3501 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3502 list_index);
3503 continue;
3504 }
3505 currentChannelMap = list_seek(&currentContextMap->channelMapList,
3506 &hCard);
3507 if (currentChannelMap != NULL)
3508 {
3509 *targetContextMap = currentContextMap;
3510 *targetChannelMap = currentChannelMap;
3511 return SCARD_S_SUCCESS;
3512 }
3513 }
3514
3515 return -1;
3516}
3517
3526{
3527 LONG rv;
3528 struct stat statBuffer;
3529 char *socketName;
3530
3531 socketName = getSocketName();
3532 rv = stat(socketName, &statBuffer);
3533
3534 if (rv != 0)
3535 {
3536 Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3537 socketName, strerror(errno));
3538 return SCARD_E_NO_SERVICE;
3539 }
3540
3541 return SCARD_S_SUCCESS;
3542}
3543
3544static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3545{
3546 int32_t dwClientID = currentContextMap->dwClientID;
3547 LONG rv;
3548
3549 rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3550 if (rv != SCARD_S_SUCCESS)
3551 return rv;
3552
3553 /* Read a message from the server */
3554 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3555 if (rv != SCARD_S_SUCCESS)
3556 return rv;
3557
3558 return SCARD_S_SUCCESS;
3559}
3560
3561static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3562{
3563 int32_t dwClientID = currentContextMap->dwClientID;
3564 LONG rv;
3565
3566 /* Get current reader states from server and register on event list */
3568 0, NULL);
3569 if (rv != SCARD_S_SUCCESS)
3570 return rv;
3571
3572 /* Read a message from the server */
3573 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3574 return rv;
3575}
3576
3577static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3578{
3579 int32_t dwClientID = currentContextMap->dwClientID;
3580 LONG rv;
3581 struct wait_reader_state_change waitStatusStruct = {0};
3582
3583 /* ask server to remove us from the event list */
3585 dwClientID, 0, NULL);
3586 if (rv != SCARD_S_SUCCESS)
3587 return rv;
3588
3589 /* This message can be the response to
3590 * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3591 * cancel notification.
3592 * The server side ensures, that no more messages will be sent to
3593 * the client. */
3594
3595 rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3596 dwClientID);
3597 if (rv != SCARD_S_SUCCESS)
3598 return rv;
3599
3600 /* if we received a cancel event the return value will be set
3601 * accordingly */
3602 rv = waitStatusStruct.rv;
3603
3604 return rv;
3605}
3606
This handles debugging.
This handles card insertion/removal events, updates ATR, protocol, and status information.
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
Definition: eventhandler.h:79
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
Definition: eventhandler.h:77
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
Definition: eventhandler.h:75
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
Definition: pcsclite.h:113
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition: pcsclite.h:125
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
Definition: pcsclite.h:115
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
Definition: pcsclite.h:111
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
Definition: pcsclite.h:119
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
Definition: pcsclite.h:201
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
Definition: pcsclite.h:129
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
Definition: pcsclite.h:141
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition: pcsclite.h:127
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
Definition: pcsclite.h:123
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:165
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
Definition: pcsclite.h:153
This keeps a list of defines for pcsc-lite.
#define PCSCLITE_STATUS_POLL_RATE
Status polling rate.
Definition: pcscd.h:53
#define PCSCLITE_LOCK_POLL_RATE
Lock polling rate.
Definition: pcscd.h:54
#define SCARD_STATE_IGNORE
Ignore this reader.
Definition: pcsclite.h:266
#define SCARD_SWALLOWED
Card not powered.
Definition: pcsclite.h:260
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
Definition: pcsclite.h:52
#define SCARD_PROTOCOL_T1
T=1 active protocol.
Definition: pcsclite.h:242
#define SCARD_PRESENT
Card is present.
Definition: pcsclite.h:259
#define SCARD_PROTOCOL_T0
T=0 active protocol.
Definition: pcsclite.h:241
#define SCARD_STATE_INUSE
Shared Mode.
Definition: pcsclite.h:274
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Definition: pcsclite.h:233
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
Definition: pcsclite.h:269
#define SCARD_STATE_PRESENT
Card inserted.
Definition: pcsclite.h:271
#define SCARD_ABSENT
Card is absent.
Definition: pcsclite.h:258
#define SCARD_UNKNOWN
Unknown state.
Definition: pcsclite.h:257
#define SCARD_STATE_UNKNOWN
Reader unknown.
Definition: pcsclite.h:268
#define INFINITE
Infinite timeout.
Definition: pcsclite.h:279
#define SCARD_STATE_EMPTY
Card removed.
Definition: pcsclite.h:270
#define SCARD_PROTOCOL_RAW
Raw active protocol.
Definition: pcsclite.h:243
#define SCARD_STATE_MUTE
Unresponsive card.
Definition: pcsclite.h:275
#define SCARD_STATE_CHANGED
State has changed.
Definition: pcsclite.h:267
#define SCARD_PROTOCOL_ANY
IFD determines prot.
Definition: pcsclite.h:246
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
Definition: pcsclite.h:297
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Definition: pcsclite.h:298
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
Definition: pcsclite.h:273
#define SCARD_STATE_UNAWARE
App wants status.
Definition: pcsclite.h:265
LONG SCARDHANDLE
hCard returned by SCardConnect()
Definition: pcsclite.h:55
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:284
This keeps track of a list of currently available reader structures.
Protocol Control Information (PCI)
Definition: pcsclite.h:80
unsigned long dwProtocol
Protocol identifier.
Definition: pcsclite.h:81
unsigned long cbPciLength
Protocol Control Inf Length.
Definition: pcsclite.h:82
Represents an Application Context Channel.
Represents an Application Context on the Client side.
pthread_mutex_t mMutex
Mutex for this context.
SCARDCONTEXT hContext
Application Context ID.
DWORD dwClientID
Client Connection ID.
char cancellable
We are in a cancellable call.
contained in SCARD_BEGIN_TRANSACTION Messages.
Definition: winscard_msg.h:188
contained in SCARD_CANCEL Messages.
Definition: winscard_msg.h:211
contained in SCARD_CONNECT Messages.
Definition: winscard_msg.h:145
contained in SCARD_CONTROL Messages.
Definition: winscard_msg.h:250
contained in SCARD_DISCONNECT Messages.
Definition: winscard_msg.h:176
contained in SCARD_END_TRANSACTION Messages.
Definition: winscard_msg.h:199
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
Definition: winscard_msg.h:122
contained in SCARD_GET_ATTRIB and Messages.
Definition: winscard_msg.h:265
list object
Definition: simclist.h:181
Define an exported public reader state structure so each application gets instant notification of cha...
Definition: eventhandler.h:53
int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
Definition: eventhandler.h:57
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
Definition: eventhandler.h:61
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
Definition: eventhandler.h:59
uint32_t eventCounter
number of card events
Definition: eventhandler.h:55
uint32_t readerState
SCARD_* bit field.
Definition: eventhandler.h:56
uint32_t cardAtrLength
ATR length.
Definition: eventhandler.h:60
contained in SCARD_RECONNECT Messages.
Definition: winscard_msg.h:161
Information contained in SCARD_RELEASE_CONTEXT Messages.
Definition: winscard_msg.h:134
contained in SCARD_STATUS Messages.
Definition: winscard_msg.h:222
contained in SCARD_TRANSMIT Messages.
Definition: winscard_msg.h:233
Information transmitted in CMD_VERSION Messages.
Definition: winscard_msg.h:58
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
Definition: winscard_msg.h:59
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Definition: winscard_msg.h:60
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
Definition: winscard_msg.h:111
This handles abstract system level calls.
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:78
long int time_sub(struct timeval *a, struct timeval *b)
return the difference (as long int) in µs between 2 struct timeval r = a - b
Definition: utils.c:138
This handles smart card reader communications.
static short isExecuted
Make sure the initialization code is executed only once.
static void SCardLockThread(void)
Locks a mutex so another thread must wait to use this function.
static int SCardGetContextValidity(SCARDCONTEXT hContext)
Tell if a context index from the Application Context vector _psContextMap is valid or not.
static void SCardRemoveContext(SCARDCONTEXT)
Removes an Application Context from a control vector.
static SCONTEXTMAP * SCardGetAndLockContext(SCARDCONTEXT)
Get the SCONTEXTMAP * from the Application Context vector _psContextMap for the passed context.
static void SCardUnlockThread(void)
Unlocks a mutex so another thread may use the client.
static pthread_mutex_t clientMutex
Ensure that some functions be accessed in thread-safe mode.
LONG SCardCheckDaemonAvailability(void)
Checks if the server is running.
static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT)
Get the address from the Application Context list _psContextMap for the passed context.
static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT)
Creates a communication context to the PC/SC Resource Manager.
PCSC_API const SCARD_IO_REQUEST g_rgSCardRawPci
Protocol Control Information for raw access.
static LONG SCardAddContext(SCARDCONTEXT, DWORD)
Functions for managing instances of SCardEstablishContext() These functions keep track of Context han...
PCSC_API const SCARD_IO_REQUEST g_rgSCardT1Pci
Protocol Control Information for T=1.
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
PCSC_API const SCARD_IO_REQUEST g_rgSCardT0Pci
Protocol Control Information for T=0.
INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
Prepares a communication channel for the client to talk to the server.
Definition: winscard_msg.c:121
INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void, uint64_t buffer_size, int32_t filedes, long timeOut)
Called by the Client to get the reponse from the server or vice-versa.
Definition: winscard_msg.c:197
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
Definition: winscard_msg.c:320
INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Sends a menssage from client to server or vice-versa.
Definition: winscard_msg.c:357
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:175
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the reponse from the server or vice-versa.
Definition: winscard_msg.c:457
This defines some structures and #defines to be used over the transport layer.
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
Definition: winscard_msg.h:50
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
Definition: winscard_msg.h:52
@ SCARD_DISCONNECT
used by SCardDisconnect()
Definition: winscard_msg.h:84
@ SCARD_SET_ATTRIB
used by SCardSetAttrib()
Definition: winscard_msg.h:94
@ SCARD_RELEASE_CONTEXT
used by SCardReleaseContext()
Definition: winscard_msg.h:80
@ CMD_STOP_WAITING_READER_STATE_CHANGE
stop waiting for a reader state change
Definition: winscard_msg.h:98
@ CMD_GET_READERS_STATE
get the readers state
Definition: winscard_msg.h:96
@ SCARD_CONTROL
used by SCardControl()
Definition: winscard_msg.h:88
@ CMD_VERSION
get the client/server protocol version
Definition: winscard_msg.h:95
@ CMD_WAIT_READER_STATE_CHANGE
wait for a reader state change
Definition: winscard_msg.h:97
@ SCARD_RECONNECT
used by SCardReconnect()
Definition: winscard_msg.h:83
@ SCARD_STATUS
used by SCardStatus()
Definition: winscard_msg.h:89
@ SCARD_GET_ATTRIB
used by SCardGetAttrib()
Definition: winscard_msg.h:93
@ SCARD_BEGIN_TRANSACTION
used by SCardBeginTransaction()
Definition: winscard_msg.h:85
@ SCARD_TRANSMIT
used by SCardTransmit()
Definition: winscard_msg.h:87
@ SCARD_END_TRANSACTION
used by SCardEndTransaction()
Definition: winscard_msg.h:86
@ SCARD_CANCEL
used by SCardCancel()
Definition: winscard_msg.h:91
@ SCARD_CONNECT
used by SCardConnect()
Definition: winscard_msg.h:82
@ SCARD_ESTABLISH_CONTEXT
used by SCardEstablishContext()
Definition: winscard_msg.h:79