1/*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All Rights Reserved.
3 * The contents of this file constitute Original Code as defined in and are
4 * subject to the Apple Public Source License Version 1.2 (the 'License').
5 * You may not use this file except in compliance with the License. Please
6 * obtain a copy of the License at http://www.apple.com/publicsource and
7 * read it before using this file.
8 *
9 * This Original Code and all software distributed under the License are
10 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
11 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
12 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
13 * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
14 * see the License for the specific language governing rights and
15 * limitations under the License.
16 */
17
18/******************************************************************
19
20        MUSCLE SmartCard Development ( http://www.linuxnet.com )
21            Title  : musclecard.c
22            Package: MuscleCard Framework
23            Author : David Corcoran
24            Date   : 09/26/01
25            License: Copyright (C) 2001-2002 David Corcoran
26                     <corcoran@linuxnet.com>
27            Purpose: This loads MuscleCard plug-ins and provides
28	    functions for applications.
29
30	    You may not remove this header from this file without
31	    prior permission from the author.
32
33********************************************************************/
34
35#ifndef WIN32
36#include "config.h"
37#else
38#include "../win32/win32_config.h"
39#endif
40
41#include "musclecard.h"
42#include "tokenfactory.h"
43#include "debuglog.h"
44
45#ifdef USE_THREAD_SAFETY
46#ifndef WIN32
47#include "wintypes.h"
48#endif
49#include "thread_generic.h"
50#include "sys_generic.h"
51#endif
52
53#ifdef USE_THREAD_SAFETY
54static PCSCLITE_MUTEX mcardMutex = PTHREAD_MUTEX_INITIALIZER;
55#endif
56
57#include <string.h>
58#include <stdlib.h>
59#include <stdio.h>
60
61static SCARDCONTEXT localHContext = 0;
62
63#ifdef USE_THREAD_SAFETY
64static PCSCLITE_THREAD_T callbackThread;
65#endif
66
67/*
68 * internal function
69 */
70MSC_RV pcscToMSC(MSCLong32);
71MSC_RV MSCReEstablishConnection(MSCLPTokenConnection);
72
73void mscLockThread()
74{
75#ifdef USE_THREAD_SAFETY
76	SYS_MutexLock(&mcardMutex);
77#endif
78}
79
80void mscUnLockThread()
81{
82#ifdef USE_THREAD_SAFETY
83	SYS_MutexUnLock(&mcardMutex);
84#endif
85}
86
87/**************** MSC Connection Functions **************************/
88
89MSC_RV MSCListTokens(MSCULong32 listScope, MSCLPTokenInfo tokenArray,
90		     MSCPULong32 arrayLength)
91{
92
93	MSCLong32 rv;
94	SCARD_READERSTATE_A rgReaderStates;
95	MSCTokenInfo tokenInfo;
96	MSCLPTokenInfo currentToken;
97	MSCULong32 tokensFound;
98	MSCULong32 readerLength;
99	char *readerList;
100	int i, strLoc;
101
102	readerLength = 0;
103	tokensFound = 0;
104	readerList = 0;
105	strLoc = 0;
106	i = 0;
107
108	if (arrayLength == 0)
109		return MSC_INVALID_PARAMETER;
110	if (listScope != MSC_LIST_KNOWN &&
111		listScope != MSC_LIST_ALL && listScope != MSC_LIST_SLOTS)
112	{
113		return MSC_INVALID_PARAMETER;
114	}
115
116	mscLockThread();
117	if (localHContext == 0)
118	{
119		rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, 0, 0,
120			&localHContext);
121		if (pcscToMSC(rv) != MSC_SUCCESS)
122		{
123			localHContext = 0;
124			mscUnLockThread();
125			return pcscToMSC(rv);
126		}
127	}
128	mscUnLockThread();
129
130	/*
131	 * Get the reader list size
132	 */
133	rv = SCardListReaders(localHContext, 0, readerList, &readerLength);
134
135	if (pcscToMSC(rv) != MSC_SUCCESS)
136	{
137		return pcscToMSC(rv);
138	}
139
140	readerList = (char *) malloc(sizeof(char) * readerLength);
141
142	if (readerList == 0)
143	{
144		return MSC_INTERNAL_ERROR;
145	}
146
147	rv = SCardListReaders(localHContext, 0, readerList, &readerLength);
148
149	/*
150	 * Now that we have the readers, lets check their status
151	 */
152	for (i = 0; i < readerLength - 1; i++)
153	{
154		rgReaderStates.szReader = &readerList[i];
155		rgReaderStates.dwCurrentState = SCARD_STATE_UNAWARE;
156
157		rv = SCardGetStatusChange(localHContext, INFINITE,
158					  &rgReaderStates,
159					  1);
160
161		if (pcscToMSC(rv) != MSC_SUCCESS)
162		{
163			if (readerList)
164				free(readerList);
165			return pcscToMSC(rv);
166		}
167
168		/*
169		 * We only care about slots with a token unless stated
170		 */
171		if ((rgReaderStates.dwEventState & SCARD_STATE_PRESENT) ||
172			(listScope == MSC_LIST_SLOTS))
173		{
174
175			if (rgReaderStates.dwEventState & SCARD_STATE_PRESENT)
176			{
177				/*
178				 * We only care about supported tokens
179				 */
180				rv = TPSearchBundlesForAtr(rgReaderStates.rgbAtr,
181					rgReaderStates.cbAtr, &tokenInfo);
182			}
183
184			/*
185			 * Success for this function
186			 */
187			if ((rv == 0) || (listScope == MSC_LIST_SLOTS) ||
188				(listScope == MSC_LIST_ALL))
189			{
190
191				/*
192				 * We found something interesting to the application
193				 */
194				tokensFound += 1;
195
196				if ((tokensFound <= *arrayLength) && (tokenArray != 0))
197				{
198					currentToken = &tokenArray[tokensFound - 1];
199					currentToken->addParams     = 0;
200					currentToken->addParamsSize = 0;
201                                        currentToken->tokenType     = 0;  /* Vinnie 1693 */
202
203					if (rgReaderStates.dwEventState & SCARD_STATE_EMPTY)
204					{
205						currentToken->tokenType |= MSC_TOKEN_TYPE_REMOVED;
206						strncpy(currentToken->tokenName,
207							MSC_TOKEN_EMPTY_STR, MSC_MAXSIZE_TOKENAME);
208					} else if (rv == 0)
209					{
210						currentToken->tokenType |= MSC_TOKEN_TYPE_KNOWN;
211						strncpy(currentToken->tokenName,
212							tokenInfo.tokenName, MSC_MAXSIZE_TOKENAME);
213					} else
214					{
215						currentToken->tokenType |= MSC_TOKEN_TYPE_UNKNOWN;
216						strncpy(currentToken->tokenName,
217							MSC_TOKEN_UNKNOWN_STR, MSC_MAXSIZE_TOKENAME);
218					}
219
220					strncpy(currentToken->slotName,
221						rgReaderStates.szReader, MAX_READERNAME);
222
223					if (rgReaderStates.dwEventState & SCARD_STATE_PRESENT)
224					{
225						memcpy(currentToken->tokenId,
226							rgReaderStates.rgbAtr, rgReaderStates.cbAtr);
227						currentToken->tokenIdLength = rgReaderStates.cbAtr;
228					}
229					else
230					{
231						memset(currentToken->tokenId, 0x00, MAX_ATR_SIZE);
232						currentToken->tokenIdLength = 0x00;
233					}
234
235					if (rv == 0)
236					{
237						memcpy(currentToken->tokenApp,
238							tokenInfo.tokenApp, tokenInfo.tokenAppLen);
239							currentToken->tokenAppLen = tokenInfo.tokenAppLen;
240
241						strncpy(currentToken->svProvider,
242							tokenInfo.svProvider, MSC_MAXSIZE_SVCPROV);
243					} else
244					{
245						memset(currentToken->tokenApp, 0x00, MSC_MAXSIZE_AID);
246						currentToken->tokenAppLen = 0x00;
247						memset(currentToken->svProvider, 0x00, MSC_MAXSIZE_SVCPROV);
248					}
249
250					currentToken->tokenState = rgReaderStates.dwEventState;
251
252				}
253			}
254			/*
255			 * End of TPSearch success
256			 */
257		}
258		/*
259		 * End of if token present
260		 */
261		while (readerList[++i] != 0) ;
262	}	/* End of for .. readers */
263
264	if (readerList)
265		free(readerList);
266
267	/*
268	 * Application provides null requesting length
269	 */
270	if (tokenArray == 0)
271	{
272		*arrayLength = tokensFound;
273		return MSC_SUCCESS;
274	}
275
276	/*
277	 * Provided length is too small
278	 */
279	if (*arrayLength < tokensFound)
280	{
281		*arrayLength = tokensFound;
282		return MSC_INSUFFICIENT_BUFFER;
283	}
284
285	*arrayLength = tokensFound;
286	return MSC_SUCCESS;
287}
288
289MSC_RV MSCEstablishConnection(MSCLPTokenInfo tokenStruct,
290			      MSCULong32 sharingMode,
291			      MSCPUChar8 applicationName,
292			      MSCULong32 nameSize,
293			      MSCLPTokenConnection pConnection)
294{
295	MSCLong32 rv;
296	MSCULong32 tokenSize;
297	MSCLPTokenInfo tokenList;
298	MSCPVoid32 vInitFunction;
299	MSCPVoid32 vIdFunction;
300	MSCLong32(*libPL_MSCInitializePlugin) (MSCLPTokenConnection);
301	MSCLong32(*libPL_MSCIdentifyToken) (MSCLPTokenConnection);
302	MSCULong32 dwActiveProtocol;
303	int selectedIFD;
304	char slotName[MAX_READERNAME];
305	MSCULong32 slotNameSize, slotState, slotProtocol;
306	MSCUChar8 tokenId[MAX_ATR_SIZE];
307	MSCULong32 tokenIdLength;
308
309	tokenSize = 0;
310	tokenList = 0;
311	tokenSize = 0;
312	selectedIFD = -1;
313	tokenIdLength = sizeof(tokenId);
314	slotState = 0;
315	slotProtocol = 0;
316	slotNameSize = sizeof(slotName);
317	vIdFunction = 0;
318	vInitFunction = 0;
319
320	if (pConnection == NULL)
321		return MSC_INVALID_PARAMETER;
322	if (tokenStruct == NULL)
323		return MSC_INVALID_PARAMETER;
324	if (nameSize > MSC_MAXSIZE_AID)
325		return MSC_INVALID_PARAMETER;
326
327	pConnection->tokenLibHandle = 0;
328	pConnection->hContext = 0;
329	pConnection->tokenInfo.tokenIdLength = 0;
330	pConnection->shareMode = 0;
331
332	/*
333	 * Check the token name strings
334	 */
335	if (sharingMode != MSC_SHARE_DIRECT)
336	{
337		if (strcmp(tokenStruct->tokenName, MSC_TOKEN_EMPTY_STR) == 0)
338		{
339			return MSC_TOKEN_REMOVED;
340		} else if (strcmp(tokenStruct->tokenName,
341				MSC_TOKEN_UNKNOWN_STR) == 0)
342		{
343			return MSC_UNRECOGNIZED_TOKEN;
344		}
345	}
346
347	/*
348	 * Set up the initial connection to the resource manager
349	 */
350
351	mscLockThread();
352	if (localHContext == 0)
353	{
354		rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, 0, 0,
355			&localHContext);
356#ifdef MSC_DEBUG
357		DebugLogB("SCardEstablishContext returns %s\n",
358			pcsc_stringify_error(rv));
359#endif
360		if (pcscToMSC(rv) != MSC_SUCCESS)
361		{
362			localHContext = 0;
363			mscUnLockThread();
364			return pcscToMSC(rv);
365		}
366
367		pConnection->hContext = localHContext;
368	} else
369	{
370		pConnection->hContext = localHContext;
371	}
372	mscUnLockThread();
373
374#ifdef WIN32
375	rv = SCardConnect(pConnection->hContext, tokenStruct->slotName,
376		SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
377		&pConnection->hCard, &dwActiveProtocol);
378#else
379	rv = SCardConnect(pConnection->hContext, tokenStruct->slotName,
380		sharingMode, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
381		&pConnection->hCard, &dwActiveProtocol);
382#endif
383
384#ifdef MSC_DEBUG
385	DebugLogB("SCardConnect returns %s\n", pcsc_stringify_error(rv));
386#endif
387
388	if (pcscToMSC(rv) != MSC_SUCCESS)
389	{
390		return pcscToMSC(rv);
391	}
392
393	/*
394	 * Set the sendPCI value based on the ActiveProtocol
395	 */
396	switch (dwActiveProtocol)
397	{
398	case SCARD_PROTOCOL_T0:
399		pConnection->ioType = SCARD_PCI_T0;
400		break;
401	case SCARD_PROTOCOL_T1:
402		pConnection->ioType = SCARD_PCI_T1;
403		break;
404	default:
405		pConnection->ioType = SCARD_PCI_RAW;
406		break;
407	}
408
409	/*
410	 * Call SCardStatus, make sure the card information matches if it does
411	 * not return an error.  If it does, copy it
412	 */
413
414	rv = SCardStatus(pConnection->hCard, slotName,
415		&slotNameSize, &slotState, &slotProtocol, tokenId, &tokenIdLength);
416
417#ifdef MSC_DEBUG
418	DebugLogB("SCardStatus returns %s\n", pcsc_stringify_error(rv));
419#endif
420
421	if (pcscToMSC(rv) != MSC_SUCCESS)
422	{
423		SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
424		pConnection->hCard = 0;
425		return pcscToMSC(rv);
426	}
427
428	if ((sharingMode == MSC_SHARE_DIRECT) && (slotState & SCARD_ABSENT))
429	{
430
431		/*
432		 * They asked for direct mode and no card is inserted so we are
433		 * done with this
434		 */
435		pConnection->shareMode = sharingMode;
436		return MSC_SUCCESS;
437	}
438
439	if ((tokenIdLength != tokenStruct->tokenIdLength) ||
440		(strcmp(slotName, tokenStruct->slotName) != 0) ||
441		(memcmp(tokenId, tokenStruct->tokenId, tokenIdLength) != 0))
442	{
443	        DebugLogA("Internal inconsistent values, ID, slotName\n");
444		SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
445		pConnection->hCard = 0;
446		return MSC_INCONSISTENT_STATUS;
447	}
448
449	memcpy(pConnection->tokenInfo.tokenId, tokenId, tokenIdLength);
450	pConnection->tokenInfo.tokenIdLength = tokenIdLength;
451	strncpy(pConnection->tokenInfo.slotName, tokenStruct->slotName,
452		MAX_READERNAME);
453	strncpy(pConnection->tokenInfo.tokenName, tokenStruct->tokenName,
454		MSC_MAXSIZE_TOKENAME);
455
456	/*
457	 * Load the library for the token
458	 */
459	rv = TPLoadToken(pConnection);
460
461#ifdef MSC_DEBUG
462	DebugLogB("TPLoadToken returns %s\n", pcsc_stringify_error(rv));
463#endif
464
465	if (rv != SCARD_S_SUCCESS)
466	{
467		SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
468		pConnection->hCard = 0;
469		return pcscToMSC(rv);
470	}
471
472	/*
473	 * Select the AID or initialization routine for the card
474	 */
475	vInitFunction = pConnection->libPointers.pvfInitializePlugin;
476	vIdFunction = pConnection->libPointers.pvfIdentifyToken;
477
478	if (vInitFunction == 0)
479	{
480		DebugLogB("Error: Card service failure: %s\n",
481			"InitializePlugin function missing");
482		SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
483		pConnection->hCard = 0;
484		return MSC_UNSUPPORTED_FEATURE;
485	}
486
487	if (vIdFunction == 0)
488	{
489		DebugLogB("Error: Card service failure: %s\n",
490			"IdentifyToken function missing");
491		SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
492		pConnection->hCard = 0;
493		return MSC_UNSUPPORTED_FEATURE;
494	}
495
496	libPL_MSCInitializePlugin = (MSCLong32(*)(MSCLPTokenConnection))
497		vInitFunction;
498
499	libPL_MSCIdentifyToken = (MSCLong32(*)(MSCLPTokenConnection))
500		vIdFunction;
501
502	rv = (*libPL_MSCInitializePlugin) (pConnection);
503
504	if (rv != MSC_SUCCESS)
505	{
506	        SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
507	        if (pConnection->tokenLibHandle != 0)
508	        {
509		       TPUnloadToken(pConnection);
510		       pConnection->tokenLibHandle = 0;
511	        }
512	        pConnection->hCard = 0;
513	}
514
515	if (sharingMode != MSC_SHARE_DIRECT)
516	{
517
518	        if ((applicationName == 0) || (nameSize == 0))
519	        {
520		        /*
521		         * Use the default AID given by the Info.plist
522		         */
523
524		         rv = (*libPL_MSCIdentifyToken) (pConnection);
525  	        } else
526	        {
527		        pConnection->tokenInfo.tokenAppLen = nameSize;
528		        memcpy(pConnection->tokenInfo.tokenApp,
529			       applicationName, nameSize);
530		        rv = (*libPL_MSCIdentifyToken) (pConnection);
531	        }
532
533#ifdef MSC_DEBUG
534	DebugLogB("MSCIdentifyToken returns %s\n", msc_error(rv));
535#endif
536
537		if (rv != MSC_SUCCESS)
538		{
539			SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
540			if (pConnection->tokenLibHandle != 0)
541			{
542				TPUnloadToken(pConnection);
543				pConnection->tokenLibHandle = 0;
544			}
545			pConnection->hCard = 0;
546
547			if (rv == MSC_SHARING_VIOLATION)
548			{
549				return rv;
550			} else
551			{
552				return MSC_UNRECOGNIZED_TOKEN;
553			}
554		}
555	}
556
557	pConnection->shareMode = sharingMode;
558	return MSC_SUCCESS;
559}
560
561MSC_RV MSCReleaseConnection(MSCLPTokenConnection pConnection,
562			    MSCULong32 endAction)
563{
564
565	MSCLong32 rv = SCARD_S_SUCCESS;
566	MSCLong32(*libPL_MSCFinalizePlugin) (MSCLPTokenConnection);
567	MSCPVoid32 vFunction;
568
569	vFunction = 0;
570
571	if (pConnection == NULL)
572		return MSC_INVALID_PARAMETER;
573	if (pConnection->tokenLibHandle == 0 ||
574		pConnection->hContext == 0 || pConnection->hCard == 0)
575	{
576		return MSC_INVALID_HANDLE;
577	}
578
579	/*
580	 * Select finalization routine for the token plugin
581	 */
582	vFunction = pConnection->libPointers.pvfFinalizePlugin;
583
584	if (vFunction == 0)
585	{
586		DebugLogB("Error: Card service failure: %s\n",
587			"FinalizePlugin function missing");
588		return MSC_INTERNAL_ERROR;
589	}
590
591	libPL_MSCFinalizePlugin = (MSCLong32(*)(MSCLPTokenConnection))
592		vFunction;
593
594	/*
595	 * Stop and clean up the plugin
596	 */
597	rv = (*libPL_MSCFinalizePlugin) (pConnection);
598
599	/*
600	 * Disconnect from the token
601	 */
602	if (pConnection->hCard != 0)
603	{
604		rv = SCardDisconnect(pConnection->hCard, endAction);
605		if (pcscToMSC(rv) != MSC_SUCCESS)
606		{
607			return pcscToMSC(rv);
608		}
609	}
610
611	/*
612	 * Unload the token driver
613	 */
614	if (pConnection->tokenLibHandle != 0)
615	{
616		rv = TPUnloadToken(pConnection);
617		pConnection->tokenLibHandle = 0;
618	}
619
620	pConnection->tokenLibHandle = 0;
621	pConnection->hCard = 0;
622	pConnection->hContext = 0;
623	pConnection->shareMode = 0;
624
625	return MSC_SUCCESS;
626}
627
628MSC_RV MSCWaitForTokenEvent(MSCLPTokenInfo tokenArray,
629			    MSCULong32 arraySize,
630			    MSCULong32 timeoutValue)
631{
632
633	MSCLong32 rv, rt;
634	LPSCARD_READERSTATE_A rgReaderStates;
635	MSCTokenInfo tokenInfo;
636	int i;
637
638	rgReaderStates = 0;
639
640	/*
641	 * Allocate array of SCARD_READERSTATE_A structures, set UNAWARE on
642	 * all of the structures to get the current status and then send them
643	 * to GetStatusChange for blocking event
644	 */
645
646	if (arraySize == 0)
647	{
648		return MSC_SUCCESS;
649	} else if (arraySize > MSC_MAXSIZE_TOKENARRAY)
650	{
651		return MSC_INSUFFICIENT_BUFFER;
652	}
653
654	/*
655	 * Set up the initial connection to the resource manager
656	 */
657
658	mscLockThread();
659	if (localHContext == 0)
660	{
661		rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, 0, 0,
662			&localHContext);
663		if (pcscToMSC(rv) != MSC_SUCCESS)
664		{
665			localHContext = 0;
666			mscUnLockThread();
667			return pcscToMSC(rv);
668		}
669	}
670	mscUnLockThread();
671
672	rgReaderStates = (LPSCARD_READERSTATE_A)
673		malloc(sizeof(SCARD_READERSTATE_A) * arraySize);
674
675	if (rgReaderStates == 0)
676	{
677		return MSC_INTERNAL_ERROR;
678	}
679
680	for (i = 0; i < arraySize; i++)
681	{
682		/*
683		 * Make sure they don't pass an empty structure
684		 */
685		if (strlen(tokenArray[i].slotName) == 0)
686		{
687			free(rgReaderStates);
688			return MSC_INVALID_PARAMETER;
689		}
690
691		rgReaderStates[i].szReader = tokenArray[i].slotName;
692		rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE;
693		rgReaderStates[i].dwEventState = 0;
694	}
695
696	rv = SCardGetStatusChange(localHContext, timeoutValue,
697		rgReaderStates, arraySize);
698
699	if (rv != SCARD_S_SUCCESS)
700	{
701		free(rgReaderStates);
702		return pcscToMSC(rv);
703	}
704
705	for (i = 0; i < arraySize; i++)
706	{
707		if (tokenArray[i].tokenState == 0)
708		{
709			rgReaderStates[i].dwCurrentState =
710				rgReaderStates[i].dwEventState;
711		} else if (tokenArray[i].tokenState == MSC_STATE_UNAWARE)
712		{
713			rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE;
714		} else
715		{
716			rgReaderStates[i].dwCurrentState = tokenArray[i].tokenState;
717		}
718		rgReaderStates[i].dwEventState = 0;
719	}
720
721	rv = SCardGetStatusChange(localHContext, timeoutValue,
722		rgReaderStates, arraySize);
723
724	for (i = 0; i < arraySize; i++)
725	{
726		tokenArray[i].tokenState = rgReaderStates[i].dwEventState;
727
728		if (tokenArray[i].tokenState & MSC_STATE_CHANGED)
729		{
730			/*
731			 * If it is removed, we need to update the names/etc
732			 */
733			if (tokenArray[i].tokenState & MSC_STATE_EMPTY)
734			{
735				memset(tokenArray[i].tokenId, 0x00, MAX_ATR_SIZE);
736				tokenArray[i].tokenIdLength = 0;
737				tokenArray[i].tokenType = MSC_TOKEN_TYPE_REMOVED;
738				strncpy(tokenArray[i].tokenName, MSC_TOKEN_EMPTY_STR,
739					MSC_MAXSIZE_TOKENAME);
740			} else if (tokenArray[i].tokenState & MSC_STATE_PRESENT)
741			{
742				memcpy(tokenArray[i].tokenId, rgReaderStates[i].rgbAtr,
743					rgReaderStates[i].cbAtr);
744				tokenArray[i].tokenIdLength = rgReaderStates[i].cbAtr;
745
746				rt = TPSearchBundlesForAtr(rgReaderStates[i].rgbAtr,
747					rgReaderStates[i].cbAtr, &tokenInfo);
748				/*
749				 * Successfully found
750				 */
751				if (rt == 0)
752				{
753					tokenArray[i].tokenType = MSC_TOKEN_TYPE_KNOWN;
754					strncpy(tokenArray[i].tokenName, tokenInfo.tokenName,
755						MSC_MAXSIZE_TOKENAME);
756				} else
757				{
758					tokenArray[i].tokenType = MSC_TOKEN_TYPE_UNKNOWN;
759					strncpy(tokenArray[i].tokenName, MSC_TOKEN_UNKNOWN_STR,
760						MSC_MAXSIZE_TOKENAME);
761				}
762			}
763		}
764	}
765
766	free(rgReaderStates);
767	return pcscToMSC(rv);
768}
769
770MSC_RV MSCCancelEventWait(void)
771{
772
773	MSCLong32 rv;
774
775	rv = SCardCancel(localHContext);
776
777	return pcscToMSC(rv);
778}
779
780/************************ Start of Callbacks ****************************/
781#ifdef USE_THREAD_SAFETY
782void *_MSCEventThread(void *arg)
783{
784
785	MSCLong32 rv;
786	MSCLPEventWaitInfo evlist;
787	MSCLong32 curToken;
788
789	if (arg == NULL)
790	{
791		SYS_ThreadExit(NULL);
792	}
793
794	evlist = (MSCLPEventWaitInfo) arg;
795	blockingContext = MSC_BLOCKSTATUS_BLOCKING;
796
797	while (1)
798	{
799		rv = MSCWaitForTokenEvent(evlist->tokenArray,
800					  evlist->arraySize,
801					  MSC_NO_TIMEOUT);
802
803		if (rv == MSC_SUCCESS)
804		{
805		       (evlist->callBack) (evlist->tokenArray,
806					   evlist->arraySize,
807					   evlist->appData);
808		} else {
809		       break;
810
811		}
812
813		if (blockingContext == MSC_BLOCKSTATUS_CANCELLING)
814		{
815		        break;
816		}
817	}
818
819	for (curToken = 0; curToken < evlist->arraySize; curToken++)
820	{
821	        if (evlist->tokenArray[curToken].addParams)
822	        {
823		        free(evlist->tokenArray[curToken].addParams);
824	        }
825	}
826
827
828	free(evlist);
829	blockingContext = MSC_BLOCKSTATUS_RESUME;
830	SYS_ThreadExit(&rv);
831
832	return NULL;
833}
834
835MSC_RV MSCCallbackForTokenEvent(MSCLPTokenInfo tokenArray,
836				MSCULong32 arraySize,
837				MSCCallBack callBack,
838				MSCPVoid32 appData)
839{
840	MSCLPEventWaitInfo evlist;
841	MSCULong32 curToken;
842
843	/*
844	 * Create the event wait list
845	 */
846	evlist = (MSCLPEventWaitInfo) malloc(sizeof(MSCEventWaitInfo));
847
848	if (evlist == NULL)
849	{
850		return MSC_INTERNAL_ERROR;
851	}
852
853	evlist->arraySize = arraySize;
854	evlist->tokenArray = malloc(sizeof(MSCTokenInfo) * arraySize);
855	evlist->appData = appData;
856	evlist->callBack = callBack;
857
858	if (evlist->tokenArray == NULL)
859	{
860		free(evlist);
861		return MSC_INTERNAL_ERROR;
862	}
863
864	mscLockThread();
865	memcpy(evlist->tokenArray, tokenArray,
866		sizeof(MSCTokenInfo) * arraySize);
867
868	/*
869	 * Copy the "extra" data
870	 */
871	for (curToken = 0; curToken < arraySize; curToken++)
872	{
873		if (tokenArray[curToken].addParams != NULL)
874		{
875			evlist->tokenArray[curToken].addParams =
876				malloc(evlist->tokenArray[curToken].addParamsSize);
877			memcpy((void *) (evlist->tokenArray[curToken].addParams),
878				&tokenArray[curToken],
879				evlist->tokenArray[curToken].addParamsSize);
880
881		}
882	}
883	mscUnLockThread();
884
885	if (SYS_ThreadCreate(&callbackThread, THREAD_ATTR_DEFAULT, _MSCEventThread,
886			     (void *) evlist) == 0)
887	{
888		return MSC_INTERNAL_ERROR;
889	}
890
891	return MSC_SUCCESS;
892}
893
894MSC_RV MSCCallbackCancelEvent()
895{
896
897        LONG rv;
898
899        /* Release the thread and stop the GetStatusChange */
900        if (blockingContext == MSC_BLOCKSTATUS_BLOCKING)
901	{
902                blockingContext = MSC_BLOCKSTATUS_CANCELLING;
903	        rv = MSCCancelEventWait();
904
905		SYS_ThreadJoin(&callbackThread, 0);
906
907	}
908
909      return MSC_SUCCESS;
910}
911
912#endif
913/************************** End of Callbacks *****************************/
914
915MSC_RV MSCBeginTransaction(MSCLPTokenConnection pConnection)
916{
917
918	MSCLong32 rv;
919	MSCLong32 ret;
920
921	if (localHContext == 0)
922		return MSC_INTERNAL_ERROR;
923
924	while (1)
925	{
926		rv = SCardBeginTransaction(pConnection->hCard);
927		ret = pcscToMSC(rv);
928
929		if (ret == MSC_SUCCESS)
930			break;
931		if (ret == MSC_TOKEN_RESET)
932		{
933		        pConnection->tokenInfo.tokenType |=
934			  MSC_TOKEN_TYPE_RESET;
935			ret = MSCReEstablishConnection(pConnection);
936			if (ret != MSC_SUCCESS)
937				break;
938			continue;
939		} else if (ret == MSC_TOKEN_REMOVED)
940		{
941		        pConnection->tokenInfo.tokenType =
942			  MSC_TOKEN_TYPE_REMOVED;
943			return ret;
944		}
945	}
946
947	return ret;
948}
949
950MSC_RV MSCEndTransaction(MSCLPTokenConnection pConnection,
951	MSCULong32 endAction)
952{
953
954	MSCLong32 rv;
955	MSCLong32 ret;
956
957	if (localHContext == 0)
958		return MSC_INTERNAL_ERROR;
959
960	while (1)
961	{
962		rv = SCardEndTransaction(pConnection->hCard, endAction);
963		ret = pcscToMSC(rv);
964
965		if (ret == MSC_SUCCESS)
966			break;
967		if (ret == MSC_TOKEN_RESET)
968		{
969		        pConnection->tokenInfo.tokenType |=
970			  MSC_TOKEN_TYPE_RESET;
971			ret = MSCReEstablishConnection(pConnection);
972			if (ret != MSC_SUCCESS)
973				break;
974			continue;
975		} else if (ret == MSC_TOKEN_REMOVED)
976		{
977		        pConnection->tokenInfo.tokenType =
978			  MSC_TOKEN_TYPE_REMOVED;
979			return ret;
980		}
981	}
982
983	return ret;
984}
985
986MSC_RV MSCWriteFramework(MSCLPTokenConnection pConnection,
987	MSCLPInitTokenParams pInitParams)
988{
989
990	MSCLong32 rv;
991	MSCPVoid32 vFunction;
992	MSCLong32(*libMSCWriteFramework) (MSCLPTokenConnection,
993		MSCLPInitTokenParams);
994
995	if (pConnection == NULL)
996		return MSC_INVALID_PARAMETER;
997	if (localHContext == 0)
998		return MSC_INTERNAL_ERROR;
999
1000	vFunction = pConnection->libPointers.pvfWriteFramework;
1001
1002	if (vFunction != 0)
1003	{
1004		libMSCWriteFramework = (MSCLong32(*)(MSCLPTokenConnection,
1005				MSCLPInitTokenParams)) vFunction;
1006		rv = (*libMSCWriteFramework) (pConnection, pInitParams);
1007
1008	} else
1009	{
1010		return MSC_UNSUPPORTED_FEATURE;
1011	}
1012
1013	return rv;
1014}
1015
1016/*
1017 * Real MSC functions
1018 */
1019
1020MSC_RV MSCGetStatus(MSCLPTokenConnection pConnection,
1021	MSCLPStatusInfo pStatusInfo)
1022{
1023	MSCLong32 rv;
1024	MSCPVoid32 vFunction;
1025	MSCLong32(*libMSCGetStatus) (MSCLPTokenConnection, MSCLPStatusInfo);
1026
1027	if (pConnection == NULL)
1028		return MSC_INVALID_PARAMETER;
1029	if (localHContext == 0)
1030		return MSC_INTERNAL_ERROR;
1031
1032	vFunction = pConnection->libPointers.pvfGetStatus;
1033
1034	if (vFunction != 0)
1035	{
1036		libMSCGetStatus = (MSCLong32(*)(MSCLPTokenConnection,
1037				MSCLPStatusInfo)) vFunction;
1038		rv = (*libMSCGetStatus) (pConnection, pStatusInfo);
1039
1040	} else
1041	{
1042		return MSC_UNSUPPORTED_FEATURE;
1043	}
1044
1045	return rv;
1046}
1047
1048MSC_RV MSCGetCapabilities(MSCLPTokenConnection pConnection, MSCULong32 Tag,
1049	MSCPUChar8 Value, MSCPULong32 Length)
1050{
1051	MSCLong32 rv;
1052	MSCPVoid32 vFunction;
1053	MSCLong32(*libMSCGetCapabilities) (MSCLPTokenConnection, MSCULong32,
1054		MSCPUChar8, MSCPULong32);
1055
1056	if (pConnection == NULL)
1057		return MSC_INVALID_PARAMETER;
1058	if (localHContext == 0)
1059		return MSC_INTERNAL_ERROR;
1060
1061	vFunction = pConnection->libPointers.pvfGetCapabilities;
1062
1063	if (vFunction != 0)
1064	{
1065		libMSCGetCapabilities =
1066			(MSCLong32(*)(MSCLPTokenConnection, MSCULong32, MSCPUChar8,
1067				MSCPULong32)) vFunction;
1068		rv = (*libMSCGetCapabilities) (pConnection, Tag, Value, Length);
1069
1070	} else
1071	{
1072		return MSC_UNSUPPORTED_FEATURE;
1073	}
1074
1075	return rv;
1076}
1077
1078MSC_RV MSCExtendedFeature(MSCLPTokenConnection pConnection,
1079	MSCULong32 extFeature, MSCPUChar8 outData,
1080	MSCULong32 outLength, MSCPUChar8 inData, MSCPULong32 inLength)
1081{
1082	MSCLong32 rv;
1083	MSCPVoid32 vFunction;
1084	MSCLong32(*libMSCExtendedFeature) (MSCLPTokenConnection, MSCULong32,
1085		MSCPUChar8, MSCULong32, MSCPUChar8, MSCPULong32);
1086
1087	if (pConnection == NULL)
1088		return MSC_INVALID_PARAMETER;
1089	if (localHContext == 0)
1090		return MSC_INTERNAL_ERROR;
1091
1092	vFunction = pConnection->libPointers.pvfExtendedFeature;
1093
1094	if (vFunction != 0)
1095	{
1096		libMSCExtendedFeature =
1097			(MSCLong32(*)(MSCLPTokenConnection, MSCULong32, MSCPUChar8,
1098				MSCULong32, MSCPUChar8, MSCPULong32)) vFunction;
1099		rv = (*libMSCExtendedFeature) (pConnection, extFeature, outData,
1100			outLength, inData, inLength);
1101
1102	} else
1103	{
1104		return MSC_UNSUPPORTED_FEATURE;
1105	}
1106
1107	return rv;
1108}
1109
1110MSC_RV MSCGenerateKeys(MSCLPTokenConnection pConnection,
1111	MSCUChar8 prvKeyNum, MSCUChar8 pubKeyNum, MSCLPGenKeyParams pParams)
1112{
1113	MSCLong32 rv;
1114	MSCPVoid32 vFunction;
1115	MSCLong32(*libMSCGenerateKeys) (MSCLPTokenConnection, MSCUChar8,
1116		MSCUChar8, MSCLPGenKeyParams);
1117
1118	if (pConnection == NULL)
1119		return MSC_INVALID_PARAMETER;
1120	if (localHContext == 0)
1121		return MSC_INTERNAL_ERROR;
1122
1123	vFunction = pConnection->libPointers.pvfGenerateKeys;
1124
1125	if (vFunction != 0)
1126	{
1127		libMSCGenerateKeys = (MSCLong32(*)(MSCLPTokenConnection,
1128						   MSCUChar8, MSCUChar8,
1129						   MSCLPGenKeyParams))
1130		  vFunction;
1131		rv = (*libMSCGenerateKeys) (pConnection, prvKeyNum, pubKeyNum,
1132					    pParams);
1133
1134	} else
1135	{
1136		return MSC_UNSUPPORTED_FEATURE;
1137	}
1138
1139	return rv;
1140}
1141
1142MSC_RV MSCImportKey(MSCLPTokenConnection pConnection, MSCUChar8 keyNum,
1143                    MSCLPKeyACL pKeyACL, MSCPUChar8 pKeyBlob,MSCULong32 keyBlobSize,
1144		    MSCLPKeyPolicy keyPolicy, MSCPVoid32 pAddParams,
1145		    MSCUChar8 addParamsSize)
1146{
1147	MSCLong32 rv;
1148	MSCPVoid32 vFunction;
1149	MSCLong32(*libMSCImportKey) (MSCLPTokenConnection, MSCUChar8,
1150                                     MSCLPKeyACL, MSCPUChar8,
1151				     MSCULong32, MSCLPKeyPolicy, MSCPVoid32,
1152				     MSCUChar8);
1153
1154	if (pConnection == NULL)
1155		return MSC_INVALID_PARAMETER;
1156	if (localHContext == 0)
1157		return MSC_INTERNAL_ERROR;
1158
1159	vFunction = pConnection->libPointers.pvfImportKey;
1160
1161	if (vFunction != 0)
1162	{
1163		libMSCImportKey = (MSCLong32(*)(MSCLPTokenConnection,
1164						MSCUChar8,
1165						MSCLPKeyACL, MSCPUChar8,
1166						MSCULong32, MSCLPKeyPolicy,
1167						MSCPVoid32, MSCUChar8))
1168		  vFunction;
1169
1170		rv = (*libMSCImportKey) (pConnection, keyNum,
1171					 pKeyACL, pKeyBlob, keyBlobSize,
1172					 keyPolicy, pAddParams, addParamsSize);
1173
1174	} else
1175	{
1176		return MSC_UNSUPPORTED_FEATURE;
1177	}
1178
1179	return rv;
1180}
1181
1182MSC_RV MSCExportKey(MSCLPTokenConnection pConnection, MSCUChar8 keyNum,
1183		    MSCPUChar8 pKeyBlob, MSCPULong32 keyBlobSize,
1184		    MSCPVoid32 pAddParams, MSCUChar8 addParamsSize)
1185{
1186	MSCLong32 rv;
1187	MSCPVoid32 vFunction;
1188	MSCLong32(*libMSCExportKey) (MSCLPTokenConnection, MSCUChar8,
1189		MSCPUChar8, MSCPULong32, MSCPVoid32, MSCUChar8);
1190
1191	if (pConnection == NULL)
1192		return MSC_INVALID_PARAMETER;
1193	if (localHContext == 0)
1194		return MSC_INTERNAL_ERROR;
1195
1196	vFunction = pConnection->libPointers.pvfExportKey;
1197
1198	if (vFunction != 0)
1199	{
1200		libMSCExportKey = (MSCLong32(*)(MSCLPTokenConnection,
1201						MSCUChar8, MSCPUChar8,
1202						MSCPULong32, MSCPVoid32,
1203						MSCUChar8)) vFunction;
1204
1205		rv = (*libMSCExportKey) (pConnection, keyNum, pKeyBlob,
1206			keyBlobSize, pAddParams, addParamsSize);
1207
1208	} else
1209	{
1210		return MSC_UNSUPPORTED_FEATURE;
1211	}
1212
1213	return rv;
1214}
1215
1216MSC_RV MSCComputeCrypt(MSCLPTokenConnection pConnection,
1217		       MSCLPCryptInit cryptInit, MSCPUChar8 pInputData,
1218		       MSCULong32 inputDataSize, MSCPUChar8 pOutputData,
1219		       MSCPULong32 outputDataSize)
1220{
1221	MSCLong32 rv;
1222	MSCPVoid32 vFunction;
1223	MSCLong32(*libMSCComputeCrypt) (MSCLPTokenConnection, MSCLPCryptInit,
1224					MSCPUChar8, MSCULong32, MSCPUChar8,
1225					MSCPULong32);
1226
1227	if (pConnection == NULL)
1228		return MSC_INVALID_PARAMETER;
1229	if (localHContext == 0)
1230		return MSC_INTERNAL_ERROR;
1231
1232	vFunction = pConnection->libPointers.pvfComputeCrypt;
1233
1234	if (vFunction != 0)
1235	{
1236		libMSCComputeCrypt =
1237			(MSCLong32(*)(MSCLPTokenConnection, MSCLPCryptInit,
1238				      MSCPUChar8, MSCULong32, MSCPUChar8,
1239				      MSCPULong32)) vFunction;
1240		rv = (*libMSCComputeCrypt) (pConnection, cryptInit, pInputData,
1241					    inputDataSize, pOutputData,
1242					    outputDataSize);
1243
1244	} else
1245	{
1246		return MSC_UNSUPPORTED_FEATURE;
1247	}
1248
1249	return rv;
1250}
1251
1252MSC_RV MSCExtAuthenticate(MSCLPTokenConnection pConnection,
1253			  MSCUChar8 keyNum, MSCUChar8 cipherMode,
1254			  MSCUChar8 cipherDirection,
1255			  MSCPUChar8 pData, MSCULong32 dataSize)
1256{
1257	MSCLong32 rv;
1258	MSCPVoid32 vFunction;
1259	MSCLong32(*libMSCExtAuthenticate) (MSCLPTokenConnection, MSCUChar8,
1260					   MSCUChar8, MSCUChar8, MSCPUChar8,
1261					   MSCULong32);
1262
1263	if (pConnection == NULL)
1264		return MSC_INVALID_PARAMETER;
1265	if (localHContext == 0)
1266		return MSC_INTERNAL_ERROR;
1267
1268	vFunction = pConnection->libPointers.pvfExtAuthenticate;
1269
1270	if (vFunction != 0)
1271	{
1272		libMSCExtAuthenticate =
1273			(MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
1274				      MSCUChar8, MSCUChar8, MSCPUChar8,
1275				      MSCULong32)) vFunction;
1276		rv = (*libMSCExtAuthenticate) (pConnection, keyNum, cipherMode,
1277			cipherDirection, pData, dataSize);
1278	} else
1279	{
1280		return MSC_UNSUPPORTED_FEATURE;
1281	}
1282
1283	return rv;
1284}
1285
1286MSC_RV MSCListKeys(MSCLPTokenConnection pConnection, MSCUChar8 seqOption,
1287		   MSCLPKeyInfo pKeyInfo)
1288{
1289	MSCLong32 rv;
1290	MSCPVoid32 vFunction;
1291	MSCLong32(*libMSCListKeys) (MSCLPTokenConnection, MSCUChar8,
1292		MSCLPKeyInfo);
1293
1294	if (pConnection == NULL)
1295		return MSC_INVALID_PARAMETER;
1296	if (localHContext == 0)
1297		return MSC_INTERNAL_ERROR;
1298
1299	vFunction = pConnection->libPointers.pvfListKeys;
1300
1301	if (vFunction != 0)
1302	{
1303		libMSCListKeys = (MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
1304					       MSCLPKeyInfo)) vFunction;
1305		rv = (*libMSCListKeys) (pConnection, seqOption, pKeyInfo);
1306
1307	} else
1308	{
1309		return MSC_UNSUPPORTED_FEATURE;
1310	}
1311
1312	return rv;
1313}
1314
1315MSC_RV MSCCreatePIN(MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
1316	MSCUChar8 pinAttempts, MSCPUChar8 pPinCode,
1317	MSCULong32 pinCodeSize, MSCPUChar8 pUnblockCode,
1318	MSCUChar8 unblockCodeSize)
1319{
1320	MSCLong32 rv;
1321	MSCPVoid32 vFunction;
1322	MSCLong32(*libMSCCreatePIN) (MSCLPTokenConnection, MSCUChar8,
1323		MSCUChar8, MSCPUChar8, MSCULong32, MSCPUChar8, MSCUChar8);
1324
1325	if (pConnection == NULL)
1326		return MSC_INVALID_PARAMETER;
1327	if (localHContext == 0)
1328		return MSC_INTERNAL_ERROR;
1329
1330	vFunction = pConnection->libPointers.pvfCreatePIN;
1331
1332	if (vFunction != 0)
1333	{
1334		libMSCCreatePIN = (MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
1335				MSCUChar8, MSCPUChar8,
1336				MSCULong32, MSCPUChar8, MSCUChar8)) vFunction;
1337		rv = (*libMSCCreatePIN) (pConnection, pinNum, pinAttempts,
1338			pPinCode, pinCodeSize, pUnblockCode, unblockCodeSize);
1339
1340	} else
1341	{
1342		return MSC_UNSUPPORTED_FEATURE;
1343	}
1344
1345	return rv;
1346}
1347
1348MSC_RV MSCVerifyPIN(MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
1349	MSCPUChar8 pPinCode, MSCULong32 pinCodeSize)
1350{
1351	MSCLong32 rv;
1352	MSCPVoid32 vFunction;
1353	MSCLong32(*libMSCVerifyPIN) (MSCLPTokenConnection, MSCUChar8,
1354		MSCPUChar8, MSCULong32);
1355
1356	if (pConnection == NULL)
1357		return MSC_INVALID_PARAMETER;
1358	if (localHContext == 0)
1359		return MSC_INTERNAL_ERROR;
1360
1361	vFunction = pConnection->libPointers.pvfVerifyPIN;
1362
1363	if (vFunction != 0)
1364	{
1365		libMSCVerifyPIN = (MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
1366				MSCPUChar8, MSCULong32)) vFunction;
1367		rv = (*libMSCVerifyPIN) (pConnection, pinNum, pPinCode,
1368			pinCodeSize);
1369
1370	} else
1371	{
1372		return MSC_UNSUPPORTED_FEATURE;
1373	}
1374
1375	return rv;
1376}
1377
1378MSC_RV MSCChangePIN(MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
1379	MSCPUChar8 pOldPinCode, MSCUChar8 oldPinCodeSize,
1380	MSCPUChar8 pNewPinCode, MSCUChar8 newPinCodeSize)
1381{
1382	MSCLong32 rv;
1383	MSCPVoid32 vFunction;
1384	MSCLong32(*libMSCChangePIN) (MSCLPTokenConnection, MSCUChar8,
1385		MSCPUChar8, MSCUChar8, MSCPUChar8, MSCUChar8);
1386
1387	if (pConnection == NULL)
1388		return MSC_INVALID_PARAMETER;
1389	if (localHContext == 0)
1390		return MSC_INTERNAL_ERROR;
1391
1392	vFunction = pConnection->libPointers.pvfChangePIN;
1393
1394	if (vFunction != 0)
1395	{
1396		libMSCChangePIN = (MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
1397				MSCPUChar8, MSCUChar8, MSCPUChar8, MSCUChar8)) vFunction;
1398		rv = (*libMSCChangePIN) (pConnection, pinNum, pOldPinCode,
1399			oldPinCodeSize, pNewPinCode, newPinCodeSize);
1400
1401	} else
1402	{
1403		return MSC_UNSUPPORTED_FEATURE;
1404	}
1405
1406	return rv;
1407}
1408
1409MSC_RV MSCUnblockPIN(MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
1410	MSCPUChar8 pUnblockCode, MSCULong32 unblockCodeSize)
1411{
1412	MSCLong32 rv;
1413	MSCPVoid32 vFunction;
1414	MSCLong32(*libMSCUnblockPIN) (MSCLPTokenConnection, MSCUChar8,
1415		MSCPUChar8, MSCULong32);
1416
1417	if (pConnection == NULL)
1418		return MSC_INVALID_PARAMETER;
1419	if (localHContext == 0)
1420		return MSC_INTERNAL_ERROR;
1421
1422	vFunction = pConnection->libPointers.pvfUnblockPIN;
1423
1424	if (vFunction != 0)
1425	{
1426		libMSCUnblockPIN = (MSCLong32(*)(MSCLPTokenConnection,
1427				MSCUChar8, MSCPUChar8, MSCULong32)) vFunction;
1428		rv = (*libMSCUnblockPIN) (pConnection, pinNum, pUnblockCode,
1429			unblockCodeSize);
1430
1431	} else
1432	{
1433		return MSC_UNSUPPORTED_FEATURE;
1434	}
1435
1436	return rv;
1437}
1438
1439MSC_RV MSCListPINs(MSCLPTokenConnection pConnection,
1440	MSCPUShort16 pPinBitMask)
1441{
1442	MSCLong32 rv;
1443	MSCPVoid32 vFunction;
1444	MSCLong32(*libMSCListPINs) (MSCLPTokenConnection, MSCPUShort16);
1445
1446	if (pConnection == NULL)
1447		return MSC_INVALID_PARAMETER;
1448	if (localHContext == 0)
1449		return MSC_INTERNAL_ERROR;
1450
1451	vFunction = pConnection->libPointers.pvfListPINs;
1452
1453	if (vFunction != 0)
1454	{
1455		libMSCListPINs = (MSCLong32(*)(MSCLPTokenConnection,
1456				MSCPUShort16)) vFunction;
1457		rv = (*libMSCListPINs) (pConnection, pPinBitMask);
1458
1459	} else
1460	{
1461		return MSC_UNSUPPORTED_FEATURE;
1462	}
1463
1464	return rv;
1465}
1466
1467MSC_RV MSCCreateObject(MSCLPTokenConnection pConnection,
1468	MSCString objectID, MSCULong32 objectSize, MSCLPObjectACL pObjectACL)
1469{
1470	MSCLong32 rv;
1471	MSCPVoid32 vFunction;
1472	MSCLong32(*libMSCCreateObject) (MSCLPTokenConnection, MSCString,
1473		MSCULong32, MSCLPObjectACL);
1474
1475	if (pConnection == NULL)
1476		return MSC_INVALID_PARAMETER;
1477	if (localHContext == 0)
1478		return MSC_INTERNAL_ERROR;
1479
1480	vFunction = pConnection->libPointers.pvfCreateObject;
1481
1482	if (vFunction != 0)
1483	{
1484		libMSCCreateObject = (MSCLong32(*)(MSCLPTokenConnection, MSCString,
1485				MSCULong32, MSCLPObjectACL)) vFunction;
1486		rv = (*libMSCCreateObject) (pConnection, objectID, objectSize,
1487			pObjectACL);
1488	} else
1489	{
1490		return MSC_UNSUPPORTED_FEATURE;
1491	}
1492
1493	return rv;
1494}
1495
1496MSC_RV MSCDeleteObject(MSCLPTokenConnection pConnection,
1497	MSCString objectID, MSCUChar8 zeroFlag)
1498{
1499	MSCLong32 rv;
1500	MSCPVoid32 vFunction;
1501	MSCLong32(*libMSCDeleteObject) (MSCLPTokenConnection, MSCString,
1502		MSCUChar8);
1503
1504	if (pConnection == NULL)
1505		return MSC_INVALID_PARAMETER;
1506	if (localHContext == 0)
1507		return MSC_INTERNAL_ERROR;
1508
1509	vFunction = pConnection->libPointers.pvfDeleteObject;
1510
1511	if (vFunction != 0)
1512	{
1513		libMSCDeleteObject = (MSCLong32(*)(MSCLPTokenConnection, MSCString,
1514				MSCUChar8)) vFunction;
1515		rv = (*libMSCDeleteObject) (pConnection, objectID, zeroFlag);
1516
1517	} else
1518	{
1519		return MSC_UNSUPPORTED_FEATURE;
1520	}
1521
1522	return rv;
1523}
1524
1525MSC_RV MSCWriteObject(MSCLPTokenConnection pConnection,
1526		      MSCString objectID, MSCULong32 offSet,
1527		      MSCPUChar8 pInputData, MSCULong32 dataSize,
1528		      LPRWEventCallback rwCallback, MSCPVoid32 addParams)
1529{
1530	MSC_RV rv = MSC_UNSPECIFIED_ERROR;
1531	MSCULong32 objectSize;
1532	int totalSteps, stepInterval;
1533	MSC_RV(*callBackFunction) (void *, int);
1534	MSCPVoid32 vFunction;
1535	MSCLong32(*libMSCWriteObject) (MSCLPTokenConnection, MSCString,
1536		MSCULong32, MSCPUChar8, MSCUChar8);
1537	int i;
1538
1539	if (pConnection == NULL)
1540		return MSC_INVALID_PARAMETER;
1541	if (localHContext == 0)
1542		return MSC_INTERNAL_ERROR;
1543
1544	vFunction        = pConnection->libPointers.pvfWriteObject;
1545	callBackFunction = (MSC_RV(*)(void *, int)) rwCallback;
1546	objectSize       = dataSize;
1547
1548	if (vFunction == 0)
1549	{
1550	        return MSC_UNSUPPORTED_FEATURE;
1551        }
1552
1553	libMSCWriteObject = (MSCLong32(*)(MSCLPTokenConnection, MSCString,
1554					  MSCULong32, MSCPUChar8, MSCUChar8))
1555	  vFunction;
1556
1557	/*
1558	 * Figure out the number of steps total and present this in a percent
1559	 * step basis
1560	 */
1561
1562	totalSteps = objectSize / MSC_SIZEOF_KEYPACKET + 1;
1563	stepInterval = MSC_PERCENT_STEPSIZE / totalSteps;
1564
1565	for (i = 0; i < objectSize / MSC_SIZEOF_KEYPACKET; i++)
1566	{
1567	  rv = (*libMSCWriteObject) (pConnection, objectID,
1568				     i * MSC_SIZEOF_KEYPACKET + offSet,
1569				     &pInputData[i * MSC_SIZEOF_KEYPACKET],
1570				     MSC_SIZEOF_KEYPACKET);
1571		if (rv != MSC_SUCCESS)
1572		{
1573			return rv;
1574		}
1575
1576		if (rwCallback)
1577		{
1578			if ((*callBackFunction) (addParams,
1579			      stepInterval * i) == MSC_CANCELLED)
1580			{
1581				return MSC_CANCELLED;
1582			}
1583		}
1584	}
1585
1586	if (objectSize % MSC_SIZEOF_KEYPACKET)
1587	{
1588
1589	  rv = (*libMSCWriteObject) (pConnection, objectID,
1590				     i * MSC_SIZEOF_KEYPACKET + offSet,
1591				     &pInputData[i * MSC_SIZEOF_KEYPACKET],
1592				     objectSize % MSC_SIZEOF_KEYPACKET);
1593
1594		if (rv != MSC_SUCCESS)
1595		{
1596			return rv;
1597		}
1598	}
1599
1600	if (rwCallback)
1601	{
1602		(*callBackFunction) (addParams, MSC_PERCENT_STEPSIZE);
1603	}
1604
1605	return rv;
1606}
1607
1608MSC_RV MSCReadObject(MSCLPTokenConnection pConnection,
1609		     MSCString objectID, MSCULong32 offSet,
1610		     MSCPUChar8 pOutputData, MSCULong32 dataSize,
1611		     LPRWEventCallback rwCallback,
1612		     MSCPVoid32 addParams)
1613{
1614
1615        MSC_RV rv = MSC_UNSPECIFIED_ERROR;
1616	MSCULong32 objectSize;
1617	int totalSteps, stepInterval;
1618	MSC_RV(*callBackFunction) (void *, int);
1619	MSCPVoid32 vFunction;
1620	MSCLong32(*libMSCReadObject) (MSCLPTokenConnection, MSCString,
1621		MSCULong32, MSCPUChar8, MSCUChar8);
1622	int i;
1623
1624	if (pConnection == NULL)
1625		return MSC_INVALID_PARAMETER;
1626	if (localHContext == 0)
1627		return MSC_INTERNAL_ERROR;
1628
1629	vFunction        = pConnection->libPointers.pvfReadObject;
1630	callBackFunction = (MSC_RV(*)(void *, int)) rwCallback;
1631	objectSize       = dataSize;
1632
1633	if (vFunction == 0)
1634	{
1635		return MSC_UNSUPPORTED_FEATURE;
1636	}
1637
1638	libMSCReadObject = (MSCLong32(*)(MSCLPTokenConnection,
1639					 MSCString, MSCULong32,
1640					 MSCPUChar8, MSCUChar8))
1641	  vFunction;
1642
1643	/*
1644	 * Figure out the number of steps total and present this in a percent
1645	 * step basis
1646	 */
1647
1648	totalSteps = objectSize / MSC_SIZEOF_KEYPACKET + 1;
1649	stepInterval = MSC_PERCENT_STEPSIZE / totalSteps;
1650
1651	for (i = 0; i < objectSize / MSC_SIZEOF_KEYPACKET; i++)
1652	{
1653	        rv = (*libMSCReadObject) (pConnection, objectID,
1654				    i * MSC_SIZEOF_KEYPACKET + offSet,
1655				    &pOutputData[i * MSC_SIZEOF_KEYPACKET],
1656				    MSC_SIZEOF_KEYPACKET);
1657
1658		if (rv != MSC_SUCCESS)
1659		{
1660			return rv;
1661		}
1662
1663		if (rwCallback)
1664		{
1665			if ((*callBackFunction) (addParams,
1666					stepInterval * i) == MSC_CANCELLED)
1667			{
1668				return MSC_CANCELLED;
1669			}
1670		}
1671	}
1672
1673	if (objectSize % MSC_SIZEOF_KEYPACKET)
1674	{
1675	        rv = (*libMSCReadObject) (pConnection, objectID,
1676				    i * MSC_SIZEOF_KEYPACKET + offSet,
1677				    &pOutputData[i * MSC_SIZEOF_KEYPACKET],
1678				    objectSize % MSC_SIZEOF_KEYPACKET);
1679
1680		if (rv != MSC_SUCCESS)
1681		{
1682			return rv;
1683		}
1684	}
1685
1686	if (rwCallback)
1687	{
1688		(*callBackFunction) (addParams, MSC_PERCENT_STEPSIZE);
1689	}
1690
1691	return rv;
1692}
1693
1694MSC_RV MSCListObjects(MSCLPTokenConnection pConnection,
1695	MSCUChar8 seqOption, MSCLPObjectInfo pObjectInfo)
1696{
1697	MSCLong32 rv;
1698	MSCPVoid32 vFunction;
1699	MSCLong32(*libMSCListObjects) (MSCLPTokenConnection, MSCUChar8,
1700		MSCLPObjectInfo);
1701
1702	if (pConnection == NULL)
1703		return MSC_INVALID_PARAMETER;
1704	if (localHContext == 0)
1705		return MSC_INTERNAL_ERROR;
1706
1707	vFunction = pConnection->libPointers.pvfListObjects;
1708
1709	if (vFunction != 0)
1710	{
1711		libMSCListObjects = (MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
1712				MSCLPObjectInfo)) vFunction;
1713		rv = (*libMSCListObjects) (pConnection, seqOption, pObjectInfo);
1714
1715	} else
1716	{
1717		return MSC_UNSUPPORTED_FEATURE;
1718	}
1719
1720	return rv;
1721}
1722
1723MSC_RV MSCLogoutAll(MSCLPTokenConnection pConnection)
1724{
1725
1726	MSCLong32 rv;
1727	MSCPVoid32 vFunction;
1728	MSCLong32(*libMSCLogoutAll) (MSCLPTokenConnection);
1729
1730	if (pConnection == NULL)
1731		return MSC_INVALID_PARAMETER;
1732	if (localHContext == 0)
1733		return MSC_INTERNAL_ERROR;
1734
1735	vFunction = pConnection->libPointers.pvfLogoutAll;
1736
1737	if (vFunction != 0)
1738	{
1739		libMSCLogoutAll = (MSCLong32(*)(MSCLPTokenConnection)) vFunction;
1740		rv = (*libMSCLogoutAll) (pConnection);
1741
1742	} else
1743	{
1744		return MSC_UNSUPPORTED_FEATURE;
1745	}
1746
1747	return rv;
1748}
1749
1750MSC_RV MSCGetChallenge(MSCLPTokenConnection pConnection, MSCPUChar8 pSeed,
1751	MSCUShort16 seedSize, MSCPUChar8 pRandomData,
1752	MSCUShort16 randomDataSize)
1753{
1754	MSCLong32 rv;
1755	MSCPVoid32 vFunction;
1756	MSCLong32(*libMSCGetChallenge) (MSCLPTokenConnection, MSCPUChar8,
1757		MSCUShort16, MSCPUChar8, MSCUShort16);
1758
1759	if (pConnection == NULL)
1760		return MSC_INVALID_PARAMETER;
1761	if (localHContext == 0)
1762		return MSC_INTERNAL_ERROR;
1763
1764	vFunction = pConnection->libPointers.pvfGetChallenge;
1765
1766	if (vFunction != 0)
1767	{
1768		libMSCGetChallenge = (MSCLong32(*)(MSCLPTokenConnection,
1769				MSCPUChar8, MSCUShort16,
1770				MSCPUChar8, MSCUShort16)) vFunction;
1771		rv = (*libMSCGetChallenge) (pConnection, pSeed, seedSize,
1772			pRandomData, randomDataSize);
1773
1774	} else
1775	{
1776		return MSC_UNSUPPORTED_FEATURE;
1777	}
1778
1779	return rv;
1780}
1781
1782MSC_RV MSCGetKeyAttributes(MSCLPTokenConnection pConnection,
1783			   MSCUChar8 keyNumber, MSCLPKeyInfo pKeyInfo)
1784{
1785
1786	MSC_RV rv;
1787	MSCKeyInfo keyInfo;
1788
1789	if (pConnection == NULL)
1790		return MSC_INVALID_PARAMETER;
1791	if (localHContext == 0)
1792		return MSC_INTERNAL_ERROR;
1793
1794	rv = MSCListKeys(pConnection, MSC_SEQUENCE_RESET, &keyInfo);
1795
1796	if (rv != MSC_SEQUENCE_END && rv != MSC_SUCCESS)
1797	{
1798		return rv;
1799	}
1800
1801	if (rv == MSC_SEQUENCE_END)
1802	{
1803		return MSC_INVALID_PARAMETER;
1804	}
1805
1806	if (keyNumber == keyInfo.keyNum)
1807	{
1808		pKeyInfo->keyNum = keyInfo.keyNum;
1809		pKeyInfo->keyType = keyInfo.keyType;
1810		pKeyInfo->keySize = keyInfo.keySize;
1811
1812		pKeyInfo->keyPolicy.cipherMode = keyInfo.keyPolicy.cipherMode;
1813		pKeyInfo->keyPolicy.cipherDirection =
1814			keyInfo.keyPolicy.cipherDirection;
1815
1816		pKeyInfo->keyACL.readPermission =
1817		  keyInfo.keyACL.readPermission;
1818		pKeyInfo->keyACL.writePermission =
1819		  keyInfo.keyACL.writePermission;
1820		pKeyInfo->keyACL.usePermission =
1821		  keyInfo.keyACL.usePermission;
1822
1823		return MSC_SUCCESS;
1824	}
1825
1826	do
1827	{
1828		rv = MSCListKeys(pConnection, MSC_SEQUENCE_NEXT, &keyInfo);
1829		if (keyNumber == keyInfo.keyNum)
1830			break;
1831	}
1832	while (rv == MSC_SUCCESS);
1833
1834	if (rv != MSC_SEQUENCE_END && rv != MSC_SUCCESS)
1835	{
1836		return rv;
1837	}
1838
1839	if (rv == MSC_SEQUENCE_END)
1840	{
1841		return MSC_INVALID_PARAMETER;
1842	}
1843
1844	pKeyInfo->keyNum = keyInfo.keyNum;
1845	pKeyInfo->keyType = keyInfo.keyType;
1846	pKeyInfo->keySize = keyInfo.keySize;
1847
1848	pKeyInfo->keyPolicy.cipherMode = keyInfo.keyPolicy.cipherMode;
1849	pKeyInfo->keyPolicy.cipherDirection =
1850		keyInfo.keyPolicy.cipherDirection;
1851
1852	pKeyInfo->keyACL.readPermission = keyInfo.keyACL.readPermission;
1853	pKeyInfo->keyACL.writePermission = keyInfo.keyACL.writePermission;
1854	pKeyInfo->keyACL.usePermission = keyInfo.keyACL.usePermission;
1855
1856	return MSC_SUCCESS;
1857}
1858
1859MSC_RV MSCGetObjectAttributes(MSCLPTokenConnection pConnection,
1860	MSCString objectID, MSCLPObjectInfo pObjectInfo)
1861{
1862
1863	MSC_RV rv;
1864	MSCObjectInfo objInfo;
1865
1866	if (pConnection == NULL)
1867		return MSC_INVALID_PARAMETER;
1868	if (localHContext == 0)
1869		return MSC_INTERNAL_ERROR;
1870
1871	rv = MSCListObjects(pConnection, MSC_SEQUENCE_RESET, &objInfo);
1872
1873	if (rv != MSC_SEQUENCE_END && rv != MSC_SUCCESS)
1874	{
1875		return rv;
1876	}
1877
1878	if (rv == MSC_SEQUENCE_END)
1879	{
1880		return MSC_OBJECT_NOT_FOUND;
1881	}
1882
1883	if (strncmp(objectID, objInfo.objectID, MSC_MAXSIZE_OBJID) == 0)
1884	{
1885		pObjectInfo->objectSize = objInfo.objectSize;
1886		pObjectInfo->objectACL.readPermission =
1887			objInfo.objectACL.readPermission;
1888		pObjectInfo->objectACL.writePermission =
1889			objInfo.objectACL.writePermission;
1890		pObjectInfo->objectACL.deletePermission =
1891			objInfo.objectACL.deletePermission;
1892		strncpy(pObjectInfo->objectID, objectID, MSC_MAXSIZE_OBJID);
1893		return MSC_SUCCESS;
1894	}
1895
1896	do
1897	{
1898		rv = MSCListObjects(pConnection, MSC_SEQUENCE_NEXT, &objInfo);
1899		if (strncmp(objectID, objInfo.objectID, MSC_MAXSIZE_OBJID) == 0)
1900			break;
1901	}
1902	while (rv == MSC_SUCCESS);
1903
1904	if (rv != MSC_SEQUENCE_END && rv != MSC_SUCCESS)
1905	{
1906		return rv;
1907	}
1908
1909	if (rv == MSC_SEQUENCE_END)
1910	{
1911		return MSC_OBJECT_NOT_FOUND;
1912	}
1913
1914	pObjectInfo->objectSize = objInfo.objectSize;
1915	pObjectInfo->objectACL.readPermission =
1916		objInfo.objectACL.readPermission;
1917	pObjectInfo->objectACL.writePermission =
1918		objInfo.objectACL.writePermission;
1919	pObjectInfo->objectACL.deletePermission =
1920		objInfo.objectACL.deletePermission;
1921	strncpy(pObjectInfo->objectID, objectID, MSC_MAXSIZE_OBJID);
1922
1923	return MSC_SUCCESS;
1924}
1925
1926MSC_RV MSCReadAllocateObject(MSCLPTokenConnection pConnection,
1927			     MSCString objectID, MSCPUChar8 * pOutputData,
1928			     MSCPULong32 dataSize,
1929			     LPRWEventCallback rwCallback,
1930			     MSCPVoid32 addParams)
1931{
1932    MSC_RV rv;
1933    MSCObjectInfo objInfo;
1934    MSCULong32 objectSize;
1935    MSCPUChar8  data = NULL;
1936
1937    if (pConnection == NULL)
1938        return MSC_INVALID_PARAMETER;
1939     if (localHContext == 0)
1940         return MSC_INTERNAL_ERROR;
1941
1942    if (pOutputData == 0)
1943    {
1944        return MSC_INVALID_PARAMETER;
1945    }
1946
1947    *dataSize = 0;
1948    *pOutputData = 0;
1949
1950    rv = MSCGetObjectAttributes(pConnection, objectID, &objInfo);
1951    if (rv == MSC_SUCCESS)
1952    {
1953        objectSize = objInfo.objectSize;
1954        data = (MSCPUChar8) malloc(sizeof(MSCUChar8) * objectSize);
1955        if(data)
1956        {
1957            rv =  MSCReadObject(pConnection, objectID, 0, data,
1958                     objectSize, rwCallback, addParams);
1959
1960            if (rv == MSC_SUCCESS)
1961            {
1962                *dataSize = objectSize;
1963                *pOutputData = data;
1964            }
1965            else
1966            {
1967                rv = MSC_INTERNAL_ERROR;
1968                free(data);
1969            }
1970        }
1971    }
1972
1973    return rv;
1974}
1975
1976
1977MSC_RV pcscToMSC(MSCLong32 pcscCode)
1978{
1979
1980	switch (pcscCode)
1981	{
1982	case SCARD_S_SUCCESS:
1983		return MSC_SUCCESS;
1984	case SCARD_E_INVALID_HANDLE:
1985		return MSC_INVALID_HANDLE;
1986	case SCARD_E_SHARING_VIOLATION:
1987		return MSC_SHARING_VIOLATION;
1988	case SCARD_W_REMOVED_CARD:
1989		return MSC_TOKEN_REMOVED;
1990	case SCARD_E_NO_SMARTCARD:
1991		return MSC_TOKEN_REMOVED;
1992	case SCARD_W_RESET_CARD:
1993		return MSC_TOKEN_RESET;
1994	case SCARD_W_INSERTED_CARD:
1995		return MSC_TOKEN_INSERTED;
1996	case SCARD_E_NO_SERVICE:
1997		return MSC_SERVICE_UNRESPONSIVE;
1998	case SCARD_E_UNKNOWN_CARD:
1999	case SCARD_W_UNSUPPORTED_CARD:
2000	case SCARD_E_CARD_UNSUPPORTED:
2001		return MSC_UNRECOGNIZED_TOKEN;
2002	case SCARD_E_INVALID_PARAMETER:
2003	case SCARD_E_INVALID_VALUE:
2004	case SCARD_E_UNKNOWN_READER:
2005	case SCARD_E_PROTO_MISMATCH:
2006	case SCARD_E_READER_UNAVAILABLE:
2007		return MSC_INVALID_PARAMETER;
2008	case SCARD_E_CANCELLED:
2009		return MSC_CANCELLED;
2010	case SCARD_E_TIMEOUT:
2011		return MSC_TIMEOUT_OCCURRED;
2012
2013	default:
2014		return MSC_INTERNAL_ERROR;
2015	}
2016}
2017
2018char *msc_error(unsigned long int errorCode)	//MSC_RV
2019{
2020
2021	static char message[500];
2022
2023	switch (errorCode)
2024	{
2025	case MSC_SUCCESS:
2026		strncpy(message, "Successful", sizeof(message));
2027		break;
2028	case MSC_NO_MEMORY_LEFT:
2029		strncpy(message, "No more memory", sizeof(message));
2030		break;
2031	case MSC_AUTH_FAILED:
2032		strncpy(message, "Authentication failed", sizeof(message));
2033		break;
2034	case MSC_OPERATION_NOT_ALLOWED:
2035		strncpy(message, "Operation not allowed", sizeof(message));
2036		break;
2037	case MSC_INCONSISTENT_STATUS:
2038		strncpy(message, "Inconsistent status", sizeof(message));
2039		break;
2040	case MSC_UNSUPPORTED_FEATURE:
2041		strncpy(message, "Feature unsupported", sizeof(message));
2042		break;
2043	case MSC_UNAUTHORIZED:
2044		strncpy(message, "Unauthorized usage", sizeof(message));
2045		break;
2046	case MSC_OBJECT_NOT_FOUND:
2047		strncpy(message, "Object not found", sizeof(message));
2048		break;
2049	case MSC_OBJECT_EXISTS:
2050		strncpy(message, "Object already exists", sizeof(message));
2051		break;
2052	case MSC_INCORRECT_ALG:
2053		strncpy(message, "Incorrect algorithm", sizeof(message));
2054		break;
2055	case MSC_SIGNATURE_INVALID:
2056		strncpy(message, "Invalid signature", sizeof(message));
2057		break;
2058	case MSC_IDENTITY_BLOCKED:
2059		strncpy(message, "Identity is blocked", sizeof(message));
2060		break;
2061	case MSC_UNSPECIFIED_ERROR:
2062		strncpy(message, "Unspecified error", sizeof(message));
2063		break;
2064	case MSC_TRANSPORT_ERROR:
2065		strncpy(message, "Transport error", sizeof(message));
2066		break;
2067	case MSC_INVALID_PARAMETER:
2068		strncpy(message, "Invalid parameter", sizeof(message));
2069		break;
2070	case MSC_SEQUENCE_END:
2071		strncpy(message, "End of sequence", sizeof(message));
2072		break;
2073	case MSC_INTERNAL_ERROR:
2074		strncpy(message, "Internal Error", sizeof(message));
2075		break;
2076	case MSC_CANCELLED:
2077		strncpy(message, "Operation Cancelled", sizeof(message));
2078		break;
2079	case MSC_INSUFFICIENT_BUFFER:
2080		strncpy(message, "Buffer is too small", sizeof(message));
2081		break;
2082	case MSC_UNRECOGNIZED_TOKEN:
2083		strncpy(message, "Token is unsupported", sizeof(message));
2084		break;
2085	case MSC_SERVICE_UNRESPONSIVE:
2086		strncpy(message, "Service is not running", sizeof(message));
2087		break;
2088	case MSC_TIMEOUT_OCCURRED:
2089		strncpy(message, "Timeout has occurred", sizeof(message));
2090		break;
2091	case MSC_TOKEN_REMOVED:
2092		strncpy(message, "Token was removed", sizeof(message));
2093		break;
2094	case MSC_TOKEN_RESET:
2095		strncpy(message, "Token was reset", sizeof(message));
2096		break;
2097	case MSC_TOKEN_INSERTED:
2098		strncpy(message, "Token was inserted", sizeof(message));
2099		break;
2100	case MSC_TOKEN_UNRESPONSIVE:
2101		strncpy(message, "Token is unresponsive", sizeof(message));
2102		break;
2103	case MSC_INVALID_HANDLE:
2104		strncpy(message, "Handle is invalid", sizeof(message));
2105		break;
2106	case MSC_SHARING_VIOLATION:
2107		strncpy(message, "Sharing violation", sizeof(message));
2108		break;
2109
2110	default:
2111		sprintf(message, "Unknown SW: %04lu", errorCode);
2112		break;
2113	}
2114
2115	return message;
2116}
2117
2118MSC_RV MSCReEstablishConnection(MSCLPTokenConnection pConnection)
2119{
2120
2121	MSC_RV rv;
2122	MSCPVoid32 vInitFunction, vFinFunction, vIdFunction;
2123	MSCULong32 dwActiveProtocol;
2124	MSCLong32(*libPL_MSCInitializePlugin) (MSCLPTokenConnection);
2125	MSCLong32(*libPL_MSCFinalizePlugin) (MSCLPTokenConnection);
2126        MSCLong32 (*libPL_MSCIdentifyToken)(MSCLPTokenConnection);
2127
2128	vInitFunction = 0;
2129	vFinFunction  = 0;
2130	vIdFunction   = 0;
2131
2132	/*
2133	 * Select the AID or initialization routine for the card
2134	 */
2135	vInitFunction = pConnection->libPointers.pvfInitializePlugin;
2136	vFinFunction  = pConnection->libPointers.pvfFinalizePlugin;
2137	vIdFunction   = pConnection->libPointers.pvfIdentifyToken;
2138
2139	if (vInitFunction == 0)
2140	{
2141		DebugLogB("Error: Card service failure: %s\n",
2142			"InitializePlugin function missing");
2143		return MSC_INTERNAL_ERROR;
2144	}
2145
2146	if (vFinFunction == 0)
2147	{
2148		DebugLogB("Error: Card service failure: %s\n",
2149			"FinalizePlugin function missing");
2150		return MSC_INTERNAL_ERROR;
2151	}
2152
2153	if ( vIdFunction == 0 )
2154	{
2155	        DebugLogB("Error: Card service failure: %s\n",
2156			  "IdentifyToken function missing");
2157		return MSC_INTERNAL_ERROR;
2158	}
2159
2160	libPL_MSCInitializePlugin = (MSCLong32(*)(MSCLPTokenConnection))
2161		vInitFunction;
2162
2163	libPL_MSCFinalizePlugin = (MSCLong32(*)(MSCLPTokenConnection))
2164		vFinFunction;
2165
2166	libPL_MSCIdentifyToken = (MSCLong32 (*)(MSCLPTokenConnection))
2167	        vIdFunction;
2168
2169	rv = SCardReconnect(pConnection->hCard, pConnection->shareMode,
2170		SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
2171		SCARD_LEAVE_CARD, &dwActiveProtocol);
2172
2173	if (rv != SCARD_S_SUCCESS)
2174		return pcscToMSC(rv);
2175
2176	/*
2177	 * Stop the plugin and start it up again
2178	 */
2179	rv = (*libPL_MSCFinalizePlugin) (pConnection);
2180
2181	/*
2182	 * Use the default AID given by the Info.plist
2183	 */
2184	rv = (*libPL_MSCInitializePlugin) (pConnection);
2185
2186	/*
2187	 * Use the default AID given by the Info.plist
2188	 */
2189	rv = (*libPL_MSCIdentifyToken)(pConnection);
2190
2191	if (rv != MSC_SUCCESS)
2192		return rv;
2193
2194	return MSC_SUCCESS;
2195}
2196
2197MSCUChar8 MSCIsTokenReset(MSCLPTokenConnection pConnection)
2198{
2199        MSCULong32 rv;
2200	char slotName[MAX_READERNAME];
2201	MSCULong32 slotNameSize, slotState, slotProtocol;
2202	MSCUChar8 tokenId[MAX_ATR_SIZE];
2203	MSCULong32 tokenIdLength;
2204
2205	rv = SCardStatus(pConnection->hCard, slotName,
2206			 &slotNameSize, &slotState, &slotProtocol,
2207			 tokenId, &tokenIdLength);
2208
2209	if (rv == SCARD_W_RESET_CARD)
2210	{
2211	        return 1;
2212	}
2213
2214	if (pConnection->tokenInfo.tokenType & MSC_TOKEN_TYPE_RESET)
2215	{
2216		return 1;
2217	} else
2218	{
2219		return 0;
2220	}
2221}
2222
2223MSCUChar8 MSCClearReset(MSCLPTokenConnection pConnection)
2224{
2225	pConnection->tokenInfo.tokenType &= ~MSC_TOKEN_TYPE_RESET;
2226	return 1;
2227}
2228
2229MSCUChar8 MSCIsTokenMoved(MSCLPTokenConnection pConnection)
2230{
2231        MSCULong32 rv;
2232	char slotName[MAX_READERNAME];
2233	MSCULong32 slotNameSize, slotState, slotProtocol;
2234	MSCUChar8 tokenId[MAX_ATR_SIZE];
2235	MSCULong32 tokenIdLength;
2236
2237
2238	rv = SCardStatus(pConnection->hCard, slotName,
2239			 &slotNameSize, &slotState, &slotProtocol,
2240			 tokenId, &tokenIdLength);
2241
2242	if (rv == SCARD_W_REMOVED_CARD)
2243	{
2244	        return 1;
2245	} else if (rv == SCARD_W_INSERTED_CARD)
2246	{
2247	        return 1;
2248	} else if (slotState & SCARD_ABSENT)
2249	{
2250	        return 1;
2251	}
2252
2253
2254	if (pConnection->tokenInfo.tokenType & MSC_TOKEN_TYPE_REMOVED)
2255	{
2256		return 1;
2257	} else
2258	{
2259		return 0;
2260	}
2261}
2262
2263MSCUChar8 MSCIsTokenChanged(MSCLPTokenConnection pConnection)
2264{
2265	if (MSCIsTokenMoved(pConnection))
2266	{
2267		return 1;
2268	} else if (MSCIsTokenReset(pConnection))
2269	{
2270		return 1;
2271	} else {
2272	        return 0;
2273	}
2274}
2275
2276MSCUChar8 MSCIsTokenKnown(MSCLPTokenConnection pConnection)
2277{
2278	if (pConnection->tokenInfo.tokenType & MSC_TOKEN_TYPE_KNOWN)
2279	{
2280		return 1;
2281	} else
2282	{
2283		return 0;
2284	}
2285}
2286