Logo Search packages:      
Sourcecode: pcsc-lite version File versions

tokenfactory.c

/*
 * This handles card abstraction attachment.
 *
 * MUSCLE SmartCard Development ( http://www.linuxnet.com )
 *
 * Copyright (C) 2000
 *  David Corcoran <corcoran@linuxnet.com>
 * Copyright (C) 2004
 *  Ludovic Rousseau <ludovic.rousseau@free.fr>
 *
 * $Id: tokenfactory.c,v 1.30 2005/02/22 15:38:55 rousseau Exp $
 */

#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#endif

#include <debuglog.h>
#include <parser.h>
#include <dyn_generic.h>

#include "tokenfactory.h"
#include "strlcpycat.h"

#ifndef WIN32
#ifndef MSC_SVC_DROPDIR
#define MSC_SVC_DROPDIR                     "/usr/local/pcsc/services"
#endif
#else
#define MSC_SVC_DROPDIR                     "C:\\Program Files\\Muscle\\Services"
#endif

#define MSC_MANUMSC_KEY_NAME                "spVendorName"
#define MSC_PRODMSC_KEY_NAME                "spProductName"
#define MSC_ATRMSC_KEY_NAME                 "spAtrValue"
#define MSC_LIBRMSC_KEY_NAME                "CFBundleExecutable"
#define MSC_DEFAULTAPP_NAME                 "spDefaultApplication"

int atrToString(MSCPUChar8 Atr, MSCULong32 Length, char *outAtr)
{
      MSCULong32 i;
      MSCULong32 j;

      j = 0;

      for (i = 0; i < Length; i++)
      {
            if ((Atr[i] / 16) > 9)
            {
                  outAtr[j] = ((Atr[i] / 16) - 10) + 'A';
            } else
            {
                  outAtr[j] = (Atr[i] / 16) + '0';
            }

            j += 1;

            if ((Atr[i] % 16) > 9)
            {
                  outAtr[j] = ((Atr[i] % 16) - 10) + 'A';
            } else
            {
                  outAtr[j] = (Atr[i] % 16) + '0';
            }

            j += 1;

      }

      outAtr[j] = 0;    /* Add the NULL */

      return 0;
}

int stringToBytes(char *inStr, MSCPUChar8 Buffer, MSCPULong32 Length)
{
      int i;
      int j;
      int inLen;

      j = 0;
      inLen = 0;

      inLen = strlen(inStr);

      if (inLen > MSC_MAXSIZE_AID)
      {
            return -1;
      }

      for (i = 0; i < inLen; i += 2)
      {
            if (inStr[i] <= '9' && inStr[i] >= '0')
            {
                  Buffer[j] = (inStr[i] - '0') * 16;
            } else if (inStr[i] <= 'F' && inStr[i] >= 'A')
            {
                  Buffer[j] = (inStr[i] - 'A' + 10) * 16;
            }

            if (inStr[i + 1] <= '9' && inStr[i + 1] >= '0')
            {
                  Buffer[j] += inStr[i + 1] - '0';
            } else if (inStr[i + 1] <= 'F' && inStr[i + 1] >= 'A')
            {
                  Buffer[j] += inStr[i + 1] - 'A' + 10;
            }

            j += 1;
      }

      *Length = j;

      return 0;
}

MSCLong32 TPSearchBundlesForAtr(MSCPUChar8 Atr, MSCULong32 Length,
      MSCLPTokenInfo tokenInfo)
{
      MSCLong32 rv;

#ifndef WIN32
      DIR *hpDir = 0;
      struct dirent *currFP = 0;
#else
      HANDLE hFind;
      WIN32_FIND_DATA findData;
      char findPath[200];
#endif

      char atrString[MAX_ATR_SIZE*2 +1]; /* ATR in ASCII */
      char fullPath[200];
      char fullLibPath[250];
      char keyValue[TOKEN_MAX_VALUE_SIZE];
      int atrIndex;

      rv = 0;
      atrIndex = 0;

      atrToString(Atr, Length, atrString);

#ifndef WIN32
      hpDir = opendir(MSC_SVC_DROPDIR);

      if (hpDir == 0)
      {
            Log2(PCSC_LOG_ERROR, "Cannot open PC/SC token drivers directory: %s",
                  MSC_SVC_DROPDIR);
            return -1;
      }
#else
      sprintf(findPath, "%s\\*.bundle", MSC_SVC_DROPDIR);
      hFind = FindFirstFile(findPath, &findData);

      if (hFind == INVALID_HANDLE_VALUE)
      {
            Log2(PCSC_LOG_ERROR, "Cannot open PC/SC token drivers directory: %s",
                  findPath);
            return -1;
      }
#endif

#ifndef WIN32
      while ((currFP = readdir(hpDir)) != 0)
      {
            if (strstr(currFP->d_name, ".bundle") != 0)
#else
      do
      {
            if (strstr(findData.cFileName, ".bundle") != 0)
#endif
            {

                  /*
                   * The bundle exists - let's form a full path name and get the
                   * vendor and product ID's for this particular bundle 
                   */
#ifndef WIN32
                  sprintf(fullPath, "%s/%s/Contents/Info.plist", MSC_SVC_DROPDIR,
                        currFP->d_name);
#else
                  sprintf(fullPath, "%s\\%s\\Contents\\Info.plist", MSC_SVC_DROPDIR,
                        findData.cFileName);
#endif

                  atrIndex = 0;

#ifndef NO_MSC_DEBUG
                  Log2(PCSC_LOG_DEBUG, "ATR comparison: FILE: %s", fullPath);
                  Log2(PCSC_LOG_DEBUG, "ATR comparison: Target Match: %s", atrString);
#endif

                  while (1)
                  {
                        rv = LTPBundleFindValueWithKey(fullPath,
                              MSC_ATRMSC_KEY_NAME, keyValue, atrIndex);
                        if (rv != 0)
                        {
                              break;      /* No aliases found, break out of search
                                           * aliases loop */
                        }
#ifndef NO_MSC_DEBUG
                        Log2(PCSC_LOG_DEBUG, "ATR comparison: Source: %s", keyValue);
#endif

                        if (strcmp(keyValue, atrString) != 0)
                        {
                              /*
                               * Go back and see if there are any aliases 
                               */
                              atrIndex += 1;
                              continue;
                        }
#ifndef NO_MSC_DEBUG
                        Log2(PCSC_LOG_DEBUG, "Match found at ATR alias %d", atrIndex);
#endif

                        /*
                         * See if this bundle has a special name for this ATR 
                         */
                        rv = LTPBundleFindValueWithKey(fullPath,
                              MSC_PRODMSC_KEY_NAME, keyValue, atrIndex);
                        if (rv != 0)
                        {
                              rv = LTPBundleFindValueWithKey(fullPath,
                                    MSC_PRODMSC_KEY_NAME, keyValue, 0);
                              if (rv != 0)
                              {
                                    Log1(PCSC_LOG_ERROR,
                                          "Match found, failed due to no product name.");
#ifndef WIN32
                                    closedir(hpDir);
#endif
                                    return -1;
                              }
                        }
#ifndef NO_MSC_DEBUG
                        Log2(PCSC_LOG_DEBUG, "Product name: %s", keyValue);
#endif
                        strlcpy(tokenInfo->tokenName, keyValue,
                              sizeof(tokenInfo->tokenName));

                        /*
                         * See if this bundle has a special driver for this card 
                         */
                        rv = LTPBundleFindValueWithKey(fullPath,
                              MSC_LIBRMSC_KEY_NAME, keyValue, atrIndex);
                        if (rv != 0)
                        {
                              rv = LTPBundleFindValueWithKey(fullPath,
                                    MSC_LIBRMSC_KEY_NAME, keyValue, 0);
                              if (rv != 0)
                              {
                                    Log1(PCSC_LOG_ERROR,
                                          "Match found, failed due to no library path.");
#ifndef WIN32
                                    closedir(hpDir);
#endif
                                    return -1;
                              }
                        }
#if defined(WIN32)
                        sprintf(fullLibPath, "%s\\%s\Contents\\Win32\\%s",
                              MSC_SVC_DROPDIR, findData.cFileName, keyValue);
#elif defined(__APPLE__)
                        sprintf(fullLibPath, "%s/%s", MSC_SVC_DROPDIR,
                              currFP->d_name);
#else
                        sprintf(fullLibPath, "%s/%s/Contents/%s/%s", MSC_SVC_DROPDIR,
                              currFP->d_name, MSC_ARCH, keyValue);
#endif

                        if (fullLibPath == NULL)
                        {
                              Log1(PCSC_LOG_ERROR, "No path to bundle library found !");
                              return -1;
                        }

                        /*
                         * Copy the library path and return successfully 
                         */
                        strlcpy(tokenInfo->svProvider, fullLibPath,
                              sizeof(tokenInfo->svProvider));

                        /*
                         * See if this bundle has a default AID 
                         */
                        rv = LTPBundleFindValueWithKey(fullPath,
                              MSC_DEFAULTAPP_NAME, keyValue, atrIndex);
                        if (rv != 0)
                        {
                              rv = LTPBundleFindValueWithKey(fullPath,
                                    MSC_DEFAULTAPP_NAME, keyValue, 0);
                        }

                        if (rv == 0)
                        {
#ifndef NO_MSC_DEBUG
                              Log2(PCSC_LOG_DEBUG, "Default AID name: %s", keyValue);
#endif
                              rv = stringToBytes(keyValue, tokenInfo->tokenApp,
                                    &tokenInfo->tokenAppLen);
                              if (rv != 0)
                              {
                                    Log1(PCSC_LOG_ERROR,
                                          "Match found, failed due to malformed aid string.");
#ifndef WIN32
                                    closedir(hpDir);
#endif
                                    return -1;
                              }

                        } else
                        {
                              Log1(PCSC_LOG_ERROR, "No AID specified in bundle");
                              tokenInfo->tokenAppLen = 0;
                        }

#ifndef WIN32
                        closedir(hpDir);
#endif
                        return 0;

                  }     /* do ... while */
            }     /* if .bundle */
      }     /* while readdir */
#ifdef WIN32
      /* This is part of a Do..While loop (see above) */
      while (FindNextFile(hFind, &findData) != 0);
#endif

#ifndef WIN32
      closedir(hpDir);
#endif
      return -1;
}

MSCLong32 TPLoadToken(MSCLPTokenConnection pConnection)
{
      MSCLong32 rv;

      pConnection->libPointers.pvfWriteFramework = 0;
      pConnection->libPointers.pvfInitializePlugin = 0;
      pConnection->libPointers.pvfFinalizePlugin = 0;
      pConnection->libPointers.pvfGetStatus = 0;
      pConnection->libPointers.pvfGetCapabilities = 0;
      pConnection->libPointers.pvfExtendedFeature = 0;
      pConnection->libPointers.pvfGenerateKeys = 0;
      pConnection->libPointers.pvfImportKey = 0;
      pConnection->libPointers.pvfExportKey = 0;
      pConnection->libPointers.pvfComputeCrypt = 0;
      pConnection->libPointers.pvfExtAuthenticate = 0;
      pConnection->libPointers.pvfListKeys = 0;
      pConnection->libPointers.pvfCreatePIN = 0;
      pConnection->libPointers.pvfVerifyPIN = 0;
      pConnection->libPointers.pvfChangePIN = 0;
      pConnection->libPointers.pvfUnblockPIN = 0;
      pConnection->libPointers.pvfListPINs = 0;
      pConnection->libPointers.pvfCreateObject = 0;
      pConnection->libPointers.pvfDeleteObject = 0;
      pConnection->libPointers.pvfWriteObject = 0;
      pConnection->libPointers.pvfReadObject = 0;
      pConnection->libPointers.pvfListObjects = 0;
      pConnection->libPointers.pvfLogoutAll = 0;
      pConnection->libPointers.pvfGetChallenge = 0;

      /*
       * Find the Card's Library 
       */

      rv = TPSearchBundlesForAtr(pConnection->tokenInfo.tokenId,
            pConnection->tokenInfo.tokenIdLength, &pConnection->tokenInfo);

      if (rv != 0)
      {
            Log1(PCSC_LOG_ERROR, "Error: Matching Token ATR Not Found.");
            LogXxd(PCSC_LOG_ERROR, "ATR: ", pConnection->tokenInfo.tokenId,
                  pConnection->tokenInfo.tokenIdLength);

            return SCARD_E_CARD_UNSUPPORTED;
      }

      /*
       * Load that library and store the handle in the SCARDCHANNEL
       * structure 
       */

      rv = DYN_LoadLibrary(&pConnection->tokenLibHandle,
            pConnection->tokenInfo.svProvider);

      if (rv != SCARD_S_SUCCESS)
      {
            Log2(PCSC_LOG_ERROR, "Error: Could not load service library %s",
                  pConnection->tokenInfo.svProvider);
            return SCARD_E_INVALID_TARGET;
      } else
      {
            Log2(PCSC_LOG_INFO, "Loading service library %s",
                  pConnection->tokenInfo.svProvider);
      }

      rv = TPBindFunctions(pConnection);

      return rv;
}

MSCLong32 TPUnloadToken(MSCLPTokenConnection pConnection)
{
      MSCLong32 rv;

      if (pConnection->tokenLibHandle == 0)
      {
            return SCARD_E_INVALID_VALUE;
      }

      rv = DYN_CloseLibrary(&pConnection->tokenLibHandle);

      if (rv != SCARD_S_SUCCESS)
      {
            return rv;
      }

      pConnection->tokenLibHandle = 0;
      return TPUnbindFunctions(pConnection);
}

MSCLong32 TPBindFunctions(MSCLPTokenConnection pConnection)
{
      MSCLong32 rv;

      if (pConnection->tokenLibHandle == 0)
      {
            return SCARD_E_INVALID_TARGET;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfWriteFramework,
            "PL_MSCWriteFramework");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfWriteFramework = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            /*
             * No big deal - this feature is just not supported 
             */
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfIdentifyToken, "PL_MSCIdentifyToken");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfIdentifyToken = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfInitializePlugin,
            "PL_MSCInitializePlugin");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfInitializePlugin = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfFinalizePlugin,
            "PL_MSCFinalizePlugin");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfFinalizePlugin = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfGetStatus, "PL_MSCGetStatus");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfGetStatus = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfGetCapabilities,
            "PL_MSCGetCapabilities");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfGetCapabilities = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfExtendedFeature,
            "PL_MSCExtendedFeature");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfExtendedFeature = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            /*
             * No big deal - there are no extended features 
             */
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfGenerateKeys, "PL_MSCGenerateKeys");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfGenerateKeys = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfImportKey, "PL_MSCImportKey");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfImportKey = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfExportKey, "PL_MSCExportKey");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfExportKey = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfComputeCrypt, "PL_MSCComputeCrypt");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfComputeCrypt = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfExtAuthenticate,
            "PL_MSCExtAuthenticate");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfExtAuthenticate = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfListKeys, "PL_MSCListKeys");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfListKeys = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfCreatePIN, "PL_MSCCreatePIN");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfCreatePIN = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfVerifyPIN, "PL_MSCVerifyPIN");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfVerifyPIN = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfChangePIN, "PL_MSCChangePIN");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfChangePIN = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfUnblockPIN, "PL_MSCUnblockPIN");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfUnblockPIN = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfListPINs, "PL_MSCListPINs");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfListPINs = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfCreateObject, "PL_MSCCreateObject");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfCreateObject = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfDeleteObject, "PL_MSCDeleteObject");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfDeleteObject = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfWriteObject, "PL_MSCWriteObject");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfWriteObject = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfReadObject, "PL_MSCReadObject");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfReadObject = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfListObjects, "PL_MSCListObjects");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfListObjects = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfLogoutAll, "PL_MSCLogoutAll");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfLogoutAll = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      rv = DYN_GetAddress(pConnection->tokenLibHandle,
            &pConnection->libPointers.pvfGetChallenge, "PL_MSCGetChallenge");

      if (rv != SCARD_S_SUCCESS)
      {
            pConnection->libPointers.pvfGetChallenge = 0;
            Log1(PCSC_LOG_ERROR, "Missing functions");
            return SCARD_F_INTERNAL_ERROR;
      }

      return SCARD_S_SUCCESS;
}

MSCLong32 TPUnbindFunctions(MSCLPTokenConnection pConnection)
{
      pConnection->libPointers.pvfWriteFramework = 0;
      pConnection->libPointers.pvfInitializePlugin = 0;
      pConnection->libPointers.pvfFinalizePlugin = 0;
      pConnection->libPointers.pvfGetStatus = 0;
      pConnection->libPointers.pvfGetCapabilities = 0;
      pConnection->libPointers.pvfExtendedFeature = 0;
      pConnection->libPointers.pvfGenerateKeys = 0;
      pConnection->libPointers.pvfImportKey = 0;
      pConnection->libPointers.pvfExportKey = 0;
      pConnection->libPointers.pvfComputeCrypt = 0;
      pConnection->libPointers.pvfExtAuthenticate = 0;
      pConnection->libPointers.pvfListKeys = 0;
      pConnection->libPointers.pvfCreatePIN = 0;
      pConnection->libPointers.pvfVerifyPIN = 0;
      pConnection->libPointers.pvfChangePIN = 0;
      pConnection->libPointers.pvfUnblockPIN = 0;
      pConnection->libPointers.pvfListPINs = 0;
      pConnection->libPointers.pvfCreateObject = 0;
      pConnection->libPointers.pvfDeleteObject = 0;
      pConnection->libPointers.pvfWriteObject = 0;
      pConnection->libPointers.pvfReadObject = 0;
      pConnection->libPointers.pvfListObjects = 0;
      pConnection->libPointers.pvfLogoutAll = 0;
      pConnection->libPointers.pvfGetChallenge = 0;

      return SCARD_S_SUCCESS;
}

Generated by  Doxygen 1.6.0   Back to index