pcsc-lite 1.9.7
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#ifndef DISABLE_AUTO_POWER_ON
1920 /* card present but not yet powered up */
1921 if (0 == rContext->cardAtrLength)
1922 /* Allow the status thread to convey information */
1924#endif
1925
1926 currReader->cbAtr = rContext->cardAtrLength;
1927 memcpy(currReader->rgbAtr, rContext->cardAtr,
1928 currReader->cbAtr);
1929 }
1930 else
1931 currReader->cbAtr = 0;
1932
1933 /* Card is now absent */
1934 if (readerState & SCARD_ABSENT)
1935 {
1936 currReader->dwEventState |= SCARD_STATE_EMPTY;
1937 currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1938 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1939 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1940 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1941 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1942 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1943 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1944 currReader->dwEventState &= ~SCARD_STATE_INUSE;
1945
1946 /* After present the rest are assumed */
1947 if (currReader->dwCurrentState & SCARD_STATE_PRESENT)
1948 {
1949 currReader->dwEventState |= SCARD_STATE_CHANGED;
1950 Log0(PCSC_LOG_DEBUG);
1951 dwBreakFlag = 1;
1952 }
1953 }
1954 /* Card is now present */
1955 else if (readerState & SCARD_PRESENT)
1956 {
1957 currReader->dwEventState |= SCARD_STATE_PRESENT;
1958 currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1959 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1960 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1961 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1962 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1963 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1964
1965 if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1966 {
1967 currReader->dwEventState |= SCARD_STATE_CHANGED;
1968 Log0(PCSC_LOG_DEBUG);
1969 dwBreakFlag = 1;
1970 }
1971
1972 if (readerState & SCARD_SWALLOWED)
1973 {
1974 currReader->dwEventState |= SCARD_STATE_MUTE;
1975 if (!(currReader->dwCurrentState & SCARD_STATE_MUTE))
1976 {
1977 currReader->dwEventState |= SCARD_STATE_CHANGED;
1978 Log0(PCSC_LOG_DEBUG);
1979 dwBreakFlag = 1;
1980 }
1981 }
1982 else
1983 {
1984 /* App thinks card is mute but it is not */
1985 if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1986 {
1987 currReader->dwEventState |= SCARD_STATE_CHANGED;
1988 Log0(PCSC_LOG_DEBUG);
1989 dwBreakFlag = 1;
1990 }
1991 }
1992 }
1993
1994 /* Now figure out sharing modes */
1996 {
1997 currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
1998 currReader->dwEventState &= ~SCARD_STATE_INUSE;
1999 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2000 {
2001 currReader->dwEventState |= SCARD_STATE_CHANGED;
2002 Log0(PCSC_LOG_DEBUG);
2003 dwBreakFlag = 1;
2004 }
2005 }
2006 else if (rContext->readerSharing >= PCSCLITE_SHARING_LAST_CONTEXT)
2007 {
2008 /* A card must be inserted for it to be INUSE */
2009 if (readerState & SCARD_PRESENT)
2010 {
2011 currReader->dwEventState |= SCARD_STATE_INUSE;
2012 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2013 if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
2014 {
2015 currReader->dwEventState |= SCARD_STATE_CHANGED;
2016 Log0(PCSC_LOG_DEBUG);
2017 dwBreakFlag = 1;
2018 }
2019 }
2020 }
2021 else if (rContext->readerSharing == PCSCLITE_SHARING_NO_CONTEXT)
2022 {
2023 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2024 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2025
2026 if (currReader->dwCurrentState & SCARD_STATE_INUSE)
2027 {
2028 currReader->dwEventState |= SCARD_STATE_CHANGED;
2029 Log0(PCSC_LOG_DEBUG);
2030 dwBreakFlag = 1;
2031 }
2032 else if (currReader-> dwCurrentState
2034 {
2035 currReader->dwEventState |= SCARD_STATE_CHANGED;
2036 Log0(PCSC_LOG_DEBUG);
2037 dwBreakFlag = 1;
2038 }
2039 }
2040
2041 if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
2042 {
2043 /*
2044 * Break out of the while .. loop and return status
2045 * once all the status's for all readers is met
2046 */
2047 currReader->dwEventState |= SCARD_STATE_CHANGED;
2048 Log0(PCSC_LOG_DEBUG);
2049 dwBreakFlag = 1;
2050 }
2051 } /* End of SCARD_STATE_UNKNOWN */
2052 } /* End of SCARD_STATE_IGNORE */
2053
2054 /* Counter and resetter */
2055 j++;
2056 if (j == cReaders)
2057 {
2058 /* go back to the first reader */
2059 j = 0;
2060
2061 /* Declare all the break conditions */
2062
2063 /* Break if UNAWARE is set and all readers have been checked */
2064 if (dwBreakFlag == 1)
2065 break;
2066
2067 /* Only sleep once for each cycle of reader checks. */
2068 {
2069 struct wait_reader_state_change waitStatusStruct = {0};
2070 struct timeval before, after;
2071
2072 gettimeofday(&before, NULL);
2073
2074 waitStatusStruct.rv = SCARD_S_SUCCESS;
2075
2076 /* another thread can do SCardCancel() */
2077 currentContextMap->cancellable = TRUE;
2078
2079 /*
2080 * Read a message from the server
2081 */
2083 &waitStatusStruct, sizeof(waitStatusStruct),
2084 currentContextMap->dwClientID, dwTime);
2085
2086 /* SCardCancel() will return immediatly with success
2087 * because something changed on the daemon side. */
2088 currentContextMap->cancellable = FALSE;
2089
2090 /* timeout */
2091 if (SCARD_E_TIMEOUT == rv)
2092 {
2093 /* ask server to remove us from the event list */
2094 rv = unregisterFromEvents(currentContextMap);
2095 }
2096
2097 if (rv != SCARD_S_SUCCESS)
2098 goto end;
2099
2100 /* an event occurs or SCardCancel() was called */
2101 if (SCARD_S_SUCCESS != waitStatusStruct.rv)
2102 {
2103 rv = waitStatusStruct.rv;
2104 goto end;
2105 }
2106
2107 /* synchronize reader states with daemon */
2108 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2109 if (rv != SCARD_S_SUCCESS)
2110 goto end;
2111
2112 if (INFINITE != dwTimeout)
2113 {
2114 long int diff;
2115
2116 gettimeofday(&after, NULL);
2117 diff = time_sub(&after, &before);
2118 dwTime -= diff/1000;
2119 }
2120 }
2121
2122 if (dwTimeout != INFINITE)
2123 {
2124 /* If time is greater than timeout and all readers have been
2125 * checked
2126 */
2127 if (dwTime <= 0)
2128 {
2129 rv = SCARD_E_TIMEOUT;
2130 goto end;
2131 }
2132 }
2133 }
2134 }
2135 while (1);
2136
2137end:
2138 Log1(PCSC_LOG_DEBUG, "Event Loop End");
2139
2140 /* if SCardCancel() has been used then the client is already
2141 * unregistered */
2142 if (SCARD_E_CANCELLED != rv)
2143 (void)unregisterFromEvents(currentContextMap);
2144
2145 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2146
2147error:
2148 PROFILE_END(rv)
2149#ifdef DO_TRACE
2150 for (j=0; j<cReaders; j++)
2151 {
2152 API_TRACE_OUT("[%d] %s %X %X", j, rgReaderStates[j].szReader,
2153 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2154 }
2155#endif
2156
2157 return rv;
2158}
2159
2210LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2211 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2212 LPDWORD lpBytesReturned)
2213{
2214 LONG rv;
2215 struct control_struct scControlStruct;
2216 SCONTEXTMAP * currentContextMap;
2217 CHANNEL_MAP * pChannelMap;
2218
2219 PROFILE_START
2220
2221 /* 0 bytes received by default */
2222 if (NULL != lpBytesReturned)
2223 *lpBytesReturned = 0;
2224
2225 /*
2226 * Make sure this handle has been opened
2227 */
2228 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2229 &pChannelMap);
2230 if (rv == -1)
2231 {
2232 PROFILE_END(SCARD_E_INVALID_HANDLE)
2234 }
2235
2236 if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2237 || (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2238 {
2240 goto end;
2241 }
2242
2243 scControlStruct.hCard = hCard;
2244 scControlStruct.dwControlCode = dwControlCode;
2245 scControlStruct.cbSendLength = cbSendLength;
2246 scControlStruct.cbRecvLength = cbRecvLength;
2247 scControlStruct.dwBytesReturned = 0;
2248 scControlStruct.rv = 0;
2249
2250 rv = MessageSendWithHeader(SCARD_CONTROL, currentContextMap->dwClientID,
2251 sizeof(scControlStruct), &scControlStruct);
2252
2253 if (rv != SCARD_S_SUCCESS)
2254 goto end;
2255
2256 /* write the sent buffer */
2257 rv = MessageSend((char *)pbSendBuffer, cbSendLength,
2258 currentContextMap->dwClientID);
2259
2260 if (rv != SCARD_S_SUCCESS)
2261 goto end;
2262
2263 /*
2264 * Read a message from the server
2265 */
2266 rv = MessageReceive(&scControlStruct, sizeof(scControlStruct),
2267 currentContextMap->dwClientID);
2268
2269 if (rv != SCARD_S_SUCCESS)
2270 goto end;
2271
2272 if (SCARD_S_SUCCESS == scControlStruct.rv)
2273 {
2274 if (scControlStruct.dwBytesReturned > cbRecvLength)
2275 {
2276 if (NULL != lpBytesReturned)
2277 *lpBytesReturned = scControlStruct.dwBytesReturned;
2279 goto end;
2280 }
2281
2282 /* read the received buffer */
2283 rv = MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2284 currentContextMap->dwClientID);
2285
2286 if (rv != SCARD_S_SUCCESS)
2287 goto end;
2288
2289 }
2290
2291 if (NULL != lpBytesReturned)
2292 *lpBytesReturned = scControlStruct.dwBytesReturned;
2293
2294 rv = scControlStruct.rv;
2295
2296end:
2297 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2298
2299 PROFILE_END(rv)
2300
2301 return rv;
2302}
2303
2421LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr,
2422 LPDWORD pcbAttrLen)
2423{
2424 LONG ret;
2425 unsigned char *buf = NULL;
2426
2427 PROFILE_START
2428
2429 if (NULL == pcbAttrLen)
2430 {
2432 goto end;
2433 }
2434
2435 if (SCARD_AUTOALLOCATE == *pcbAttrLen)
2436 {
2437 if (NULL == pbAttr)
2439
2440 *pcbAttrLen = MAX_BUFFER_SIZE;
2441 buf = malloc(*pcbAttrLen);
2442 if (NULL == buf)
2443 {
2444 ret = SCARD_E_NO_MEMORY;
2445 goto end;
2446 }
2447
2448 *(unsigned char **)pbAttr = buf;
2449 }
2450 else
2451 {
2452 buf = pbAttr;
2453
2454 /* if only get the length */
2455 if (NULL == pbAttr)
2456 /* use a reasonable size */
2457 *pcbAttrLen = MAX_BUFFER_SIZE;
2458 }
2459
2460 ret = SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, buf,
2461 pcbAttrLen);
2462
2463end:
2464 PROFILE_END(ret)
2465
2466 return ret;
2467}
2468
2504LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr,
2505 DWORD cbAttrLen)
2506{
2507 LONG ret;
2508
2509 PROFILE_START
2510
2511 if (NULL == pbAttr || 0 == cbAttrLen)
2513
2514 ret = SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2515 &cbAttrLen);
2516
2517 PROFILE_END(ret)
2518
2519 return ret;
2520}
2521
2522static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2523 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2524{
2525 LONG rv;
2526 struct getset_struct scGetSetStruct;
2527 SCONTEXTMAP * currentContextMap;
2528 CHANNEL_MAP * pChannelMap;
2529
2530 /*
2531 * Make sure this handle has been opened
2532 */
2533 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2534 &pChannelMap);
2535 if (rv == -1)
2537
2538 if (*pcbAttrLen > MAX_BUFFER_SIZE)
2539 {
2541 goto end;
2542 }
2543
2544 scGetSetStruct.hCard = hCard;
2545 scGetSetStruct.dwAttrId = dwAttrId;
2546 scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2547 memset(scGetSetStruct.pbAttr, 0, sizeof(scGetSetStruct.pbAttr));
2548 if (SCARD_SET_ATTRIB == command)
2549 {
2550 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2551 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2552 }
2553 else
2554 /* we can get up to the communication buffer size */
2555 scGetSetStruct.cbAttrLen = sizeof scGetSetStruct.pbAttr;
2556
2557 rv = MessageSendWithHeader(command, currentContextMap->dwClientID,
2558 sizeof(scGetSetStruct), &scGetSetStruct);
2559
2560 if (rv != SCARD_S_SUCCESS)
2561 goto end;
2562
2563 /*
2564 * Read a message from the server
2565 */
2566 rv = MessageReceive(&scGetSetStruct, sizeof(scGetSetStruct),
2567 currentContextMap->dwClientID);
2568
2569 if (rv != SCARD_S_SUCCESS)
2570 goto end;
2571
2572 if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2573 {
2574 /*
2575 * Copy and zero it so any secret information is not leaked
2576 */
2577 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2578 {
2579 /* restrict the value of scGetSetStruct.cbAttrLen to avoid a
2580 * buffer overflow in the memcpy() bellow */
2581 DWORD correct_value = scGetSetStruct.cbAttrLen;
2582 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2583 *pcbAttrLen = correct_value;
2584
2585 scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2586 }
2587 else
2588 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2589
2590 if (pbAttr)
2591 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2592
2593 memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2594 }
2595 rv = scGetSetStruct.rv;
2596
2597end:
2598 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2599
2600 return rv;
2601}
2602
2661LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
2662 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2663 SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer,
2664 LPDWORD pcbRecvLength)
2665{
2666 LONG rv;
2667 SCONTEXTMAP * currentContextMap;
2668 CHANNEL_MAP * pChannelMap;
2669 struct transmit_struct scTransmitStruct;
2670
2671 PROFILE_START
2672
2673 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2674 pcbRecvLength == NULL || pioSendPci == NULL)
2676
2677 /* Retry loop for blocking behaviour */
2678retry:
2679
2680 /*
2681 * Make sure this handle has been opened
2682 */
2683 rv = SCardGetContextChannelAndLockFromHandle(hCard, &currentContextMap,
2684 &pChannelMap);
2685 if (rv == -1)
2686 {
2687 *pcbRecvLength = 0;
2688 PROFILE_END(SCARD_E_INVALID_HANDLE)
2690 }
2691
2692 if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2693 || (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2694 {
2696 goto end;
2697 }
2698
2699 scTransmitStruct.hCard = hCard;
2700 scTransmitStruct.cbSendLength = cbSendLength;
2701 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2702 scTransmitStruct.ioSendPciProtocol = pioSendPci->dwProtocol;
2703 scTransmitStruct.ioSendPciLength = pioSendPci->cbPciLength;
2704 scTransmitStruct.rv = SCARD_S_SUCCESS;
2705
2706 if (pioRecvPci)
2707 {
2708 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->dwProtocol;
2709 scTransmitStruct.ioRecvPciLength = pioRecvPci->cbPciLength;
2710 }
2711 else
2712 {
2713 scTransmitStruct.ioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2714 scTransmitStruct.ioRecvPciLength = sizeof(SCARD_IO_REQUEST);
2715 }
2716
2717 rv = MessageSendWithHeader(SCARD_TRANSMIT, currentContextMap->dwClientID,
2718 sizeof(scTransmitStruct), (void *) &scTransmitStruct);
2719
2720 if (rv != SCARD_S_SUCCESS)
2721 goto end;
2722
2723 /* write the sent buffer */
2724 rv = MessageSend((void *)pbSendBuffer, cbSendLength,
2725 currentContextMap->dwClientID);
2726
2727 if (rv != SCARD_S_SUCCESS)
2728 goto end;
2729
2730 /*
2731 * Read a message from the server
2732 */
2733 rv = MessageReceive(&scTransmitStruct, sizeof(scTransmitStruct),
2734 currentContextMap->dwClientID);
2735
2736 if (rv != SCARD_S_SUCCESS)
2737 goto end;
2738
2739 if (SCARD_S_SUCCESS == scTransmitStruct.rv)
2740 {
2741 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2742 {
2743 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2745 goto end;
2746 }
2747
2748 /* read the received buffer */
2749 rv = MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2750 currentContextMap->dwClientID);
2751
2752 if (rv != SCARD_S_SUCCESS)
2753 goto end;
2754
2755 if (pioRecvPci)
2756 {
2757 pioRecvPci->dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2758 pioRecvPci->cbPciLength = scTransmitStruct.ioRecvPciLength;
2759 }
2760 }
2761
2762 rv = scTransmitStruct.rv;
2763
2764 if (sharing_shall_block && (SCARD_E_SHARING_VIOLATION == rv))
2765 {
2766 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2768 goto retry;
2769 }
2770
2771 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2772
2773end:
2774 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2775
2776 PROFILE_END(rv)
2777
2778 return rv;
2779}
2780
2843LONG SCardListReaders(SCARDCONTEXT hContext, /*@unused@*/ LPCSTR mszGroups,
2844 LPSTR mszReaders, LPDWORD pcchReaders)
2845{
2846 DWORD dwReadersLen = 0;
2847 int i;
2848 SCONTEXTMAP * currentContextMap;
2849 LONG rv = SCARD_S_SUCCESS;
2850 char *buf = NULL;
2851
2852 (void)mszGroups;
2853 PROFILE_START
2854 API_TRACE_IN("%ld", hContext)
2855
2856 /*
2857 * Check for NULL parameters
2858 */
2859 if (pcchReaders == NULL)
2861
2862 /*
2863 * Make sure this context has been opened
2864 */
2865 currentContextMap = SCardGetAndLockContext(hContext);
2866 if (NULL == currentContextMap)
2867 {
2868 PROFILE_END(SCARD_E_INVALID_HANDLE)
2870 }
2871
2872 /* synchronize reader states with daemon */
2873 rv = getReaderStates(currentContextMap);
2874 if (rv != SCARD_S_SUCCESS)
2875 goto end;
2876
2877 dwReadersLen = 0;
2878 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2879 if (readerStates[i].readerName[0] != '\0')
2880 dwReadersLen += strlen(readerStates[i].readerName) + 1;
2881
2882 /* for the last NULL byte */
2883 dwReadersLen += 1;
2884
2885 if (1 == dwReadersLen)
2886 {
2888 goto end;
2889 }
2890
2891 if (SCARD_AUTOALLOCATE == *pcchReaders)
2892 {
2893 if (NULL == mszReaders)
2894 {
2896 goto end;
2897 }
2898 buf = malloc(dwReadersLen);
2899 if (NULL == buf)
2900 {
2901 rv = SCARD_E_NO_MEMORY;
2902 goto end;
2903 }
2904 *(char **)mszReaders = buf;
2905 }
2906 else
2907 {
2908 buf = mszReaders;
2909
2910 /* not enough place to store the reader names */
2911 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2912 {
2914 goto end;
2915 }
2916 }
2917
2918 if (mszReaders == NULL) /* text array not allocated */
2919 goto end;
2920
2921 for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2922 {
2923 if (readerStates[i].readerName[0] != '\0')
2924 {
2925 /*
2926 * Build the multi-string
2927 */
2928 strcpy(buf, readerStates[i].readerName);
2929 buf += strlen(readerStates[i].readerName)+1;
2930 }
2931 }
2932 *buf = '\0'; /* Add the last null */
2933
2934end:
2935 /* set the reader names length */
2936 *pcchReaders = dwReadersLen;
2937
2938 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
2939
2940 PROFILE_END(rv)
2941 API_TRACE_OUT("%d", *pcchReaders)
2942
2943 return rv;
2944}
2945
2959LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
2960{
2961 LONG rv = SCARD_S_SUCCESS;
2962
2963 PROFILE_START
2964
2965 /*
2966 * Make sure this context has been opened
2967 */
2968 if (! SCardGetContextValidity(hContext))
2970
2971 free((void *)pvMem);
2972
2973 PROFILE_END(rv)
2974
2975 return rv;
2976}
2977
3029LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
3030 LPDWORD pcchGroups)
3031{
3032 LONG rv = SCARD_S_SUCCESS;
3033 SCONTEXTMAP * currentContextMap;
3034 char *buf = NULL;
3035
3036 PROFILE_START
3037
3038 /* Multi-string with two trailing \0 */
3039 const char ReaderGroup[] = "SCard$DefaultReaders\0";
3040 const unsigned int dwGroups = sizeof(ReaderGroup);
3041
3042 /*
3043 * Make sure this context has been opened
3044 */
3045 currentContextMap = SCardGetAndLockContext(hContext);
3046 if (NULL == currentContextMap)
3048
3049 if (SCARD_AUTOALLOCATE == *pcchGroups)
3050 {
3051 if (NULL == mszGroups)
3052 {
3054 goto end;
3055 }
3056 buf = malloc(dwGroups);
3057 if (NULL == buf)
3058 {
3059 rv = SCARD_E_NO_MEMORY;
3060 goto end;
3061 }
3062 *(char **)mszGroups = buf;
3063 }
3064 else
3065 {
3066 buf = mszGroups;
3067
3068 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3069 {
3071 goto end;
3072 }
3073 }
3074
3075 if (buf)
3076 memcpy(buf, ReaderGroup, dwGroups);
3077
3078end:
3079 *pcchGroups = dwGroups;
3080
3081 (void)pthread_mutex_unlock(&currentContextMap->mMutex);
3082
3083 PROFILE_END(rv)
3084
3085 return rv;
3086}
3087
3120{
3121 SCONTEXTMAP * currentContextMap;
3122 LONG rv = SCARD_S_SUCCESS;
3123 uint32_t dwClientID = 0;
3124 struct cancel_struct scCancelStruct;
3125 char cancellable;
3126
3127 PROFILE_START
3128 API_TRACE_IN("%ld", hContext)
3129
3130 /*
3131 * Make sure this context has been opened
3132 */
3133 (void)SCardLockThread();
3134 currentContextMap = SCardGetContextTH(hContext);
3135
3136 if (NULL == currentContextMap)
3137 {
3138 (void)SCardUnlockThread();
3140 goto error;
3141 }
3142 cancellable = currentContextMap->cancellable;
3143 (void)SCardUnlockThread();
3144
3145 if (! cancellable)
3146 {
3147 rv = SCARD_S_SUCCESS;
3148 goto error;
3149 }
3150
3151 /* create a new connection to the server */
3152 if (ClientSetupSession(&dwClientID) != 0)
3153 {
3154 rv = SCARD_E_NO_SERVICE;
3155 goto error;
3156 }
3157
3158 scCancelStruct.hContext = hContext;
3159 scCancelStruct.rv = SCARD_S_SUCCESS;
3160
3161 rv = MessageSendWithHeader(SCARD_CANCEL, dwClientID,
3162 sizeof(scCancelStruct), (void *) &scCancelStruct);
3163
3164 if (rv != SCARD_S_SUCCESS)
3165 goto end;
3166
3167 /*
3168 * Read a message from the server
3169 */
3170 rv = MessageReceive(&scCancelStruct, sizeof(scCancelStruct), dwClientID);
3171
3172 if (rv != SCARD_S_SUCCESS)
3173 goto end;
3174
3175 rv = scCancelStruct.rv;
3176end:
3177 ClientCloseSession(dwClientID);
3178
3179error:
3180 PROFILE_END(rv)
3181 API_TRACE_OUT("")
3182
3183 return rv;
3184}
3185
3210{
3211 LONG rv;
3212
3213 PROFILE_START
3214 API_TRACE_IN("%ld", hContext)
3215
3216 rv = SCARD_S_SUCCESS;
3217
3218 /*
3219 * Make sure this context has been opened
3220 */
3221 if (! SCardGetContextValidity(hContext))
3223
3224 PROFILE_END(rv)
3225 API_TRACE_OUT("")
3226
3227 return rv;
3228}
3229
3246static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3247{
3248 int lrv;
3249 SCONTEXTMAP * newContextMap;
3250
3251 newContextMap = malloc(sizeof(SCONTEXTMAP));
3252 if (NULL == newContextMap)
3253 return SCARD_E_NO_MEMORY;
3254
3255 Log2(PCSC_LOG_DEBUG, "Allocating new SCONTEXTMAP @%p", newContextMap);
3256 newContextMap->hContext = hContext;
3257 newContextMap->dwClientID = dwClientID;
3258 newContextMap->cancellable = FALSE;
3259
3260 (void)pthread_mutex_init(&newContextMap->mMutex, NULL);
3261
3262 lrv = list_init(&newContextMap->channelMapList);
3263 if (lrv < 0)
3264 {
3265 Log2(PCSC_LOG_CRITICAL, "list_init failed with return value: %d", lrv);
3266 goto error;
3267 }
3268
3269 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3270 CHANNEL_MAP_seeker);
3271 if (lrv <0)
3272 {
3273 Log2(PCSC_LOG_CRITICAL,
3274 "list_attributes_seeker failed with return value: %d", lrv);
3275 list_destroy(&newContextMap->channelMapList);
3276 goto error;
3277 }
3278
3279 lrv = list_append(&contextMapList, newContextMap);
3280 if (lrv < 0)
3281 {
3282 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3283 lrv);
3284 list_destroy(&newContextMap->channelMapList);
3285 goto error;
3286 }
3287
3288 return SCARD_S_SUCCESS;
3289
3290error:
3291
3292 (void)pthread_mutex_destroy(&newContextMap->mMutex);
3293 free(newContextMap);
3294
3295 return SCARD_E_NO_MEMORY;
3296}
3297
3315{
3316 SCONTEXTMAP * currentContextMap;
3317
3319 currentContextMap = SCardGetContextTH(hContext);
3320
3321 /* lock the context (if available) */
3322 if (NULL != currentContextMap)
3323 (void)pthread_mutex_lock(&currentContextMap->mMutex);
3324
3326
3327 return currentContextMap;
3328}
3329
3343{
3344 return list_seek(&contextMapList, &hContext);
3345}
3346
3354{
3355 SCONTEXTMAP * currentContextMap;
3356 currentContextMap = SCardGetContextTH(hContext);
3357
3358 if (NULL != currentContextMap)
3359 SCardCleanContext(currentContextMap);
3360}
3361
3362static void SCardCleanContext(SCONTEXTMAP * targetContextMap)
3363{
3364 int list_index, lrv;
3365 int listSize;
3366 CHANNEL_MAP * currentChannelMap;
3367
3368 targetContextMap->hContext = 0;
3369 ClientCloseSession(targetContextMap->dwClientID);
3370 targetContextMap->dwClientID = 0;
3371 (void)pthread_mutex_destroy(&targetContextMap->mMutex);
3372
3373 listSize = list_size(&targetContextMap->channelMapList);
3374 for (list_index = 0; list_index < listSize; list_index++)
3375 {
3376 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3377 list_index);
3378 if (NULL == currentChannelMap)
3379 {
3380 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3381 list_index);
3382 continue;
3383 }
3384 else
3385 {
3386 free(currentChannelMap->readerName);
3387 free(currentChannelMap);
3388 }
3389
3390 }
3391 list_destroy(&targetContextMap->channelMapList);
3392
3393 lrv = list_delete(&contextMapList, targetContextMap);
3394 if (lrv < 0)
3395 {
3396 Log2(PCSC_LOG_CRITICAL,
3397 "list_delete failed with return value: %d", lrv);
3398 }
3399
3400 free(targetContextMap);
3401
3402 return;
3403}
3404
3405/*
3406 * Functions for managing hCard values returned from SCardConnect.
3407 */
3408
3409static LONG SCardAddHandle(SCARDHANDLE hCard, SCONTEXTMAP * currentContextMap,
3410 LPCSTR readerName)
3411{
3412 CHANNEL_MAP * newChannelMap;
3413 int lrv = -1;
3414
3415 newChannelMap = malloc(sizeof(CHANNEL_MAP));
3416 if (NULL == newChannelMap)
3417 return SCARD_E_NO_MEMORY;
3418
3419 newChannelMap->hCard = hCard;
3420 newChannelMap->readerName = strdup(readerName);
3421
3422 lrv = list_append(&currentContextMap->channelMapList, newChannelMap);
3423 if (lrv < 0)
3424 {
3425 free(newChannelMap->readerName);
3426 free(newChannelMap);
3427 Log2(PCSC_LOG_CRITICAL, "list_append failed with return value: %d",
3428 lrv);
3429 return SCARD_E_NO_MEMORY;
3430 }
3431
3432 return SCARD_S_SUCCESS;
3433}
3434
3435static void SCardRemoveHandle(SCARDHANDLE hCard)
3436{
3437 SCONTEXTMAP * currentContextMap;
3438 CHANNEL_MAP * currentChannelMap;
3439 int lrv;
3440 LONG rv;
3441
3442 rv = SCardGetContextAndChannelFromHandleTH(hCard, &currentContextMap,
3443 &currentChannelMap);
3444 if (rv == -1)
3445 return;
3446
3447 free(currentChannelMap->readerName);
3448
3449 lrv = list_delete(&currentContextMap->channelMapList, currentChannelMap);
3450 if (lrv < 0)
3451 {
3452 Log2(PCSC_LOG_CRITICAL,
3453 "list_delete failed with return value: %d", lrv);
3454 }
3455
3456 free(currentChannelMap);
3457
3458 return;
3459}
3460
3461static LONG SCardGetContextChannelAndLockFromHandle(SCARDHANDLE hCard,
3462 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3463{
3464 LONG rv;
3465
3466 if (0 == hCard)
3467 return -1;
3468
3470 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3471 targetChannelMap);
3472
3473 if (SCARD_S_SUCCESS == rv)
3474 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3475
3477
3478 return rv;
3479}
3480
3481static LONG SCardGetContextAndChannelFromHandleTH(SCARDHANDLE hCard,
3482 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3483{
3484 int listSize;
3485 int list_index;
3486 SCONTEXTMAP * currentContextMap;
3487 CHANNEL_MAP * currentChannelMap;
3488
3489 /* Best to get the caller a crash early if we fail unsafely */
3490 *targetContextMap = NULL;
3491 *targetChannelMap = NULL;
3492
3493 listSize = list_size(&contextMapList);
3494
3495 for (list_index = 0; list_index < listSize; list_index++)
3496 {
3497 currentContextMap = list_get_at(&contextMapList, list_index);
3498 if (currentContextMap == NULL)
3499 {
3500 Log2(PCSC_LOG_CRITICAL, "list_get_at failed for index %d",
3501 list_index);
3502 continue;
3503 }
3504 currentChannelMap = list_seek(&currentContextMap->channelMapList,
3505 &hCard);
3506 if (currentChannelMap != NULL)
3507 {
3508 *targetContextMap = currentContextMap;
3509 *targetChannelMap = currentChannelMap;
3510 return SCARD_S_SUCCESS;
3511 }
3512 }
3513
3514 return -1;
3515}
3516
3525{
3526 LONG rv;
3527 struct stat statBuffer;
3528 char *socketName;
3529
3530 socketName = getSocketName();
3531 rv = stat(socketName, &statBuffer);
3532
3533 if (rv != 0)
3534 {
3535 Log3(PCSC_LOG_INFO, "PCSC Not Running: %s: %s",
3536 socketName, strerror(errno));
3537 return SCARD_E_NO_SERVICE;
3538 }
3539
3540 return SCARD_S_SUCCESS;
3541}
3542
3543static LONG getReaderStates(SCONTEXTMAP * currentContextMap)
3544{
3545 int32_t dwClientID = currentContextMap->dwClientID;
3546 LONG rv;
3547
3548 rv = MessageSendWithHeader(CMD_GET_READERS_STATE, dwClientID, 0, NULL);
3549 if (rv != SCARD_S_SUCCESS)
3550 return rv;
3551
3552 /* Read a message from the server */
3553 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3554 if (rv != SCARD_S_SUCCESS)
3555 return rv;
3556
3557 return SCARD_S_SUCCESS;
3558}
3559
3560static LONG getReaderStatesAndRegisterForEvents(SCONTEXTMAP * currentContextMap)
3561{
3562 int32_t dwClientID = currentContextMap->dwClientID;
3563 LONG rv;
3564
3565 /* Get current reader states from server and register on event list */
3567 0, NULL);
3568 if (rv != SCARD_S_SUCCESS)
3569 return rv;
3570
3571 /* Read a message from the server */
3572 rv = MessageReceive(&readerStates, sizeof(readerStates), dwClientID);
3573 return rv;
3574}
3575
3576static LONG unregisterFromEvents(SCONTEXTMAP * currentContextMap)
3577{
3578 int32_t dwClientID = currentContextMap->dwClientID;
3579 LONG rv;
3580 struct wait_reader_state_change waitStatusStruct = {0};
3581
3582 /* ask server to remove us from the event list */
3584 dwClientID, 0, NULL);
3585 if (rv != SCARD_S_SUCCESS)
3586 return rv;
3587
3588 /* This message can be the response to
3589 * CMD_STOP_WAITING_READER_STATE_CHANGE, an event notification or a
3590 * cancel notification.
3591 * The server side ensures, that no more messages will be sent to
3592 * the client. */
3593
3594 rv = MessageReceive(&waitStatusStruct, sizeof(waitStatusStruct),
3595 dwClientID);
3596 if (rv != SCARD_S_SUCCESS)
3597 return rv;
3598
3599 /* if we received a cancel event the return value will be set
3600 * accordingly */
3601 rv = waitStatusStruct.rv;
3602
3603 return rv;
3604}
3605
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