pcsc-lite 1.9.5
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
138#define SCARD_PROTOCOL_ANY_OLD 0x1000
139
140#ifndef TRUE
141#define TRUE 1
142#define FALSE 0
143#endif
144
145static char sharing_shall_block = TRUE;
146
147#define COLOR_RED "\33[01;31m"
148#define COLOR_GREEN "\33[32m"
149#define COLOR_BLUE "\33[34m"
150#define COLOR_MAGENTA "\33[35m"
151#define COLOR_NORMAL "\33[0m"
152
153#ifdef DO_TRACE
154
155#include <stdio.h>
156#include <stdarg.h>
157
158static void trace(const char *func, const char direction, const char *fmt, ...)
159{
160 va_list args;
161
162 fprintf(stderr, COLOR_GREEN "%c " COLOR_BLUE "[%lX] " COLOR_GREEN "%s ",
163 direction, pthread_self(), func);
164
165 fprintf(stderr, COLOR_MAGENTA);
166 va_start(args, fmt);
167 vfprintf(stderr, fmt, args);
168 va_end(args);
169
170 fprintf(stderr, COLOR_NORMAL "\n");
171}
172
173#define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
174#define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
175#else
176#define API_TRACE_IN(...)
177#define API_TRACE_OUT(...)
178#endif
179
180#ifdef DO_PROFILE
181
182#define PROFILE_FILE "/tmp/pcsc_profile"
183#include <stdio.h>
184#include <sys/time.h>
185
186/* we can profile a maximum of 5 simultaneous calls */
187#define MAX_THREADS 5
188pthread_t threads[MAX_THREADS];
189struct timeval profile_time_start[MAX_THREADS];
190FILE *profile_fd;
191char profile_tty;
192
193#define PROFILE_START profile_start();
194#define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
195
196static void profile_start(void)
197{
198 static char initialized = FALSE;
199 pthread_t t;
200 int i;
201
202 if (!initialized)
203 {
204 char filename[80];
205
206 initialized = TRUE;
207 sprintf(filename, "%s-%d", PROFILE_FILE, getuid());
208 profile_fd = fopen(filename, "a+");
209 if (NULL == profile_fd)
210 {
211 fprintf(stderr, COLOR_RED "Can't open %s: %s" COLOR_NORMAL "\n",
212 PROFILE_FILE, strerror(errno));
213 exit(-1);
214 }
215 fprintf(profile_fd, "\nStart a new profile\n");
216
217 if (isatty(fileno(stderr)))
218 profile_tty = TRUE;
219 else
220 profile_tty = FALSE;
221 }
222
223 t = pthread_self();
224 for (i=0; i<MAX_THREADS; i++)
225 if (pthread_equal(0, threads[i]))
226 {
227 threads[i] = t;
228 break;
229 }
230
231 gettimeofday(&profile_time_start[i], NULL);
232} /* profile_start */
233
234static void profile_end(const char *f, LONG rv)
235{
236 struct timeval profile_time_end;
237 long d;
238 pthread_t t;
239 int i;
240
241 gettimeofday(&profile_time_end, NULL);
242
243 t = pthread_self();
244 for (i=0; i<MAX_THREADS; i++)
245 if (pthread_equal(t, threads[i]))
246 break;
247
248 if (i>=MAX_THREADS)
249 {
250 fprintf(stderr, COLOR_BLUE " WARNING: no start info for %s\n", f);
251 return;
252 }
253
254 d = time_sub(&profile_time_end, &profile_time_start[i]);
255
256 /* free this entry */
257 threads[i] = 0;
258
259 if (profile_tty)
260 {
261 if (rv != SCARD_S_SUCCESS)
262 fprintf(stderr,
263 COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld "
264 COLOR_BLUE "0x%08lX %s" COLOR_NORMAL "\n",
265 f, d, rv, pcsc_stringify_error(rv));
266 else
267 fprintf(stderr, COLOR_RED "RESULT %s " COLOR_MAGENTA "%ld"
268 COLOR_NORMAL "\n", f, d);
269 }
270 fprintf(profile_fd, "%s %ld\n", f, d);
271 fflush(profile_fd);
272} /* profile_end */
273
274#else
275#define PROFILE_START
276#define PROFILE_END(rv)
277#endif
278
284{
285 SCARDHANDLE hCard;
286 LPSTR readerName;
287};
288
289typedef struct _psChannelMap CHANNEL_MAP;
290
291static int CHANNEL_MAP_seeker(const void *el, const void *key)
292{
293 const CHANNEL_MAP * channelMap = el;
294
295 if ((el == NULL) || (key == NULL))
296 {
297 Log3(PCSC_LOG_CRITICAL,
298 "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
299 el, key);
300 return 0;
301 }
302
303 if (channelMap->hCard == *(SCARDHANDLE *)key)
304 return 1;
305
306 return 0;
307}
308
315{
318 pthread_mutex_t mMutex;
319 list_t channelMapList;
321};
328
329static list_t contextMapList;
330
331static int SCONTEXTMAP_seeker(const void *el, const void *key)
332{
333 const SCONTEXTMAP * contextMap = el;
334
335 if ((el == NULL) || (key == NULL))
336 {
337 Log3(PCSC_LOG_CRITICAL,
338 "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
339 el, key);
340 return 0;
341 }
342
343 if (contextMap->hContext == *(SCARDCONTEXT *) key)
344 return 1;
345
346 return 0;
347}
348
352static short isExecuted = 0;
353
354
359static pthread_mutex_t clientMutex = PTHREAD_MUTEX_INITIALIZER;
360
365
372
373
374static LONG SCardAddContext(SCARDCONTEXT, DWORD);
378static void SCardCleanContext(SCONTEXTMAP *);
379
380static LONG SCardAddHandle(SCARDHANDLE, SCONTEXTMAP *, LPCSTR);
381static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE,
382 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
383static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE,
384 /*@out@*/ SCONTEXTMAP * *, /*@out@*/ CHANNEL_MAP * *);
385static void SCardRemoveHandle(SCARDHANDLE);
386
387static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
388 LPBYTE pbAttr, LPDWORD pcbAttrLen);
389
390static LONG getReaderStates(SCONTEXTMAP * currentContextMap);
391static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap);
392static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap);
393
394/*
395 * Thread safety functions
396 */
403inline static void SCardLockThread(void)
404{
405 pthread_mutex_lock(&clientMutex);
406}
407
413inline static void SCardUnlockThread(void)
414{
415 pthread_mutex_unlock(&clientMutex);
416}
417
428{
429 SCONTEXTMAP * currentContextMap;
430
432 currentContextMap = SCardGetContextTH(hContext);
434
435 return currentContextMap != NULL;
436}
437
438static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID,
439 /*@out@*/ LPSCARDCONTEXT);
440
476LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
477 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
478{
479 LONG rv;
480
481 API_TRACE_IN("%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
482 PROFILE_START
483
484 /* Check if the server is running */
486 if (rv != SCARD_S_SUCCESS)
487 goto end;
488
490 rv = SCardEstablishContextTH(dwScope, pvReserved1,
491 pvReserved2, phContext);
493
494end:
495 PROFILE_END(rv)
496 API_TRACE_OUT("%ld", *phContext)
497
498 return rv;
499}
500
527static LONG SCardEstablishContextTH(DWORD dwScope,
528 /*@unused@*/ LPCVOID pvReserved1,
529 /*@unused@*/ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
530{
531 LONG rv;
532 struct establish_struct scEstablishStruct;
533 uint32_t dwClientID = 0;
534
535 (void)pvReserved1;
536 (void)pvReserved2;
537 if (phContext == NULL)
539 else
540 *phContext = 0;
541
542 /*
543 * Do this only once:
544 * - Initialize context list.
545 */
546 if (isExecuted == 0)
547 {
548 int lrv;
549
550 /* NOTE: The list will never be freed (No API call exists to
551 * "close all contexts".
552 * Applications which load and unload the library will leak
553 * the list's internal structures. */
554 lrv = list_init(&contextMapList);
555 if (lrv < 0)
556 {
557 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d",
558 lrv);
559 return SCARD_E_NO_MEMORY;
560 }
561
562 lrv = list_attributes_seeker(&contextMapList,
563 SCONTEXTMAP_seeker);
564 if (lrv <0)
565 {
566 Log2(PCSC_LOG_CRITICAL,
567 "list_attributes_seeker failed with return value: %d", lrv);
568 list_destroy(&contextMapList);
569 return SCARD_E_NO_MEMORY;
570 }
571
572 if (getenv("PCSCLITE_NO_BLOCKING"))
573 {
574 Log1(PCSC_LOG_INFO, "Disable shared blocking");
575 sharing_shall_block = FALSE;
576 }
577
578 isExecuted = 1;
579 }
580
581
582 /* Establishes a connection to the server */
583 if (ClientSetupSession(&dwClientID) != 0)
584 {
585 return SCARD_E_NO_SERVICE;
586 }
587
588 { /* exchange client/server protocol versions */
589 struct version_struct veStr;
590
593 veStr.rv = SCARD_S_SUCCESS;
594
595 rv = MessageSendWithHeader(CMD_VERSION, dwClientID, sizeof(veStr),
596 &veStr);
597 if (rv != SCARD_S_SUCCESS)
598 goto cleanup;
599
600 /* Read a message from the server */
601 rv = MessageReceive(&veStr, sizeof(veStr), dwClientID);
602 if (rv != SCARD_S_SUCCESS)
603 {
604 Log1(PCSC_LOG_CRITICAL,
605 "Your pcscd is too old and does not support CMD_VERSION");
607 goto cleanup;
608 }
609
610 Log3(PCSC_LOG_INFO, "Server is protocol version %d:%d",
611 veStr.major, veStr.minor);
612
613 if (veStr.rv != SCARD_S_SUCCESS)
614 {
615 rv = veStr.rv;
616 goto cleanup;
617 }
618 }
619
620again:
621 /*
622 * Try to establish an Application Context with the server
623 */
624 scEstablishStruct.dwScope = dwScope;
625 scEstablishStruct.hContext = 0;
626 scEstablishStruct.rv = SCARD_S_SUCCESS;
627
629 sizeof(scEstablishStruct), (void *) &scEstablishStruct);
630
631 if (rv != SCARD_S_SUCCESS)
632 goto cleanup;
633
634 /*
635 * Read the response from the server
636 */
637 rv = MessageReceive(&scEstablishStruct, sizeof(scEstablishStruct),
638 dwClientID);
639
640 if (rv != SCARD_S_SUCCESS)
641 goto cleanup;
642
643 if (scEstablishStruct.rv != SCARD_S_SUCCESS)
644 {
645 rv = scEstablishStruct.rv;
646 goto cleanup;
647 }
648
649 /* check we do not reuse an existing hContext */
650 if (NULL != SCardGetContextTH(scEstablishStruct.hContext))
651 /* we do not need to release the allocated context since
652 * SCardReleaseContext() does nothing on the server side */
653 goto again;
654
655 *phContext = scEstablishStruct.hContext;
656
657 /*
658 * Allocate the new hContext - if allocator full return an error
659 */
660 rv = SCardAddContext(*phContext, dwClientID);
661
662 return rv;
663
664cleanup:
665 ClientCloseSession(dwClientID);
666
667 return rv;
668}
669
692{
693 LONG rv;
694 struct release_struct scReleaseStruct;
695 SCONTEXTMAP * currentContextMap;
696
697 API_TRACE_IN("%ld", hContext)
698 PROFILE_START
699
700 /*
701 * Make sure this context has been opened
702 * and get currentContextMap
703 */
704 currentContextMap = SCardGetAndLockContext(hContext);
705 if (NULL == currentContextMap)
706 {
708 goto error;
709 }
710
711 scReleaseStruct.hContext = hContext;
712 scReleaseStruct.rv = SCARD_S_SUCCESS;
713
715 currentContextMap->dwClientID,
716 sizeof(scReleaseStruct), (void *) &scReleaseStruct);
717
718 if (rv != SCARD_S_SUCCESS)
719 goto end;
720
721 /*
722 * Read a message from the server
723 */
724 rv = MessageReceive(&scReleaseStruct, sizeof(scReleaseStruct),
725 currentContextMap->dwClientID);
726
727 if (rv != SCARD_S_SUCCESS)
728 goto end;
729
730 rv = scReleaseStruct.rv;
731end:
732 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
733
734 /*
735 * Remove the local context from the stack
736 */
738 SCardRemoveContext(hContext);
740
741error:
742 PROFILE_END(rv)
743 API_TRACE_OUT("")
744
745 return rv;
746}
747
803LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
804 DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
805 LPDWORD pdwActiveProtocol)
806{
807 LONG rv;
808 struct connect_struct scConnectStruct;
809 SCONTEXTMAP * currentContextMap;
810
811 PROFILE_START
812 API_TRACE_IN("%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
813
814 /*
815 * Check for NULL parameters
816 */
817 if (phCard == NULL || pdwActiveProtocol == NULL)
819 else
820 *phCard = 0;
821
822 if (szReader == NULL)
824
825 /*
826 * Check for uninitialized strings
827 */
828 if (strlen(szReader) > MAX_READERNAME)
830
831 /*
832 * Make sure this context has been opened
833 */
834 currentContextMap = SCardGetAndLockContext(hContext);
835 if (NULL == currentContextMap)
837
838 memset(scConnectStruct.szReader, 0, sizeof scConnectStruct.szReader);
839 strncpy(scConnectStruct.szReader, szReader, sizeof scConnectStruct.szReader);
840 scConnectStruct.szReader[sizeof scConnectStruct.szReader -1] = '\0';
841
842 scConnectStruct.hContext = hContext;
843 scConnectStruct.dwShareMode = dwShareMode;
844 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
845 scConnectStruct.hCard = 0;
846 scConnectStruct.dwActiveProtocol = 0;
847 scConnectStruct.rv = SCARD_S_SUCCESS;
848
849 rv = MessageSendWithHeader(SCARD_CONNECT, currentContextMap->dwClientID,
850 sizeof(scConnectStruct), (void *) &scConnectStruct);
851
852 if (rv != SCARD_S_SUCCESS)
853 goto end;
854
855 /*
856 * Read a message from the server
857 */
858 rv = MessageReceive(&scConnectStruct, sizeof(scConnectStruct),
859 currentContextMap->dwClientID);
860
861 if (rv != SCARD_S_SUCCESS)
862 goto end;
863
864 *phCard = scConnectStruct.hCard;
865 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
866
867 if (scConnectStruct.rv == SCARD_S_SUCCESS)
868 {
869 /*
870 * Keep track of the handle locally
871 */
872 rv = SCardAddHandle(*phCard, currentContextMap, szReader);
873 }
874 else
875 rv = scConnectStruct.rv;
876
877end:
878 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
879
880 PROFILE_END(rv)
881 API_TRACE_OUT("%d", *pdwActiveProtocol)
882
883 return rv;
884}
885
958LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
959 DWORD dwPreferredProtocols, DWORD dwInitialization,
960 LPDWORD pdwActiveProtocol)
961{
962 LONG rv;
963 struct reconnect_struct scReconnectStruct;
964 SCONTEXTMAP * currentContextMap;
965 CHANNEL_MAP * pChannelMap;
966
967 PROFILE_START
968 API_TRACE_IN("%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
969
970 if (pdwActiveProtocol == NULL)
972
973 /* Retry loop for blocking behaviour */
974retry:
975
976 /*
977 * Make sure this handle has been opened
978 */
979 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
980 &pChannelMap);
981 if (rv == -1)
983
984 scReconnectStruct.hCard = hCard;
985 scReconnectStruct.dwShareMode = dwShareMode;
986 scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
987 scReconnectStruct.dwInitialization = dwInitialization;
988 scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
989 scReconnectStruct.rv = SCARD_S_SUCCESS;
990
991 rv = MessageSendWithHeader(SCARD_RECONNECT, currentContextMap->dwClientID,
992 sizeof(scReconnectStruct), (void *) &scReconnectStruct);
993
994 if (rv != SCARD_S_SUCCESS)
995 goto end;
996
997 /*
998 * Read a message from the server
999 */
1000 rv = MessageReceive(&scReconnectStruct, sizeof(scReconnectStruct),
1001 currentContextMap->dwClientID);
1002
1003 if (rv != SCARD_S_SUCCESS)
1004 goto end;
1005
1006 rv = scReconnectStruct.rv;
1007
1008 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1009 {
1010 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1012 goto retry;
1013 }
1014
1015 *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1016
1017end:
1018 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1019
1020 PROFILE_END(rv)
1021 API_TRACE_OUT("%ld", *pdwActiveProtocol)
1022
1023 return rv;
1024}
1025
1057LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
1058{
1059 LONG rv;
1060 struct disconnect_struct scDisconnectStruct;
1061 SCONTEXTMAP * currentContextMap;
1062 CHANNEL_MAP * pChannelMap;
1063
1064 PROFILE_START
1065 API_TRACE_IN("%ld %ld", hCard, dwDisposition)
1066
1067 /*
1068 * Make sure this handle has been opened
1069 */
1070 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1071 &pChannelMap);
1072 if (rv == -1)
1073 {
1075 goto error;
1076 }
1077
1078 scDisconnectStruct.hCard = hCard;
1079 scDisconnectStruct.dwDisposition = dwDisposition;
1080 scDisconnectStruct.rv = SCARD_S_SUCCESS;
1081
1082 rv = MessageSendWithHeader(SCARD_DISCONNECT, currentContextMap->dwClientID,
1083 sizeof(scDisconnectStruct), (void *) &scDisconnectStruct);
1084
1085 if (rv != SCARD_S_SUCCESS)
1086 goto end;
1087
1088 /*
1089 * Read a message from the server
1090 */
1091 rv = MessageReceive(&scDisconnectStruct, sizeof(scDisconnectStruct),
1092 currentContextMap->dwClientID);
1093
1094 if (rv != SCARD_S_SUCCESS)
1095 goto end;
1096
1097 if (SCARD_S_SUCCESS == scDisconnectStruct.rv)
1098 SCardRemoveHandle(hCard);
1099 rv = scDisconnectStruct.rv;
1100
1101end:
1102 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1103
1104error:
1105 PROFILE_END(rv)
1106 API_TRACE_OUT("")
1107
1108 return rv;
1109}
1110
1147{
1148
1149 LONG rv;
1150 struct begin_struct scBeginStruct;
1151 SCONTEXTMAP * currentContextMap;
1152 CHANNEL_MAP * pChannelMap;
1153
1154 PROFILE_START
1155 API_TRACE_IN("%ld", hCard)
1156
1157 /*
1158 * Query the server every so often until the sharing violation ends
1159 * and then hold the lock for yourself.
1160 */
1161
1162 for(;;)
1163 {
1164 /*
1165 * Make sure this handle has been opened
1166 */
1167 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1168 &pChannelMap);
1169 if (rv == -1)
1171
1172 scBeginStruct.hCard = hCard;
1173 scBeginStruct.rv = SCARD_S_SUCCESS;
1174
1176 currentContextMap->dwClientID,
1177 sizeof(scBeginStruct), (void *) &scBeginStruct);
1178
1179 if (rv != SCARD_S_SUCCESS)
1180 break;
1181
1182 /*
1183 * Read a message from the server
1184 */
1185 rv = MessageReceive(&scBeginStruct, sizeof(scBeginStruct),
1186 currentContextMap->dwClientID);
1187
1188 if (rv != SCARD_S_SUCCESS)
1189 break;
1190
1191 rv = scBeginStruct.rv;
1192
1193 if (SCARD_E_SHARING_VIOLATION != rv)
1194 break;
1195
1196 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1198 }
1199
1200 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1201
1202 PROFILE_END(rv)
1203 API_TRACE_OUT("")
1204
1205 return rv;
1206}
1207
1247LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1248{
1249 LONG rv;
1250 struct end_struct scEndStruct;
1251 SCONTEXTMAP * currentContextMap;
1252 CHANNEL_MAP * pChannelMap;
1253
1254 PROFILE_START
1255 API_TRACE_IN("%ld", hCard)
1256
1257 /*
1258 * Make sure this handle has been opened
1259 */
1260 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1261 &pChannelMap);
1262 if (rv == -1)
1264
1265 scEndStruct.hCard = hCard;
1266 scEndStruct.dwDisposition = dwDisposition;
1267 scEndStruct.rv = SCARD_S_SUCCESS;
1268
1270 currentContextMap->dwClientID,
1271 sizeof(scEndStruct), (void *) &scEndStruct);
1272
1273 if (rv != SCARD_S_SUCCESS)
1274 goto end;
1275
1276 /*
1277 * Read a message from the server
1278 */
1279 rv = MessageReceive(&scEndStruct, sizeof(scEndStruct),
1280 currentContextMap->dwClientID);
1281
1282 if (rv != SCARD_S_SUCCESS)
1283 goto end;
1284
1285 rv = scEndStruct.rv;
1286
1287end:
1288 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1289
1290 PROFILE_END(rv)
1291 API_TRACE_OUT("")
1292
1293 return rv;
1294}
1295
1391LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName,
1392 LPDWORD pcchReaderLen, LPDWORD pdwState,
1393 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1394{
1395 DWORD dwReaderLen, dwAtrLen;
1396 LONG rv;
1397 int i;
1398 struct status_struct scStatusStruct;
1399 SCONTEXTMAP * currentContextMap;
1400 CHANNEL_MAP * pChannelMap;
1401 char *r;
1402 char *bufReader = NULL;
1403 LPBYTE bufAtr = NULL;
1404 DWORD dummy = 0;
1405
1406 PROFILE_START
1407
1408 /* default output values */
1409 if (pdwState)
1410 *pdwState = 0;
1411
1412 if (pdwProtocol)
1413 *pdwProtocol = 0;
1414
1415 /* Check for NULL parameters */
1416 if (pcchReaderLen == NULL)
1417 pcchReaderLen = &dummy;
1418
1419 if (pcbAtrLen == NULL)
1420 pcbAtrLen = &dummy;
1421
1422 /* length passed from caller */
1423 dwReaderLen = *pcchReaderLen;
1424 dwAtrLen = *pcbAtrLen;
1425
1426 *pcchReaderLen = 0;
1427 *pcbAtrLen = 0;
1428
1429 /* Retry loop for blocking behaviour */
1430retry:
1431
1432 /*
1433 * Make sure this handle has been opened
1434 */
1435 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
1436 &pChannelMap);
1437 if (rv == -1)
1439
1440 /* synchronize reader states with daemon */
1441 rv = getReaderStates(currentContextMap);
1442 if (rv != SCARD_S_SUCCESS)
1443 goto end;
1444
1445 r = pChannelMap->readerName;
1446 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1447 {
1448 /* by default r == NULL */
1449 if (r && strcmp(r, readerStates[i].readerName) == 0)
1450 break;
1451 }
1452
1454 {
1456 goto end;
1457 }
1458
1459 /* initialise the structure */
1460 memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1461 scStatusStruct.hCard = hCard;
1462
1463 rv = MessageSendWithHeader(SCARD_STATUS, currentContextMap->dwClientID,
1464 sizeof(scStatusStruct), (void *) &scStatusStruct);
1465
1466 if (rv != SCARD_S_SUCCESS)
1467 goto end;
1468
1469 /*
1470 * Read a message from the server
1471 */
1472 rv = MessageReceive(&scStatusStruct, sizeof(scStatusStruct),
1473 currentContextMap->dwClientID);
1474
1475 if (rv != SCARD_S_SUCCESS)
1476 goto end;
1477
1478 rv = scStatusStruct.rv;
1479
1480 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
1481 {
1482 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1484 goto retry;
1485 }
1486
1488 {
1489 /*
1490 * An event must have occurred
1491 */
1492 goto end;
1493 }
1494
1495 /*
1496 * Now continue with the client side SCardStatus
1497 */
1498
1499 *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1500 *pcbAtrLen = readerStates[i].cardAtrLength;
1501
1502 if (pdwState)
1503 *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1504
1505 if (pdwProtocol)
1506 *pdwProtocol = readerStates[i].cardProtocol;
1507
1508 if (SCARD_AUTOALLOCATE == dwReaderLen)
1509 {
1510 dwReaderLen = *pcchReaderLen;
1511 if (NULL == szReaderName)
1512 {
1514 goto end;
1515 }
1516 bufReader = malloc(dwReaderLen);
1517 if (NULL == bufReader)
1518 {
1519 rv = SCARD_E_NO_MEMORY;
1520 goto end;
1521 }
1522 *(char **)szReaderName = bufReader;
1523 }
1524 else
1525 bufReader = szReaderName;
1526
1527 /* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1528 if (bufReader)
1529 {
1530 if (*pcchReaderLen > dwReaderLen)
1532
1533 strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1534 }
1535
1536 if (SCARD_AUTOALLOCATE == dwAtrLen)
1537 {
1538 dwAtrLen = *pcbAtrLen;
1539 if (NULL == pbAtr)
1540 {
1542 goto end;
1543 }
1544 bufAtr = malloc(dwAtrLen);
1545 if (NULL == bufAtr)
1546 {
1547 rv = SCARD_E_NO_MEMORY;
1548 goto end;
1549 }
1550 *(LPBYTE *)pbAtr = bufAtr;
1551 }
1552 else
1553 bufAtr = pbAtr;
1554
1555 if (bufAtr)
1556 {
1557 if (*pcbAtrLen > dwAtrLen)
1559
1560 memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1561 }
1562
1563end:
1564 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
1565
1566 PROFILE_END(rv)
1567
1568 return rv;
1569}
1570
1678LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1679 SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
1680{
1681 SCARD_READERSTATE *currReader;
1682 READER_STATE *rContext;
1683 long dwTime;
1684 DWORD dwBreakFlag = 0;
1685 unsigned int j;
1686 SCONTEXTMAP * currentContextMap;
1687 int currentReaderCount = 0;
1688 LONG rv = SCARD_S_SUCCESS;
1689
1690 PROFILE_START
1691 API_TRACE_IN("%ld %ld %d", hContext, dwTimeout, cReaders)
1692#ifdef DO_TRACE
1693 for (j=0; j<cReaders; j++)
1694 {
1695 API_TRACE_IN("[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1696 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1697 }
1698#endif
1699
1700 if ((rgReaderStates == NULL && cReaders > 0)
1701 || (cReaders > PCSCLITE_MAX_READERS_CONTEXTS))
1702 {
1704 goto error;
1705 }
1706
1707 /* Check the integrity of the reader states structures */
1708 for (j = 0; j < cReaders; j++)
1709 {
1710 if (rgReaderStates[j].szReader == NULL)
1711 return SCARD_E_INVALID_VALUE;
1712 }
1713
1714 /* return if all readers are SCARD_STATE_IGNORE */
1715 if (cReaders > 0)
1716 {
1717 int nbNonIgnoredReaders = cReaders;
1718
1719 for (j=0; j<cReaders; j++)
1720 if (rgReaderStates[j].dwCurrentState & SCARD_STATE_IGNORE)
1721 nbNonIgnoredReaders--;
1722
1723 if (0 == nbNonIgnoredReaders)
1724 {
1725 rv = SCARD_S_SUCCESS;
1726 goto error;
1727 }
1728 }
1729 else
1730 {
1731 /* reader list is empty */
1732 rv = SCARD_S_SUCCESS;
1733 goto error;
1734 }
1735
1736 /*
1737 * Make sure this context has been opened
1738 */
1739 currentContextMap = SCardGetAndLockContext(hContext);
1740 if (NULL == currentContextMap)
1741 {
1743 goto error;
1744 }
1745
1746 /* synchronize reader states with daemon */
1747 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1748 if (rv != SCARD_S_SUCCESS)
1749 goto end;
1750
1751 /* check all the readers are already known */
1752 for (j=0; j<cReaders; j++)
1753 {
1754 const char *readerName;
1755 int i;
1756
1757 readerName = rgReaderStates[j].szReader;
1758 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1759 {
1760 if (strcmp(readerName, readerStates[i].readerName) == 0)
1761 break;
1762 }
1763
1764 /* The requested reader name is not recognized */
1766 {
1767 /* PnP special reader? */
1768 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") != 0)
1769 {
1771 goto end;
1772 }
1773 }
1774 }
1775
1776 /* Clear the event state for all readers */
1777 for (j = 0; j < cReaders; j++)
1778 rgReaderStates[j].dwEventState = 0;
1779
1780 /* Now is where we start our event checking loop */
1781 Log2(PCSC_LOG_DEBUG, "Event Loop Start, dwTimeout: %ld", dwTimeout);
1782
1783 /* Get the initial reader count on the system */
1784 for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1785 if (readerStates[j].readerName[0] != '\0')
1786 currentReaderCount++;
1787
1788 /* catch possible sign extension problems from 32 to 64-bits integers */
1789 if ((DWORD)-1 == dwTimeout)
1790 dwTimeout = INFINITE;
1791 if (INFINITE == dwTimeout)
1792 dwTime = 60*1000; /* "infinite" timeout */
1793 else
1794 dwTime = dwTimeout;
1795
1796 j = 0;
1797 do
1798 {
1799 currReader = &rgReaderStates[j];
1800
1801 /* Ignore for IGNORED readers */
1802 if (!(currReader->dwCurrentState & SCARD_STATE_IGNORE))
1803 {
1804 const char *readerName;
1805 int i;
1806
1807 /* Looks for correct readernames */
1808 readerName = currReader->szReader;
1809 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1810 {
1811 if (strcmp(readerName, readerStates[i].readerName) == 0)
1812 break;
1813 }
1814
1815 /* The requested reader name is not recognized */
1817 {
1818 /* PnP special reader? */
1819 if (strcasecmp(readerName, "\\\\?PnP?\\Notification") == 0)
1820 {
1821 int k, newReaderCount = 0;
1822
1823 for (k=0; k < PCSCLITE_MAX_READERS_CONTEXTS; k++)
1824 if (readerStates[k].readerName[0] != '\0')
1825 newReaderCount++;
1826
1827 if (newReaderCount != currentReaderCount)
1828 {
1829 Log1(PCSC_LOG_INFO, "Reader list changed");
1830 currentReaderCount = newReaderCount;
1831
1832 currReader->dwEventState |= SCARD_STATE_CHANGED;
1833 dwBreakFlag = 1;
1834 }
1835 }
1836 else
1837 {
1838 currReader->dwEventState =
1840 if (!(currReader->dwCurrentState & SCARD_STATE_UNKNOWN))
1841 {
1842 currReader->dwEventState |= SCARD_STATE_CHANGED;
1843 /*
1844 * Spec says use SCARD_STATE_IGNORE but a removed USB
1845 * reader with eventState fed into currentState will
1846 * be ignored forever
1847 */
1848 dwBreakFlag = 1;
1849 }
1850 }
1851 }
1852 else
1853 {
1854 uint32_t readerState;
1855
1856 /* The reader has come back after being away */
1857 if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1858 {
1859 currReader->dwEventState |= SCARD_STATE_CHANGED;
1860 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1861 Log0(PCSC_LOG_DEBUG);
1862 dwBreakFlag = 1;
1863 }
1864
1865 /* Set the reader status structure */
1866 rContext = &readerStates[i];
1867
1868 /* Now we check all the Reader States */
1869 readerState = rContext->readerState;
1870
1871 /* only if current state has an non null event counter */
1872 if (currReader->dwCurrentState & 0xFFFF0000)
1873 {
1874 unsigned int currentCounter;
1875
1876 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1877
1878 /* has the event counter changed since the last call? */
1879 if (rContext->eventCounter != currentCounter)
1880 {
1881 currReader->dwEventState |= SCARD_STATE_CHANGED;
1882 Log0(PCSC_LOG_DEBUG);
1883 dwBreakFlag = 1;
1884 }
1885 }
1886
1887 /* add an event counter in the upper word of dwEventState */
1888 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1889 | (rContext->eventCounter << 16));
1890
1891 /* Check if the reader is in the correct state */
1892 if (readerState & SCARD_UNKNOWN)
1893 {
1894 /* reader is in bad state */
1895 currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1896 if (!(currReader->dwCurrentState & SCARD_STATE_UNAVAILABLE))
1897 {
1898 /* App thinks reader is in good state and it is not */
1899 currReader->dwEventState |= SCARD_STATE_CHANGED;
1900 Log0(PCSC_LOG_DEBUG);
1901 dwBreakFlag = 1;
1902 }
1903 }
1904 else
1905 {
1906 /* App thinks reader in bad state but it is not */
1907 if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1908 {
1909 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1910 currReader->dwEventState |= SCARD_STATE_CHANGED;
1911 Log0(PCSC_LOG_DEBUG);
1912 dwBreakFlag = 1;
1913 }
1914 }
1915
1916 /* Check for card presence in the reader */
1917 if (readerState & SCARD_PRESENT)
1918 {
1919 /* card present but not yet powered up */
1920 if (0 == rContext->cardAtrLength)
1921 /* Allow the status thread to convey information */
1923
1924 currReader->cbAtr = rContext->cardAtrLength;
1925 memcpy(currReader->rgbAtr, rContext->cardAtr,
1926 currReader->cbAtr);
1927 }
1928 else
1929 currReader->cbAtr = 0;
1930
1931 /* Card is now absent */
1932 if (readerState & SCARD_ABSENT)
1933 {
1934 currReader->dwEventState |= SCARD_STATE_EMPTY;
1935 currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1936 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1937 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1938 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1939 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1940 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1941 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1942 currReader->dwEventState &= ~SCARD_STATE_INUSE;
1943
1944 /* After present the rest are assumed */
1945 if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1946 {
1947 currReader->dwEventState |= SCARD_STATE_CHANGED;
1948 Log0(PCSC_LOG_DEBUG);
1949 dwBreakFlag = 1;
1950 }
1951 }
1952 /* Card is now present */
1953 else if (readerState & SCARD_PRESENT)
1954 {
1955 currReader->dwEventState |= SCARD_STATE_PRESENT;
1956 currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1957 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1958 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1959 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1960 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1961 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1962
1963 if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1964 {
1965 currReader->dwEventState |= SCARD_STATE_CHANGED;
1966 Log0(PCSC_LOG_DEBUG);
1967 dwBreakFlag = 1;
1968 }
1969
1970 if (readerState & SCARD_SWALLOWED)
1971 {
1972 currReader->dwEventState |= SCARD_STATE_MUTE;
1973 if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1974 {
1975 currReader->dwEventState |= SCARD_STATE_CHANGED;
1976 Log0(PCSC_LOG_DEBUG);
1977 dwBreakFlag = 1;
1978 }
1979 }
1980 else
1981 {
1982 /* App thinks card is mute but it is not */
1983 if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1984 {
1985 currReader->dwEventState |= SCARD_STATE_CHANGED;
1986 Log0(PCSC_LOG_DEBUG);
1987 dwBreakFlag = 1;
1988 }
1989 }
1990 }
1991
1992 /* Now figure out sharing modes */
1994 {
1995 currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
1996 currReader->dwEventState &= ~SCARD_STATE_INUSE;
1997 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
1998 {
1999 currReader->dwEventState |= SCARD_STATE_CHANGED;
2000 Log0(PCSC_LOG_DEBUG);
2001 dwBreakFlag = 1;
2002 }
2003 }
2004 else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2005 {
2006 /* A card must be inserted for it to be INUSE */
2007 if (readerState & SCARD_PRESENT)
2008 {
2009 currReader->dwEventState |= SCARD_STATE_INUSE;
2010 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2011 if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2012 {
2013 currReader->dwEventState |= SCARD_STATE_CHANGED;
2014 Log0(PCSC_LOG_DEBUG);
2015 dwBreakFlag = 1;
2016 }
2017 }
2018 }
2019 else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2020 {
2021 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2022 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2023
2024 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2025 {
2026 currReader->dwEventState |= SCARD_STATE_CHANGED;
2027 Log0(PCSC_LOG_DEBUG);
2028 dwBreakFlag = 1;
2029 }
2030 else if (currReader-> dwCurrentState
2032 {
2033 currReader->dwEventState |= SCARD_STATE_CHANGED;
2034 Log0(PCSC_LOG_DEBUG);
2035 dwBreakFlag = 1;
2036 }
2037 }
2038
2039 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2040 {
2041 /*
2042 * Break out of the while .. loop and return status
2043 * once all the status's for all readers is met
2044 */
2045 currReader->dwEventState |= SCARD_STATE_CHANGED;
2046 Log0(PCSC_LOG_DEBUG);
2047 dwBreakFlag = 1;
2048 }
2049 } /* End of SCARD_STATE_UNKNOWN */
2050 } /* End of SCARD_STATE_IGNORE */
2051
2052 /* Counter and resetter */
2053 j++;
2054 if (j == cReaders)
2055 {
2056 /* go back to the first reader */
2057 j = 0;
2058
2059 /* Declare all the break conditions */
2060
2061 /* Break if UNAWARE is set and all readers have been checked */
2062 if (dwBreakFlag == 1)
2063 break;
2064
2065 /* Only sleep once for each cycle of reader checks. */
2066 {
2067 struct wait_reader_state_change waitStatusStruct = {0};
2068 struct timeval before, after;
2069
2070 gettimeofday(&before, NULL);
2071
2072 waitStatusStruct.rv = SCARD_S_SUCCESS;
2073
2074 /* another thread can do SCardCancel() */
2075 currentContextMap->cancellable = TRUE;
2076
2077 /*
2078 * Read a message from the server
2079 */
2081 &waitStatusStruct, sizeof(waitStatusStruct),
2082 currentContextMap->dwClientID, dwTime);
2083
2084 /* SCardCancel() will return immediatly with success
2085 * because something changed on the daemon side. */
2086 currentContextMap->cancellable = FALSE;
2087
2088 /* timeout */
2089 if (SCARD_E_TIMEOUT == rv)
2090 {
2091 /* ask server to remove us from the event list */
2092 rv = unregisterFromEvents(currentContextMap);
2093 }
2094
2095 if (rv != SCARD_S_SUCCESS)
2096 goto end;
2097
2098 /* an event occurs or SCardCancel() was called */
2099 if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2100 {
2101 rv = waitStatusStruct.rv;
2102 goto end;
2103 }
2104
2105 /* synchronize reader states with daemon */
2106 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2107 if (rv != SCARD_S_SUCCESS)
2108 goto end;
2109
2110 if (INFINITE != dwTimeout)
2111 {
2112 long int diff;
2113
2114 gettimeofday(&after, NULL);
2115 diff = time_sub(&after, &before);
2116 dwTime -= diff/1000;
2117 }
2118 }
2119
2120 if (dwTimeout != INFINITE)
2121 {
2122 /* If time is greater than timeout and all readers have been
2123 * checked
2124 */
2125 if (dwTime <= 0)
2126 {
2127 rv = SCARD_E_TIMEOUT;
2128 goto end;
2129 }
2130 }
2131 }
2132 }
2133 while (1);
2134
2135end:
2136 Log1(PCSC_LOG_DEBUG, "Event Loop End");
2137
2138 /* if SCardCancel() has been used then the client is already
2139 * unregistered */
2140 if (SCARD_E_CANCELLED != rv)
2141 (void)unregisterFromEvents(currentContextMap);
2142
2143 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2144
2145error:
2146 PROFILE_END(rv)
2147#ifdef DO_TRACE
2148 for (j=0; j<cReaders; j++)
2149 {
2150 API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2151 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2152 }
2153#endif
2154
2155 return rv;
2156}
2157
2208LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2209 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2210 LPDWORD lpBytesReturned)
2211{
2212 LONG rv;
2213 struct control_struct scControlStruct;
2214 SCONTEXTMAP * currentContextMap;
2215 CHANNEL_MAP * pChannelMap;
2216
2217 PROFILE_START
2218
2219 /* 0 bytes received by default */
2220 if (NULL != lpBytesReturned)
2221 *lpBytesReturned = 0;
2222
2223 /*
2224 * Make sure this handle has been opened
2225 */
2226 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2227 &pChannelMap);
2228 if (rv == -1)
2229 {
2230 PROFILE_END(SCARD_E_INVALID_HANDLE)
2232 }
2233
2234 if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2235 || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2236 {
2238 goto end;
2239 }
2240
2241 scControlStruct.hCard = hCard;
2242 scControlStruct.dwControlCode = dwControlCode;
2243 scControlStruct.cbSendLength = cbSendLength;
2244 scControlStruct.cbRecvLength = cbRecvLength;
2245 scControlStruct.dwBytesReturned = 0;
2246 scControlStruct.rv = 0;
2247
2248 rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2249 sizeof(scControlStruct), &scControlStruct);
2250
2251 if (rv != SCARD_S_SUCCESS)
2252 goto end;
2253
2254 /* write the sent buffer */
2255 rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2256 currentContextMap->dwClientID);
2257
2258 if (rv != SCARD_S_SUCCESS)
2259 goto end;
2260
2261 /*
2262 * Read a message from the server
2263 */
2264 rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2265 currentContextMap->dwClientID);
2266
2267 if (rv != SCARD_S_SUCCESS)
2268 goto end;
2269
2270 if (SCARD_S_SUCCESS == scControlStruct.rv)
2271 {
2272 /* read the received buffer */
2273 rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2274 currentContextMap->dwClientID);
2275
2276 if (rv != SCARD_S_SUCCESS)
2277 goto end;
2278
2279 }
2280
2281 if (NULL != lpBytesReturned)
2282 *lpBytesReturned = scControlStruct.dwBytesReturned;
2283
2284 rv = scControlStruct.rv;
2285
2286end:
2287 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2288
2289 PROFILE_END(rv)
2290
2291 return rv;
2292}
2293
2411LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2412 LPDWORD pcbAttrLen)
2413{
2414 LONG ret;
2415 unsigned char *buf = NULL;
2416
2417 PROFILE_START
2418
2419 if (NULL == pcbAttrLen)
2420 {
2422 goto end;
2423 }
2424
2425 if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2426 {
2427 if (NULL == pbAttr)
2429
2430 *pcbAttrLen = MAX_BUFFER_SIZE;
2431 buf = malloc(*pcbAttrLen);
2432 if (NULL == buf)
2433 {
2434 ret = SCARD_E_NO_MEMORY;
2435 goto end;
2436 }
2437
2438 *(unsigned char **)pbAttr = buf;
2439 }
2440 else
2441 {
2442 buf = pbAttr;
2443
2444 /* if only get the length */
2445 if (NULL == pbAttr)
2446 /* use a reasonable size */
2447 *pcbAttrLen = MAX_BUFFER_SIZE;
2448 }
2449
2450 ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2451 pcbAttrLen);
2452
2453end:
2454 PROFILE_END(ret)
2455
2456 return ret;
2457}
2458
2494LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2495 DWORD cbAttrLen)
2496{
2497 LONG ret;
2498
2499 PROFILE_START
2500
2501 if (NULL == pbAttr || 0 == cbAttrLen)
2503
2504 ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2505 &cbAttrLen);
2506
2507 PROFILE_END(ret)
2508
2509 return ret;
2510}
2511
2512static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2513 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2514{
2515 LONG rv;
2516 struct getset_struct scGetSetStruct;
2517 SCONTEXTMAP * currentContextMap;
2518 CHANNEL_MAP * pChannelMap;
2519
2520 /*
2521 * Make sure this handle has been opened
2522 */
2523 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2524 &pChannelMap);
2525 if (rv == -1)
2527
2528 if (*pcbAttrLen > MAX_BUFFER_SIZE)
2529 {
2531 goto end;
2532 }
2533
2534 scGetSetStruct.hCard = hCard;
2535 scGetSetStruct.dwAttrId = dwAttrId;
2536 scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2537 memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2538 if (SCARD_SET_ATTRIB == command)
2539 {
2540 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2541 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2542 }
2543 else
2544 /* we can get up to the communication buffer size */
2545 scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2546
2547 rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2548 sizeof(scGetSetStruct), &scGetSetStruct);
2549
2550 if (rv != SCARD_S_SUCCESS)
2551 goto end;
2552
2553 /*
2554 * Read a message from the server
2555 */
2556 rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2557 currentContextMap->dwClientID);
2558
2559 if (rv != SCARD_S_SUCCESS)
2560 goto end;
2561
2562 if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2563 {
2564 /*
2565 * Copy and zero it so any secret information is not leaked
2566 */
2567 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2568 {
2569 /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2570 * buffer overflow in the memcpy() bellow */
2571 DWORD correct_value = scGetSetStruct.cbAttrLen;
2572 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2573 *pcbAttrLen = correct_value;
2574
2575 scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2576 }
2577 else
2578 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2579
2580 if (pbAttr)
2581 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2582
2583 memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2584 }
2585 rv = scGetSetStruct.rv;
2586
2587end:
2588 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2589
2590 return rv;
2591}
2592
2651LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2652 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2653 SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2654 LPDWORD pcbRecvLength)
2655{
2656 LONG rv;
2657 SCONTEXTMAP * currentContextMap;
2658 CHANNEL_MAP * pChannelMap;
2659 struct transmit_struct scTransmitStruct;
2660
2661 PROFILE_START
2662
2663 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2664 pcbRecvLength == NULL || pioSendPci == NULL)
2666
2667 /* Retry loop for blocking behaviour */
2668retry:
2669
2670 /*
2671 * Make sure this handle has been opened
2672 */
2673 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2674 &pChannelMap);
2675 if (rv == -1)
2676 {
2677 *pcbRecvLength = 0;
2678 PROFILE_END(SCARD_E_INVALID_HANDLE)
2680 }
2681
2682 if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2683 || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2684 {
2686 goto end;
2687 }
2688
2689 scTransmitStruct.hCard = hCard;
2690 scTransmitStruct.cbSendLength = cbSendLength;
2691 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2692 scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2693 scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2694 scTransmitStruct.rv = SCARD_S_SUCCESS;
2695
2696 if (pioRecvPci)
2697 {
2698 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2699 scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2700 }
2701 else
2702 {
2703 scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2704 scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2705 }
2706
2707 rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2708 sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2709
2710 if (rv != SCARD_S_SUCCESS)
2711 goto end;
2712
2713 /* write the sent buffer */
2714 rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2715 currentContextMap->dwClientID);
2716
2717 if (rv != SCARD_S_SUCCESS)
2718 goto end;
2719
2720 /*
2721 * Read a message from the server
2722 */
2723 rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2724 currentContextMap->dwClientID);
2725
2726 if (rv != SCARD_S_SUCCESS)
2727 goto end;
2728
2729 if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2730 {
2731 /* read the received buffer */
2732 rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2733 currentContextMap->dwClientID);
2734
2735 if (rv != SCARD_S_SUCCESS)
2736 goto end;
2737
2738 if (pioRecvPci)
2739 {
2740 pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2741 pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2742 }
2743 }
2744
2745 rv = scTransmitStruct.rv;
2746
2747 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2748 {
2749 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2751 goto retry;
2752 }
2753
2754 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2755
2756end:
2757 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2758
2759 PROFILE_END(rv)
2760
2761 return rv;
2762}
2763
2826LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2827 LPSTR mszReaders, LPDWORD pcchReaders)
2828{
2829 DWORD dwReadersLen = 0;
2830 int i;
2831 SCONTEXTMAP * currentContextMap;
2832 LONG rv = SCARD_S_SUCCESS;
2833 char *buf = NULL;
2834
2835 (void)mszGroups;
2836 PROFILE_START
2837 API_TRACE_IN("%ld", hContext)
2838
2839 /*
2840 * Check for NULL parameters
2841 */
2842 if (pcchReaders == NULL)
2844
2845 /*
2846 * Make sure this context has been opened
2847 */
2848 currentContextMap = SCardGetAndLockContext(hContext);
2849 if (NULL == currentContextMap)
2850 {
2851 PROFILE_END(SCARD_E_INVALID_HANDLE)
2853 }
2854
2855 /* synchronize reader states with daemon */
2856 rv = getReaderStates(currentContextMap);
2857 if (rv != SCARD_S_SUCCESS)
2858 goto end;
2859
2860 dwReadersLen = 0;
2861 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2862 if (readerStates[i].readerName[0] != '\0')
2863 dwReadersLen += strlen(readerStates[i].readerName) + 1;
2864
2865 /* for the last NULL byte */
2866 dwReadersLen += 1;
2867
2868 if (1 == dwReadersLen)
2869 {
2871 goto end;
2872 }
2873
2874 if (SCARD_AUTOALLOCATE == *pcchReaders)
2875 {
2876 if (NULL == mszReaders)
2877 {
2879 goto end;
2880 }
2881 buf = malloc(dwReadersLen);
2882 if (NULL == buf)
2883 {
2884 rv = SCARD_E_NO_MEMORY;
2885 goto end;
2886 }
2887 *(char **)mszReaders = buf;
2888 }
2889 else
2890 {
2891 buf = mszReaders;
2892
2893 /* not enough place to store the reader names */
2894 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2895 {
2897 goto end;
2898 }
2899 }
2900
2901 if (mszReaders == NULL) /* text array not allocated */
2902 goto end;
2903
2904 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2905 {
2906 if (readerStates[i].readerName[0] != '\0')
2907 {
2908 /*
2909 * Build the multi-string
2910 */
2911 strcpy(buf, readerStates[i].readerName);
2912 buf += strlen(readerStates[i].readerName)+1;
2913 }
2914 }
2915 *buf = '\0'; /* Add the last null */
2916
2917end:
2918 /* set the reader names length */
2919 *pcchReaders = dwReadersLen;
2920
2921 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2922
2923 PROFILE_END(rv)
2924 API_TRACE_OUT("%d", *pcchReaders)
2925
2926 return rv;
2927}
2928
2942LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2943{
2944 LONG rv = SCARD_S_SUCCESS;
2945
2946 PROFILE_START
2947
2948 /*
2949 * Make sure this context has been opened
2950 */
2951 if (! SCardGetContextValidity(hContext))
2953
2954 free((void *)pvMem);
2955
2956 PROFILE_END(rv)
2957
2958 return rv;
2959}
2960
3012LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3013 LPDWORD pcchGroups)
3014{
3015 LONG rv = SCARD_S_SUCCESS;
3016 SCONTEXTMAP * currentContextMap;
3017 char *buf = NULL;
3018
3019 PROFILE_START
3020
3021 /* Multi-string with two trailing \0 */
3022 const char ReaderGroup[] = "SCard$DefaultReaders\0";
3023 const unsigned int dwGroups = sizeof(ReaderGroup);
3024
3025 /*
3026 * Make sure this context has been opened
3027 */
3028 currentContextMap = SCardGetAndLockContext(hContext);
3029 if (NULL == currentContextMap)
3031
3032 if (SCARD_AUTOALLOCATE == *pcchGroups)
3033 {
3034 if (NULL == mszGroups)
3035 {
3037 goto end;
3038 }
3039 buf = malloc(dwGroups);
3040 if (NULL == buf)
3041 {
3042 rv = SCARD_E_NO_MEMORY;
3043 goto end;
3044 }
3045 *(char **)mszGroups = buf;
3046 }
3047 else
3048 {
3049 buf = mszGroups;
3050
3051 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3052 {
3054 goto end;
3055 }
3056 }
3057
3058 if (buf)
3059 memcpy(buf, ReaderGroup, dwGroups);
3060
3061end:
3062 *pcchGroups = dwGroups;
3063
3064 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3065
3066 PROFILE_END(rv)
3067
3068 return rv;
3069}
3070
3103{
3104 SCONTEXTMAP * currentContextMap;
3105 LONG rv = SCARD_S_SUCCESS;
3106 uint32_t dwClientID = 0;
3107 struct cancel_struct scCancelStruct;
3108 char cancellable;
3109
3110 PROFILE_START
3111 API_TRACE_IN("%ld", hContext)
3112
3113 /*
3114 * Make sure this context has been opened
3115 */
3116 (void)SCardLockThread();
3117 currentContextMap = SCardGetContextTH(hContext);
3118
3119 if (NULL == currentContextMap)
3120 {
3121 (void)SCardUnlockThread();
3123 goto error;
3124 }
3125 cancellable = currentContextMap->cancellable;
3126 (void)SCardUnlockThread();
3127
3128 if (! cancellable)
3129 {
3130 rv = SCARD_S_SUCCESS;
3131 goto error;
3132 }
3133
3134 /* create a new connection to the server */
3135 if (ClientSetupSession(&dwClientID) != 0)
3136 {
3137 rv = SCARD_E_NO_SERVICE;
3138 goto error;
3139 }
3140
3141 scCancelStruct.hContext = hContext;
3142 scCancelStruct.rv = SCARD_S_SUCCESS;
3143
3144 rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3145 sizeof(scCancelStruct), (void *) &scCancelStruct);
3146
3147 if (rv != SCARD_S_SUCCESS)
3148 goto end;
3149
3150 /*
3151 * Read a message from the server
3152 */
3153 rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3154
3155 if (rv != SCARD_S_SUCCESS)
3156 goto end;
3157
3158 rv = scCancelStruct.rv;
3159end:
3160 ClientCloseSession(dwClientID);
3161
3162error:
3163 PROFILE_END(rv)
3164 API_TRACE_OUT("")
3165
3166 return rv;
3167}
3168
3193{
3194 LONG rv;
3195
3196 PROFILE_START
3197 API_TRACE_IN("%ld", hContext)
3198
3199 rv = SCARD_S_SUCCESS;
3200
3201 /*
3202 * Make sure this context has been opened
3203 */
3204 if (! SCardGetContextValidity(hContext))
3206
3207 PROFILE_END(rv)
3208 API_TRACE_OUT("")
3209
3210 return rv;
3211}
3212
3229static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3230{
3231 int lrv;
3232 SCONTEXTMAP * newContextMap;
3233
3234 newContextMap = malloc(sizeof(SCONTEXTMAP));
3235 if (NULL == newContextMap)
3236 return SCARD_E_NO_MEMORY;
3237
3238 Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3239 newContextMap->hContext = hContext;
3240 newContextMap->dwClientID = dwClientID;
3241 newContextMap->cancellable = FALSE;
3242
3243 (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3244
3245 lrv = list_init(&newContextMap->channelMapList);
3246 if (lrv < 0)
3247 {
3248 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3249 goto error;
3250 }
3251
3252 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3253 CHANNEL_MAP_seeker);
3254 if (lrv <0)
3255 {
3256 Log2(PCSC_LOG_CRITICAL,
3257 "list_attributes_seeker failed with return value: %d", lrv);
3258 list_destroy(&newContextMap->channelMapList);
3259 goto error;
3260 }
3261
3262 lrv = list_append(&contextMapList, newContextMap);
3263 if (lrv < 0)
3264 {
3265 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3266 lrv);
3267 list_destroy(&newContextMap->channelMapList);
3268 goto error;
3269 }
3270
3271 return SCARD_S_SUCCESS;
3272
3273error:
3274
3275 (void)pthread_mutex_destroy(&newContextMap->mMutex);
3276 free(newContextMap);
3277
3278 return SCARD_E_NO_MEMORY;
3279}
3280
3298{
3299 SCONTEXTMAP * currentContextMap;
3300
3302 currentContextMap = SCardGetContextTH(hContext);
3303
3304 /* lock the context (if available) */
3305 if (NULL != currentContextMap)
3306 (void)pthread_mutex_lock(&currentContextMap->mMutex);
3307
3309
3310 return currentContextMap;
3311}
3312
3326{
3327 return list_seek(&contextMapList, &hContext);
3328}
3329
3337{
3338 SCONTEXTMAP * currentContextMap;
3339 currentContextMap = SCardGetContextTH(hContext);
3340
3341 if (NULL != currentContextMap)
3342 SCardCleanContext(currentContextMap);
3343}
3344
3345static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3346{
3347 int list_index, lrv;
3348 int listSize;
3349 CHANNEL_MAP * currentChannelMap;
3350
3351 targetContextMap->hContext = 0;
3352 ClientCloseSession(targetContextMap->dwClientID);
3353 targetContextMap->dwClientID = 0;
3354 (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3355
3356 listSize = list_size(&targetContextMap->channelMapList);
3357 for (list_index = 0; list_index < listSize; list_index++)
3358 {
3359 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3360 list_index);
3361 if (NULL == currentChannelMap)
3362 {
3363 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3364 list_index);
3365 continue;
3366 }
3367 else
3368 {
3369 free(currentChannelMap->readerName);
3370 free(currentChannelMap);
3371 }
3372
3373 }
3374 list_destroy(&targetContextMap->channelMapList);
3375
3376 lrv = list_delete(&contextMapList, targetContextMap);
3377 if (lrv < 0)
3378 {
3379 Log2(PCSC_LOG_CRITICAL,
3380 "list_delete failed with return value: %d", lrv);
3381 }
3382
3383 free(targetContextMap);
3384
3385 return;
3386}
3387
3388/*
3389 * Functions for managing hCard values returned from SCardConnect.
3390 */
3391
3392static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3393 LPCSTR readerName)
3394{
3395 CHANNEL_MAP * newChannelMap;
3396 int lrv = -1;
3397
3398 newChannelMap = malloc(sizeof(CHANNEL_MAP));
3399 if (NULL == newChannelMap)
3400 return SCARD_E_NO_MEMORY;
3401
3402 newChannelMap->hCard = hCard;
3403 newChannelMap->readerName = strdup(readerName);
3404
3405 lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3406 if (lrv < 0)
3407 {
3408 free(newChannelMap->readerName);
3409 free(newChannelMap);
3410 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3411 lrv);
3412 return SCARD_E_NO_MEMORY;
3413 }
3414
3415 return SCARD_S_SUCCESS;
3416}
3417
3418static void SCardRemoveHandle(SCARDHANDLE hCard)
3419{
3420 SCONTEXTMAP * currentContextMap;
3421 CHANNEL_MAP * currentChannelMap;
3422 int lrv;
3423 LONG rv;
3424
3425 rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3426 &currentChannelMap);
3427 if (rv == -1)
3428 return;
3429
3430 free(currentChannelMap->readerName);
3431
3432 lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3433 if (lrv < 0)
3434 {
3435 Log2(PCSC_LOG_CRITICAL,
3436 "list_delete failed with return value: %d", lrv);
3437 }
3438
3439 free(currentChannelMap);
3440
3441 return;
3442}
3443
3444static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3445 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3446{
3447 LONG rv;
3448
3449 if (0 == hCard)
3450 return -1;
3451
3453 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3454 targetChannelMap);
3455
3456 if (SCARD_S_SUCCESS == rv)
3457 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3458
3460
3461 return rv;
3462}
3463
3464static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3465 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3466{
3467 int listSize;
3468 int list_index;
3469 SCONTEXTMAP * currentContextMap;
3470 CHANNEL_MAP * currentChannelMap;
3471
3472 /* Best to get the caller a crash early if we fail unsafely */
3473 *targetContextMap = NULL;
3474 *targetChannelMap = NULL;
3475
3476 listSize = list_size(&contextMapList);
3477
3478 for (list_index = 0; list_index < listSize; list_index++)
3479 {
3480 currentContextMap = list_get_at(&contextMapList, list_index);
3481 if (currentContextMap == NULL)
3482 {
3483 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3484 list_index);
3485 continue;
3486 }
3487 currentChannelMap = list_seek(&currentContextMap->channelMapList,
3488 &hCard);
3489 if (currentChannelMap != NULL)
3490 {
3491 *targetContextMap = currentContextMap;
3492 *targetChannelMap = currentChannelMap;
3493 return SCARD_S_SUCCESS;
3494 }
3495 }
3496
3497 return -1;
3498}
3499
3508{
3509 LONG rv;
3510 struct stat statBuffer;
3511 char *socketName;
3512
3513 socketName = getSocketName();
3514 rv = stat(socketName, &statBuffer);
3515
3516 if (rv != 0)
3517 {
3518 Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3519 socketName, strerror(errno));
3520 return SCARD_E_NO_SERVICE;
3521 }
3522
3523 return SCARD_S_SUCCESS;
3524}
3525
3526static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3527{
3528 int32_t dwClientID = currentContextMap->dwClientID;
3529 LONG rv;
3530
3531 rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3532 if (rv != SCARD_S_SUCCESS)
3533 return rv;
3534
3535 /* Read a message from the server */
3536 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3537 if (rv != SCARD_S_SUCCESS)
3538 return rv;
3539
3540 return SCARD_S_SUCCESS;
3541}
3542
3543static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3544{
3545 int32_t dwClientID = currentContextMap->dwClientID;
3546 LONG rv;
3547
3548 /* Get current reader states from server and register on event list */
3550 0, NULL);
3551 if (rv != SCARD_S_SUCCESS)
3552 return rv;
3553
3554 /* Read a message from the server */
3555 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3556 return rv;
3557}
3558
3559static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3560{
3561 int32_t dwClientID = currentContextMap->dwClientID;
3562 LONG rv;
3563 struct wait_reader_state_change waitStatusStruct = {0};
3564
3565 /* ask server to remove us from the event list */
3567 dwClientID, 0, NULL);
3568 if (rv != SCARD_S_SUCCESS)
3569 return rv;
3570
3571 /* This message can be the response to
3572 * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3573 * cancel notification.
3574 * The server side ensures, that no more messages will be sent to
3575 * the client. */
3576
3577 rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3578 dwClientID);
3579 if (rv != SCARD_S_SUCCESS)
3580 return rv;
3581
3582 /* if we received a cancel event the return value will be set
3583 * accordingly */
3584 rv = waitStatusStruct.rv;
3585
3586 return rv;
3587}
3588
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
LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
Releases memory that has been returned from the resource manager using the SCARD_AUTOALLOCATE length ...
LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
PCSC_API const char * pcsc_stringify_error(const LONG pcscError)
Returns a human readable text for the given PC/SC error code.
Definition: error.c:82
LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
Blocks execution until the current availability of the cards in a specific set of readers changes.
LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
Establishes a connection to the reader specified in * szReader.
LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.
LONG SCardIsValidContext(SCARDCONTEXT hContext)
Check if a SCARDCONTEXT is valid.
LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders)
Returns a list of currently available readers on the system.
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().
LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups)
Returns a list of currently available reader groups on the system.
LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
Creates an Application Context to the PC/SC Resource Manager.
LONG SCardCancel(SCARDCONTEXT hContext)
Cancels a specific blocking SCardGetStatusChange() function.
LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
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.
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().
LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a serie of commands in a transaction.
LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
Returns the current status of the reader connected to by hCard.
LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
#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_F_COMM_ERROR
An internal communications error has been detected.
Definition: pcsclite.h:145
#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:71
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