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  : tokenfactory.c
22		Package: pcsc lite
23		Author : David Corcoran
24		Date   : 01/01/00
25		Purpose: This handles card abstraction attachment.
26
27 $Id: tokenfactory.c 123 2010-03-27 10:50:42Z ludovic.rousseau@gmail.com $
28
29*******************************************************************/
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <sys/types.h>
35
36#ifndef WIN32
37#include <dirent.h>
38#include "config.h"
39#else
40#include "../win32/win32_config.h"
41#endif
42
43#include "debuglog.h"
44#include "dyn_generic.h"
45#include "tokenfactory.h"
46
47#define MSC_MANUMSC_KEY_NAME                "spVendorName"
48#define MSC_PRODMSC_KEY_NAME                "spProductName"
49#define MSC_ATRMSC_KEY_NAME                 "spAtrValue"
50#define MSC_LIBRMSC_KEY_NAME                "CFBundleExecutable"
51#define MSC_DEFAULTAPP_NAME                 "spDefaultApplication"
52
53extern int LTPBundleFindValueWithKey(char *, char *, char *, int);
54
55int atrToString(MSCPUChar8 Atr, MSCULong32 Length, char *outAtr)
56{
57
58	int i;
59	int j;
60
61	j = 0;
62
63	for (i = 0; i < Length; i++)
64	{
65		if ((Atr[i] / 16) > 9)
66		{
67			outAtr[j] = ((Atr[i] / 16) - 10) + 'A';
68		} else
69		{
70			outAtr[j] = (Atr[i] / 16) + '0';
71		}
72
73		j += 1;
74
75		if ((Atr[i] % 16) > 9)
76		{
77			outAtr[j] = ((Atr[i] % 16) - 10) + 'A';
78		} else
79		{
80			outAtr[j] = (Atr[i] % 16) + '0';
81		}
82
83		j += 1;
84
85	}
86
87	outAtr[j] = 0;	/* Add the NULL */
88
89	return 0;
90}
91
92int stringToBytes(char *inStr, MSCPUChar8 Buffer, MSCPULong32 Length)
93{
94
95	int i;
96	int j;
97	int inLen;
98
99	j = 0;
100	inLen = 0;
101
102	inLen = strlen(inStr);
103
104	if (inLen > MSC_MAXSIZE_AID)
105	{
106		return -1;
107	}
108
109	for (i = 0; i < inLen; i += 2)
110	{
111		if (inStr[i] <= '9' && inStr[i] >= '0')
112		{
113			Buffer[j] = (inStr[i] - '0') * 16;
114		} else if (inStr[i] <= 'F' && inStr[i] >= 'A')
115		{
116			Buffer[j] = (inStr[i] - 'A' + 10) * 16;
117		}
118
119		if (inStr[i + 1] <= '9' && inStr[i + 1] >= '0')
120		{
121			Buffer[j] += inStr[i + 1] - '0';
122		} else if (inStr[i + 1] <= 'F' && inStr[i + 1] >= 'A')
123		{
124			Buffer[j] += inStr[i + 1] - 'A' + 10;
125		}
126
127		j += 1;
128	}
129
130	*Length = j;
131
132	return 0;
133}
134
135MSCLong32 TPSearchBundlesForAtr(MSCPUChar8 Atr, MSCULong32 Length,
136	MSCLPTokenInfo tokenInfo)
137{
138
139	MSCLong32 rv;
140
141#ifndef WIN32
142	DIR *hpDir = 0;
143	struct dirent *currFP = 0;
144#else
145	HANDLE hFind;
146	WIN32_FIND_DATA findData;
147	char findPath[200];
148#endif
149
150	char atrString[100];
151	char fullPath[200];
152	char fullLibPath[250];
153	char keyValue[200];
154	int atrIndex;
155
156	rv = 0;
157	atrIndex = 0;
158
159	atrToString(Atr, Length, atrString);
160
161#ifndef WIN32
162
163	hpDir = opendir(MSC_SVC_DROPDIR);
164
165	if (hpDir == 0)
166#else
167	sprintf(findPath, "%s\\*.bundle", MSC_SVC_DROPDIR);
168	hFind = FindFirstFile(findPath, &findData);
169
170	if (hFind == INVALID_HANDLE_VALUE)
171#endif
172	{
173		DebugLogA("Cannot open PC/SC token drivers directory.\n");
174
175		return -1;
176	}
177
178#ifndef WIN32
179	while ((currFP = readdir(hpDir)) != 0)
180	{
181		if (strstr(currFP->d_name, ".bundle") != 0)
182#else
183	do
184	{
185		if (strstr(findData.cFileName, ".bundle") != 0)
186#endif
187		{
188
189			/*
190			 * The bundle exists - let's form a full path name and get the
191			 * vendor and product ID's for this particular bundle
192			 */
193#ifndef WIN32
194			sprintf(fullPath, "%s%s%s", MSC_SVC_DROPDIR, currFP->d_name,
195				"/Contents/Info.plist");
196#else
197			sprintf(fullPath, "%s%s%s", MSC_SVC_DROPDIR, findData.cFileName,
198				"\\Contents\\Info.plist");
199#endif
200
201			atrIndex = 0;
202
203#ifdef MSC_DEBUG
204			DebugLogB("ATR comparison: FILE: %s\n", fullPath);
205			DebugLogB("ATR comparison: Target Match: %s\n", atrString);
206#endif
207
208			while (1)
209			{
210				rv = LTPBundleFindValueWithKey(fullPath,
211					MSC_ATRMSC_KEY_NAME, keyValue, atrIndex);
212				if (rv != 0)
213				{
214					break;	/* No aliases found, break out of search
215							 * aliases loop */
216				}
217#ifdef MSC_DEBUG
218				DebugLogB("ATR comparison: Source: %s\n", keyValue);
219#endif
220
221				if (strcmp(keyValue, atrString) != 0)
222				{
223					/*
224					 * Go back and see if there are any aliases
225					 */
226					atrIndex += 1;
227					continue;
228				}
229#ifdef MSC_DEBUG
230				DebugLogB("Match found at ATR alias %d\n", atrIndex);
231#endif
232
233				/*
234				 * See if this bundle has a special name for this ATR
235				 */
236				rv = LTPBundleFindValueWithKey(fullPath,
237					MSC_PRODMSC_KEY_NAME, keyValue, atrIndex);
238				if (rv != 0)
239				{
240					rv = LTPBundleFindValueWithKey(fullPath,
241						MSC_PRODMSC_KEY_NAME, keyValue, 0);
242					if (rv != 0)
243					{
244						DebugLogA
245							("Match found, failed due to no product name.\n");
246#ifndef WIN32
247						closedir(hpDir);
248#endif
249						return -1;
250					}
251				}
252#ifdef MSC_DEBUG
253				DebugLogB("Product name: %s\n", keyValue);
254#endif
255				strcpy(tokenInfo->tokenName, keyValue);
256
257				/*
258				 * See if this bundle has a special driver for this card
259				 */
260				rv = LTPBundleFindValueWithKey(fullPath,
261					MSC_LIBRMSC_KEY_NAME, keyValue, atrIndex);
262				if (rv != 0)
263				{
264					rv = LTPBundleFindValueWithKey(fullPath,
265						MSC_LIBRMSC_KEY_NAME, keyValue, 0);
266					if (rv != 0)
267					{
268						DebugLogA
269							("Match found, failed due to no library path.\n");
270#ifndef WIN32
271						closedir(hpDir);
272#endif
273						return -1;
274					}
275				}
276#ifdef WIN32
277				sprintf(fullLibPath, "%s%s%s%s", MSC_SVC_DROPDIR,
278					findData.cFileName, "\\Contents\\Win32\\", keyValue);
279#else
280#ifdef MSC_TARGET_LINUX
281				sprintf(fullLibPath, "%s%s%s%s", MSC_SVC_DROPDIR,
282					currFP->d_name, "/Contents/Linux/", keyValue);
283#else
284#ifdef MSC_TARGET_OSX
285				sprintf(fullLibPath, "%s%s", MSC_SVC_DROPDIR,
286					currFP->d_name);
287
288#else
289#ifdef MSC_TARGET_BSD
290				sprintf(fullLibPath, "%s%s%s%s", MSC_SVC_DROPDIR,
291					currFP->d_name, "/Contents/BSD/", keyValue);
292
293#else
294#ifdef MSC_TARGET_SOLARIS
295				sprintf(fullLibPath, "%s%s%s%s", MSC_SVC_DROPDIR,
296					currFP->d_name, "/Contents/Solaris/", keyValue);
297
298#else
299#ifdef MSC_TARGET_HPUX
300				sprintf(fullLibPath, "%s%s%s%s", MSC_SVC_DROPDIR,
301					currFP->d_name, "/Contents/HPUX/", keyValue);
302
303#else
304#ifdef MSC_TARGET_TRU64
305				sprintf(fullLibPath, "%s%s%s%s", MSC_SVC_DROPDIR,
306					currFP->d_name, "/Contents/Tru64/", keyValue);
307
308#else
309#ifdef MSC_TARGET_CYGWIN
310				sprintf(fullLibPath, "%s%s%s%s", MSC_SVC_DROPDIR,
311					currFP->d_name, "/Contents/CygWin/", keyValue);
312#endif
313#endif
314#endif
315#endif
316#endif
317#endif
318#endif
319#endif
320
321				if (fullLibPath == NULL)
322				{
323					DebugLogA("No path to bundle library found !\n");
324					return -1;
325				}
326
327				/*
328				 * Copy the library path and return successfully
329				 */
330				strcpy(tokenInfo->svProvider, fullLibPath);
331
332				/*
333				 * See if this bundle has a default AID
334				 */
335				rv = LTPBundleFindValueWithKey(fullPath,
336					MSC_DEFAULTAPP_NAME, keyValue, atrIndex);
337				if (rv != 0)
338				{
339					rv = LTPBundleFindValueWithKey(fullPath,
340						MSC_DEFAULTAPP_NAME, keyValue, 0);
341				}
342
343				if (rv == 0)
344				{
345#ifdef MSC_DEBUG
346					DebugLogB("Default AID name: %s\n", keyValue);
347#endif
348					rv = stringToBytes(keyValue, tokenInfo->tokenApp,
349						&tokenInfo->tokenAppLen);
350					if (rv != 0)
351					{
352						DebugLogA
353							("Match found, failed due to malformed aid string.\n");
354#ifndef WIN32
355						closedir(hpDir);
356#endif
357						return -1;
358					}
359
360				} else
361				{
362					DebugLogA("No AID specified in bundle\n");
363					tokenInfo->tokenAppLen = 0;
364				}
365
366#ifndef WIN32
367				closedir(hpDir);
368#endif
369				return 0;
370
371			}	/* do ... while */
372		}	/* if .bundle */
373	}	/* while readdir */
374#ifdef WIN32
375	// This is part of a Do..While loop (see above)
376	while (FindNextFile(hFind, &findData) != 0);
377#endif
378
379#ifndef WIN32
380	closedir(hpDir);
381#endif
382	return -1;
383}
384
385const char *TPSvcDropdir(void)
386{
387	const char *dropDir = getenv(MSC_SVC_DROPDIR_ENV);
388	if (dropDir)
389		return dropDir;
390
391	return MSC_SVC_DROPDIR_DEFAULT;
392}
393
394MSCLong32 TPLoadToken(MSCLPTokenConnection pConnection)
395{
396
397	MSCLong32 rv;
398
399	pConnection->libPointers.pvfWriteFramework = 0;
400	pConnection->libPointers.pvfInitializePlugin = 0;
401	pConnection->libPointers.pvfFinalizePlugin = 0;
402	pConnection->libPointers.pvfGetStatus = 0;
403	pConnection->libPointers.pvfGetCapabilities = 0;
404	pConnection->libPointers.pvfExtendedFeature = 0;
405	pConnection->libPointers.pvfGenerateKeys = 0;
406	pConnection->libPointers.pvfImportKey = 0;
407	pConnection->libPointers.pvfExportKey = 0;
408	pConnection->libPointers.pvfComputeCrypt = 0;
409	pConnection->libPointers.pvfExtAuthenticate = 0;
410	pConnection->libPointers.pvfListKeys = 0;
411	pConnection->libPointers.pvfCreatePIN = 0;
412	pConnection->libPointers.pvfVerifyPIN = 0;
413	pConnection->libPointers.pvfChangePIN = 0;
414	pConnection->libPointers.pvfUnblockPIN = 0;
415	pConnection->libPointers.pvfListPINs = 0;
416	pConnection->libPointers.pvfCreateObject = 0;
417	pConnection->libPointers.pvfDeleteObject = 0;
418	pConnection->libPointers.pvfWriteObject = 0;
419	pConnection->libPointers.pvfReadObject = 0;
420	pConnection->libPointers.pvfListObjects = 0;
421	pConnection->libPointers.pvfLogoutAll = 0;
422	pConnection->libPointers.pvfGetChallenge = 0;
423
424	/*
425	 * Find the Card's Library
426	 */
427
428	rv = TPSearchBundlesForAtr(pConnection->tokenInfo.tokenId,
429		pConnection->tokenInfo.tokenIdLength, &pConnection->tokenInfo);
430
431	if (rv != 0)
432	{
433		DebugLogA("Error: Matching Token ATR Not Found.\n");
434		log_xxd(PCSC_LOG_INFO, "ATR  : ", pConnection->tokenInfo.tokenId,
435			pConnection->tokenInfo.tokenIdLength);
436
437		return SCARD_E_CARD_UNSUPPORTED;
438	}
439
440	/*
441	 * Load that library and store the handle in the SCARDCHANNEL
442	 * structure
443	 */
444
445	rv = DYN_LoadLibrary(&pConnection->tokenLibHandle,
446		pConnection->tokenInfo.svProvider);
447
448	if (rv != SCARD_S_SUCCESS)
449	{
450		DebugLogA("Error: Could not load service library\n");
451		DebugLogB("->> %s\n", pConnection->tokenInfo.svProvider);
452		return SCARD_E_INVALID_TARGET;
453	} else
454	{
455		DebugLogB("Loading service library %s\n",
456			pConnection->tokenInfo.svProvider);
457	}
458
459	rv = TPBindFunctions(pConnection);
460
461	return rv;
462}
463
464MSCLong32 TPUnloadToken(MSCLPTokenConnection pConnection)
465{
466
467	MSCLong32 rv;
468
469	if (pConnection->tokenLibHandle == 0)
470	{
471		return SCARD_E_INVALID_VALUE;
472	}
473
474	rv = DYN_CloseLibrary(&pConnection->tokenLibHandle);
475
476	if (rv != SCARD_S_SUCCESS)
477	{
478		return rv;
479	}
480
481	pConnection->tokenLibHandle = 0;
482	return TPUnbindFunctions(pConnection);
483}
484
485MSCLong32 TPBindFunctions(MSCLPTokenConnection pConnection)
486{
487
488	MSCLong32 rv;
489
490	if (pConnection->tokenLibHandle == 0)
491	{
492		return SCARD_E_INVALID_TARGET;
493	}
494
495	rv = DYN_GetAddress(pConnection->tokenLibHandle,
496		&pConnection->libPointers.pvfWriteFramework,
497		"PL_MSCWriteFramework");
498
499	if (rv != SCARD_S_SUCCESS)
500	{
501		pConnection->libPointers.pvfWriteFramework = 0;
502		DebugLogA("TPBindFunctions: Missing functions");
503		/*
504		 * No big deal - this feature is just not supported
505		 */
506	}
507
508	rv = DYN_GetAddress(pConnection->tokenLibHandle,
509		&pConnection->libPointers.pvfIdentifyToken, "PL_MSCIdentifyToken");
510
511	if (rv != SCARD_S_SUCCESS)
512	{
513		pConnection->libPointers.pvfIdentifyToken = 0;
514		DebugLogA("TPBindFunctions: Missing functions");
515		return SCARD_F_INTERNAL_ERROR;
516	}
517
518	rv = DYN_GetAddress(pConnection->tokenLibHandle,
519		&pConnection->libPointers.pvfInitializePlugin,
520		"PL_MSCInitializePlugin");
521
522	if (rv != SCARD_S_SUCCESS)
523	{
524		pConnection->libPointers.pvfInitializePlugin = 0;
525		DebugLogA("TPBindFunctions: Missing functions");
526		return SCARD_F_INTERNAL_ERROR;
527	}
528
529	rv = DYN_GetAddress(pConnection->tokenLibHandle,
530		&pConnection->libPointers.pvfFinalizePlugin,
531		"PL_MSCFinalizePlugin");
532
533	if (rv != SCARD_S_SUCCESS)
534	{
535		pConnection->libPointers.pvfFinalizePlugin = 0;
536		DebugLogA("TPBindFunctions: Missing functions");
537		return SCARD_F_INTERNAL_ERROR;
538	}
539
540	rv = DYN_GetAddress(pConnection->tokenLibHandle,
541		&pConnection->libPointers.pvfGetStatus, "PL_MSCGetStatus");
542
543	if (rv != SCARD_S_SUCCESS)
544	{
545		pConnection->libPointers.pvfGetStatus = 0;
546		DebugLogA("TPBindFunctions: Missing functions");
547		return SCARD_F_INTERNAL_ERROR;
548	}
549
550	rv = DYN_GetAddress(pConnection->tokenLibHandle,
551		&pConnection->libPointers.pvfGetCapabilities,
552		"PL_MSCGetCapabilities");
553
554	if (rv != SCARD_S_SUCCESS)
555	{
556		pConnection->libPointers.pvfGetCapabilities = 0;
557		DebugLogA("TPBindFunctions: Missing functions");
558		return SCARD_F_INTERNAL_ERROR;
559	}
560
561	rv = DYN_GetAddress(pConnection->tokenLibHandle,
562		&pConnection->libPointers.pvfExtendedFeature,
563		"PL_MSCExtendedFeature");
564
565	if (rv != SCARD_S_SUCCESS)
566	{
567		pConnection->libPointers.pvfExtendedFeature = 0;
568		DebugLogA("TPBindFunctions: Missing functions");
569		/*
570		 * No big deal - there are no extended features
571		 */
572	}
573
574	rv = DYN_GetAddress(pConnection->tokenLibHandle,
575		&pConnection->libPointers.pvfGenerateKeys, "PL_MSCGenerateKeys");
576
577	if (rv != SCARD_S_SUCCESS)
578	{
579		pConnection->libPointers.pvfGenerateKeys = 0;
580		DebugLogA("TPBindFunctions: Missing functions");
581		return SCARD_F_INTERNAL_ERROR;
582	}
583
584	rv = DYN_GetAddress(pConnection->tokenLibHandle,
585		&pConnection->libPointers.pvfImportKey, "PL_MSCImportKey");
586
587	if (rv != SCARD_S_SUCCESS)
588	{
589		pConnection->libPointers.pvfImportKey = 0;
590		DebugLogA("TPBindFunctions: Missing functions");
591		return SCARD_F_INTERNAL_ERROR;
592	}
593
594	rv = DYN_GetAddress(pConnection->tokenLibHandle,
595		&pConnection->libPointers.pvfExportKey, "PL_MSCExportKey");
596
597	if (rv != SCARD_S_SUCCESS)
598	{
599		pConnection->libPointers.pvfExportKey = 0;
600		DebugLogA("TPBindFunctions: Missing functions");
601		return SCARD_F_INTERNAL_ERROR;
602	}
603
604	rv = DYN_GetAddress(pConnection->tokenLibHandle,
605		&pConnection->libPointers.pvfComputeCrypt, "PL_MSCComputeCrypt");
606
607	if (rv != SCARD_S_SUCCESS)
608	{
609		pConnection->libPointers.pvfComputeCrypt = 0;
610		DebugLogA("TPBindFunctions: Missing functions");
611		return SCARD_F_INTERNAL_ERROR;
612	}
613
614	rv = DYN_GetAddress(pConnection->tokenLibHandle,
615		&pConnection->libPointers.pvfExtAuthenticate,
616		"PL_MSCExtAuthenticate");
617
618	if (rv != SCARD_S_SUCCESS)
619	{
620		pConnection->libPointers.pvfExtAuthenticate = 0;
621		DebugLogA("TPBindFunctions: Missing functions");
622		return SCARD_F_INTERNAL_ERROR;
623	}
624
625	rv = DYN_GetAddress(pConnection->tokenLibHandle,
626		&pConnection->libPointers.pvfListKeys, "PL_MSCListKeys");
627
628	if (rv != SCARD_S_SUCCESS)
629	{
630		pConnection->libPointers.pvfListKeys = 0;
631		DebugLogA("TPBindFunctions: Missing functions");
632		return SCARD_F_INTERNAL_ERROR;
633	}
634
635	rv = DYN_GetAddress(pConnection->tokenLibHandle,
636		&pConnection->libPointers.pvfCreatePIN, "PL_MSCCreatePIN");
637
638	if (rv != SCARD_S_SUCCESS)
639	{
640		pConnection->libPointers.pvfCreatePIN = 0;
641		DebugLogA("TPBindFunctions: Missing functions");
642		return SCARD_F_INTERNAL_ERROR;
643	}
644
645	rv = DYN_GetAddress(pConnection->tokenLibHandle,
646		&pConnection->libPointers.pvfVerifyPIN, "PL_MSCVerifyPIN");
647
648	if (rv != SCARD_S_SUCCESS)
649	{
650		pConnection->libPointers.pvfVerifyPIN = 0;
651		DebugLogA("TPBindFunctions: Missing functions");
652		return SCARD_F_INTERNAL_ERROR;
653	}
654
655	rv = DYN_GetAddress(pConnection->tokenLibHandle,
656		&pConnection->libPointers.pvfChangePIN, "PL_MSCChangePIN");
657
658	if (rv != SCARD_S_SUCCESS)
659	{
660		pConnection->libPointers.pvfChangePIN = 0;
661		DebugLogA("TPBindFunctions: Missing functions");
662		return SCARD_F_INTERNAL_ERROR;
663	}
664
665	rv = DYN_GetAddress(pConnection->tokenLibHandle,
666		&pConnection->libPointers.pvfUnblockPIN, "PL_MSCUnblockPIN");
667
668	if (rv != SCARD_S_SUCCESS)
669	{
670		pConnection->libPointers.pvfUnblockPIN = 0;
671		DebugLogA("TPBindFunctions: Missing functions");
672		return SCARD_F_INTERNAL_ERROR;
673	}
674
675	rv = DYN_GetAddress(pConnection->tokenLibHandle,
676		&pConnection->libPointers.pvfListPINs, "PL_MSCListPINs");
677
678	if (rv != SCARD_S_SUCCESS)
679	{
680		pConnection->libPointers.pvfListPINs = 0;
681		DebugLogA("TPBindFunctions: Missing functions");
682		return SCARD_F_INTERNAL_ERROR;
683	}
684
685	rv = DYN_GetAddress(pConnection->tokenLibHandle,
686		&pConnection->libPointers.pvfCreateObject, "PL_MSCCreateObject");
687
688	if (rv != SCARD_S_SUCCESS)
689	{
690		pConnection->libPointers.pvfCreateObject = 0;
691		DebugLogA("TPBindFunctions: Missing functions");
692		return SCARD_F_INTERNAL_ERROR;
693	}
694
695	rv = DYN_GetAddress(pConnection->tokenLibHandle,
696		&pConnection->libPointers.pvfDeleteObject, "PL_MSCDeleteObject");
697
698	if (rv != SCARD_S_SUCCESS)
699	{
700		pConnection->libPointers.pvfDeleteObject = 0;
701		DebugLogA("TPBindFunctions: Missing functions");
702		return SCARD_F_INTERNAL_ERROR;
703	}
704
705	rv = DYN_GetAddress(pConnection->tokenLibHandle,
706		&pConnection->libPointers.pvfWriteObject, "PL_MSCWriteObject");
707
708	if (rv != SCARD_S_SUCCESS)
709	{
710		pConnection->libPointers.pvfWriteObject = 0;
711		DebugLogA("TPBindFunctions: Missing functions");
712		return SCARD_F_INTERNAL_ERROR;
713	}
714
715	rv = DYN_GetAddress(pConnection->tokenLibHandle,
716		&pConnection->libPointers.pvfReadObject, "PL_MSCReadObject");
717
718	if (rv != SCARD_S_SUCCESS)
719	{
720		pConnection->libPointers.pvfReadObject = 0;
721		DebugLogA("TPBindFunctions: Missing functions");
722		return SCARD_F_INTERNAL_ERROR;
723	}
724
725	rv = DYN_GetAddress(pConnection->tokenLibHandle,
726		&pConnection->libPointers.pvfListObjects, "PL_MSCListObjects");
727
728	if (rv != SCARD_S_SUCCESS)
729	{
730		pConnection->libPointers.pvfListObjects = 0;
731		DebugLogA("TPBindFunctions: Missing functions");
732		return SCARD_F_INTERNAL_ERROR;
733	}
734
735	rv = DYN_GetAddress(pConnection->tokenLibHandle,
736		&pConnection->libPointers.pvfLogoutAll, "PL_MSCLogoutAll");
737
738	if (rv != SCARD_S_SUCCESS)
739	{
740		pConnection->libPointers.pvfLogoutAll = 0;
741		DebugLogA("TPBindFunctions: Missing functions");
742		return SCARD_F_INTERNAL_ERROR;
743	}
744
745	rv = DYN_GetAddress(pConnection->tokenLibHandle,
746		&pConnection->libPointers.pvfGetChallenge, "PL_MSCGetChallenge");
747
748	if (rv != SCARD_S_SUCCESS)
749	{
750		pConnection->libPointers.pvfGetChallenge = 0;
751		DebugLogA("TPBindFunctions: Missing functions");
752		return SCARD_F_INTERNAL_ERROR;
753	}
754
755	return SCARD_S_SUCCESS;
756}
757
758MSCLong32 TPUnbindFunctions(MSCLPTokenConnection pConnection)
759{
760
761	pConnection->libPointers.pvfWriteFramework = 0;
762	pConnection->libPointers.pvfInitializePlugin = 0;
763	pConnection->libPointers.pvfFinalizePlugin = 0;
764	pConnection->libPointers.pvfGetStatus = 0;
765	pConnection->libPointers.pvfGetCapabilities = 0;
766	pConnection->libPointers.pvfExtendedFeature = 0;
767	pConnection->libPointers.pvfGenerateKeys = 0;
768	pConnection->libPointers.pvfImportKey = 0;
769	pConnection->libPointers.pvfExportKey = 0;
770	pConnection->libPointers.pvfComputeCrypt = 0;
771	pConnection->libPointers.pvfExtAuthenticate = 0;
772	pConnection->libPointers.pvfListKeys = 0;
773	pConnection->libPointers.pvfCreatePIN = 0;
774	pConnection->libPointers.pvfVerifyPIN = 0;
775	pConnection->libPointers.pvfChangePIN = 0;
776	pConnection->libPointers.pvfUnblockPIN = 0;
777	pConnection->libPointers.pvfListPINs = 0;
778	pConnection->libPointers.pvfCreateObject = 0;
779	pConnection->libPointers.pvfDeleteObject = 0;
780	pConnection->libPointers.pvfWriteObject = 0;
781	pConnection->libPointers.pvfReadObject = 0;
782	pConnection->libPointers.pvfListObjects = 0;
783	pConnection->libPointers.pvfLogoutAll = 0;
784	pConnection->libPointers.pvfGetChallenge = 0;
785
786	return SCARD_S_SUCCESS;
787}
788