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

musclecard.c

/*
 * This abstracts the MUSCLE Card Edge Inteface.
 *
 * MUSCLE SmartCard Development ( http://www.linuxnet.com )
 *
 * Copyright (C) 2001-2004
 *  David Corcoran <corcoran@linuxnet.com>
 *  Ludovic Rousseau <ludovic.rousseau@free.fr>
 *
 * You may not remove this header from this file without 
 * prior permission from the author.
 *
 * $Id: musclecard.c,v 1.46 2005/02/22 15:38:54 rousseau Exp $
 */

#include "config.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include <winscard.h>
#include <debuglog.h>

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

#ifdef USE_THREAD_SAFETY
#include <wintypes.h>
#include <thread_generic.h>
#include <sys_generic.h>
#endif

#ifdef USE_THREAD_SAFETY

#ifndef WIN32
static PCSCLITE_MUTEX PCSC_MCARD_mutex = PTHREAD_MUTEX_INITIALIZER;
#else
/* This is initialized once in PCSC.cpp */
PCSCLITE_MUTEX PCSC_MCARD_mutex;
#endif

static PCSCLITE_THREAD_T callbackThread;
static ULONG blockingContext = MSC_BLOCKSTATUS_RESUME;
#endif      /* USE_THREAD_SAFETY */

static SCARDCONTEXT localHContext = 0;

/*
 * internal function 
 */
MSC_RV pcscToMSC(MSCLong32);
MSC_RV MSCReEstablishConnection(MSCLPTokenConnection);

static void mscLockThread(void)
{
#ifdef USE_THREAD_SAFETY
      SYS_MutexLock(&PCSC_MCARD_mutex);
#endif
}

static void mscUnLockThread(void)
{
#ifdef USE_THREAD_SAFETY
      SYS_MutexUnLock(&PCSC_MCARD_mutex);
#endif
}

/**************** MSC Connection Functions **************************/

MSC_RV MSCListTokens(MSCULong32 listScope, MSCLPTokenInfo tokenArray,
      MSCPULong32 arrayLength)
{
      MSCLong32 rv;
      SCARD_READERSTATE_A rgReaderStates;
      MSCTokenInfo tokenInfo;
      MSCLPTokenInfo currentToken;
      MSCULong32 tokensFound;
      MSCULong32 readerLength;
      char *readerList;
      int i, strLoc;

      readerLength = 0;
      tokensFound = 0;
      readerList = NULL;
      strLoc = 0;
      i = 0;

      if (arrayLength == 0)
            return MSC_INVALID_PARAMETER;
      if (listScope != MSC_LIST_KNOWN &&
            listScope != MSC_LIST_ALL && listScope != MSC_LIST_SLOTS)
      {
            return MSC_INVALID_PARAMETER;
      }

      mscLockThread();
      if (localHContext == 0)
      {
            rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, 0, 0, &localHContext);
            if (pcscToMSC(rv) != MSC_SUCCESS)
            {
                  localHContext = 0;
                  mscUnLockThread();
                  return pcscToMSC(rv);
            }
      }
      mscUnLockThread();

      /*
       * Get the reader list size 
       */
      rv = SCardListReaders(localHContext, NULL, readerList, &readerLength);

      if (pcscToMSC(rv) != MSC_SUCCESS)
            return pcscToMSC(rv);

      readerList = (char *) malloc(sizeof(char) * readerLength);

      if (readerList == NULL)
            return MSC_INTERNAL_ERROR;

      rv = SCardListReaders(localHContext, NULL, readerList, &readerLength);

      /*
       * Now that we have the readers, lets check their status 
       */
      for (i = 0; i < readerLength - 1; i++)
      {
            rgReaderStates.szReader = &readerList[i];
            rgReaderStates.dwCurrentState = SCARD_STATE_UNAWARE;

            rv = SCardGetStatusChange(localHContext, INFINITE,
                  &rgReaderStates, 1);

            if (pcscToMSC(rv) != MSC_SUCCESS)
            {
                  if (readerList)
                        free(readerList);
                  return pcscToMSC(rv);
            }

            /*
             * We only care about slots with a token unless stated 
             */
            if ((rgReaderStates.dwEventState & SCARD_STATE_PRESENT) ||
                  (listScope == MSC_LIST_SLOTS))
            {

                  if (rgReaderStates.dwEventState & SCARD_STATE_PRESENT)
                  {
                        /*
                         * We only care about supported tokens 
                         */
                        rv = TPSearchBundlesForAtr(rgReaderStates.rgbAtr,
                              rgReaderStates.cbAtr, &tokenInfo);
                  }

                  /*
                   * Success for this function 
                   */
                  if ((rv == 0) || (listScope == MSC_LIST_SLOTS) ||
                        (listScope == MSC_LIST_ALL))
                  {

                        /*
                         * We found something interesting to the application 
                         */
                        tokensFound += 1;

                        if ((tokensFound <= *arrayLength) && (tokenArray != NULL))
                        {
                              currentToken = &tokenArray[tokensFound - 1];
                              currentToken->addParams = 0;
                              currentToken->addParamsSize = 0;
                              currentToken->tokenType = 0;

                              if (rgReaderStates.dwEventState & SCARD_STATE_EMPTY)
                              {
                                    currentToken->tokenType |= MSC_TOKEN_TYPE_REMOVED;
                                    strlcpy(currentToken->tokenName,
                                          MSC_TOKEN_EMPTY_STR, MSC_MAXSIZE_TOKENAME);
                              }
                              else if (rv == 0)
                              {
                                    currentToken->tokenType |= MSC_TOKEN_TYPE_KNOWN;
                                    strlcpy(currentToken->tokenName,
                                          tokenInfo.tokenName, MSC_MAXSIZE_TOKENAME);
                              }
                              else
                              {
                                    currentToken->tokenType |= MSC_TOKEN_TYPE_UNKNOWN;
                                    strlcpy(currentToken->tokenName,
                                          MSC_TOKEN_UNKNOWN_STR, MSC_MAXSIZE_TOKENAME);
                              }

                              strlcpy(currentToken->slotName,
                                    rgReaderStates.szReader, MAX_READERNAME);

                              if (rgReaderStates.dwEventState & SCARD_STATE_PRESENT)
                              {
                                    memcpy(currentToken->tokenId,
                                          rgReaderStates.rgbAtr, rgReaderStates.cbAtr);
                                    currentToken->tokenIdLength = rgReaderStates.cbAtr;

                                    if (rv != -1) {
                                                memcpy(currentToken->tokenApp,
                                                tokenInfo.tokenApp,
                                                tokenInfo.tokenAppLen);
                                          currentToken->tokenAppLen =
                                                tokenInfo.tokenAppLen;
                                    }
                                      strlcpy(currentToken->svProvider,
                                          tokenInfo.svProvider, MSC_MAXSIZE_SVCPROV);
                              }
                              else
                              {
                                    memset(currentToken->tokenId, 0x00, MAX_ATR_SIZE);
                                    currentToken->tokenIdLength = 0x00;

                                      memset(currentToken->tokenApp, 0x00, MSC_MAXSIZE_AID);
                                    currentToken->tokenAppLen = 0x00;
                                    memset(currentToken->svProvider, 0x00, MSC_MAXSIZE_SVCPROV);
                              }

                              currentToken->tokenState = rgReaderStates.dwEventState;

                        }
                  }
                  /*
                   * End of TPSearch success 
                   */
            }
            /*
             * End of if token present 
             */
            while (readerList[++i] != 0);
      }     /* End of for .. readers */

      if (readerList)
            free(readerList);

      /*
       * Application provides null requesting length 
       */
      if (tokenArray == NULL)
      {
            *arrayLength = tokensFound;
            return MSC_SUCCESS;
      }

      /*
       * Provided length is too small 
       */
      if (*arrayLength < tokensFound)
      {
            *arrayLength = tokensFound;
            return MSC_INSUFFICIENT_BUFFER;
      }

      *arrayLength = tokensFound;
      return MSC_SUCCESS;
}

MSC_RV MSCEstablishConnection(MSCLPTokenInfo tokenStruct,
      MSCULong32 sharingMode,
      MSCPUChar8 applicationName,
      MSCULong32 nameSize, MSCLPTokenConnection pConnection)
{
      MSCLong32 rv;
      MSCULong32 tokenSize;
      MSCLPTokenInfo tokenList;
      MSCPVoid32 vInitFunction;
      MSCPVoid32 vIdFunction;

      MSCLong32(*libPL_MSCInitializePlugin) (MSCLPTokenConnection);
      MSCLong32(*libPL_MSCIdentifyToken) (MSCLPTokenConnection);
      MSCULong32 dwActiveProtocol;
      int selectedIFD;
      char slotName[MAX_READERNAME];
      MSCULong32 slotNameSize, slotState, slotProtocol;
      MSCUChar8 tokenId[MAX_ATR_SIZE];
      MSCULong32 tokenIdLength;

      tokenSize = 0;
      tokenList = NULL;
      tokenSize = 0;
      selectedIFD = -1;
      tokenIdLength = sizeof(tokenId);
      slotState = 0;
      slotProtocol = 0;
      slotNameSize = sizeof(slotName);
      vIdFunction = NULL;
      vInitFunction = NULL;

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (tokenStruct == NULL)
            return MSC_INVALID_PARAMETER;
      if (nameSize > MSC_MAXSIZE_AID)
            return MSC_INVALID_PARAMETER;

      pConnection->tokenLibHandle = 0;
      pConnection->hContext = 0;
      pConnection->tokenInfo.tokenIdLength = 0;
      pConnection->shareMode = 0;

      /*
       * Check the token name strings 
       */
      if (sharingMode != MSC_SHARE_DIRECT)
      {
            if (strcmp(tokenStruct->tokenName, MSC_TOKEN_EMPTY_STR) == 0)
                  return MSC_TOKEN_REMOVED;
            else
                  if (strcmp(tokenStruct->tokenName, MSC_TOKEN_UNKNOWN_STR) == 0)
                        return MSC_UNRECOGNIZED_TOKEN;
      }

      /*
       * Set up the initial connection to the resource manager 
       */

      mscLockThread();
      if (localHContext == 0)
      {
            rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, 0, 0, &localHContext);
#ifndef NO_MSC_DEBUG
            Log2(PCSC_LOG_DEBUG, "SCardEstablishContext returns %s",
                  pcsc_stringify_error(rv));
#endif
            if (pcscToMSC(rv) != MSC_SUCCESS)
            {
                  localHContext = 0;
                  mscUnLockThread();
                  return pcscToMSC(rv);
            }

            pConnection->hContext = localHContext;
      }
      else
            pConnection->hContext = localHContext;

      mscUnLockThread();

#ifdef WIN32
      rv = SCardConnect(pConnection->hContext, tokenStruct->slotName,
            SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
            &pConnection->hCard, &dwActiveProtocol);
#else
      rv = SCardConnect(pConnection->hContext, tokenStruct->slotName,
            sharingMode, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
            &pConnection->hCard, &dwActiveProtocol);
#endif

#ifndef NO_MSC_DEBUG
      Log2(PCSC_LOG_DEBUG, "SCardConnect returns %s", pcsc_stringify_error(rv));
#endif

      if (pcscToMSC(rv) != MSC_SUCCESS)
            return pcscToMSC(rv);

      pConnection->shareMode = sharingMode;

      /*
       * Set the sendPCI value based on the ActiveProtocol 
       */
      switch (dwActiveProtocol)
      {
            case SCARD_PROTOCOL_T0:
                  pConnection->ioType = SCARD_PCI_T0;
                  break;
            case SCARD_PROTOCOL_T1:
                  pConnection->ioType = SCARD_PCI_T1;
                  break;
            default:
                  pConnection->ioType = SCARD_PCI_RAW;
                  break;
      }

      /*
       * Call SCardStatus, make sure the card information matches if it does 
       * not return an error.  If it does, copy it 
       */

      rv = SCardStatus(pConnection->hCard, slotName,
            &slotNameSize, &slotState, &slotProtocol, tokenId, &tokenIdLength);

#ifndef NO_MSC_DEBUG
      Log2(PCSC_LOG_DEBUG, "SCardStatus returns %s", pcsc_stringify_error(rv));
#endif

      if (pcscToMSC(rv) != MSC_SUCCESS)
      {
            SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
            pConnection->hCard = 0;
            return pcscToMSC(rv);
      }

      if ((sharingMode == MSC_SHARE_DIRECT) && (slotState & SCARD_ABSENT))
      {
            /*
             * They asked for direct mode and no card is inserted so we are
             * done with this 
             */
            return MSC_SUCCESS;
      }

      if ((tokenIdLength != tokenStruct->tokenIdLength) ||
            (strcmp(slotName, tokenStruct->slotName) != 0) ||
            (memcmp(tokenId, tokenStruct->tokenId, tokenIdLength) != 0))
      {
            Log1(PCSC_LOG_ERROR, "Internal inconsistent values, ID, slotName");
            SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
            pConnection->hCard = 0;
            return MSC_INCONSISTENT_STATUS;
      }

      memcpy(pConnection->tokenInfo.tokenId, tokenId, tokenIdLength);
      pConnection->tokenInfo.tokenIdLength = tokenIdLength;
      strlcpy(pConnection->tokenInfo.slotName, tokenStruct->slotName,
            MAX_READERNAME);
      strlcpy(pConnection->tokenInfo.tokenName, tokenStruct->tokenName,
            MSC_MAXSIZE_TOKENAME);

      /*
       * Load the library for the token 
       */
      rv = TPLoadToken(pConnection);

#ifndef NO_MSC_DEBUG
      Log2(PCSC_LOG_DEBUG, "TPLoadToken returns %s", pcsc_stringify_error(rv));
#endif

      if (rv != SCARD_S_SUCCESS)
      {
            SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
            pConnection->hCard = 0;
            return pcscToMSC(rv);
      }

      /*
       * Select the AID or initialization routine for the card 
       */
      vInitFunction = pConnection->libPointers.pvfInitializePlugin;
      vIdFunction = pConnection->libPointers.pvfIdentifyToken;

      if (vInitFunction == NULL)
      {
            Log2(PCSC_LOG_ERROR, "Error: Card service failure: %s",
                  "InitializePlugin function missing");
            SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
            pConnection->hCard = 0;
            return MSC_UNSUPPORTED_FEATURE;
      }

      if (vIdFunction == NULL)
      {
            Log2(PCSC_LOG_ERROR, "Error: Card service failure: %s",
                  "IdentifyToken function missing");
            SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
            pConnection->hCard = 0;
            return MSC_UNSUPPORTED_FEATURE;
      }

      libPL_MSCInitializePlugin = (MSCLong32(*)(MSCLPTokenConnection))
            vInitFunction;

      libPL_MSCIdentifyToken = (MSCLong32(*)(MSCLPTokenConnection)) vIdFunction;

      rv = (*libPL_MSCInitializePlugin) (pConnection);

      if (rv != MSC_SUCCESS)
      {
            SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
            if (pConnection->tokenLibHandle != 0)
            {
                  TPUnloadToken(pConnection);
                  pConnection->tokenLibHandle = 0;
            }
            pConnection->hCard = 0;
      }

      if (sharingMode != MSC_SHARE_DIRECT)
      {

            if ((applicationName == 0) || (nameSize == 0))
            {
                  /*
                   * Use the default AID given by the Info.plist 
                   */

                  rv = (*libPL_MSCIdentifyToken) (pConnection);
            }
            else
            {
                  pConnection->tokenInfo.tokenAppLen = nameSize;
                  memcpy(pConnection->tokenInfo.tokenApp,
                        applicationName, nameSize);
                  rv = (*libPL_MSCIdentifyToken) (pConnection);
            }

#ifndef NO_MSC_DEBUG
            Log2(PCSC_LOG_DEBUG, "MSCIdentifyToken returns %s", msc_error(rv));
#endif

            if (rv != MSC_SUCCESS)
            {
                  SCardDisconnect(pConnection->hCard, SCARD_LEAVE_CARD);
                  if (pConnection->tokenLibHandle != 0)
                  {
                        TPUnloadToken(pConnection);
                        pConnection->tokenLibHandle = 0;
                  }
                  pConnection->hCard = 0;

                  if (rv == MSC_SHARING_VIOLATION)
                        return rv;
                  else
                        return MSC_UNRECOGNIZED_TOKEN;
            }
      }

      return MSC_SUCCESS;
}

MSC_RV MSCReleaseConnection(MSCLPTokenConnection pConnection,
      MSCULong32 endAction)
{
      MSCLong32 rv = SCARD_S_SUCCESS;

      MSCLong32(*libPL_MSCFinalizePlugin) (MSCLPTokenConnection);
      MSCPVoid32 vFunction;

      vFunction = NULL;

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;

      if (pConnection->tokenLibHandle == 0 ||
            pConnection->hContext == 0 || pConnection->hCard == 0)
      {
            return MSC_INVALID_HANDLE;
      }

      /*
       * Select finalization routine for the token plugin 
       */
      vFunction = pConnection->libPointers.pvfFinalizePlugin;

      if (vFunction == NULL)
      {
            Log2(PCSC_LOG_ERROR, "Error: Card service failure: %s",
                  "FinalizePlugin function missing");
            return MSC_INTERNAL_ERROR;
      }

      libPL_MSCFinalizePlugin = (MSCLong32(*)(MSCLPTokenConnection)) vFunction;

      /*
       * Stop and clean up the plugin 
       */
      rv = (*libPL_MSCFinalizePlugin) (pConnection);

      /*
       * Disconnect from the token 
       */
      if (pConnection->hCard != 0)
      {
            rv = SCardDisconnect(pConnection->hCard, endAction);
            if (pcscToMSC(rv) != MSC_SUCCESS)
                  return pcscToMSC(rv);
      }

      /*
       * Unload the token driver 
       */
      if (pConnection->tokenLibHandle != 0)
      {
            rv = TPUnloadToken(pConnection);
            pConnection->tokenLibHandle = 0;
      }

      pConnection->tokenLibHandle = 0;
      pConnection->hCard = 0;
      pConnection->hContext = 0;
      pConnection->shareMode = 0;

      return MSC_SUCCESS;
}

MSC_RV MSCWaitForTokenEvent(MSCLPTokenInfo tokenArray,
      MSCULong32 arraySize, MSCULong32 timeoutValue)
{
      MSCLong32 rv, rt;
      LPSCARD_READERSTATE_A rgReaderStates;
      MSCTokenInfo tokenInfo;
      int i;

      rgReaderStates = NULL;

      /*
       * Allocate array of SCARD_READERSTATE_A structures, set UNAWARE on
       * all of the structures to get the current status and then send them
       * to GetStatusChange for blocking event 
       */

      if (arraySize == 0)
            return MSC_SUCCESS;
      else
            if (arraySize > MSC_MAXSIZE_TOKENARRAY)
                  return MSC_INSUFFICIENT_BUFFER;

      /*
       * Set up the initial connection to the resource manager 
       */

      mscLockThread();
      if (localHContext == 0)
      {
            rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, 0, 0, &localHContext);
            if (pcscToMSC(rv) != MSC_SUCCESS)
            {
                  localHContext = 0;
                  mscUnLockThread();
                  return pcscToMSC(rv);
            }
      }
      mscUnLockThread();

      rgReaderStates = (LPSCARD_READERSTATE_A)
            malloc(sizeof(SCARD_READERSTATE_A) * arraySize);

      if (rgReaderStates == NULL)
            return MSC_INTERNAL_ERROR;

      for (i = 0; i < arraySize; i++)
      {
            /*
             * Make sure they don't pass an empty structure 
             */
            if (strlen(tokenArray[i].slotName) == 0)
            {
                  free(rgReaderStates);
                  return MSC_INVALID_PARAMETER;
            }

            rgReaderStates[i].szReader = tokenArray[i].slotName;
            rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE;
            rgReaderStates[i].dwEventState = 0;
      }

      rv = SCardGetStatusChange(localHContext, timeoutValue,
            rgReaderStates, arraySize);

      if (rv != SCARD_S_SUCCESS)
      {
            free(rgReaderStates);
            return pcscToMSC(rv);
      }

      for (i = 0; i < arraySize; i++)
      {
            if (tokenArray[i].tokenState == 0)
                  rgReaderStates[i].dwCurrentState = rgReaderStates[i].dwEventState;
            else
                  if (tokenArray[i].tokenState == MSC_STATE_UNAWARE)
                        rgReaderStates[i].dwCurrentState = SCARD_STATE_UNAWARE;
                  else
                        rgReaderStates[i].dwCurrentState = tokenArray[i].tokenState;

            rgReaderStates[i].dwEventState = 0;
      }

      rv = SCardGetStatusChange(localHContext, timeoutValue,
            rgReaderStates, arraySize);

      for (i = 0; i < arraySize; i++)
      {
            tokenArray[i].tokenState = rgReaderStates[i].dwEventState;

            if (tokenArray[i].tokenState & MSC_STATE_CHANGED)
            {
                  /*
                   * If it is removed, we need to update the names/etc 
                   */
                  if (tokenArray[i].tokenState & MSC_STATE_EMPTY)
                  {
                        memset(tokenArray[i].tokenId, 0x00, MAX_ATR_SIZE);
                        tokenArray[i].tokenIdLength = 0;
                        tokenArray[i].tokenType = MSC_TOKEN_TYPE_REMOVED;
                        strlcpy(tokenArray[i].tokenName, MSC_TOKEN_EMPTY_STR,
                              MSC_MAXSIZE_TOKENAME);
                  }
                  else if (tokenArray[i].tokenState & MSC_STATE_PRESENT)
                  {
                        memcpy(tokenArray[i].tokenId, rgReaderStates[i].rgbAtr,
                              rgReaderStates[i].cbAtr);
                        tokenArray[i].tokenIdLength = rgReaderStates[i].cbAtr;

                        rt = TPSearchBundlesForAtr(rgReaderStates[i].rgbAtr,
                              rgReaderStates[i].cbAtr, &tokenInfo);
                        /*
                         * Successfully found 
                         */
                        if (rt == 0)
                        {
                              tokenArray[i].tokenType = MSC_TOKEN_TYPE_KNOWN;
                              strlcpy(tokenArray[i].tokenName, tokenInfo.tokenName,
                                    MSC_MAXSIZE_TOKENAME);
                        }
                        else
                        {
                              tokenArray[i].tokenType = MSC_TOKEN_TYPE_UNKNOWN;
                              strlcpy(tokenArray[i].tokenName, MSC_TOKEN_UNKNOWN_STR,
                                    MSC_MAXSIZE_TOKENAME);
                        }
                  }
            }
      }

      free(rgReaderStates);
      return pcscToMSC(rv);
}

MSC_RV MSCCancelEventWait(void)
{
      MSCLong32 rv;

      rv = SCardCancel(localHContext);

      return pcscToMSC(rv);
}

/************************ Start of Callbacks ****************************/
#ifdef USE_THREAD_SAFETY
void *_MSCEventThread(void *arg)
{
      MSCLong32 rv;
      MSCLPEventWaitInfo evlist;
      MSCLong32 curToken;

      if (arg == NULL)
            SYS_ThreadExit(NULL);

      evlist = (MSCLPEventWaitInfo) arg;
      blockingContext = MSC_BLOCKSTATUS_BLOCKING;

      while (1)
      {
            rv = MSCWaitForTokenEvent(evlist->tokenArray,
                  evlist->arraySize, MSC_NO_TIMEOUT);

            if (rv == MSC_SUCCESS)
                  (evlist->callBack) (evlist->tokenArray, evlist->arraySize, evlist->appData);
            else
                  break;

            if (blockingContext == MSC_BLOCKSTATUS_CANCELLING)
                  break;
      }

      for (curToken = 0; curToken < evlist->arraySize; curToken++)
      {
            if (evlist->tokenArray[curToken].addParams)
                  free(evlist->tokenArray[curToken].addParams);
      }

      free(evlist->tokenArray);
      free(evlist);
      blockingContext = MSC_BLOCKSTATUS_RESUME;
      SYS_ThreadExit(&rv);

      return NULL;
}

MSC_RV MSCCallbackForTokenEvent(MSCLPTokenInfo tokenArray,
      MSCULong32 arraySize, MSCCallBack callBack, MSCPVoid32 appData)
{
      MSCLPEventWaitInfo evlist;
      MSCULong32 curToken;

      /*
       * Create the event wait list 
       */
      evlist = (MSCLPEventWaitInfo) malloc(sizeof(MSCEventWaitInfo));

      if (evlist == NULL)
            return MSC_INTERNAL_ERROR;

      evlist->arraySize = arraySize;
      evlist->tokenArray = malloc(sizeof(MSCTokenInfo) * arraySize);
      evlist->appData = appData;
      evlist->callBack = callBack;

      if (evlist->tokenArray == NULL)
      {
            free(evlist);
            return MSC_INTERNAL_ERROR;
      }

      mscLockThread();
      memcpy(evlist->tokenArray, tokenArray, sizeof(MSCTokenInfo) * arraySize);

      /*
       * Copy the "extra" data 
       */
      for (curToken = 0; curToken < arraySize; curToken++)
      {
            if (tokenArray[curToken].addParams != NULL)
            {
                  evlist->tokenArray[curToken].addParams =
                        malloc(evlist->tokenArray[curToken].addParamsSize);
                  memcpy((void *) (evlist->tokenArray[curToken].addParams),
                        &tokenArray[curToken],
                        evlist->tokenArray[curToken].addParamsSize);
            }
      }
      mscUnLockThread();

      if (SYS_ThreadCreate(&callbackThread, THREAD_ATTR_DEFAULT,
                  _MSCEventThread, (void *) evlist) == 0)
            return MSC_INTERNAL_ERROR;

      return MSC_SUCCESS;
}

MSC_RV MSCCallbackCancelEvent(void)
{
      LONG rv;

      /* Release the thread and stop the GetStatusChange */
      if (blockingContext == MSC_BLOCKSTATUS_BLOCKING)
      {
            blockingContext = MSC_BLOCKSTATUS_CANCELLING;
            rv = MSCCancelEventWait();

            SYS_ThreadJoin(&callbackThread, 0);

      }

      return MSC_SUCCESS;
}

#endif
/************************** End of Callbacks *****************************/

MSC_RV MSCBeginTransaction(MSCLPTokenConnection pConnection)
{
      MSCLong32 rv;
      MSCLong32 ret;

      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      while (1)
      {
            rv = SCardBeginTransaction(pConnection->hCard);
            ret = pcscToMSC(rv);

            if (ret == MSC_TOKEN_RESET)
            {
                  pConnection->tokenInfo.tokenType |= MSC_TOKEN_TYPE_RESET;
                  ret = MSCReEstablishConnection(pConnection);
                  if (ret != MSC_SUCCESS)
                        break;
            }
            else if (ret == MSC_TOKEN_REMOVED)
            {
                  pConnection->tokenInfo.tokenType = MSC_TOKEN_TYPE_REMOVED;

                  break;
            }
            else
                  break;
      }

      return ret;
}

MSC_RV MSCEndTransaction(MSCLPTokenConnection pConnection,
      MSCULong32 endAction)
{
      MSCLong32 rv;
      MSCLong32 ret;

      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      while (1)
      {
            rv = SCardEndTransaction(pConnection->hCard, endAction);
            ret = pcscToMSC(rv);

            if (ret == MSC_TOKEN_RESET)
            {
                  pConnection->tokenInfo.tokenType |= MSC_TOKEN_TYPE_RESET;
                  ret = MSCReEstablishConnection(pConnection);
                  if (ret != MSC_SUCCESS)
                        break;
            }
            else if (ret == MSC_TOKEN_REMOVED)
            {
                  pConnection->tokenInfo.tokenType = MSC_TOKEN_TYPE_REMOVED;
                  break;
            }
            else
                  break;
      }

      return ret;
}

MSC_RV MSCWriteFramework(MSCLPTokenConnection pConnection,
      MSCLPInitTokenParams pInitParams)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCWriteFramework) (MSCLPTokenConnection,
            MSCLPInitTokenParams);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfWriteFramework;

      if (vFunction != NULL)
      {
            libMSCWriteFramework = (MSCLong32(*)(MSCLPTokenConnection,
                        MSCLPInitTokenParams)) vFunction;
            rv = (*libMSCWriteFramework) (pConnection, pInitParams);

      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

/*
 * Real MSC functions 
 */

MSC_RV MSCGetStatus(MSCLPTokenConnection pConnection,
      MSCLPStatusInfo pStatusInfo)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCGetStatus) (MSCLPTokenConnection, MSCLPStatusInfo);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfGetStatus;

      if (vFunction != NULL)
      {
            libMSCGetStatus = (MSCLong32(*)(MSCLPTokenConnection,
                        MSCLPStatusInfo)) vFunction;
            rv = (*libMSCGetStatus) (pConnection, pStatusInfo);

      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCGetCapabilities(MSCLPTokenConnection pConnection, MSCULong32 Tag,
      MSCPUChar8 Value, MSCPULong32 Length)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCGetCapabilities) (MSCLPTokenConnection, MSCULong32,
            MSCPUChar8, MSCPULong32);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfGetCapabilities;

      if (vFunction != NULL)
      {
            libMSCGetCapabilities =
                  (MSCLong32(*)(MSCLPTokenConnection, MSCULong32, MSCPUChar8,
                        MSCPULong32)) vFunction;
            rv = (*libMSCGetCapabilities) (pConnection, Tag, Value, Length);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCExtendedFeature(MSCLPTokenConnection pConnection,
      MSCULong32 extFeature, MSCPUChar8 outData,
      MSCULong32 outLength, MSCPUChar8 inData, MSCPULong32 inLength)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCExtendedFeature) (MSCLPTokenConnection, MSCULong32,
            MSCPUChar8, MSCULong32, MSCPUChar8, MSCPULong32);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfExtendedFeature;

      if (vFunction != NULL)
      {
            libMSCExtendedFeature =
                  (MSCLong32(*)(MSCLPTokenConnection, MSCULong32, MSCPUChar8,
                        MSCULong32, MSCPUChar8, MSCPULong32)) vFunction;
            rv = (*libMSCExtendedFeature) (pConnection, extFeature, outData,
                  outLength, inData, inLength);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCGenerateKeys(MSCLPTokenConnection pConnection,
      MSCUChar8 prvKeyNum, MSCUChar8 pubKeyNum, MSCLPGenKeyParams pParams)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCGenerateKeys) (MSCLPTokenConnection, MSCUChar8,
            MSCUChar8, MSCLPGenKeyParams);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfGenerateKeys;

      if (vFunction != NULL)
      {
            libMSCGenerateKeys = (MSCLong32(*)(MSCLPTokenConnection,
                        MSCUChar8, MSCUChar8, MSCLPGenKeyParams)) vFunction;
            rv = (*libMSCGenerateKeys) (pConnection, prvKeyNum, pubKeyNum,
                  pParams);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCImportKey(MSCLPTokenConnection pConnection, MSCUChar8 keyNum,
      MSCLPKeyACL pKeyACL, MSCPUChar8 pKeyBlob, MSCULong32 keyBlobSize,
      MSCLPKeyPolicy keyPolicy, MSCPVoid32 pAddParams, MSCUChar8 addParamsSize)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCImportKey) (MSCLPTokenConnection, MSCUChar8,
            MSCLPKeyACL, MSCPUChar8,
            MSCULong32, MSCLPKeyPolicy, MSCPVoid32, MSCUChar8);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfImportKey;

      if (vFunction != NULL)
      {
            libMSCImportKey = (MSCLong32(*)(MSCLPTokenConnection,
                        MSCUChar8,
                        MSCLPKeyACL, MSCPUChar8,
                        MSCULong32, MSCLPKeyPolicy, MSCPVoid32, MSCUChar8)) vFunction;

            rv = (*libMSCImportKey) (pConnection, keyNum,
                  pKeyACL, pKeyBlob, keyBlobSize,
                  keyPolicy, pAddParams, addParamsSize);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCExportKey(MSCLPTokenConnection pConnection, MSCUChar8 keyNum,
      MSCPUChar8 pKeyBlob, MSCPULong32 keyBlobSize,
      MSCPVoid32 pAddParams, MSCUChar8 addParamsSize)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCExportKey) (MSCLPTokenConnection, MSCUChar8,
            MSCPUChar8, MSCPULong32, MSCPVoid32, MSCUChar8);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfExportKey;

      if (vFunction != NULL)
      {
            libMSCExportKey = (MSCLong32(*)(MSCLPTokenConnection,
                        MSCUChar8, MSCPUChar8,
                        MSCPULong32, MSCPVoid32, MSCUChar8)) vFunction;

            rv = (*libMSCExportKey) (pConnection, keyNum, pKeyBlob,
                  keyBlobSize, pAddParams, addParamsSize);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCComputeCrypt(MSCLPTokenConnection pConnection,
      MSCLPCryptInit cryptInit, MSCPUChar8 pInputData,
      MSCULong32 inputDataSize, MSCPUChar8 pOutputData,
      MSCPULong32 outputDataSize)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCComputeCrypt) (MSCLPTokenConnection, MSCLPCryptInit,
            MSCPUChar8, MSCULong32, MSCPUChar8, MSCPULong32);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfComputeCrypt;

      if (vFunction != NULL)
      {
            libMSCComputeCrypt =
                  (MSCLong32(*)(MSCLPTokenConnection, MSCLPCryptInit,
                        MSCPUChar8, MSCULong32, MSCPUChar8, MSCPULong32)) vFunction;
            rv = (*libMSCComputeCrypt) (pConnection, cryptInit, pInputData,
                  inputDataSize, pOutputData, outputDataSize);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCExtAuthenticate(MSCLPTokenConnection pConnection,
      MSCUChar8 keyNum, MSCUChar8 cipherMode,
      MSCUChar8 cipherDirection, MSCPUChar8 pData, MSCULong32 dataSize)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCExtAuthenticate) (MSCLPTokenConnection, MSCUChar8,
            MSCUChar8, MSCUChar8, MSCPUChar8, MSCULong32);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfExtAuthenticate;

      if (vFunction != NULL)
      {
            libMSCExtAuthenticate =
                  (MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
                        MSCUChar8, MSCUChar8, MSCPUChar8, MSCULong32)) vFunction;
            rv = (*libMSCExtAuthenticate) (pConnection, keyNum, cipherMode,
                  cipherDirection, pData, dataSize);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCListKeys(MSCLPTokenConnection pConnection, MSCUChar8 seqOption,
      MSCLPKeyInfo pKeyInfo)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCListKeys) (MSCLPTokenConnection, MSCUChar8,
            MSCLPKeyInfo);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfListKeys;

      if (vFunction != NULL)
      {
            libMSCListKeys = (MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
                        MSCLPKeyInfo)) vFunction;
            rv = (*libMSCListKeys) (pConnection, seqOption, pKeyInfo);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCCreatePIN(MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
      MSCUChar8 pinAttempts, MSCPUChar8 pPinCode,
      MSCULong32 pinCodeSize, MSCPUChar8 pUnblockCode,
      MSCUChar8 unblockCodeSize)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCCreatePIN) (MSCLPTokenConnection, MSCUChar8,
            MSCUChar8, MSCPUChar8, MSCULong32, MSCPUChar8, MSCUChar8);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfCreatePIN;

      if (vFunction != NULL)
      {
            libMSCCreatePIN = (MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
                        MSCUChar8, MSCPUChar8,
                        MSCULong32, MSCPUChar8, MSCUChar8)) vFunction;
            rv = (*libMSCCreatePIN) (pConnection, pinNum, pinAttempts,
                  pPinCode, pinCodeSize, pUnblockCode, unblockCodeSize);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCVerifyPIN(MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
      MSCPUChar8 pPinCode, MSCULong32 pinCodeSize)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCVerifyPIN) (MSCLPTokenConnection, MSCUChar8,
            MSCPUChar8, MSCULong32);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfVerifyPIN;

      if (vFunction != NULL)
      {
            libMSCVerifyPIN = (MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
                        MSCPUChar8, MSCULong32)) vFunction;
            rv = (*libMSCVerifyPIN) (pConnection, pinNum, pPinCode, pinCodeSize);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCChangePIN(MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
      MSCPUChar8 pOldPinCode, MSCUChar8 oldPinCodeSize,
      MSCPUChar8 pNewPinCode, MSCUChar8 newPinCodeSize)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCChangePIN) (MSCLPTokenConnection, MSCUChar8,
            MSCPUChar8, MSCUChar8, MSCPUChar8, MSCUChar8);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfChangePIN;

      if (vFunction != NULL)
      {
            libMSCChangePIN = (MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
                        MSCPUChar8, MSCUChar8, MSCPUChar8, MSCUChar8)) vFunction;
            rv = (*libMSCChangePIN) (pConnection, pinNum, pOldPinCode,
                  oldPinCodeSize, pNewPinCode, newPinCodeSize);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCUnblockPIN(MSCLPTokenConnection pConnection, MSCUChar8 pinNum,
      MSCPUChar8 pUnblockCode, MSCULong32 unblockCodeSize)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCUnblockPIN) (MSCLPTokenConnection, MSCUChar8,
            MSCPUChar8, MSCULong32);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfUnblockPIN;

      if (vFunction != NULL)
      {
            libMSCUnblockPIN = (MSCLong32(*)(MSCLPTokenConnection,
                        MSCUChar8, MSCPUChar8, MSCULong32)) vFunction;
            rv = (*libMSCUnblockPIN) (pConnection, pinNum, pUnblockCode,
                  unblockCodeSize);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCListPINs(MSCLPTokenConnection pConnection, MSCPUShort16 pPinBitMask)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCListPINs) (MSCLPTokenConnection, MSCPUShort16);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfListPINs;

      if (vFunction != NULL)
      {
            libMSCListPINs = (MSCLong32(*)(MSCLPTokenConnection,
                        MSCPUShort16)) vFunction;
            rv = (*libMSCListPINs) (pConnection, pPinBitMask);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCCreateObject(MSCLPTokenConnection pConnection,
      MSCString objectID, MSCULong32 objectSize, MSCLPObjectACL pObjectACL)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCCreateObject) (MSCLPTokenConnection, MSCString,
            MSCULong32, MSCLPObjectACL);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfCreateObject;

      if (vFunction != NULL)
      {
            libMSCCreateObject = (MSCLong32(*)(MSCLPTokenConnection, MSCString,
                        MSCULong32, MSCLPObjectACL)) vFunction;
            rv = (*libMSCCreateObject) (pConnection, objectID, objectSize,
                  pObjectACL);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCDeleteObject(MSCLPTokenConnection pConnection,
      MSCString objectID, MSCUChar8 zeroFlag)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCDeleteObject) (MSCLPTokenConnection, MSCString,
            MSCUChar8);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfDeleteObject;

      if (vFunction != NULL)
      {
            libMSCDeleteObject = (MSCLong32(*)(MSCLPTokenConnection, MSCString,
                        MSCUChar8)) vFunction;
            rv = (*libMSCDeleteObject) (pConnection, objectID, zeroFlag);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCWriteObject(MSCLPTokenConnection pConnection,
      MSCString objectID, MSCULong32 offSet,
      MSCPUChar8 pInputData, MSCULong32 dataSize,
      LPRWEventCallback rwCallback, MSCPVoid32 addParams)
{
      MSC_RV rv = MSC_UNSPECIFIED_ERROR;
      MSCULong32 objectSize;
      int totalSteps, stepInterval;

      MSC_RV(*callBackFunction) (void *, int);
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCWriteObject) (MSCLPTokenConnection, MSCString,
            MSCULong32, MSCPUChar8, MSCUChar8);
      int i;

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfWriteObject;
      callBackFunction = (MSC_RV(*)(void *, int)) rwCallback;
      objectSize = dataSize;

      if (vFunction == NULL)
            return MSC_UNSUPPORTED_FEATURE;

      libMSCWriteObject = (MSCLong32(*)(MSCLPTokenConnection, MSCString,
                  MSCULong32, MSCPUChar8, MSCUChar8)) vFunction;

      /*
       * Figure out the number of steps total and present this in a percent
       * step basis 
       */

      totalSteps = objectSize / MSC_SIZEOF_KEYPACKET + 1;
      stepInterval = MSC_PERCENT_STEPSIZE / totalSteps;

      for (i = 0; i < objectSize / MSC_SIZEOF_KEYPACKET; i++)
      {
            rv = (*libMSCWriteObject) (pConnection, objectID,
                  i * MSC_SIZEOF_KEYPACKET + offSet,
                  &pInputData[i * MSC_SIZEOF_KEYPACKET], MSC_SIZEOF_KEYPACKET);
            if (rv != MSC_SUCCESS)
                  return rv;

            if (rwCallback)
            {
                  if ((*callBackFunction) (addParams,
                              stepInterval * i) == MSC_CANCELLED)
                        return MSC_CANCELLED;
            }
      }

      if (objectSize % MSC_SIZEOF_KEYPACKET)
      {
            rv = (*libMSCWriteObject) (pConnection, objectID,
                  i * MSC_SIZEOF_KEYPACKET + offSet,
                  &pInputData[i * MSC_SIZEOF_KEYPACKET],
                  objectSize % MSC_SIZEOF_KEYPACKET);

            if (rv != MSC_SUCCESS)
                  return rv;
      }

      if (rwCallback)
            (*callBackFunction) (addParams, MSC_PERCENT_STEPSIZE);

      return rv;
}

MSC_RV MSCReadObject(MSCLPTokenConnection pConnection,
      MSCString objectID, MSCULong32 offSet,
      MSCPUChar8 pOutputData, MSCULong32 dataSize,
      LPRWEventCallback rwCallback, MSCPVoid32 addParams)
{
      MSC_RV rv = MSC_UNSPECIFIED_ERROR;
      MSCULong32 objectSize;
      int totalSteps, stepInterval;

      MSC_RV(*callBackFunction) (void *, int);
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCReadObject) (MSCLPTokenConnection, MSCString,
            MSCULong32, MSCPUChar8, MSCUChar8);
      int i;

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfReadObject;
      callBackFunction = (MSC_RV(*)(void *, int)) rwCallback;
      objectSize = dataSize;

      if (vFunction == NULL)
            return MSC_UNSUPPORTED_FEATURE;

      libMSCReadObject = (MSCLong32(*)(MSCLPTokenConnection,
                  MSCString, MSCULong32, MSCPUChar8, MSCUChar8)) vFunction;

      /*
       * Figure out the number of steps total and present this in a percent
       * step basis 
       */

      totalSteps = objectSize / MSC_SIZEOF_KEYPACKET + 1;
      stepInterval = MSC_PERCENT_STEPSIZE / totalSteps;

      for (i = 0; i < objectSize / MSC_SIZEOF_KEYPACKET; i++)
      {
            rv = (*libMSCReadObject) (pConnection, objectID,
                  i * MSC_SIZEOF_KEYPACKET + offSet,
                  &pOutputData[i * MSC_SIZEOF_KEYPACKET], MSC_SIZEOF_KEYPACKET);

            if (rv != MSC_SUCCESS)
                  return rv;

            if (rwCallback)
            {
                  if ((*callBackFunction) (addParams,
                              stepInterval * i) == MSC_CANCELLED)
                        return MSC_CANCELLED;
            }
      }

      if (objectSize % MSC_SIZEOF_KEYPACKET)
      {
            rv = (*libMSCReadObject) (pConnection, objectID,
                  i * MSC_SIZEOF_KEYPACKET + offSet,
                  &pOutputData[i * MSC_SIZEOF_KEYPACKET],
                  objectSize % MSC_SIZEOF_KEYPACKET);

            if (rv != MSC_SUCCESS)
                  return rv;
      }

      if (rwCallback)
      {
            (*callBackFunction) (addParams, MSC_PERCENT_STEPSIZE);
      }

      return rv;
}

MSC_RV MSCListObjects(MSCLPTokenConnection pConnection,
      MSCUChar8 seqOption, MSCLPObjectInfo pObjectInfo)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCListObjects) (MSCLPTokenConnection, MSCUChar8,
            MSCLPObjectInfo);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfListObjects;

      if (vFunction != NULL)
      {
            libMSCListObjects = (MSCLong32(*)(MSCLPTokenConnection, MSCUChar8,
                        MSCLPObjectInfo)) vFunction;
            rv = (*libMSCListObjects) (pConnection, seqOption, pObjectInfo);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCLogoutAll(MSCLPTokenConnection pConnection)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCLogoutAll) (MSCLPTokenConnection);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfLogoutAll;

      if (vFunction != NULL)
      {
            libMSCLogoutAll = (MSCLong32(*)(MSCLPTokenConnection)) vFunction;
            rv = (*libMSCLogoutAll) (pConnection);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCGetChallenge(MSCLPTokenConnection pConnection, MSCPUChar8 pSeed,
      MSCUShort16 seedSize, MSCPUChar8 pRandomData, MSCUShort16 randomDataSize)
{
      MSCLong32 rv;
      MSCPVoid32 vFunction;

      MSCLong32(*libMSCGetChallenge) (MSCLPTokenConnection, MSCPUChar8,
            MSCUShort16, MSCPUChar8, MSCUShort16);

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      vFunction = pConnection->libPointers.pvfGetChallenge;

      if (vFunction != NULL)
      {
            libMSCGetChallenge = (MSCLong32(*)(MSCLPTokenConnection,
                        MSCPUChar8, MSCUShort16, MSCPUChar8, MSCUShort16)) vFunction;
            rv = (*libMSCGetChallenge) (pConnection, pSeed, seedSize,
                  pRandomData, randomDataSize);
      }
      else
            return MSC_UNSUPPORTED_FEATURE;

      return rv;
}

MSC_RV MSCGetKeyAttributes(MSCLPTokenConnection pConnection,
      MSCUChar8 keyNumber, MSCLPKeyInfo pKeyInfo)
{
      MSC_RV rv;
      MSCKeyInfo keyInfo;

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      rv = MSCListKeys(pConnection, MSC_SEQUENCE_RESET, &keyInfo);

      if (rv != MSC_SEQUENCE_END && rv != MSC_SUCCESS)
            return rv;

      if (rv == MSC_SEQUENCE_END)
            return MSC_INVALID_PARAMETER;

      if (keyNumber == keyInfo.keyNum)
      {
            pKeyInfo->keyNum = keyInfo.keyNum;
            pKeyInfo->keyType = keyInfo.keyType;
            pKeyInfo->keySize = keyInfo.keySize;

            pKeyInfo->keyPolicy.cipherMode = keyInfo.keyPolicy.cipherMode;
            pKeyInfo->keyPolicy.cipherDirection =
                  keyInfo.keyPolicy.cipherDirection;

            pKeyInfo->keyACL.readPermission = keyInfo.keyACL.readPermission;
            pKeyInfo->keyACL.writePermission = keyInfo.keyACL.writePermission;
            pKeyInfo->keyACL.usePermission = keyInfo.keyACL.usePermission;

            return MSC_SUCCESS;
      }

      do
      {
            rv = MSCListKeys(pConnection, MSC_SEQUENCE_NEXT, &keyInfo);
            if (keyNumber == keyInfo.keyNum)
                  break;
      }
      while (rv == MSC_SUCCESS);

      if (rv != MSC_SEQUENCE_END && rv != MSC_SUCCESS)
            return rv;

      if (rv == MSC_SEQUENCE_END)
            return MSC_INVALID_PARAMETER;

      pKeyInfo->keyNum = keyInfo.keyNum;
      pKeyInfo->keyType = keyInfo.keyType;
      pKeyInfo->keySize = keyInfo.keySize;

      pKeyInfo->keyPolicy.cipherMode = keyInfo.keyPolicy.cipherMode;
      pKeyInfo->keyPolicy.cipherDirection = keyInfo.keyPolicy.cipherDirection;

      pKeyInfo->keyACL.readPermission = keyInfo.keyACL.readPermission;
      pKeyInfo->keyACL.writePermission = keyInfo.keyACL.writePermission;
      pKeyInfo->keyACL.usePermission = keyInfo.keyACL.usePermission;

      return MSC_SUCCESS;
}

MSC_RV MSCGetObjectAttributes(MSCLPTokenConnection pConnection,
      MSCString objectID, MSCLPObjectInfo pObjectInfo)
{
      MSC_RV rv;
      MSCObjectInfo objInfo;

      if (pConnection == NULL)
            return MSC_INVALID_PARAMETER;
      if (localHContext == 0)
            return MSC_INTERNAL_ERROR;

      rv = MSCListObjects(pConnection, MSC_SEQUENCE_RESET, &objInfo);

      if (rv != MSC_SEQUENCE_END && rv != MSC_SUCCESS)
            return rv;

      if (rv == MSC_SEQUENCE_END)
            return MSC_OBJECT_NOT_FOUND;

      if (strncmp(objectID, objInfo.objectID, MSC_MAXSIZE_OBJID) == 0)
      {
            pObjectInfo->objectSize = objInfo.objectSize;
            pObjectInfo->objectACL.readPermission =
                  objInfo.objectACL.readPermission;
            pObjectInfo->objectACL.writePermission =
                  objInfo.objectACL.writePermission;
            pObjectInfo->objectACL.deletePermission =
                  objInfo.objectACL.deletePermission;
            strlcpy(pObjectInfo->objectID, objectID, MSC_MAXSIZE_OBJID);
            return MSC_SUCCESS;
      }

      do
      {
            rv = MSCListObjects(pConnection, MSC_SEQUENCE_NEXT, &objInfo);
            if (strncmp(objectID, objInfo.objectID, MSC_MAXSIZE_OBJID) == 0)
                  break;
      }
      while (rv == MSC_SUCCESS);

      if (rv != MSC_SEQUENCE_END && rv != MSC_SUCCESS)
            return rv;

      if (rv == MSC_SEQUENCE_END)
            return MSC_OBJECT_NOT_FOUND;

      pObjectInfo->objectSize = objInfo.objectSize;
      pObjectInfo->objectACL.readPermission = objInfo.objectACL.readPermission;
      pObjectInfo->objectACL.writePermission =
            objInfo.objectACL.writePermission;
      pObjectInfo->objectACL.deletePermission =
            objInfo.objectACL.deletePermission;
      strlcpy(pObjectInfo->objectID, objectID, MSC_MAXSIZE_OBJID);

      return MSC_SUCCESS;
}

MSC_RV MSCReadAllocateObject(MSCLPTokenConnection pConnection,
      MSCString objectID, MSCPUChar8 * pOutputData,
      MSCPULong32 dataSize, LPRWEventCallback rwCallback, MSCPVoid32 addParams)
{
    MSC_RV rv;
    MSCObjectInfo objInfo;
    MSCULong32 objectSize;
    MSCPUChar8  data = NULL;
    
    if (pConnection == NULL)
        return MSC_INVALID_PARAMETER;
     if (localHContext == 0)
         return MSC_INTERNAL_ERROR;

    if (pOutputData == 0)
    {
        return MSC_INVALID_PARAMETER;
    }

    *dataSize = 0;
    *pOutputData = 0;

    rv = MSCGetObjectAttributes(pConnection, objectID, &objInfo);
    if (rv == MSC_SUCCESS) 
    {
        objectSize = objInfo.objectSize;
        data = (MSCPUChar8) malloc(sizeof(MSCUChar8) * objectSize);
        if(data)
        {
            rv =  MSCReadObject(pConnection, objectID, 0, data,
                     objectSize, rwCallback, addParams);
            
            if (rv == MSC_SUCCESS)
            {
                *dataSize = objectSize;
                *pOutputData = data;
            }
            else
            {
                rv = MSC_INTERNAL_ERROR;
                free(data);
            }
        }
    }

    return rv;
}


MSC_RV pcscToMSC(MSCLong32 pcscCode)
{
      switch (pcscCode)
      {
            case SCARD_S_SUCCESS:
                  return MSC_SUCCESS;
            case SCARD_E_INVALID_HANDLE:
                  return MSC_INVALID_HANDLE;
            case SCARD_E_SHARING_VIOLATION:
                  return MSC_SHARING_VIOLATION;
            case SCARD_W_REMOVED_CARD:
                  return MSC_TOKEN_REMOVED;
            case SCARD_E_NO_SMARTCARD:
                  return MSC_TOKEN_REMOVED;
            case SCARD_W_RESET_CARD:
                  return MSC_TOKEN_RESET;
            case SCARD_W_INSERTED_CARD:
                  return MSC_TOKEN_INSERTED;
            case SCARD_E_NO_SERVICE:
                  return MSC_SERVICE_UNRESPONSIVE;
            case SCARD_E_UNKNOWN_CARD:
            case SCARD_W_UNSUPPORTED_CARD:
            case SCARD_E_CARD_UNSUPPORTED:
                  return MSC_UNRECOGNIZED_TOKEN;
            case SCARD_E_INVALID_PARAMETER:
            case SCARD_E_INVALID_VALUE:
            case SCARD_E_UNKNOWN_READER:
            case SCARD_E_PROTO_MISMATCH:
            case SCARD_E_READER_UNAVAILABLE:
                  return MSC_INVALID_PARAMETER;
            case SCARD_E_CANCELLED:
                  return MSC_CANCELLED;
            case SCARD_E_TIMEOUT:
                  return MSC_TIMEOUT_OCCURRED;

            default:
                  return MSC_INTERNAL_ERROR;
      }
}

char *msc_error(MSC_RV errorCode)
{
      static char message[500];

      switch (errorCode)
      {
            case MSC_SUCCESS:
                  strlcpy(message, "Successful", sizeof(message));
                  break;
            case MSC_NO_MEMORY_LEFT:
                  strlcpy(message, "No more memory", sizeof(message));
                  break;
            case MSC_AUTH_FAILED:
                  strlcpy(message, "Authentication failed", sizeof(message));
                  break;
            case MSC_OPERATION_NOT_ALLOWED:
                  strlcpy(message, "Operation not allowed", sizeof(message));
                  break;
            case MSC_INCONSISTENT_STATUS:
                  strlcpy(message, "Inconsistent status", sizeof(message));
                  break;
            case MSC_UNSUPPORTED_FEATURE:
                  strlcpy(message, "Feature unsupported", sizeof(message));
                  break;
            case MSC_UNAUTHORIZED:
                  strlcpy(message, "Unauthorized usage", sizeof(message));
                  break;
            case MSC_OBJECT_NOT_FOUND:
                  strlcpy(message, "Object not found", sizeof(message));
                  break;
            case MSC_OBJECT_EXISTS:
                  strlcpy(message, "Object already exists", sizeof(message));
                  break;
            case MSC_INCORRECT_ALG:
                  strlcpy(message, "Incorrect algorithm", sizeof(message));
                  break;
            case MSC_SIGNATURE_INVALID:
                  strlcpy(message, "Invalid signature", sizeof(message));
                  break;
            case MSC_IDENTITY_BLOCKED:
                  strlcpy(message, "Identity is blocked", sizeof(message));
                  break;
            case MSC_UNSPECIFIED_ERROR:
                  strlcpy(message, "Unspecified error", sizeof(message));
                  break;
            case MSC_TRANSPORT_ERROR:
                  strlcpy(message, "Transport error", sizeof(message));
                  break;
            case MSC_INVALID_PARAMETER:
                  strlcpy(message, "Invalid parameter", sizeof(message));
                  break;
            case MSC_INCORRECT_P1:
                  strlcpy(message, "Incorrect P1 parameter", sizeof(message));
                  break;
            case MSC_INCORRECT_P2:
                  strlcpy(message, "Incorrect P2 parameter", sizeof(message));
                  break;
            case MSC_SEQUENCE_END:
                  strlcpy(message, "End of sequence", sizeof(message));
                  break;
            case MSC_INTERNAL_ERROR:
                  strlcpy(message, "Internal Error", sizeof(message));
                  break;
            case MSC_CANCELLED:
                  strlcpy(message, "Operation Cancelled", sizeof(message));
                  break;
            case MSC_INSUFFICIENT_BUFFER:
                  strlcpy(message, "Buffer is too small", sizeof(message));
                  break;
            case MSC_UNRECOGNIZED_TOKEN:
                  strlcpy(message, "Token is unsupported", sizeof(message));
                  break;
            case MSC_SERVICE_UNRESPONSIVE:
                  strlcpy(message, "Service is not running", sizeof(message));
                  break;
            case MSC_TIMEOUT_OCCURRED:
                  strlcpy(message, "Timeout has occurred", sizeof(message));
                  break;
            case MSC_TOKEN_REMOVED:
                  strlcpy(message, "Token was removed", sizeof(message));
                  break;
            case MSC_TOKEN_RESET:
                  strlcpy(message, "Token was reset", sizeof(message));
                  break;
            case MSC_TOKEN_INSERTED:
                  strlcpy(message, "Token was inserted", sizeof(message));
                  break;
            case MSC_TOKEN_UNRESPONSIVE:
                  strlcpy(message, "Token is unresponsive", sizeof(message));
                  break;
            case MSC_INVALID_HANDLE:
                  strlcpy(message, "Handle is invalid", sizeof(message));
                  break;
            case MSC_SHARING_VIOLATION:
                  strlcpy(message, "Sharing violation", sizeof(message));
                  break;

            default:
                  sprintf(message, "Unknown SW: %04lX", errorCode);
                  break;
      }

      return message;
}

MSC_RV MSCReEstablishConnection(MSCLPTokenConnection pConnection)
{
      MSC_RV rv;
      MSCPVoid32 vInitFunction, vFinFunction, vIdFunction;
      MSCULong32 dwActiveProtocol;

      MSCLong32(*libPL_MSCInitializePlugin) (MSCLPTokenConnection);
      MSCLong32(*libPL_MSCFinalizePlugin) (MSCLPTokenConnection);
      MSCLong32(*libPL_MSCIdentifyToken) (MSCLPTokenConnection);

      vInitFunction = NULL;
      vFinFunction = NULL;
      vIdFunction = NULL;

      /*
       * Select the AID or initialization routine for the card 
       */
      vInitFunction = pConnection->libPointers.pvfInitializePlugin;
      vFinFunction = pConnection->libPointers.pvfFinalizePlugin;
      vIdFunction = pConnection->libPointers.pvfIdentifyToken;

      if (vInitFunction == NULL)
      {
            Log2(PCSC_LOG_ERROR, "Error: Card service failure: %s",
                  "InitializePlugin function missing");
            return MSC_INTERNAL_ERROR;
      }

      if (vFinFunction == NULL)
      {
            Log2(PCSC_LOG_ERROR, "Error: Card service failure: %s",
                  "FinalizePlugin function missing");
            return MSC_INTERNAL_ERROR;
      }

      if (vIdFunction == NULL)
      {
            Log2(PCSC_LOG_ERROR, "Error: Card service failure: %s",
                  "IdentifyToken function missing");
            return MSC_INTERNAL_ERROR;
      }

      libPL_MSCInitializePlugin = (MSCLong32(*)(MSCLPTokenConnection))
            vInitFunction;

      libPL_MSCFinalizePlugin = (MSCLong32(*)(MSCLPTokenConnection))
            vFinFunction;

      libPL_MSCIdentifyToken = (MSCLong32(*)(MSCLPTokenConnection)) vIdFunction;

      rv = SCardReconnect(pConnection->hCard, pConnection->shareMode,
            SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
            SCARD_LEAVE_CARD, &dwActiveProtocol);

      if (rv != SCARD_S_SUCCESS)
            return pcscToMSC(rv);

      /*
       * Stop the plugin and start it up again 
       */
      rv = (*libPL_MSCFinalizePlugin) (pConnection);

      /*
       * Use the default AID given by the Info.plist 
       */
      rv = (*libPL_MSCInitializePlugin) (pConnection);

      /* 
       * Use the default AID given by the Info.plist 
       */
      rv = (*libPL_MSCIdentifyToken) (pConnection);

      if (rv != MSC_SUCCESS)
            return rv;

      return MSC_SUCCESS;
}

MSCUChar8 MSCIsTokenReset(MSCLPTokenConnection pConnection)
{
      MSCULong32 rv;
      char slotName[MAX_READERNAME];
      MSCULong32 slotNameSize, slotState, slotProtocol;
      MSCUChar8 tokenId[MAX_ATR_SIZE];
      MSCULong32 tokenIdLength;

      slotNameSize = sizeof(slotName);
      tokenIdLength = sizeof(tokenId);

      rv = SCardStatus(pConnection->hCard, slotName,
            &slotNameSize, &slotState, &slotProtocol, tokenId, &tokenIdLength);

      if (rv == SCARD_W_RESET_CARD)
            return 1;

      if (pConnection->tokenInfo.tokenType & MSC_TOKEN_TYPE_RESET)
            return 1;
      else
            return 0;
}

MSCUChar8 MSCClearReset(MSCLPTokenConnection pConnection)
{
      pConnection->tokenInfo.tokenType &= ~MSC_TOKEN_TYPE_RESET;
      return 1;
}

MSCUChar8 MSCIsTokenMoved(MSCLPTokenConnection pConnection)
{
      MSCULong32 rv;
      char slotName[MAX_READERNAME];
      MSCULong32 slotNameSize = MAX_READERNAME, slotState, slotProtocol;
      MSCUChar8 tokenId[MAX_ATR_SIZE];
      MSCULong32 tokenIdLength = MAX_ATR_SIZE;

      if (pConnection->tokenInfo.tokenType & MSC_TOKEN_TYPE_REMOVED)
            return 1;

      rv = SCardStatus(pConnection->hCard, slotName,
            &slotNameSize, &slotState, &slotProtocol, tokenId, &tokenIdLength);

      if (rv != SCARD_S_SUCCESS || (slotState & SCARD_ABSENT))
            return 1;

      return 0;
}

MSCUChar8 MSCIsTokenChanged(MSCLPTokenConnection pConnection)
{
      if (MSCIsTokenMoved(pConnection))
            return 1;
      else
            if (MSCIsTokenReset(pConnection))
                  return 1;
            else
                  return 0;
}

MSCUChar8 MSCIsTokenKnown(MSCLPTokenConnection pConnection)
{
      if (pConnection->tokenInfo.tokenType & MSC_TOKEN_TYPE_KNOWN)
            return 1;
      else
            return 0;
}


Generated by  Doxygen 1.6.0   Back to index