2
* MUSCLE SmartCard Development ( http://www.linuxnet.com )
4
* Copyright (C) 2001-2004
5
* David Corcoran <corcoran@linuxnet.com>
6
* Damien Sauveron <damien.sauveron@labri.fr>
7
* Ludovic Rousseau <ludovic.rousseau@free.fr>
9
* $Id: winscard_svc.c 1695 2005-10-29 16:27:33Z rousseau $
14
* @brief This demarshalls functions over the message queue and keeps
15
* track of clients and their handles.
17
* Each Client message is deald by creating a thread (\c CreateContextThread).
18
* The thread establishes reands and demarshalls the message and calls the
19
* appropriate function to threat it.
30
#include "winscard_msg.h"
31
#include "winscard_svc.h"
32
#include "sys_generic.h"
33
#include "thread_generic.h"
36
* @brief Represents the an Application Context on the Server side.
38
* An Application Context contains Channels (\c hCard).
40
static struct _psContext
42
SCARDCONTEXT hContext;
43
SCARDHANDLE hCard[PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS];
44
DWORD dwClientID; /* Connection ID used to reference the Client. */
45
PCSCLITE_THREAD_T pthThread; /* Event polling thread's ID */
46
sharedSegmentMsg msgStruct; /* Msg sent by the Client */
47
int protocol_major, protocol_minor; /* Protocol number agreed between client and server*/
48
} psContext[PCSCLITE_MAX_APPLICATIONS_CONTEXTS];
51
* @brief Index of an avaiable Application Context slot in \c psContext.
53
static DWORD dwNextContextIndex;
55
LONG MSGCheckHandleAssociation(SCARDHANDLE, DWORD);
56
LONG MSGFunctionDemarshall(psharedSegmentMsg, DWORD);
57
LONG MSGAddContext(SCARDCONTEXT, DWORD);
58
LONG MSGRemoveContext(SCARDCONTEXT, DWORD);
59
LONG MSGAddHandle(SCARDCONTEXT, SCARDHANDLE, DWORD);
60
LONG MSGRemoveHandle(SCARDHANDLE, DWORD);
61
LONG MSGCleanupClient(DWORD);
63
static void ContextThread(DWORD* pdwIndex);
65
LONG ContextsInitialize(void)
67
memset(psContext, 0, sizeof(struct _psContext)*PCSCLITE_MAX_APPLICATIONS_CONTEXTS);
72
* @brief Creates threads to handle messages received from Clients.
74
* @param[in] pdwClientID Connection ID used to reference the Client.
77
* @retval SCARD_S_SUCCESS Success.
78
* @retval SCARD_F_INTERNAL_ERROR Exceded the maximum number of simultaneous Application Contexts.
79
* @retval SCARD_E_NO_MEMORY Error creating the Context Thread.
81
LONG CreateContextThread(PDWORD pdwClientID)
85
for (i = 0; i < PCSCLITE_MAX_APPLICATIONS_CONTEXTS; i++)
87
if (psContext[i].dwClientID == 0)
89
psContext[i].dwClientID = *pdwClientID;
95
if (i == PCSCLITE_MAX_APPLICATIONS_CONTEXTS)
97
SYS_CloseFile(psContext[i].dwClientID);
98
psContext[i].dwClientID = 0;
99
return SCARD_F_INTERNAL_ERROR;
102
dwNextContextIndex = i;
104
if (SYS_ThreadCreate(&psContext[i].pthThread, THREAD_ATTR_DETACHED,
105
(PCSCLITE_THREAD_FUNCTION( )) ContextThread,
106
(LPVOID) &dwNextContextIndex) != 1)
108
SYS_CloseFile(psContext[i].dwClientID);
109
psContext[i].dwClientID = 0;
110
return SCARD_E_NO_MEMORY;
113
return SCARD_S_SUCCESS;
117
* A list of local functions used to keep track of clients and their
122
* @brief Handles messages received from Clients.
124
* For each Client message a new instance of this thread is created.
126
* @param[in] pdwIndex Index of an avaiable Application Context slot in
129
static void ContextThread(DWORD* pdwIndex)
132
sharedSegmentMsg msgStruct;
133
DWORD dwContextIndex = *pdwIndex;
135
Log2(PCSC_LOG_DEBUG, "Thread is started: %d",
136
psContext[dwContextIndex].dwClientID);
140
switch (rv = SHMProcessEventsContext(&psContext[dwContextIndex].dwClientID, &msgStruct, 0))
143
if (msgStruct.mtype == CMD_CLIENT_DIED)
146
* Clean up the dead client
148
Log2(PCSC_LOG_DEBUG, "Client die: %d",
149
psContext[dwContextIndex].dwClientID);
150
MSGCleanupClient(dwContextIndex);
151
SYS_ThreadExit((LPVOID) NULL);
156
if (msgStruct.mtype == CMD_FUNCTION)
159
* Command must be found
161
MSGFunctionDemarshall(&msgStruct, dwContextIndex);
162
rv = SHMMessageSend(&msgStruct, psContext[dwContextIndex].dwClientID,
163
PCSCLITE_SERVER_ATTEMPTS);
166
/* pcsc-lite client/server protocol version */
167
if (msgStruct.mtype == CMD_VERSION)
169
version_struct *veStr;
170
veStr = (version_struct *) msgStruct.data;
172
/* get the client protocol version */
173
psContext[dwContextIndex].protocol_major = veStr->major;
174
psContext[dwContextIndex].protocol_minor = veStr->minor;
177
"Client is protocol version %d:%d",
178
veStr->major, veStr->minor);
180
/* set the server protocol version */
181
veStr->major = PROTOCOL_VERSION_MAJOR;
182
veStr->minor = PROTOCOL_VERSION_MINOR;
183
veStr->rv = SCARD_S_SUCCESS;
185
/* send back the response */
186
rv = SHMMessageSend(&msgStruct,
187
psContext[dwContextIndex].dwClientID,
188
PCSCLITE_SERVER_ATTEMPTS);
197
* timeout in SHMProcessEventsContext(): do nothing
198
* this is used to catch the Ctrl-C signal at some time when
199
* nothing else happens
204
Log1(PCSC_LOG_ERROR, "Error in SHMProcessEventsContext");
209
"SHMProcessEventsContext unknown retval: %d", rv);
216
* @brief Find out which message was sent by the Client and execute the right task.
218
* According to the command type sent by the client (\c pcsc_msg_commands),
219
* cast the message data to the correct struct so that is can be demarshalled.
220
* Then call the appropriate function to handle the request.
222
* Possible structs are: \c establish_struct \c release_struct
223
* \c connect_struct \c reconnect_struct \c disconnect_struct \c begin_struct
224
* \c cancel_struct \c end_struct \c status_struct \c transmit_struct
225
* \c control_struct \c getset_struct.
227
* @param[in] msgStruct Message to be demarshalled and executed.
228
* @param[in] dwContextIndex
230
LONG MSGFunctionDemarshall(psharedSegmentMsg msgStruct, DWORD dwContextIndex)
233
establish_struct *esStr;
234
release_struct *reStr;
235
connect_struct *coStr;
236
reconnect_struct *rcStr;
237
disconnect_struct *diStr;
239
cancel_struct *caStr;
241
status_struct *stStr;
242
transmit_struct *trStr;
243
control_struct *ctStr;
244
getset_struct *gsStr;
247
* Zero out everything
250
switch (msgStruct->command)
253
case SCARD_ESTABLISH_CONTEXT:
254
esStr = ((establish_struct *) msgStruct->data);
255
esStr->rv = SCardEstablishContext(esStr->dwScope, 0, 0,
258
if (esStr->rv == SCARD_S_SUCCESS)
260
MSGAddContext(esStr->phContext, dwContextIndex);
263
case SCARD_RELEASE_CONTEXT:
264
reStr = ((release_struct *) msgStruct->data);
265
reStr->rv = SCardReleaseContext(reStr->hContext);
267
if (reStr->rv == SCARD_S_SUCCESS)
269
MSGRemoveContext(reStr->hContext, dwContextIndex);
274
coStr = ((connect_struct *) msgStruct->data);
275
coStr->rv = SCardConnect(coStr->hContext, coStr->szReader,
276
coStr->dwShareMode, coStr->dwPreferredProtocols,
277
&coStr->phCard, &coStr->pdwActiveProtocol);
279
if (coStr->rv == SCARD_S_SUCCESS)
281
MSGAddHandle(coStr->hContext, coStr->phCard, dwContextIndex);
285
case SCARD_RECONNECT:
286
rcStr = ((reconnect_struct *) msgStruct->data);
287
rv = MSGCheckHandleAssociation(rcStr->hCard, dwContextIndex);
288
if (rv != 0) return rv;
290
rcStr->rv = SCardReconnect(rcStr->hCard, rcStr->dwShareMode,
291
rcStr->dwPreferredProtocols,
292
rcStr->dwInitialization, &rcStr->pdwActiveProtocol);
295
case SCARD_DISCONNECT:
296
diStr = ((disconnect_struct *) msgStruct->data);
297
rv = MSGCheckHandleAssociation(diStr->hCard, dwContextIndex);
298
if (rv != 0) return rv;
299
diStr->rv = SCardDisconnect(diStr->hCard, diStr->dwDisposition);
301
if (diStr->rv == SCARD_S_SUCCESS)
303
MSGRemoveHandle(diStr->hCard, dwContextIndex);
306
case SCARD_BEGIN_TRANSACTION:
307
beStr = ((begin_struct *) msgStruct->data);
308
rv = MSGCheckHandleAssociation(beStr->hCard, dwContextIndex);
309
if (rv != 0) return rv;
310
beStr->rv = SCardBeginTransaction(beStr->hCard);
313
case SCARD_END_TRANSACTION:
314
enStr = ((end_struct *) msgStruct->data);
315
rv = MSGCheckHandleAssociation(enStr->hCard, dwContextIndex);
316
if (rv != 0) return rv;
318
SCardEndTransaction(enStr->hCard, enStr->dwDisposition);
321
case SCARD_CANCEL_TRANSACTION:
322
caStr = ((cancel_struct *) msgStruct->data);
323
rv = MSGCheckHandleAssociation(caStr->hCard, dwContextIndex);
324
if (rv != 0) return rv;
325
caStr->rv = SCardCancelTransaction(caStr->hCard);
329
stStr = ((status_struct *) msgStruct->data);
330
rv = MSGCheckHandleAssociation(stStr->hCard, dwContextIndex);
331
if (rv != 0) return rv;
332
stStr->rv = SCardStatus(stStr->hCard, stStr->mszReaderNames,
333
&stStr->pcchReaderLen, &stStr->pdwState,
334
&stStr->pdwProtocol, stStr->pbAtr, &stStr->pcbAtrLen);
338
trStr = ((transmit_struct *) msgStruct->data);
339
rv = MSGCheckHandleAssociation(trStr->hCard, dwContextIndex);
340
if (rv != 0) return rv;
341
trStr->rv = SCardTransmit(trStr->hCard, &trStr->pioSendPci,
342
trStr->pbSendBuffer, trStr->cbSendLength,
343
&trStr->pioRecvPci, trStr->pbRecvBuffer,
344
&trStr->pcbRecvLength);
348
ctStr = ((control_struct *) msgStruct->data);
349
rv = MSGCheckHandleAssociation(ctStr->hCard, dwContextIndex);
350
if (rv != 0) return rv;
351
ctStr->rv = SCardControl(ctStr->hCard, ctStr->dwControlCode,
352
ctStr->pbSendBuffer, ctStr->cbSendLength,
353
ctStr->pbRecvBuffer, ctStr->cbRecvLength,
354
&ctStr->dwBytesReturned);
357
case SCARD_GET_ATTRIB:
358
gsStr = ((getset_struct *) msgStruct->data);
359
rv = MSGCheckHandleAssociation(gsStr->hCard, dwContextIndex);
360
if (rv != 0) return rv;
361
gsStr->rv = SCardGetAttrib(gsStr->hCard, gsStr->dwAttrId,
362
gsStr->pbAttr, &gsStr->cbAttrLen);
365
case SCARD_SET_ATTRIB:
366
gsStr = ((getset_struct *) msgStruct->data);
367
rv = MSGCheckHandleAssociation(gsStr->hCard, dwContextIndex);
368
if (rv != 0) return rv;
369
gsStr->rv = SCardSetAttrib(gsStr->hCard, gsStr->dwAttrId,
370
gsStr->pbAttr, gsStr->cbAttrLen);
380
LONG MSGAddContext(SCARDCONTEXT hContext, DWORD dwContextIndex)
382
psContext[dwContextIndex].hContext = hContext;
383
return SCARD_S_SUCCESS;
386
LONG MSGRemoveContext(SCARDCONTEXT hContext, DWORD dwContextIndex)
391
if (psContext[dwContextIndex].hContext == hContext)
394
for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
397
* Disconnect each of these just in case
400
if (psContext[dwContextIndex].hCard[i] != 0)
404
* We will use SCardStatus to see if the card has been
405
* reset there is no need to reset each time
406
* Disconnect is called
409
rv = SCardStatus(psContext[dwContextIndex].hCard[i], 0, 0, 0, 0, 0, 0);
411
if (rv == SCARD_W_RESET_CARD
412
|| rv == SCARD_W_REMOVED_CARD)
414
SCardDisconnect(psContext[dwContextIndex].hCard[i], SCARD_LEAVE_CARD);
417
SCardDisconnect(psContext[dwContextIndex].hCard[i], SCARD_RESET_CARD);
420
psContext[dwContextIndex].hCard[i] = 0;
425
psContext[dwContextIndex].hContext = 0;
426
return SCARD_S_SUCCESS;
429
return SCARD_E_INVALID_VALUE;
432
LONG MSGAddHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard, DWORD dwContextIndex)
436
if (psContext[dwContextIndex].hContext == hContext)
440
* Find an empty spot to put the hCard value
442
for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
444
if (psContext[dwContextIndex].hCard[i] == 0)
446
psContext[dwContextIndex].hCard[i] = hCard;
451
if (i == PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS)
453
return SCARD_F_INTERNAL_ERROR;
456
return SCARD_S_SUCCESS;
461
return SCARD_E_INVALID_VALUE;
464
LONG MSGRemoveHandle(SCARDHANDLE hCard, DWORD dwContextIndex)
468
for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
470
if (psContext[dwContextIndex].hCard[i] == hCard)
472
psContext[dwContextIndex].hCard[i] = 0;
473
return SCARD_S_SUCCESS;
477
return SCARD_E_INVALID_VALUE;
481
LONG MSGCheckHandleAssociation(SCARDHANDLE hCard, DWORD dwContextIndex)
485
for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
487
if (psContext[dwContextIndex].hCard[i] == hCard)
493
/* Must be a rogue client, debug log and sleep a couple of seconds */
494
Log1(PCSC_LOG_ERROR, "Client failed to authenticate");
500
LONG MSGCleanupClient(DWORD dwContextIndex)
502
if (psContext[dwContextIndex].hContext != 0)
504
SCardReleaseContext(psContext[dwContextIndex].hContext);
505
MSGRemoveContext(psContext[dwContextIndex].hContext, dwContextIndex);
508
psContext[dwContextIndex].dwClientID = 0;
509
psContext[dwContextIndex].protocol_major = 0;
510
psContext[dwContextIndex].protocol_minor = 0;