/*
             Common Public License Version 0.5

             THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF
             THIS COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE,
             REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES
             RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

             1. DEFINITIONS

             "Contribution" means: 
                   a) in the case of the initial Contributor, the
                   initial code and documentation distributed under
                   this Agreement, and 

                   b) in the case of each subsequent Contributor:
                   i) changes to the Program, and
                   ii) additions to the Program;

                   where such changes and/or additions to the Program
                   originate from and are distributed by that
                   particular Contributor. A Contribution 'originates'
                   from a Contributor if it was added to the Program
                   by such Contributor itself or anyone acting on such
                   Contributor's behalf. Contributions do not include
                   additions to the Program which: (i) are separate
                   modules of software distributed in conjunction with
                   the Program under their own license agreement, and
                   (ii) are not derivative works of the Program.


             "Contributor" means any person or entity that distributes
             the Program.

             "Licensed Patents " mean patent claims licensable by a
             Contributor which are necessarily infringed by the use or
             sale of its Contribution alone or when combined with the
             Program. 

             "Program" means the Contributions distributed in
             accordance with this Agreement.

             "Recipient" means anyone who receives the Program under
             this Agreement, including all Contributors.

             2. GRANT OF RIGHTS

                   a) Subject to the terms of this Agreement, each
                   Contributor hereby grants Recipient a
                   non-exclusive, worldwide, royalty-free copyright
                   license to reproduce, prepare derivative works of,
                   publicly display, publicly perform, distribute and
                   sublicense the Contribution of such Contributor, if
                   any, and such derivative works, in source code and
                   object code form.

                   b) Subject to the terms of this Agreement, each
                   Contributor hereby grants Recipient a
                   non-exclusive, worldwide, royalty-free patent
                   license under Licensed Patents to make, use, sell,
                   offer to sell, import and otherwise transfer the
                   Contribution of such Contributor, if any, in source
                   code and object code form. This patent license
                   shall apply to the combination of the Contribution
                   and the Program if, at the time the Contribution is
                   added by the Contributor, such addition of the
                   Contribution causes such combination to be covered
                   by the Licensed Patents. The patent license shall
                   not apply to any other combinations which include
                   the Contribution. No hardware per se is licensed
                   hereunder.

                   c) Recipient understands that although each
                   Contributor grants the licenses to its
                   Contributions set forth herein, no assurances are
                   provided by any Contributor that the Program does
                   not infringe the patent or other intellectual
                   property rights of any other entity. Each
                   Contributor disclaims any liability to Recipient
                   for claims brought by any other entity based on
                   infringement of intellectual property rights or
                   otherwise. As a condition to exercising the rights
                   and licenses granted hereunder, each Recipient
                   hereby assumes sole responsibility to secure any
                   other intellectual property rights needed, if any.

                   For example, if a third party patent license is
                   required to allow Recipient to distribute the
                   Program, it is Recipient's responsibility to
                   acquire that license before distributing the
                   Program.

                   d) Each Contributor represents that to its
                   knowledge it has sufficient copyright rights in its
                   Contribution, if any, to grant the copyright
                   license set forth in this Agreement.

             3. REQUIREMENTS

             A Contributor may choose to distribute the Program in
             object code form under its own license agreement, provided
             that:
                   a) it complies with the terms and conditions of
                   this Agreement; and

                   b) its license agreement:
                   i) effectively disclaims on behalf of all
                   Contributors all warranties and conditions, express
                   and implied, including warranties or conditions of
                   title and non-infringement, and implied warranties
                   or conditions of merchantability and fitness for a
                   particular purpose;

                   ii) effectively excludes on behalf of all
                   Contributors all liability for damages, including
                   direct, indirect, special, incidental and
                   consequential damages, such as lost profits;

                   iii) states that any provisions which differ from
                   this Agreement are offered by that Contributor
                   alone and not by any other party; and

                   iv) states that source code for the Program is
                   available from such Contributor, and informs
                   licensees how to obtain it in a reasonable manner
                   on or through a medium customarily used for
                   software exchange.

             When the Program is made available in source code form:
                   a) it must be made available under this Agreement;
                   and
                   b) a copy of this Agreement must be included with
                   each copy of the Program. 

             Contributors may not remove or alter any copyright notices
             contained within the Program.

             Each Contributor must identify itself as the originator of
             its Contribution, if any, in a manner that reasonably
             allows subsequent Recipients to identify the originator of
             the Contribution. 


             4. COMMERCIAL DISTRIBUTION

             Commercial distributors of software may accept certain
             responsibilities with respect to end users, business
             partners and the like. While this license is intended to
             facilitate the commercial use of the Program, the
             Contributor who includes the Program in a commercial
             product offering should do so in a manner which does not
             create potential liability for other Contributors.
             Therefore, if a Contributor includes the Program in a
             commercial product offering, such Contributor ("Commercial
             Contributor") hereby agrees to defend and indemnify every
             other Contributor ("Indemnified Contributor") against any
             losses, damages and costs (collectively "Losses") arising
             from claims, lawsuits and other legal actions brought by a
             third party against the Indemnified Contributor to the
             extent caused by the acts or omissions of such Commercial
             Contributor in connection with its distribution of the
             Program in a commercial product offering. The obligations
             in this section do not apply to any claims or Losses
             relating to any actual or alleged intellectual property
             infringement. In order to qualify, an Indemnified
             Contributor must: a) promptly notify the Commercial
             Contributor in writing of such claim, and b) allow the
             Commercial Contributor to control, and cooperate with the
             Commercial Contributor in, the defense and any related
             settlement negotiations. The Indemnified Contributor may
             participate in any such claim at its own expense.


             For example, a Contributor might include the Program in a
             commercial product offering, Product X. That Contributor
             is then a Commercial Contributor. If that Commercial
             Contributor then makes performance claims, or offers
             warranties related to Product X, those performance claims
             and warranties are such Commercial Contributor's
             responsibility alone. Under this section, the Commercial
             Contributor would have to defend claims against the other
             Contributors related to those performance claims and
             warranties, and if a court requires any other Contributor
             to pay any damages as a result, the Commercial Contributor
             must pay those damages.


             5. NO WARRANTY

             EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE
             PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT
             WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
             IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR
             CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
             FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
             responsible for determining the appropriateness of using
             and distributing the Program and assumes all risks
             associated with its exercise of rights under this
             Agreement, including but not limited to the risks and
             costs of program errors, compliance with applicable laws,
             damage to or loss of data, programs or equipment, and
             unavailability or interruption of operations. 

             6. DISCLAIMER OF LIABILITY
             EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER
             RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY
             FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
             OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
             LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
             LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
             (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
             OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE
             OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
             POSSIBILITY OF SUCH DAMAGES.

             7. GENERAL

             If any provision of this Agreement is invalid or
             unenforceable under applicable law, it shall not affect
             the validity or enforceability of the remainder of the
             terms of this Agreement, and without further action by the
             parties hereto, such provision shall be reformed to the
             minimum extent necessary to make such provision valid and
             enforceable.


             If Recipient institutes patent litigation against a
             Contributor with respect to a patent applicable to
             software (including a cross-claim or counterclaim in a
             lawsuit), then any patent licenses granted by that
             Contributor to such Recipient under this Agreement shall
             terminate as of the date such litigation is filed. In
             addition, If Recipient institutes patent litigation
             against any entity (including a cross-claim or
             counterclaim in a lawsuit) alleging that the Program
             itself (excluding combinations of the Program with other
             software or hardware) infringes such Recipient's
             patent(s), then such Recipient's rights granted under
             Section 2(b) shall terminate as of the date such
             litigation is filed.

             All Recipient's rights under this Agreement shall
             terminate if it fails to comply with any of the material
             terms or conditions of this Agreement and does not cure
             such failure in a reasonable period of time after becoming
             aware of such noncompliance. If all Recipient's rights
             under this Agreement terminate, Recipient agrees to cease
             use and distribution of the Program as soon as reasonably
             practicable. However, Recipient's obligations under this
             Agreement and any licenses granted by Recipient relating
             to the Program shall continue and survive. 

             Everyone is permitted to copy and distribute copies of
             this Agreement, but in order to avoid inconsistency the
             Agreement is copyrighted and may only be modified in the
             following manner. The Agreement Steward reserves the right
             to publish new versions (including revisions) of this
             Agreement from time to time. No one other than the
             Agreement Steward has the right to modify this Agreement.

             IBM is the initial Agreement Steward. IBM may assign the
             responsibility to serve as the Agreement Steward to a
             suitable separate entity. Each new version of the
             Agreement will be given a distinguishing version number.
             The Program (including Contributions) may always be
             distributed subject to the version of the Agreement under
             which it was received. In addition, after a new version of
             the Agreement is published, Contributor may elect to
             distribute the Program (including its Contributions) under
             the new version. Except as expressly stated in Sections
             2(a) and 2(b) above, Recipient receives no rights or
             licenses to the intellectual property of any Contributor
             under this Agreement, whether expressly, by implication,
             estoppel or otherwise. All rights in the Program not
             expressly granted under this Agreement are reserved.


             This Agreement is governed by the laws of the State of New
             York and the intellectual property laws of the United
             States of America. No party to this Agreement will bring a
             legal action under this Agreement more than one year after
             the cause of action arose. Each party waives its rights to
             a jury trial in any resulting litigation. 



*/

/* (C) COPYRIGHT International Business Machines Corp. 2001          */


// File:  host_api.c
//

#if defined(LEEDS_BUILD)

  #include <pthread.h>

  #include <scctypes.h>
  #include <scc_host.h>
  #include <scc_err.h>

  #include <stdio.h>
  #include <stdlib.h>

  #include "pkcs11types.h"
#ifdef PKCS64
  #include "pkcs32.h"
#endif
  #include "stdll.h"

  #include "defs.h"
  #include "args.h"

  #include "h_extern.h"
#endif


CK_VOID_PTR adjust_mech_parameter(CK_MECHANISM_PTR);  // 64 bit needs prototypes
#if PKCS64
CK_ULONG_32 get_mech_parameter_len(CK_MECHANISM_PTR); // util.c prototype
#else
CK_ULONG get_mech_parameter_len(CK_MECHANISM_PTR); // util.c prototype
#endif

#if (!PKCS64)
#define CK_ULONG_32   CK_ULONG
#endif



#ifdef DEBUGON
#include <stdio.h>
#include <dlfcn.h>
#include <errno.h>
#include <sys/syslog.h>

#include <sys/ipc.h>

#include <stdarg.h>


#ifdef SOCKET
#define DBGTAG "Leeds_Socket_Debug"
#else
#define DBGTAG "Leeds_STDLL_Debug"
#endif

static int enabled=0;
// Logging types.  Ultimately this will allow
// us to log to different log files.  The logger will also
// handle keeping the files to a decent size.
// Much work needs to be done on this capability... 
// Other logging types need to be implemented

void 
loginit(){
   if (!enabled){
      enabled=1;
      openlog(DBGTAG,LOG_PID|LOG_NDELAY,LOG_DAEMON);
      setlogmask(LOG_UPTO(LOG_DEBUG));
   }

}


void
logit(int type,char *fmt, ...)
{
      int n;
      va_list pvar;
      char *env;
      char buffer[4096*4];

   if ( enabled){
         va_start(pvar, fmt);
         vsprintf(buffer,fmt,pvar);
         va_end(pvar);
         syslog(LOG_DEBUG,buffer);
   }

}
#endif




#ifdef SOCKET
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>

#define PORT  4000
#define HOSTNAME  "mayfield.lexington.ibm.com"


struct  proxy_req {
   CK_ULONG  pid;
	CK_ULONG  cmd_id;
	CK_ULONG req_len;
	CK_ULONG repl_len;  // (of course this will be the actual replen that I'm looking for dereferenced off *repl_len parameter)
	CK_ULONG out_len;
	CK_ULONG in_len;
//	[Data from pRequest]
//	[data from pOut]   This will not be present if pOut is NULL
};

typedef struct proxy_req proxy_req_t;

struct proxy_resp{
	CK_ULONG return_code;
	CK_ULONG repl_len;
	CK_ULONG  in_len;
	//[Reply Data]
	//[In Data]
};

typedef struct proxy_resp proxy_resp_t;


#endif



#if 0   // BIG BLOCK OF COMMENTS
//XXX Development Note


Note for 64 bit enablers.   The leeds card is a 486 processor with a 32 bit pkcs
implementation running on it.  All the values will have to be translated to
little endian 32 bit values BEFORE being passed into the card.  Results will
have to be converted to 64 bit values.  This is not a trivial task.

Notes:

session handles - returned values from the adapter are byte swapped because of 
the way the original code from Lex was implemented.   the session create code was
modified to swap the value that was returned.


Object handles on the other hand are NOT reversed.   They have meaning only to
the card and to many places would have to be changed to swap the handles.  Much of
the Lex code originally tried to swap the results without originaly swapping the values.

Every effort has been made to  properly ifdef the code to correctly handle these
situations.



#endif



// XXX  Communicate2 added on 12-09 and following to handle performance 
// improvements etc with the firmware.  The interface to the card had to
// change.
CK_RV communicate( CK_ULONG    cmd_id,  CK_SLOT_ID   slot_id,
                    CK_VOID_PTR pReq,    CK_ULONG     req_len,
                    CK_VOID_PTR pRep,    CK_ULONG_PTR rep_len,
                    CK_BYTE_PTR pOut,    CK_ULONG     out_len,
                    CK_BYTE_PTR pIn,     CK_ULONG     in_len );


CK_BBOOL          initialized = FALSE;
pid_t             initedpid=0;
CK_ULONG          usage_count = 0;

#ifdef PKCS64
CK_ULONG_32          pid_list[ PKW_MAX_DEVICES ] = {0,0,0,0,0,0,0,0,0,0};
#else
CK_ULONG          pid_list[ PKW_MAX_DEVICES ] = {0,0,0,0,0,0,0,0,0,0};
#endif

static sccAdapterNumber_t  num_adapters;
static sccAgentID_t        leeds_id;
static sccAdapterHandle_t  adapter_handle[MAX_SLOT_ID];

// Need to handle the mutex correctly.  for portability purposes 
// make the NT Wait and Release map to the pthreads code

#ifdef PKCS64
pthread_mutex_t   pkcs_mutex; 
#else
pthread_mutex_t   pkcs_mutex = PTHREAD_MUTEX_INITIALIZER; // Local module lock
#endif

#ifdef SOCKET
pthread_mutex_t   smtx = PTHREAD_MUTEX_INITIALIZER; // Local module lock
#endif


#define   WaitForSingleObject( x, y )  pthread_mutex_lock(&x) 
#define   ReleaseMutex( x )            pthread_mutex_unlock(&x)

typedef unsigned char UCHAR;



#if __64BIT__
#define  ADJUSTMECHPTR()  \
      { \
      CK_ULONG_PTR  padjust; \
      padjust = (CK_ULONG_PTR)adjust_mech_parameter(pMechanism); \
      if (padjust ) { \
         memcpy((void *) ptr,(void *) padjust, get_mech_parameter_len(pMechanism)); \
         free(padjust); \
      } else { \
         memcpy( ptr, pMechanism->pParameter, pMechanism->ulParameterLen ); \
      } \
      }
#else
#define  ADJUSTMECHPTR()  \
      { \
      CK_ULONG_PTR  padjust; \
      padjust = (CK_ULONG_PTR)adjust_mech_parameter(pMechanism); \
      if (padjust ) { \
         memcpy((void *) ptr,(void *) padjust, pMechanism->ulParameterLen ); \
         free(padjust); \
      } else { \
         memcpy( ptr, pMechanism->pParameter, pMechanism->ulParameterLen ); \
      } \
      }
#endif


DL_NODE *session_list = NULL;

#ifdef PKCS64
CK_ULONG_32 next_session_handle = 1;
#else
CK_ULONG next_session_handle = 1;
#endif

CK_BBOOL
Initialized()
{
  if (initialized == FALSE ) return FALSE;
  if (initedpid != getpid()) return FALSE;
  return TRUE;

}

// Global initialized value for each slot indicating if the coorelator
// used has been initialized already.
struct  Cor_init{
   unsigned char init;
   CK_SLOT_ID    API_Slotid;
} correlator_init[PKW_MAX_DEVICES];


struct ST_FCN_LIST  function_list;
  extern CK_RV SC_Initialize();                                 /* extern CK_RV SC_Initialize             */
  extern CK_RV SC_GetTokenInfo();                               /* extern CK_RV SC_GetTokenInfo           */
  extern CK_RV SC_GetMechanismList();                           /* extern CK_RV SC_GetMechanismList       */
  extern CK_RV SC_GetMechanismInfo();                           /* extern CK_RV SC_GetMechanismInfo       */
  extern CK_RV SC_InitToken();                                  /* extern CK_RV SC_InitToken              */
  extern CK_RV SC_InitPIN();                                    /* extern CK_RV SC_InitPIN                */
  extern CK_RV SC_SetPIN();                                     /* extern CK_RV SC_SetPIN                 */
  extern CK_RV SC_OpenSession();                                /* extern CK_RV SC_OpenSession            */
  extern CK_RV SC_CloseSession();                               /* extern CK_RV SC_CloseSession           */
  extern CK_RV SC_CloseAllSessions();                           /* extern CK_RV SC_CloseAllSessions       */
  extern CK_RV SC_GetSessionInfo();                             /* extern CK_RV SC_GetSessionInfo         */
  extern CK_RV SC_GetOperationState();                          /* extern CK_RV SC_GetOperationState      */
  extern CK_RV SC_SetOperationState();                          /* extern CK_RV SC_SetOperationState      */
  extern CK_RV SC_Login();                                      /* extern CK_RV SC_Login                  */
  extern CK_RV SC_Logout();                                     /* extern CK_RV SC_Logout                 */
  extern CK_RV SC_CreateObject();                               /* extern CK_RV SC_CreateObject           */
  extern CK_RV SC_CopyObject();                                 /* extern CK_RV SC_CopyObject             */
  extern CK_RV SC_DestroyObject();                              /* extern CK_RV SC_DestroyObject          */
  extern CK_RV SC_GetObjectSize();                              /* extern CK_RV SC_GetObjectSize          */
  extern CK_RV SC_GetAttributeValue();                          /* extern CK_RV SC_GetAttributeValue      */
  extern CK_RV SC_SetAttributeValue();                          /* extern CK_RV SC_SetAttributeValue      */
  extern CK_RV SC_FindObjectsInit();                            /* extern CK_RV SC_FindObjectsInit        */
  extern CK_RV SC_FindObjects();                                /* extern CK_RV SC_FindObjects            */
  extern CK_RV SC_FindObjectsFinal();                           /* extern CK_RV SC_FindObjectsFinal       */
  extern CK_RV SC_EncryptInit();                                /* extern CK_RV SC_EncryptInit            */
  extern CK_RV SC_Encrypt();                                    /* extern CK_RV SC_Encrypt                */
  extern CK_RV SC_EncryptUpdate();                              /* extern CK_RV SC_EncryptUpdate          */
  extern CK_RV SC_EncryptFinal();                               /* extern CK_RV SC_EncryptFinal           */
  extern CK_RV SC_DecryptInit();                                /* extern CK_RV SC_DecryptInit            */
  extern CK_RV SC_Decrypt();                                    /* extern CK_RV SC_Decrypt                */
  extern CK_RV SC_DecryptUpdate();                              /* extern CK_RV SC_DecryptUpdate          */
  extern CK_RV SC_DecryptFinal();                               /* extern CK_RV SC_DecryptFinal           */
  extern CK_RV SC_DigestInit();                                 /* extern CK_RV SC_DigestInit             */
  extern CK_RV SC_Digest();                                     /* extern CK_RV SC_Digest                 */
  extern CK_RV SC_DigestUpdate();                               /* extern CK_RV SC_DigestUpdate           */
  extern CK_RV SC_DigestKey();                                  /* extern CK_RV SC_DigestKey              */
  extern CK_RV SC_DigestFinal();                                /* extern CK_RV SC_DigestFinal            */
  extern CK_RV SC_SignInit();                                   /* extern CK_RV SC_SignInit               */
  extern CK_RV SC_Sign();                                       /* extern CK_RV SC_Sign                   */
  extern CK_RV SC_SignUpdate();                                 /* extern CK_RV SC_SignUpdate             */
  extern CK_RV SC_SignFinal();                                  /* extern CK_RV SC_SignFinal              */
  extern CK_RV SC_SignRecoverInit();                            /* extern CK_RV SC_SignRecoverInit        */
  extern CK_RV SC_SignRecover();                                /* extern CK_RV SC_SignRecover            */
  extern CK_RV SC_VerifyInit();                                 /* extern CK_RV SC_VerifyInit             */
  extern CK_RV SC_Verify();                                     /* extern CK_RV SC_Verify                 */
  extern CK_RV SC_VerifyUpdate();                               /* extern CK_RV SC_VerifyUpdate           */
  extern CK_RV SC_VerifyFinal();                                /* extern CK_RV SC_VerifyFinal            */
  extern CK_RV SC_VerifyRecoverInit();                          /* extern CK_RV SC_VerifyRecoverInit      */
  extern CK_RV SC_VerifyRecover();                              /* extern CK_RV SC_VerifyRecover          */
  extern CK_RV SC_DigestEncryptUpdate();                        /* extern CK_RV SC_DigestEncryptUpdate    */
  extern CK_RV SC_DecryptDigestUpdate();                        /* extern CK_RV SC_DecryptDigestUpdate    */
  extern CK_RV SC_SignEncryptUpdate();                          /* extern CK_RV SC_SignEncryptUpdate      */
  extern CK_RV SC_DecryptVerifyUpdate();                        /* extern CK_RV SC_DecryptVerifyUpdate    */
  extern CK_RV SC_GenerateKey();                                /* extern CK_RV SC_GenerateKey            */
  extern CK_RV SC_GenerateKeyPair();                            /* extern CK_RV SC_GenerateKeyPair        */
  extern CK_RV SC_WrapKey();                                    /* extern CK_RV SC_WrapKey                */
  extern CK_RV SC_UnwrapKey();                                  /* extern CK_RV SC_UnwrapKey              */
  extern CK_RV SC_DeriveKey();                                  /* extern CK_RV SC_DeriveKey              */
  extern CK_RV SC_SeedRandom();                                 /* extern CK_RV SC_SeedRandom             */
  extern CK_RV SC_GenerateRandom();                             /* extern CK_RV SC_GenerateRandom         */
  extern CK_RV SC_GetFunctionStatus();                          /* extern CK_RV SC_GetFunctionStatus      */
  extern CK_RV SC_CancelFunction();                             /* extern CK_RV SC_CancelFunction         */


// Added for AIX work
void
SC_SetFunctionList(void){

   function_list.ST_Initialize          = SC_Initialize;
   function_list.ST_GetTokenInfo        = SC_GetTokenInfo;
   function_list.ST_GetMechanismList    = SC_GetMechanismList;
   function_list.ST_GetMechanismInfo    = SC_GetMechanismInfo;
   function_list.ST_InitToken           = SC_InitToken;
   function_list.ST_InitPIN             = SC_InitPIN;
   function_list.ST_SetPIN              = SC_SetPIN;
   function_list.ST_OpenSession         = SC_OpenSession;
   function_list.ST_CloseSession        = SC_CloseSession;
   function_list.ST_GetSessionInfo      = SC_GetSessionInfo;
   function_list.ST_GetOperationState   = SC_GetOperationState;
   function_list.ST_SetOperationState   = SC_SetOperationState;
   function_list.ST_Login               = SC_Login;
   function_list.ST_Logout              = SC_Logout;
   function_list.ST_CreateObject        = SC_CreateObject;
   function_list.ST_CopyObject          = SC_CopyObject;
   function_list.ST_DestroyObject       = SC_DestroyObject;
   function_list.ST_GetObjectSize       = SC_GetObjectSize;
   function_list.ST_GetAttributeValue   = SC_GetAttributeValue;
   function_list.ST_SetAttributeValue   = SC_SetAttributeValue;
   function_list.ST_FindObjectsInit     = SC_FindObjectsInit;
   function_list.ST_FindObjects         = SC_FindObjects;
   function_list.ST_FindObjectsFinal    = SC_FindObjectsFinal;
   function_list.ST_EncryptInit         = SC_EncryptInit;
   function_list.ST_Encrypt             = SC_Encrypt;
   function_list.ST_EncryptUpdate       = SC_EncryptUpdate;
   function_list.ST_EncryptFinal        = SC_EncryptFinal;
   function_list.ST_DecryptInit         = SC_DecryptInit;
   function_list.ST_Decrypt             = SC_Decrypt;
   function_list.ST_DecryptUpdate       = SC_DecryptUpdate;
   function_list.ST_DecryptFinal        = SC_DecryptFinal;
   function_list.ST_DigestInit          = SC_DigestInit;
   function_list.ST_Digest              = SC_Digest;
   function_list.ST_DigestUpdate        = SC_DigestUpdate;
   function_list.ST_DigestKey           = SC_DigestKey;
   function_list.ST_DigestFinal         = SC_DigestFinal;
   function_list.ST_SignInit            = SC_SignInit;
   function_list.ST_Sign                = SC_Sign;
   function_list.ST_SignUpdate          = SC_SignUpdate;
   function_list.ST_SignFinal           = SC_SignFinal;
   function_list.ST_SignRecoverInit     = SC_SignRecoverInit;
   function_list.ST_SignRecover         = SC_SignRecover;
   function_list.ST_VerifyInit          = SC_VerifyInit;
   function_list.ST_Verify              = SC_Verify;
   function_list.ST_VerifyUpdate        = SC_VerifyUpdate;
   function_list.ST_VerifyFinal         = SC_VerifyFinal;
   function_list.ST_VerifyRecoverInit   = SC_VerifyRecoverInit;
   function_list.ST_VerifyRecover       = SC_VerifyRecover;
   function_list.ST_DigestEncryptUpdate = NULL; // SC_DigestEncryptUpdate;
   function_list.ST_DecryptDigestUpdate = NULL; // SC_DecryptDigestUpdate;
   function_list.ST_SignEncryptUpdate   = NULL; //SC_SignEncryptUpdate;
   function_list.ST_DecryptVerifyUpdate = NULL; // SC_DecryptVerifyUpdate;
   function_list.ST_GenerateKey         = SC_GenerateKey;
   function_list.ST_GenerateKeyPair     = SC_GenerateKeyPair;
   function_list.ST_WrapKey             = SC_WrapKey;
   function_list.ST_UnwrapKey           = SC_UnwrapKey;
   function_list.ST_DeriveKey           = SC_DeriveKey;
   function_list.ST_SeedRandom          = SC_SeedRandom ;
   function_list.ST_GenerateRandom      = SC_GenerateRandom;
   function_list.ST_GetFunctionStatus   = NULL; // SC_GetFunctionStatus;
   function_list.ST_CancelFunction      = NULL; // SC_CancelFunction;

}

int
APISlot2Local(snum)
   CK_SLOT_ID  snum;
{
   int i;

//   return snum; /// temp to change this..

   for (i=0;i< PKW_MAX_DEVICES; i++){
      if (correlator_init[i].init)
         if (correlator_init[i].API_Slotid == snum)
            return (i+1);  // Slots from Lex code are 1 based not 0...
   }
   return -1;
}


#define  SLT_CHECK  \
   CK_SLOT_ID     slot_id; \
   int            sid1; \
 \
   if ( (sid1 = APISlot2Local(sid)) != -1 ){ \
      slot_id = sid1; \
   } else { \
      return CKR_ARGUMENTS_BAD; \
   } 


#define SESSION   sSession.sessionh
#define SLOTID    APISlot2Local(sSession.slotID)

#define  SESS_SET \
   CK_SESSION_HANDLE  hSession; \
\
   hSession = sSession.sessionh; 



void
hex_dump(char *str,CK_BYTE_PTR ptr, int  len )
{
   int  lendone=0;
   int  by10 = 0;
   int   i,j;


   printf("%s Dumping  %d bytes \n",str,len);
   by10 = len/10;
   for (i=0;i< by10;i++){
      for (j=0;j<10;j++){
         lendone ++;
         printf("0x%02X ",*ptr);
         ptr++;
      }
      printf("\n");
   }

   for (j=lendone; j< len;j++){
         printf("0x%02X ",*ptr);
         ptr++;
   }

      printf("\n Done Dumping  \n");


}



CK_RV
MY_LockMutex(void)
{
   WaitForSingleObject( pkcs_mutex, INFINITE );
   return CKR_OK;
}

CK_RV
MY_UnlockMutex(void)
{
   ReleaseMutex(pkcs_mutex);
   return CKR_OK;
}


#ifdef PKCS64
CK_ULONG_32 long_reverse( CK_ULONG_32 x )
#else
CK_ULONG long_reverse( CK_ULONG x )
#endif
{
#ifdef _BIG_ENDIAN   // Power Architecture requires reversal to talk to adapter
      return (
         ((0x000000FF & x)<<24) |
         ((0x0000FF00 & x)<<8) |
         ((0x00FF0000 & x)>>8) |
         ((0xFF000000 & x)>>24) );
#else
      return (x); // Others don't require  reversal.

#endif
}

// SAB FIXME Added for 64bit
uint32
get_attrib_len(CK_ATTRIBUTE *attr)
{

   switch(attr->type){
      case CKA_CLASS:
      case CKA_KEY_TYPE:
      case CKA_MODULUS_BITS:
      case CKA_VALUE_BITS:
      case CKA_VALUE_LEN:
      case CKA_CERTIFICATE_TYPE:  // SAB FIXME 64bit
         // These are unsigned longs, which in 64bit need
         // to be made into 32bit values to be passed to the
         // card.
         return(sizeof(unsigned int));
         break;
      default:
         return (attr->ulValueLen);
         break;
   }

}

void
copy_attribute_value(void *source, void *dest, CK_ATTRIBUTE *attr)
{

#if PKCS64
   CK_ULONG_32  d;
#else
   CK_ULONG  d;
#endif
   CK_ULONG  *p;

   switch(attr->type){
      case CKA_CLASS:
      case CKA_KEY_TYPE:
      case CKA_MODULUS_BITS:
      case CKA_VALUE_BITS:
      case CKA_VALUE_LEN:
      case CKA_CERTIFICATE_TYPE:  // SAB FIXME 64bit
         // These are unsigned longs, which in 64bit need
         // to be made into 32bit values to be passed to the
         // card.
         
         p = (CK_ULONG *)(attr->pValue);
         d  = *p;
         //printf("copy attribute value d = %x  p %x\n",d,*p);
          *((CK_ULONG_32 *)dest) = d;
         //*((CK_ULONG_32 *)dest) = *((CK_ULONG *)(attr->pValue));
         
         break;
      default:
         memcpy(dest, source, attr->ulValueLen);
         break;
   }

}

// SAB FIXME END Added for 64bit
#ifdef _BIG_ENDIAN
   // Routine to modify a template attribute if necessary
void
ModifyAttribute(type,val)
   CK_ATTRIBUTE_TYPE  type;

#ifdef PKCS64
   CK_ULONG_PTR_32       val;
{
   CK_ULONG_32   tval;
#else
   CK_ULONG_PTR       val;
{
   CK_ULONG   tval;
#endif


   switch (type){
      case CKA_CLASS:
      case CKA_KEY_TYPE:
      case CKA_MODULUS_BITS:
      case CKA_VALUE_BITS:
      case CKA_VALUE_LEN:
      case CKA_CERTIFICATE_TYPE:  // SAB FIXME 64bit
         // These are the ones which need to be swapped

#ifdef PKCS64
        tval =  HTOCL((CK_ULONG_32)*val);
	*val = tval; 
        // memcpy(val, &tval, sizeof(CK_ULONG_32));
#else
        tval =  HTOCL((CK_ULONG)*val);
        memcpy(val, &tval, sizeof(CK_ULONG));
#endif

      default:
         break;
   }
}
#else
// NOTE FIXME  intel 64bit systems will have a problem here
// and need to be adjusted properly
void
ModifyAttribute(type,val)
   CK_ATTRIBUTE_TYPE  type;
   CK_ULONG_PTR       val;
{
   // This is a no op function for Intel AIX based systems
}

#endif




#ifndef SOCKET
// Function:  communicate()
//
// Specialized communicate routine for use with Encryption/Decryption.  The
// data to be encrypted/decrypted is sent in a separate buffer.  This allows
// the mechanisms to take advantage of external-to-external buffer transfers
// where possible.  Everything else is the same (LEEDS_REQUEST/LEEDS_REPLY
// still occurs on buffer #0, etc).
//
// Args:    pReq:    the 'normal' request structure
//          pRep:    the 'normal' reply structure
//          pOut:    the cleartext/ciphertext to be sent TO the card
//          pIn      the cleartext/ciphertext to be received FROM the card
//

//
// Assemble a request packet for the 4758, send it across, and unmarshal the
// reply.
//
// cmd_id   - Command identifier (specifies which function to invoke)
// slot_id  - Slot number of 4758 to which request is addressed
// pReq     - -> buffer containing data (args, etc.) associated with request
// req_len  - Length in bytes of *pReq
// pRep     - -> buffer that is to hold the reply
// repl_len - -> length in bytes of *pRep
// pOut     - -> buffer containing additional data to be supplied with the
//            command (e.g., address of buffer of data to encrypt)
// out_len  - Length in bytes of *pOut
// pIn      - -> buffer that is to hold additional data returned by the
//            coprocessor (e.g., address of buffer to hold encrypted data)
// in_len   - Length in bytes of *pIn
//
// Any of the buffer pointers may be NULL (in which case the corresponding
// length must be 0).
//
// cmd_id is sent in the UserDefined field of the sccRequest structure.
// The buffers defined by pReq and pOut are passed in pOutBuffer[0] and
// pOutBuffer[1], respectively.  The buffers defined by pRep and pIn are
// passed in pInBuffer[0] and pInBuffer[1], respectively.
//
// Data in the buffers must be in the proper byte order.  Other fields (e.g.,
// cmd_id) are handled automatically.
//
// On successful return, *repl_len contains the actual length in bytes of the
// reply.
//
CK_RV communicate( CK_ULONG cmd_id, CK_SLOT_ID   slot_id,
                   CK_VOID_PTR pReq,   CK_ULONG     req_len,
                   CK_VOID_PTR pRep,   CK_ULONG_PTR repl_len,
                   CK_BYTE_PTR pOut,   CK_ULONG     outlen,
                   CK_BYTE_PTR pIn,    CK_ULONG     inlen )
{
   union
   {
      double  d;
      CK_BYTE b[1024];
   } alignedBuffers[2];

   LEEDS_REQUEST  * send_packet = (LEEDS_REQUEST *)&(alignedBuffers[0]);
   LEEDS_REPLY    * recv_packet = (LEEDS_REPLY   *)&(alignedBuffers[1]);
   CK_BYTE        * ptr         = NULL;
   CK_BYTE        * in_buf      = pIn;
   CK_BYTE        * out_buf     = pOut;
   CK_ULONG         send_len, recv_len;
   CK_ULONG         out_len = outlen;
   CK_ULONG         in_len = inlen;
   CK_ULONG         in_buf_len = in_len, out_buf_len = out_len;

   CK_RV            rc;
   sccRB_t          request_block;


   int i; // XXX WJH

   //LARGE_INTEGER    start,end;

   if (repl_len == NULL)
      return CKR_GENERAL_ERROR;

   if (slot_id > MAX_SLOT_ID)
      return CKR_FUNCTION_FAILED;

   if (pReq == NULL && req_len != 0)
      return CKR_FUNCTION_FAILED;

   if (pRep == NULL && *repl_len != 0)
      return CKR_FUNCTION_FAILED;

   if (pOut == NULL && out_len != 0) {
      out_len = 0;
      in_buf_len = in_len, out_buf_len = out_len;
      //return CKR_FUNCTION_FAILED;
   }

   if (pIn == NULL && in_len != 0) {
        in_len = 0;
        in_buf_len = in_len, out_buf_len = out_len;
      //return CKR_FUNCTION_FAILED;
   }


   // ensure the buffer lengths are multiples of 4 and that the buffers we
   // have are big enough
   //
   send_len = (sizeof(LEEDS_REQUEST) + req_len + 3) & ~3;
   recv_len = (sizeof(LEEDS_REPLY) + *repl_len + 3) & ~3;

   if (send_len > sizeof(alignedBuffers[0]))
      send_packet = (LEEDS_REQUEST *)malloc( send_len );

   if (recv_len > sizeof(alignedBuffers[1]))
      recv_packet = (LEEDS_REPLY *)malloc( recv_len );

   if ((out_len & 3) != 0)
   {
      out_buf_len = (out_len + 3) & ~3;
      out_buf = (CK_BYTE *)malloc( out_buf_len );
      memcpy( out_buf, pOut, out_len );
   }

   if ((in_len & 3) != 0)
   {
      in_buf_len = (in_len + 3) & ~3;
      in_buf = (CK_BYTE *)malloc( in_buf_len );
   }

   // If we couldn't allocate something we needed, die
   //
   if (send_packet == NULL ||
       recv_packet == NULL ||
      (out_buf     == NULL && out_buf_len != 0) ||
      (in_buf      == NULL && in_buf_len  != 0))
   {
      if (send_len > sizeof(alignedBuffers[0]) && send_packet != NULL)
         free( send_packet );

      if (recv_len > sizeof(alignedBuffers[1]) && recv_packet != NULL)
         free( recv_packet );

      if (out_buf != NULL && out_buf != pOut)
         free( out_buf );

      if (in_buf != NULL && in_buf != pIn)
         free( in_buf );

      return CKR_HOST_MEMORY;
   }

   memset( send_packet, 0x0, send_len );
   memset( recv_packet, 0x0, recv_len );

   memset( &request_block,         0x00,      sizeof(request_block) );
   memcpy( &request_block.AgentID, &leeds_id, sizeof(leeds_id) );

   send_packet->pid     = HTOCL( pid_list[slot_id - 1] );
   send_packet->req_len = HTOCL( req_len );

   send_packet->repl_max[0] = HTOCL( *repl_len );
   send_packet->repl_max[1] = HTOCL( in_len );
   send_packet->repl_max[2] = 0;      // we don't currently use these buffers
   send_packet->repl_max[3] = 0;      // but maybe in the future...


 


   // Skip request header
   //
   ptr = (CK_BYTE *)send_packet + sizeof(LEEDS_REQUEST);

   if (pReq != NULL)
      memcpy( ptr, pReq, req_len );

   request_block.pOutBuffer[0] = (UCHAR *)send_packet;
   request_block.pInBuffer [0] = (UCHAR *)recv_packet;
   request_block.pOutBuffer[1] = (UCHAR *)out_buf;
   request_block.pInBuffer [1] = (UCHAR *)in_buf;

   // I don't know if the following needs to be adjusted for endianness or not
   // (the device driver could in principle take care of the swapping)
   //
   request_block.UserDefined = cmd_id;

   request_block.OutBufferLength[0] = send_len;
   request_block.InBufferLength [0] = recv_len;
   request_block.OutBufferLength[1] = out_buf_len;
   request_block.InBufferLength [1] = in_buf_len;

#if 0
   printf("\n\nRequest Block Dump:\n\n");

   printf("request_block.AgentID.DeveloperID[0] %X\n", 
         	  request_block.AgentID.DeveloperID[0]);
   printf("request_block.AgentID.DeveloperID[1] %X\n", 
         	  request_block.AgentID.DeveloperID[1]);

   for ( i=0;i<11;i++) {
        printf("request_block.AgentID.ProgramID[%X] %X\n", 
         	  i, request_block.AgentID.ProgramID[i]);
   }
   printf("request_block.AgentID.Version[0] %X\n", 
         	  request_block.AgentID.Version[0]); 

   printf("request_block.AgentID.Instance[0] %X\n", 
         	  request_block.AgentID.Instance[0]); 

   printf("request_block.AgentID.Queue[0] %X\n", 
         	  request_block.AgentID.Instance[0]); 

   printf("request_block.reserved %X\n", request_block.reserved);

   printf("request_block.UserDefined %X\n", request_block.UserDefined);

   for (i=0;i<4;i++){
      printf("request_block.OutBufferLength[%X] %X\n", 
	     i, request_block.OutBufferLength[i]);
   }

   for (i=0;i<4;i++){
      printf("request_block.InBufferLength[%X] %X\n", 
	     i, request_block.InBufferLength[i]);
   }

   for (i=0;i<4;i++){
      printf("request_block.pOutBuffer[%X] %X\n", 
	     i, request_block.pOutBuffer[i]);
   }
   for (i=0;i<4;i++){
      printf("request_block.pInBuffer[%X] %X\n", 
	     i, request_block.pInBuffer[i]);
   }

   printf("request_block.Status %X\n", request_block.Status);

   printf("\nLEEDS_REQUEST Dump:\n\n");


   printf("send_packet->pid %d\n", send_packet->pid);
   printf("send_packet->req_len %d\n", send_packet->req_len );
   printf("send_packet->repl_max[0] %x\n", send_packet->repl_max[0]);
   printf("send_packet->repl_max[1] %x\n",send_packet->repl_max[1]); 

   printf("\n\n");
#endif


   // send the request synchronously to the adapter
   //

   rc = sccRequest( adapter_handle[slot_id - 1], &request_block );


   if (rc != 0)
   {
      rc = CKR_FUNCTION_FAILED;
      goto error;
   }

   // handle the replies
   //
   if ((CTOHL(recv_packet->repl_len[0]) > *repl_len) ||
       (CTOHL(recv_packet->repl_len[1]) >  in_len))
   {
#if 0
      printf(" rep from card 0 %x \n rep from card 1 %x \n repl_len %x \n in_len %x \n",
            CTOHL(recv_packet->repl_len[0]),CTOHL(recv_packet->repl_len[1]),
               *repl_len, in_len);
#endif
      rc = CKR_FUNCTION_FAILED;
      goto error;
   }

   *repl_len = CTOHL(recv_packet->repl_len[0]);

   // Skip reply header
   //
   ptr = (CK_BYTE *)recv_packet + sizeof(LEEDS_REPLY);

   if (pRep != NULL)
      memcpy( pRep, ptr, CTOHL(recv_packet->repl_len[0]) );

   if (in_buf != pIn)
      memcpy( pIn, in_buf, CTOHL(recv_packet->repl_len[1]) );

   // This may need to be swapped...
   //
   rc = request_block.Status;

error:
   if (send_len > sizeof(alignedBuffers[0])) free( send_packet );
   if (recv_len > sizeof(alignedBuffers[1])) free( recv_packet );
   if (in_buf  != pIn)  free( in_buf );
   if (out_buf != pOut) free( out_buf );

   return rc;
}

#else
// Socket
CK_RV communicate( CK_ULONG    cmd_id, CK_SLOT_ID   slot_id,
                    CK_VOID_PTR pReq,   CK_ULONG     req_len,
                    CK_VOID_PTR pRep,   CK_ULONG_PTR repl_len,
                    CK_BYTE_PTR pOut,   CK_ULONG     out_len,
                    CK_BYTE_PTR pIn,    CK_ULONG     in_len )
{
   proxy_req_t  * send_packet = NULL;
   proxy_resp_t    * recv_packet = NULL;
   char          *rpkt = NULL;
   CK_BYTE        * ptr         = NULL;
   CK_BYTE        * in_buf      = NULL;
   CK_BYTE        * out_buf     = NULL;
   CK_ULONG         send_len, recv_len;
   CK_ULONG         in_buf_len, out_buf_len;
   CK_BBOOL         alloc_in = FALSE, alloc_out=FALSE;
   CK_RV            rc;
   long              rv;
   long              total_read = 0;
   sccRB_t          request_block;
      struct hostent  *hs,hst;
      struct sockaddr_in   saddr;
      struct sockaddr_in   caddr;
      int   sock;




   if (!repl_len)
      return CKR_GENERAL_ERROR;

   if (slot_id > MAX_SLOT_ID)
      return CKR_FUNCTION_FAILED;

   if (pOut == NULL && out_len != 0)
      return CKR_FUNCTION_FAILED;

   if (pIn == NULL && in_len != 0)
      return CKR_FUNCTION_FAILED;

#ifdef ALLSOCK
// Create the socket here.
//
  pthread_mutex_lock(&smtx);
   {
      int j;
      int count=0;
         j = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
         if (j) {
             sock = j; 
            hs = gethostbyname(HOSTNAME);
           if (! hs ) {
              exit(2 );
           }
            hst=*hs;
            saddr.sin_family = AF_INET;
            memcpy((char *)&saddr.sin_addr, hs->h_addr, hs->h_length);
            //saddr.sin_addr.s_addr  =  htonl(0x0933510c);
            saddr.sin_port = htons(PORT);

            if ( connect (sock,(struct sockaddr *)&saddr,sizeof(struct sockaddr_in)) < 0 ){
               // XXX FIXME   just bail for now.

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s: socket failed to connect errno %d \n","communicate",errno);
#endif
               pthread_mutex_unlock(&smtx);
               return CKR_FUNCTION_FAILED;
            } else {
                  rc = 0;
            }

         } else {
            pthread_mutex_unlock(&smtx);
            return CKR_FUNCTION_FAILED;
         }
   }
  pthread_mutex_unlock(&smtx);
#else
  sock = adapter_handle[slot_id-1];
#endif
   // end socket creation


   // ensure the buffer lengths are multiples of 4
   //  Allocate contiguous memory for both send and receive
   send_len = sizeof(proxy_req_t) + req_len + out_len;
   recv_len = sizeof(proxy_resp_t) + *repl_len + in_len;


#ifdef DEBUGON
   logit(LOG_DEBUG, "\t\t%-25s:  slot_id %d  %d, 0x%x \n","communicate",slot_id,slot_id-1,cmd_id);
#endif

   // this probably isn't guaranteed to be longword-aligned...
   //
#if 1
   send_packet = (proxy_req_t *)malloc( send_len );
   recv_packet = (proxy_resp_t   *)malloc( recv_len );
#endif

   if (!send_packet || !recv_packet)
      return CKR_HOST_MEMORY;

   memset( send_packet, 0x0, send_len );
   memset( recv_packet, 0x0, recv_len );

   ptr = (CK_BYTE *)send_packet + sizeof(proxy_req_t);

   if (pReq != NULL)
      memcpy( ptr, pReq, req_len );

   ptr = (CK_BYTE *)send_packet + sizeof(proxy_req_t) + req_len;
   if (pOut != NULL)
      memcpy(ptr,pOut,out_len);


   send_packet->pid     = HTOCL( pid_list[slot_id - 1] );
   send_packet->cmd_id = HTOCL(cmd_id);
   send_packet->req_len = HTOCL( req_len );
   send_packet->repl_len = HTOCL((*repl_len)); // These have to be swapped
   send_packet->in_len = HTOCL(in_len);
   send_packet->out_len = HTOCL(out_len);



   // send the request synchronously to the adapter
   //
   // This is actualy send asynchronously to the remote hoset
// SAB XXX FIXME  this needs to be done...
//

  pthread_mutex_lock(&smtx);

#ifdef DEBUGON
   logit(LOG_DEBUG, "\t\t%-25s:  writing   \n","communicate");
#endif
   //rv = write(adapter_handle[slot_id -1 ],send_packet,send_len);
   rv = write(sock,send_packet,send_len);
#ifdef DEBUGON
   logit(LOG_DEBUG, "\t\t%-25s:  wrote  %d  \n","communicate",rv);
#endif

   if (rv == -1) {
#ifdef DEBUGON
   logit(LOG_DEBUG, "\t\t%-25s: write failed  %d  errno %d \n","communicate",rv,errno);
#endif
      rc = CKR_FUNCTION_FAILED; // socket failure
      close(sock);
      pthread_mutex_unlock(&smtx);
      goto error;
   }

   total_read = 0;
   rv = 1;
   //while ( (total_read < recv_len) && ( rv != -1)){ 

   rpkt = (char *)recv_packet;

   while ( (total_read < sizeof(proxy_resp_t)) && ( rv != -1)){ 
#ifdef DEBUGON
//   logit(LOG_DEBUG, "\t\t%-25s: reading  header  %d   \n","communicate",total_read);
//   logit(LOG_DEBUG, "\t\t%-25s: reading  into %x  \n","communicate", rpkt + total_read);
#endif
      // rv = read(sock,recv_packet + total_read,recv_len-total_read);
      rv = read(sock,rpkt + total_read,sizeof(proxy_resp_t)-total_read);
#ifdef DEBUGON
//   logit(LOG_DEBUG, "\t\t%-25s: reading   %d   \n","communicate",rv);
#endif
      if (rv > 0 )
         total_read += rv;

      if (rv == 0 && total_read < recv_len) {
         rv = 1;
         continue;
      }
   };

#ifdef DEBUGON
//   logit(LOG_DEBUG, "\t\t%-25s: second phase read   %d  resp %d %d  \n","communicate",
//         total_read,(CTOHL(recv_packet->repl_len)),(CTOHL(recv_packet->in_len)));
//   logit(LOG_DEBUG, "\t\t%-25s: rpkt %x %x  \n","communicate",
//         rpkt,rpkt + total_read);
#endif


   if (total_read == sizeof(proxy_resp_t)) {// && rv != -1){
      int  local_count=0;

      rpkt += total_read;

      while (total_read < 
               (sizeof(proxy_resp_t) + 
               (CTOHL(recv_packet->repl_len)) + 
               (CTOHL(recv_packet->in_len)))) {

#ifdef DEBUGON
//         logit(LOG_DEBUG, "\t\t%-25s: reading  rest  %d   \n","communicate", total_read);
//         logit(LOG_DEBUG, "\t\t%-25s: reading  into %x  \n","communicate", rpkt);
#endif
         rv = read(sock,rpkt,
          ((CTOHL(recv_packet->repl_len)) + (CTOHL(recv_packet->in_len)))-local_count);

         if (rv > 0 ) {
            total_read += rv;
            local_count += rv;
            rpkt += rv;
         }

#ifdef DEBUGON
//         logit(LOG_DEBUG, "\t\t%-25s: read  %d   \n","communicate", rv);
//         logit(LOG_DEBUG, "\t\t%-25s: total  %d   \n","communicate", total_read);
#endif

         if (rv == 0 && total_read < 
               (sizeof(proxy_resp_t) + 
               (CTOHL(recv_packet->repl_len)) + 
               (CTOHL(recv_packet->in_len)))) {
 
            rv = 1;
            continue;
         }
      }
   } else {
#ifdef DEBUGON
   logit(LOG_DEBUG, "\t\t%-25s: we are screwed  %d   \n","communicate",total_read);
#endif
      rc = CKR_FUNCTION_FAILED;
      pthread_mutex_unlock(&smtx);
#ifdef ALLSOCK
      close(sock);
#endif
      goto error;
   }



   if (rv == -1  && total_read == 0) {
#ifdef DEBUGON
   logit(LOG_DEBUG, "\t\t%-25s: eof on socket  %d  errno %d \n","communicate",rv,errno);
#endif
      rc = CKR_FUNCTION_FAILED;
   pthread_mutex_unlock(&smtx);
#ifdef ALLSOCK
   close(sock);
#endif
      goto error;

   }
#ifdef ALLSOCK
   close(sock);
#endif
   pthread_mutex_unlock(&smtx);


   if ( total_read < sizeof(proxy_resp_t)) {
      logit(LOG_DEBUG, "\t\t%-25s: Total read not enough    %d   \n","communicate",total_read);
      rc = CKR_FUNCTION_FAILED;
      goto error;
   }


// SAB end XXX FIXME

   // handle the replies
   //

   if ((CTOHL(recv_packet->repl_len) > *repl_len) ||
       (CTOHL(recv_packet->in_len) >  in_len))
   {
#ifdef DEBUGON
   logit(LOG_DEBUG, "\t\t%-25s: rep length delta %d a %d  \n","communicate",*repl_len,CTOHL(recv_packet->repl_len));
   logit(LOG_DEBUG, "\t\t%-25s: in length delta %d  %d \n","communicate",in_len,
         CTOHL(recv_packet->in_len));
#endif
      rc = CKR_FUNCTION_FAILED;
      goto error;
   }


   if (total_read < (CTOHL(recv_packet->repl_len) + CTOHL(recv_packet->in_len))){
      logit(LOG_DEBUG, "\t\t%-25s: Total read not enough    %d  expected %d  \n","communicate",
            total_read,(CTOHL(recv_packet->repl_len) + CTOHL(recv_packet->in_len)));
      rc = CKR_FUNCTION_FAILED;
      goto error;
   }


   ptr = (CK_BYTE *)recv_packet + sizeof(proxy_resp_t);

   if (pRep != NULL)
      memcpy( pRep, ptr, CTOHL(recv_packet->repl_len) );

   ptr = (CK_BYTE *)recv_packet + sizeof(proxy_resp_t) + CTOHL(recv_packet->repl_len);
   if (pIn != NULL)
      memcpy( pIn, ptr,CTOHL( recv_packet->in_len) );

   rc = CTOHL(recv_packet->return_code);

#ifdef DEBUGON
   logit(LOG_DEBUG, "\t\t%-25s: Card returned  %d  \n","communicate",rc);
#endif

error:
   if (send_packet)  free( send_packet );
   if (recv_packet)  free( recv_packet );
   if (alloc_in)     free( in_buf );
   if (alloc_out)    free( out_buf );

   return rc;
}

#endif



//
//
CK_RV SC_Initialize( void **FunctionList,
                      CK_SLOT_ID SlotNumber,
                     char  *Correlator)
{
   int    i, j, bad, rc;
#ifdef SOCKET
      struct hostent  *hs,hst;
      struct sockaddr_in   saddr;
      struct sockaddr_in   caddr;
#endif

#ifdef BRKPT
   break_point();
#endif

   WaitForSingleObject( pkcs_mutex, INFINITE );
   
   // Handle global initialization issues first if we have not
   // been initialized.
   if (Initialized() == FALSE){
      memset( &leeds_id, 0, sizeof(leeds_id) );

      leeds_id.DeveloperID[0] = PKCS_11_DEVELOPER_ID;
      leeds_id.DeveloperID[1] = 0x00;

      memcpy( leeds_id.ProgramID,
              PKCS_11_PRG_ID,
              sizeof(leeds_id.ProgramID) );

      leeds_id.Version[0]  = PKCS_11_VERSION;
      leeds_id.Instance[0] = PKCS_11_INSTANCE;
      leeds_id.Queue[0]    = PKCS_11_QUEUE;

#ifdef DEBUGON
      loginit();
#endif

      // Zero out the adapter handle array
      //  an adapter handle of 0 indicates that the particular adapter has
      // NOT been initialized
      memset((char *)adapter_handle, 0, sizeof(sccAdapterHandle_t)*MAX_SLOT_ID);
      initialized = TRUE;
      initedpid = getpid();
      SC_SetFunctionList(); 
      memset((char *)correlator_init, 0, PKW_MAX_DEVICES * sizeof(struct Cor_init));

      {
         int i;
         for (i=0;i<PKW_MAX_DEVICES;i++){
            pid_list[i] = 0x00;
         }
      }

   }

#ifndef SOCKET
   {
  // Take the correlator as the minor number of the device we want to use
  // check the correlator_init array to determine if the slot has been
  // initialized already.
  //
  // Correlators start with 0 - N being the number of adapters -1.
  // Right now we do no additional validation of the usage.  It is possible
  // that non-initialized correlators can be accessed.  It is unlikely.
  //
  int i;

      i = (int)atoi((char *)Correlator);
      if ( correlator_init[i].init != 0 ){
         (*FunctionList) = NULL;
         ReleaseMutex(pkcs_mutex);
         return CKR_FUNCTION_FAILED;
      } else {
         // Open the file for the adapter here..
         // The open will fail if the adapter does not exist  

         rc = sccOpenAdapter( i, &adapter_handle[i] );
         if (rc == 0 ){
            correlator_init[i].init = 1; // Mark in use
            correlator_init[i].API_Slotid = SlotNumber;
         } else {
            (*FunctionList) = NULL;
            ReleaseMutex(pkcs_mutex);
            return CKR_FUNCTION_FAILED;
         }
      }
      usage_count++;
   }
#else


   {
  // Take the correlator as the minor number of the device we want to use
  // check the correlator_init array to determine if the slot has been
  // initialized already.
  //
  // Correlators start with 0 - N being the number of adapters -1.
  // Right now we do no additional validation of the usage.  It is possible
  // that non-initialized correlators can be accessed.  It is unlikely.
  //
   int i;

      i = atoi(Correlator);
      if ( correlator_init[i].init != 0 ){
         (*FunctionList) = NULL;
         ReleaseMutex(pkcs_mutex);
         return CKR_FUNCTION_FAILED;
      } else {
         // Open the file for the adapter here..
         // The open will fail if the adapter does not exist  

rc = 0;
#ifndef ALLSOCK
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  slot_id %d, \n","SC_Initialize",i);
#endif
   {
      int j;
         j = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
         if (j) {
             adapter_handle[i] = j; 
            hs = gethostbyname(HOSTNAME);
            if (! hs ) {
               exit(2 );
            }
            hst=*hs;


            saddr.sin_family = AF_INET;
            memcpy((char *)&saddr.sin_addr, hs->h_addr, hs->h_length);
            saddr.sin_port = htons(PORT);
            if ( connect (adapter_handle[i],(struct sockaddr *)&saddr,sizeof(struct sockaddr_in)) < 0 ){
               // XXX FIXME   just bail for now.
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s: connect errno %d \n","SC_Initialize",errno);
#endif
               ReleaseMutex(pkcs_mutex);
               return CKR_FUNCTION_FAILED;
            } else {
                  rc = 0;
            }

         } else {
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s: open errno %d \n","SC_Initialize",errno);
#endif
            ReleaseMutex(pkcs_mutex);
            return CKR_FUNCTION_FAILED;
         }
   }

         if (rc == 0 ){
            correlator_init[i].init = 1; // Mark in use
            correlator_init[i].API_Slotid = SlotNumber;
         } else {
            (*FunctionList) = NULL;
            ReleaseMutex(pkcs_mutex);
            return CKR_FUNCTION_FAILED;
         }
      }
      usage_count++;
   }
#endif // ifdef ALLSOCK

#endif

    (*FunctionList) = &function_list;

   ReleaseMutex( pkcs_mutex );
   return CKR_OK;
}


// FIXME : This needs to be more fully debugged.
//
CK_RV SC_Finalize( CK_SLOT_ID sid )
{
   CK_ULONG       req_len, repl_len;
   CK_ULONG       i;
   SLT_CHECK

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  sid %d slot_id %d, \n","SC_Finalize",sid,slot_id);
#endif

   WaitForSingleObject( pkcs_mutex, INFINITE );

   if (Initialized() == FALSE){
      ReleaseMutex(pkcs_mutex);
      return CKR_CRYPTOKI_NOT_INITIALIZED;
   }

#if 0
   if (pReserved != NULL){
      ReleaseMutex(pkcs_mutex);
      return CKR_ARGUMENTS_BAD;
   }
#endif

   {
#ifdef DEBUGON
   logit(LOG_DEBUG, "\t Slot %x  pid list %x %x\n",slot_id,pid_list[slot_id],pid_list[slot_id-1]);
#endif

      if (pid_list[slot_id -1 ] != 0){
         req_len  = 0;
         repl_len = 0;

         communicate(C_FINALIZE,slot_id,NULL,req_len,
                     NULL,&repl_len,
                     NULL,0,
                     NULL,0);

         // need to close the correct adapter handle...
      }
      i = slot_id -1; // slot id's are 1 based for leeds, array is zero based
      if ( adapter_handle[i] != 0 ){
         sccCloseAdapter( adapter_handle[i] );
	 i++;
      }
   }

   // Decrement module usage count
   // if module usage account is 0 then whack it.
   // since all instances of the module are cleaned up
   usage_count --;
   if (usage_count == 0 ){
      initialized = FALSE;
   }


   ReleaseMutex( pkcs_mutex );

   return CKR_OK;
}


#ifdef PKCS64

//
//
CK_RV SC_GetTokenInfo( CK_SLOT_ID         sid,
                      CK_TOKEN_INFO_PTR  pInfo )
{
   CK_TOKEN_INFO_32     reply;
   CK_ULONG          req_len;
   CK_ULONG          repl_len;
   CK_RV             rc;

   SLT_CHECK

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pInfo)
      return CKR_FUNCTION_FAILED;

   if (slot_id > MAX_SLOT_ID)
      return CKR_SLOT_ID_INVALID;

   // no arguments
   //
   req_len = 0;
   repl_len = sizeof(reply);

   rc = communicate( C_GETTOKENINFO, slot_id,
                   NULL,   req_len,
                  &reply, &repl_len,
                   NULL,   0,
                   NULL,   0 );

#ifdef __64BIT__

   if (rc == CKR_OK) {

     // The first 96 bytes are ok since the fields contain no longs: 
     // label, manufacture ID, etc. See  CK_TOKEN_INFO for details.

      memcpy( pInfo, &reply, 96 );

      pInfo->flags                = reply.flags;
      pInfo->ulMaxSessionCount    = reply.ulMaxSessionCount;
      pInfo->ulSessionCount       = reply.ulSessionCount;
      pInfo->ulMaxRwSessionCount  = reply.ulMaxRwSessionCount; 
      pInfo->ulRwSessionCount     = reply.ulRwSessionCount;
      pInfo->ulMaxPinLen          = reply.ulMaxPinLen;
      pInfo->ulMinPinLen          = reply.ulMinPinLen;
      pInfo->ulTotalPublicMemory  = reply.ulTotalPublicMemory;
      pInfo->ulFreePublicMemory   = reply.ulFreePublicMemory;
      pInfo->ulTotalPrivateMemory = reply.ulTotalPrivateMemory;
      pInfo->ulFreePrivateMemory  = reply.ulFreePrivateMemory;

   }

#else

   if (rc == CKR_OK)
      memcpy( pInfo, &reply, sizeof(CK_TOKEN_INFO) );

#endif

   pInfo->flags                = CTOHL( pInfo->flags                );
   pInfo->ulMaxSessionCount    = CTOHL( pInfo->ulMaxSessionCount    );
   pInfo->ulSessionCount       = CTOHL( pInfo->ulSessionCount       );
   pInfo->ulMaxRwSessionCount  = CTOHL( pInfo->ulMaxRwSessionCount  );
   pInfo->ulRwSessionCount     = CTOHL( pInfo->ulRwSessionCount     );
   pInfo->ulMaxPinLen          = CTOHL( pInfo->ulMaxPinLen          );
   pInfo->ulMinPinLen          = CTOHL( pInfo->ulMinPinLen          );
   pInfo->ulTotalPublicMemory  = CTOHL( pInfo->ulTotalPublicMemory  );
   pInfo->ulFreePublicMemory   = CTOHL( pInfo->ulFreePublicMemory   );
   pInfo->ulTotalPrivateMemory = CTOHL( pInfo->ulTotalPrivateMemory );
   pInfo->ulFreePrivateMemory  = CTOHL( pInfo->ulFreePrivateMemory  );
   // These don't need to be swapped at this time.
   //pInfo->hardwareVersion      = long_reverse( pInfo->hardwareVersion      );
   //pInfo->firmwareVersion      = long_reverse( pInfo->firmwareVersion      );
   //
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x\n", "C_GetTokenInfo", rc );
#endif


   return rc;
}

#else

//
//
CK_RV SC_GetTokenInfo( CK_SLOT_ID         sid,
                      CK_TOKEN_INFO_PTR  pInfo )
{
   CK_TOKEN_INFO     reply;
   CK_ULONG          req_len;
   CK_ULONG          repl_len;
   CK_RV             rc;

   SLT_CHECK

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pInfo)
      return CKR_FUNCTION_FAILED;

   if (slot_id > MAX_SLOT_ID)
      return CKR_SLOT_ID_INVALID;

   // no arguments
   //
   req_len = 0;
   repl_len = sizeof(reply);

   rc = communicate( C_GETTOKENINFO, slot_id,
                   NULL,   req_len,
                  &reply, &repl_len,
                   NULL,   0,
                   NULL,   0 );

   if (rc == CKR_OK)
      memcpy( pInfo, &reply, sizeof(CK_TOKEN_INFO) );

   pInfo->flags                = CTOHL( pInfo->flags                );
   pInfo->ulMaxSessionCount    = CTOHL( pInfo->ulMaxSessionCount    );
   pInfo->ulSessionCount       = CTOHL( pInfo->ulSessionCount       );
   pInfo->ulMaxRwSessionCount  = CTOHL( pInfo->ulMaxRwSessionCount  );
   pInfo->ulRwSessionCount     = CTOHL( pInfo->ulRwSessionCount     );
   pInfo->ulMaxPinLen          = CTOHL( pInfo->ulMaxPinLen          );
   pInfo->ulMinPinLen          = CTOHL( pInfo->ulMinPinLen          );
   pInfo->ulTotalPublicMemory  = CTOHL( pInfo->ulTotalPublicMemory  );
   pInfo->ulFreePublicMemory   = CTOHL( pInfo->ulFreePublicMemory   );
   pInfo->ulTotalPrivateMemory = CTOHL( pInfo->ulTotalPrivateMemory );
   pInfo->ulFreePrivateMemory  = CTOHL( pInfo->ulFreePrivateMemory  );
   // These don't need to be swapped at this time.
   //pInfo->hardwareVersion      = long_reverse( pInfo->hardwareVersion      );
   //pInfo->firmwareVersion      = long_reverse( pInfo->firmwareVersion      );
   //
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x\n", "C_GetTokenInfo", rc );
#endif


   return rc;
}

#endif


#ifdef PKCS64

//
//
CK_RV SC_GetMechanismList( CK_SLOT_ID             sid,
                          CK_MECHANISM_TYPE_PTR  pMechList,
                          CK_ULONG_PTR           count )
{
   GetMechList_Args   args;
   CK_BYTE          * reply = NULL;
   CK_ULONG           req_len;
   CK_ULONG           repl_len;
   CK_ULONG           i;
   CK_RV              rc;

   CK_MECHANISM_TYPE_32 *mechp;

   SLT_CHECK // This is the last in the list of variables.



   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (count == NULL)
      return CKR_FUNCTION_FAILED;

   req_len = sizeof(args);

   if (slot_id > MAX_SLOT_ID)
      return CKR_SLOT_ID_INVALID;

   if (pMechList != NULL) {
      args.list_length = HTOCL( *count );
      args.length_only = FALSE;
      repl_len = sizeof(CK_ULONG_32) + (*count * sizeof(CK_MECHANISM_TYPE_32));
   }
   else {
      args.list_length = 0;
      args.length_only = TRUE;
      repl_len = sizeof(CK_ULONG_32);
   }

   reply = (CK_BYTE *)malloc(repl_len);
   if (!reply)
      return CKR_HOST_MEMORY;

   rc = communicate( C_GETMECHANISMLIST, slot_id,
                     &args,   req_len,
                      reply, &repl_len,
                      NULL,   0,
                      NULL,   0 );

   if (rc == CKR_OK) {

     *count = *(CK_ULONG_32 *)reply;

     // memcpy( count, reply, sizeof(CK_ULONG) );

      // Swap the reply length
      *count = CTOHL( *count );

      if (pMechList != NULL) {

#if __64BIT__

	 mechp = (CK_MECHANISM_TYPE_32 *)(reply + sizeof(CK_ULONG_32));
	
         for (i=0; i < *count; i++) {
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  Mechanism[%d] = 0x%08x \n", "C_GetMechanismList", i, pMechList[i] );
#endif
         printf("%-25s:  Mechanism[%d] = 0x%08x \n", "C_GetMechanismList", i, CTOHL(mechp[i]) );
            pMechList[i] = CTOHL( mechp[i] );

	 }   

#else

         memcpy( pMechList, reply + sizeof(CK_ULONG), *count * sizeof(CK_MECHANISM_TYPE) );

         for (i=0; i < *count; i++) {
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  Mechanism[%d] = 0x%08x \n", "C_GetMechanismList", i, pMechList[i] );
#endif
            pMechList[i] = CTOHL( pMechList[i] );

	 }   
#endif
      
      }
   }

   free( reply );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, # mechanisms:  %d\n", "C_GetMechanismList", rc, *count );
#endif


   return rc;
}


#else

//
//
CK_RV SC_GetMechanismList( CK_SLOT_ID             sid,
                          CK_MECHANISM_TYPE_PTR  pMechList,
                          CK_ULONG_PTR           count )
{
   GetMechList_Args   args;
   CK_BYTE          * reply = NULL;
   CK_ULONG           req_len;
   CK_ULONG           repl_len;
   CK_ULONG           i;
   CK_RV              rc;
   SLT_CHECK // This is the last in the list of variables.


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (count == NULL)
      return CKR_FUNCTION_FAILED;

   req_len = sizeof(args);

   if (slot_id > MAX_SLOT_ID)
      return CKR_SLOT_ID_INVALID;

   if (pMechList != NULL) {
      args.list_length = HTOCL( *count );
      args.length_only = FALSE;
      repl_len = sizeof(CK_ULONG) + (*count * sizeof(CK_MECHANISM_TYPE));
   }
   else {
      args.list_length = 0;
      args.length_only = TRUE;
      repl_len = sizeof(CK_ULONG);
   }

   reply = (CK_BYTE *)malloc(repl_len);
   if (!reply)
      return CKR_HOST_MEMORY;

   rc = communicate( C_GETMECHANISMLIST, slot_id,
                     &args,   req_len,
                      reply, &repl_len,
                      NULL,   0,
                      NULL,   0 );

   if (rc == CKR_OK) {
      memcpy( count, reply, sizeof(CK_ULONG) );

      // Swap the reply length
      *count = CTOHL( *count );

      if (pMechList != NULL) {
         memcpy( pMechList, reply + sizeof(CK_ULONG), *count * sizeof(CK_MECHANISM_TYPE) );

         for (i=0; i < *count; i++) {
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  Mechanism[%d] = 0x%08x \n", "C_GetMechanismList", i, pMechList[i] );
#endif
            pMechList[i] = CTOHL( pMechList[i] );

         }
      }
   }

   free( reply );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, # mechanisms:  %d\n", "C_GetMechanismList", rc, *count );
#endif


   return rc;
}


#endif


//
//

#ifdef PKCS64

CK_RV SC_GetMechanismInfo( CK_SLOT_ID             sid,
                          CK_MECHANISM_TYPE      type,
                          CK_MECHANISM_INFO_PTR  pInfo )
{
   GetMechInfo_Args     args;
   CK_ULONG             req_len, repl_len;
   CK_RV                rc;
   CK_MECHANISM_INFO_32 reply;
   SLT_CHECK


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (pInfo == NULL)
      return CKR_FUNCTION_FAILED;

   if (slot_id > MAX_SLOT_ID)
      return CKR_SLOT_ID_INVALID;

   req_len  = sizeof(args);
   repl_len = sizeof(reply);

   args.mech_type = HTOCL( type );

   rc = communicate( C_GETMECHANISMINFO, slot_id,
                     &args,   req_len,
                     &reply, &repl_len,
                      NULL,   0,
                      NULL,   0 );

   if (rc == CKR_OK) {

#ifdef __64BIT__

      pInfo->ulMinKeySize = CTOHL(reply.ulMinKeySize);
      pInfo->ulMaxKeySize = CTOHL(reply.ulMaxKeySize);
      pInfo->flags        = CTOHL(reply.flags);  

#else

      memcpy( pInfo, &reply, sizeof(CK_MECHANISM_INFO) );

      pInfo->ulMinKeySize = CTOHL( pInfo->ulMinKeySize );
      pInfo->ulMaxKeySize = CTOHL( pInfo->ulMaxKeySize );
      pInfo->flags        = CTOHL( pInfo->flags        );
#endif
   }
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, mech type = %08x\n", "C_GetMechanismInfo", rc, type );
#endif

   return rc;
}

#else

CK_RV SC_GetMechanismInfo( CK_SLOT_ID             sid,
                          CK_MECHANISM_TYPE      type,
                          CK_MECHANISM_INFO_PTR  pInfo )
{
   GetMechInfo_Args     args;
   CK_ULONG             req_len, repl_len;
   CK_RV                rc;
   CK_MECHANISM_INFO    reply;
   SLT_CHECK


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (pInfo == NULL)
      return CKR_FUNCTION_FAILED;

   if (slot_id > MAX_SLOT_ID)
      return CKR_SLOT_ID_INVALID;

   req_len  = sizeof(args);
   repl_len = sizeof(reply);

   args.mech_type = HTOCL( type );

   rc = communicate( C_GETMECHANISMINFO, slot_id,
                     &args,   req_len,
                     &reply, &repl_len,
                      NULL,   0,
                      NULL,   0 );

   if (rc == CKR_OK) {
      memcpy( pInfo, &reply, sizeof(CK_MECHANISM_INFO) );

      pInfo->ulMinKeySize = CTOHL( pInfo->ulMinKeySize );
      pInfo->ulMaxKeySize = CTOHL( pInfo->ulMaxKeySize );
      pInfo->flags        = CTOHL( pInfo->flags        );
   }
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, mech type = %08x\n", "C_GetMechanismInfo", rc, type );
#endif

   return rc;
}

#endif

//
//
CK_RV SC_InitPIN( ST_SESSION_HANDLE  sSession,
                 CK_CHAR_PTR        pPin,
                 CK_ULONG           ulPinLen )
{
   InitPIN_Args          args;
   HOST_SESSION_HANDLE * node = NULL;
   CK_SLOT_ID            slot_id;
   CK_ULONG              req_len, repl_len;
   CK_RV                 rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (pPin == NULL)
      return CKR_PIN_INVALID;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;

   if (ulPinLen >MAX_PIN_LEN)
	return CKR_PIN_LEN_RANGE;



   slot_id = SLOTID;

   if (slot_id > MAX_SLOT_ID)
      return CKR_SLOT_ID_INVALID;

   req_len = sizeof(args);
   repl_len = 0;

   args.session_handle = HTOCL( SESSION );
   args.pin_len        = HTOCL( ulPinLen     );
   memcpy( &args.pin, pPin, ulPinLen );

   rc = communicate( C_INITPIN, slot_id,
                     &args,   req_len,
                      NULL,  &repl_len,
                      NULL,   0,
                      NULL,   0 );

   // there is no reply data
   //
#ifdef DEBUGON
   logit(LOG_DEBUG,"%-25s:  rc = %x\n", "C_InitPIN", rc );
#endif

   return rc;
}


//
//
CK_RV SC_SetPIN( ST_SESSION_HANDLE  sSession,
                CK_CHAR_PTR        pOldPin,
                CK_ULONG           ulOldLen,
                CK_CHAR_PTR        pNewPin,
                CK_ULONG           ulNewLen )
{
   SetPIN_Args           args;
   HOST_SESSION_HANDLE * node = NULL;
   CK_SLOT_ID            slot_id;
   CK_ULONG              req_len, repl_len;
   CK_RV                 rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if ((pOldPin == NULL) || (pNewPin == NULL))
      return CKR_PIN_INVALID;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;

   if (ulNewLen >MAX_PIN_LEN)
	  return CKR_PIN_LEN_RANGE;



   slot_id = SLOTID;

   if (slot_id > MAX_SLOT_ID)
      return CKR_SLOT_ID_INVALID;

   req_len = sizeof(args);
   repl_len = 0;  // no reply

   args.session_handle = HTOCL( SESSION );
   args.old_pin_len    = HTOCL( ulOldLen     );
   args.new_pin_len    = HTOCL( ulNewLen     );
   memcpy( &args.old_pin, pOldPin, ulOldLen );
   memcpy( &args.new_pin, pNewPin, ulNewLen );

   rc = communicate( C_SETPIN, slot_id,
                     &args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );


   // there is no reply data
   //
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x\n", "C_SetPIN", rc );
#endif

   return rc;
}

#ifdef PKCS64

//
//
CK_RV SC_OpenSession( CK_SLOT_ID             sid,
                     CK_FLAGS               flags,
                     CK_SESSION_HANDLE_PTR  phSession )
{
   OpenSession_Args       args;
   HOST_SESSION_HANDLE  * node  = NULL;
   CK_BYTE              * reply = NULL;
   CK_ULONG               req_len, repl_len;
   CK_RV                  rc;
   SLT_CHECK

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:   sid %d slot_id %d, \n",">SC_OpenSession",sid,slot_id);
#endif

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (phSession == NULL)
      return CKR_FUNCTION_FAILED;

   if (slot_id > MAX_SLOT_ID)
      return CKR_SLOT_ID_INVALID;

   rc = MY_LockMutex();
   if (rc != CKR_OK) {
#ifdef DEBUGON
      logit(LOG_DEBUG, "%-25s:  rc = %08x sid %d slotid %d\n", "C_OpenSession", rc,sid,slot_id );
#endif
      return rc;
   }

   // do we need a process handle too?
   //
   if (pid_list[slot_id - 1] == 0) {
      repl_len = sizeof(CK_SESSION_HANDLE_32) + sizeof(CK_ULONG_32);
      args.req_proc_handle = TRUE;
   }
   else {
      repl_len = sizeof(CK_SESSION_HANDLE_32);
      args.req_proc_handle = FALSE;
   }


   reply = (CK_BYTE *)malloc(repl_len);
   if (!reply)
      rc = CKR_HOST_MEMORY;
   else {
      // allocate the node here instead of inside the CKR_OK processing block
      // after the call to communcate() because if there is a host memory
      // error, we want to know before we create a session on the coprocessor
      //
      node = (HOST_SESSION_HANDLE *)malloc(sizeof(HOST_SESSION_HANDLE));
      if (!node)
         rc = CKR_HOST_MEMORY;
      else {
         args.slot_id         = HTOCL( slot_id );
         args.flags           = HTOCL( flags   );
         // In the case of a STDLL, nothing is even passed int.
         args.application_ptr = NULL;     // not used
         args.notify          = NULL;           // not used
         args.slot_id         = HTOCL( slot_id );

         req_len  = sizeof(args);
         rc = communicate( C_OPENSESSION, slot_id,
                           &args,   req_len,
                            reply, &repl_len,
                            NULL,   0,
                            NULL,   0 );


         if (rc == CKR_OK) {

            node->handle = *(CK_SESSION_HANDLE_32 *)reply;
	    // memcpy( &node->handle, reply, sizeof(CK_SESSION_HANDLE_32) );

            node->slot_id = slot_id;
            node->host_session = next_session_handle++;
            node->handle = CTOHL(node->handle); // Do this since the all the
                                                       // code from LEX swaps
                                                       // this.  In reality this
                                                       // is not necessary, but
                                                       // rather than change
                                                       // every location which
                                                       // uses the node->handle
                                                       // it is simpler to just
                                                       // swap it here.


            if (args.req_proc_handle == TRUE) {

               pid_list[slot_id - 1] =   *(CK_SESSION_HANDLE_32 *)(reply + 
                                           sizeof(CK_ULONG_32) );

	       //               memcpy( &pid_list[slot_id - 1],  reply + 
               //        sizeof(CK_SESSION_HANDLE_32), sizeof(CK_ULONG_32) );

               pid_list[slot_id - 1] = CTOHL( pid_list[slot_id - 1] );
            }

            *phSession = node->handle; // main api handles the control block
            free(node);
         }
         else
            free( node );  // only free the node if the OpenSession attempt failed
      }
   }

   if (reply)
      free( reply );

   MY_UnlockMutex();

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x  ", "C_OpenSession", rc );
   if (rc == CKR_OK)
      logit(LOG_DEBUG, "sess = %d", *phSession );
#endif

   return rc;
}

#else

//
//
CK_RV SC_OpenSession( CK_SLOT_ID             sid,
                     CK_FLAGS               flags,
                     CK_SESSION_HANDLE_PTR  phSession )
{
   OpenSession_Args       args;
   HOST_SESSION_HANDLE  * node  = NULL;
   CK_BYTE              * reply = NULL;
   CK_ULONG               req_len, repl_len;
   CK_RV                  rc;
   SLT_CHECK

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:   sid %d slot_id %d, \n",">SC_OpenSession",sid,slot_id);
#endif

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (phSession == NULL)
      return CKR_FUNCTION_FAILED;

   if (slot_id > MAX_SLOT_ID)
      return CKR_SLOT_ID_INVALID;

   rc = MY_LockMutex();
   if (rc != CKR_OK) {
#ifdef DEBUGON
      logit(LOG_DEBUG, "%-25s:  rc = %08x sid %d slotid %d\n", "C_OpenSession", rc,sid,slot_id );
#endif
      return rc;
   }

   // do we need a process handle too?
   //
   if (pid_list[slot_id - 1] == 0) {
      repl_len = sizeof(CK_SESSION_HANDLE) + sizeof(CK_ULONG);
      args.req_proc_handle = TRUE;
   }
   else {
      repl_len = sizeof(CK_SESSION_HANDLE);
      args.req_proc_handle = FALSE;
   }


   reply = (CK_BYTE *)malloc(repl_len);
   if (!reply)
      rc = CKR_HOST_MEMORY;
   else {
      // allocate the node here instead of inside the CKR_OK processing block
      // after the call to communcate() because if there is a host memory
      // error, we want to know before we create a session on the coprocessor
      //
      node = (HOST_SESSION_HANDLE *)malloc(sizeof(HOST_SESSION_HANDLE));
      if (!node)
         rc = CKR_HOST_MEMORY;
      else {
         args.slot_id         = HTOCL( slot_id );
         args.flags           = HTOCL( flags   );
         // In the case of a STDLL, nothing is even passed int.
         args.application_ptr = NULL;     // not used
         args.notify          = NULL;           // not used
         args.slot_id         = HTOCL( slot_id );

         req_len  = sizeof(args);
         rc = communicate( C_OPENSESSION, slot_id,
                           &args,   req_len,
                            reply, &repl_len,
                            NULL,   0,
                            NULL,   0 );


         if (rc == CKR_OK) {
            memcpy( &node->handle, reply, sizeof(CK_SESSION_HANDLE) );
            node->slot_id = slot_id;
            node->host_session = next_session_handle++;
            node->handle = CTOHL(node->handle); // Do this since the all the
                                                       // code from LEX swaps
                                                       // this.  In reality this
                                                       // is not necessary, but
                                                       // rather than change
                                                       // every location which
                                                       // uses the node->handle
                                                       // it is simpler to just
                                                       // swap it here.


            if (args.req_proc_handle == TRUE) {
               memcpy( &pid_list[slot_id - 1],  reply + 
                       sizeof(CK_SESSION_HANDLE), sizeof(CK_ULONG) );

               pid_list[slot_id - 1] = CTOHL( pid_list[slot_id - 1] );
            }

            *phSession = node->handle; // main api handles the control block
            free(node);
         }
         else
            free( node );  // only free the node if the OpenSession attempt failed
      }
   }

   if (reply)
      free( reply );

   MY_UnlockMutex();

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x  ", "C_OpenSession", rc );
   if (rc == CKR_OK)
      logit(LOG_DEBUG, "sess = %d", *phSession );
#endif

   return rc;
}

#endif

//
//
//
CK_RV SC_CloseSession( ST_SESSION_HANDLE  sSession )
{
   CloseSession_Args      args;
   HOST_SESSION_HANDLE  * node = NULL;
   CK_SLOT_ID             slot_id;
   CK_ULONG               req_len, repl_len;
   CK_RV                  rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;



   args.session_handle = HTOCL( SESSION );


   slot_id = SLOTID;

   req_len  = sizeof(args);
   repl_len = 0;  // no reply data

   rc = communicate( C_CLOSESESSION, slot_id,
                     &args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x  sess = %d\n", "C_CloseSession", rc, SESSION );
#endif

   return rc;
}


//
//
CK_RV SC_CloseAllSessions( CK_SLOT_ID sid )
{
   CK_ULONG               req_len, repl_len;
   CK_RV                  rc;
   SLT_CHECK

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   req_len  = 0;
   repl_len = 0;

   rc = communicate( C_CLOSEALLSESSIONS, slot_id,
                      NULL,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x\n", "C_CloseAllSessions", rc );
#endif

   return rc;

}


#ifdef PKCS64

//
//
CK_RV SC_GetSessionInfo( ST_SESSION_HANDLE   sSession,
                        CK_SESSION_INFO_PTR pInfo )
{
   GetSessionInfo_Args    args;
   HOST_SESSION_HANDLE  * node = NULL;
   CK_SESSION_INFO_32     info;
   CK_ULONG               req_len, repl_len;
   CK_RV                  rc;
   CK_SLOT_ID             slot_id;
   SESS_SET

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;


   if (!pInfo) {
      return CKR_FUNCTION_FAILED;
   }

   args.session_handle = HTOCL( SESSION );

   slot_id = SLOTID;

   req_len  = sizeof(args);
   repl_len = sizeof(info);

   rc = communicate( C_GETSESSIONINFO, slot_id,
                     &args,   req_len,
                     &info,  &repl_len,
                      NULL,   0,
                      NULL,   0 );

   if (rc == CKR_OK) {

#ifdef __64BIT__

      pInfo->slotID = sSession.slotID;

      pInfo->state  = info->state;
      pInfo->flags  = info->flags;

      pInfo->ulDeviceError = info->ulDeviceError;
#else

      memcpy( pInfo, &info, sizeof(info) );

#endif

      // Normalize the session information for STDLL 
      pInfo->slotID = sSession.slotID;

      pInfo->state  = CTOHL( pInfo->state  );
      pInfo->flags  = CTOHL( pInfo->flags  );

      pInfo->ulDeviceError = CTOHL( pInfo->ulDeviceError );
   }
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d\n", "C_GetSessionInfo", rc, SESSION );
#endif

   return rc;
}

#else

//
//
CK_RV SC_GetSessionInfo( ST_SESSION_HANDLE   sSession,
                        CK_SESSION_INFO_PTR pInfo )
{
   GetSessionInfo_Args    args;
   HOST_SESSION_HANDLE  * node = NULL;
   CK_SESSION_INFO        info;
   CK_ULONG               req_len, repl_len;
   CK_RV                  rc;
   CK_SLOT_ID             slot_id;
   SESS_SET

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;


   if (!pInfo) {
      return CKR_FUNCTION_FAILED;
   }

   args.session_handle = HTOCL( SESSION );

   slot_id = SLOTID;

   req_len  = sizeof(args);
   repl_len = sizeof(info);

   rc = communicate( C_GETSESSIONINFO, slot_id,
                     &args,   req_len,
                     &info,  &repl_len,
                      NULL,   0,
                      NULL,   0 );

   if (rc == CKR_OK) {
      memcpy( pInfo, &info, sizeof(info) );

      // Normalize the session information for STDLL 
      pInfo->slotID = sSession.slotID;

      pInfo->state  = CTOHL( pInfo->state  );
      pInfo->flags  = CTOHL( pInfo->flags  );

      pInfo->ulDeviceError = CTOHL( pInfo->ulDeviceError );
   }
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d\n", "C_GetSessionInfo", rc, SESSION );
#endif

   return rc;
}

#endif

//
//
CK_RV SC_Login( ST_SESSION_HANDLE   sSession,
               CK_USER_TYPE        userType,
               CK_CHAR_PTR         pPin,
               CK_ULONG            ulPinLen )
{
   Login_Args            args;
   HOST_SESSION_HANDLE * node = NULL;
   CK_SLOT_ID            slot_id;
   CK_ULONG              req_len, repl_len;
   CK_RV                 rc;
   SESS_SET

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pPin || ulPinLen > MAX_PIN_LEN)
      return CKR_PIN_INCORRECT;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;



   slot_id = SLOTID;

   args.session_handle = HTOCL( SESSION );
   args.user_type      = HTOCL( userType     );
   args.pin_len        = HTOCL( ulPinLen     );

   memcpy( &args.pin, pPin, ulPinLen );

   req_len  = sizeof(args);
   repl_len = 0;

   rc = communicate( C_LOGIN, slot_id,
                     &args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x\n", "C_Login", rc );
#endif

   return rc;
}


//
//
CK_RV SC_Logout( ST_SESSION_HANDLE  sSession )
{
   Logout_Args              args;
   HOST_SESSION_HANDLE    * node = NULL;
   CK_SLOT_ID               slot_id;
   CK_ULONG                 req_len, repl_len;
   CK_RV                    rc;
   SESS_SET

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;



   slot_id = SLOTID;

   args.session_handle = HTOCL( SESSION );

   req_len = sizeof(args);
   repl_len = 0;

   rc = communicate( C_LOGOUT, slot_id,
                     &args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x\n", "C_Logout", rc );
#endif

   return rc;
}


//
//
CK_RV SC_CreateObject( ST_SESSION_HANDLE    sSession,
                      CK_ATTRIBUTE_PTR     pTemplate,
                      CK_ULONG             ulCount,
                      CK_OBJECT_HANDLE_PTR phObject )
{
   CreateObject_Args     * args = NULL;
   HOST_SESSION_HANDLE   * node = NULL;
   ATTRIBUTE             * attrib_block = NULL;
   CK_BYTE               * ptr = NULL;
   CK_ATTRIBUTE          * attr = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_ULONG                tmpl_len;
   CK_ULONG                i;
   CK_RV                   rc;

   SESS_SET

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  \n", ">>C_CreateObject" );
#endif

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;

   if ( !pTemplate ) {
      return CKR_TEMPLATE_INCOMPLETE; // a template is required
   }

   if ( ulCount  == 0){
      return CKR_TEMPLATE_INCOMPLETE; // this is the best of the choices
   }


   slot_id = SLOTID;


   // compute the total template size
   //
   tmpl_len = 0;
#if __64BIT__
   for (attr = pTemplate, i = 0; i < ulCount; i++, attr++)
      tmpl_len += sizeof(ATTRIBUTE) + get_attrib_len(attr); // attr->ulValueLen;
#else
   for (attr = pTemplate, i = 0; i < ulCount; i++, attr++)
      tmpl_len += sizeof(ATTRIBUTE) + attr->ulValueLen;
#endif

   args = (CreateObject_Args *)malloc(sizeof(CreateObject_Args) + tmpl_len);
   if (!args)
      return CKR_HOST_MEMORY;

   args->session_handle      = HTOCL( SESSION );
   args->attribute_count     = HTOCL( ulCount      );
   args->attribute_block_len = HTOCL( tmpl_len     );


   // set the attribute block pointer to point to the extra space we allocated
   //
   attrib_block = (ATTRIBUTE *)((CK_BYTE*)args + sizeof(CreateObject_Args));


   // build the new attribute block
   //
   attr = pTemplate;
   ptr  = (CK_BYTE *)attrib_block;

   for (i = 0; i < ulCount; i++, attr++) {
      ATTRIBUTE *p_attrib = (ATTRIBUTE *)ptr;
      unsigned char  *pd,*ps;
      unsigned long *pl;

      p_attrib->type         = HTOCL( attr->type       );
#if __64BIT__
      p_attrib->value_length = HTOCL(get_attrib_len(attr)); //attr->ulValueLen);
#else
      p_attrib->value_length = HTOCL( attr->ulValueLen );
#endif

#ifdef DEBUGON
   logit(LOG_DEBUG, "\t\t\t>>%-25s:  \n", "C_CreateObject -- as passed before endian adjust" );
   {
      CK_BYTE *p;
      p = (CK_BYTE *)attr->pValue;

      logit(LOG_DEBUG, "\t\t\t\t>>%3d:  Attribute type:  0x%08x\n", i, attr->type );
      logit(LOG_DEBUG, "\t\t\t\t>>Value Length:    %08d\n",   attr->ulValueLen );

      if (attr->ulValueLen != (CK_ULONG)(-1) && (p != NULL))
         logit(LOG_DEBUG, "\t\t\t\t>>First 4 bytes:   %02x %02x %02x %02x", p[0], p[1], p[2], p[3] );

      logit(LOG_DEBUG, "\n\n");
   }
#endif

      // WARNING:  on BIG-ENDIAN machines, it is important to ensure that
      // the value of the attribute has the appropriate endianness if it will
      // be used by the coprocessor.  For instance, CKA_VALUE for a data_object
      // is ignored.  But CKA_KEY_TYPE attribute is used by the coprocessor
      // so it must be in LITTLE-ENDIAN format before the call to CreateObject.
      //
#ifndef _BIG_ENDIAN
      memcpy( (ptr + sizeof(ATTRIBUTE)), attr->pValue, attr->ulValueLen );
#else
      // We need to swap the values.
      pd = (unsigned char *)(ptr + sizeof(ATTRIBUTE));

#if __64BIT__
      copy_attribute_value(attr->pValue,ptr + sizeof(ATTRIBUTE), attr);
#else
      memcpy( (ptr + sizeof(ATTRIBUTE)), attr->pValue, attr->ulValueLen );
#endif

#if __64BIT__
      if ( attr->ulValueLen == 8 ) {
#else
      if ( attr->ulValueLen == 4 ) {
#endif

#ifdef PKCS64
         ModifyAttribute(attr->type,(CK_ULONG_PTR_32)pd);
#else
         ModifyAttribute(attr->type,(CK_ULONG_PTR)pd);
#endif

      }

#endif

      // This  is  an  error  since we  have performed byte swapping on
      // the p_attrib->value_length.   This  will  core dump.
      //ptr += sizeof(ATTRIBUTE) + p_attrib->value_length;
#if __64BIT__
      ptr += sizeof(ATTRIBUTE) + get_attrib_len(attr); //attr->ulValueLen;
#else
      ptr += sizeof(ATTRIBUTE) + attr->ulValueLen;
#endif
   }

   req_len  = sizeof(CreateObject_Args) + tmpl_len;
   repl_len = sizeof(CK_OBJECT_HANDLE);


#if __64BIT__
{
   CK_OBJECT_HANDLE_32  thandle;
   rc = communicate( C_CREATEOBJECT, slot_id,
                      args,      req_len,
                      &thandle, &repl_len,
                      NULL,      0,
                      NULL,      0 );
   *phObject = thandle;
}
#else
   rc = communicate( C_CREATEOBJECT, slot_id,
                      args,      req_len,
                      phObject, &repl_len,
                      NULL,      0,
                      NULL,      0 );
#endif


   free( args );
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x\n", "C_CreateObject", rc );

   {
      int i;
      for (i=0; i < ulCount; i++) {
         if (pTemplate[i].type == CKA_CLASS)
           logit(LOG_DEBUG, "%28s:  0x%02X\n", "Object Type", *(CK_ULONG *)pTemplate[i].pValue );
      }
   }
   if (rc == CKR_OK)
     logit(LOG_DEBUG, "%28s:  %d\n", "Handle", *phObject );

#endif

   return rc;
}


//
//
CK_RV  SC_CopyObject( ST_SESSION_HANDLE    sSession,
                     CK_OBJECT_HANDLE     hObject,
                     CK_ATTRIBUTE_PTR     pTemplate,
                     CK_ULONG             ulCount,
                     CK_OBJECT_HANDLE_PTR phNewObject )
{
   CopyObject_Args      * args = NULL;
   HOST_SESSION_HANDLE  * node = NULL;
   ATTRIBUTE            * attrib_block = NULL;
   CK_BYTE              * ptr = NULL;
   CK_SLOT_ID             slot_id;
   CK_ATTRIBUTE_PTR       attr;
   CK_ULONG               req_len, repl_len;
   CK_ULONG               tmpl_len;
   CK_ULONG               i;
   CK_RV                  rc;
   SESS_SET

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;


   slot_id = SLOTID;


   // compute the total template size
   //
   tmpl_len = 0;
#if __64BIT__
   for (attr = pTemplate, i = 0; i < ulCount; i++, attr++)
      tmpl_len += sizeof(ATTRIBUTE) + get_attrib_len(attr); // attr->ulValueLen;
#else
   for (attr = pTemplate, i = 0; i < ulCount; i++, attr++)
      tmpl_len += sizeof(ATTRIBUTE) + attr->ulValueLen;
#endif

   args = (CopyObject_Args *)malloc(sizeof(CopyObject_Args) + tmpl_len);
   if (!args)
      return CKR_HOST_MEMORY;

   args->session_handle      = HTOCL( SESSION );
   args->object_handle       = ( hObject      );  // Object handles have meaning at the
                                                  // adapter only and are NOT reversed
   args->attribute_count     = HTOCL( ulCount      );
   args->attribute_block_len = HTOCL( tmpl_len     );

   // set the attribute block pointer to point to the extra space we allocated
   //
   attrib_block = (ATTRIBUTE *)((CK_BYTE*)args + sizeof(CopyObject_Args));


   // build the new attribute block
   //
   attr = pTemplate;
   ptr  = (CK_BYTE *)attrib_block;

   for (i = 0; i < ulCount; i++, attr++) {
      ATTRIBUTE *p_attrib = (ATTRIBUTE *)ptr;
      unsigned char  *pd,*ps;
      unsigned long *pl;


      p_attrib->type         = HTOCL( attr->type       );
#if __64BIT__
      p_attrib->value_length = HTOCL(get_attrib_len(attr)); //attr->ulValueLen);
#else
      p_attrib->value_length = HTOCL( attr->ulValueLen );
#endif

      // WARNING:  on BIG-ENDIAN machines, it is important to ensure that
      // the value of the attribute has the appropriate endianness if it will
      // be used by the coprocessor.  For instance, CKA_VALUE for a data_object
      // is ignored.  But CKA_KEY_TYPE attribute is used by the coprocessor
      // so it must be in LITTLE-ENDIAN format before the call to CreateObject.
      //
#ifndef _BIG_ENDIAN
#if __64BIT__
      memcpy( (ptr + sizeof(ATTRIBUTE)), attr->pValue, get_attrib_len(attr)); //attr->ulValueLen );
#else
      memcpy( (ptr + sizeof(ATTRIBUTE)), attr->pValue, attr->ulValueLen );
#endif
#else
      // We need to swap the values.
      pd = (unsigned char *)(ptr + sizeof(ATTRIBUTE));
      ps = (unsigned char *)(attr->pValue);

#if __64BIT__
      copy_attribute_value(ps,pd,attr);
#else
      memcpy(pd, ps, attr->ulValueLen);
#endif

#if __64BIT__
      if ( attr->ulValueLen == 8 ) {
#else
      if ( attr->ulValueLen == 4 ) {
#endif

#ifdef PKCS64
         ModifyAttribute(attr->type,(CK_ULONG_PTR_32)pd);
#else
         ModifyAttribute(attr->type,(CK_ULONG_PTR)pd);
#endif

      }

#endif

      ptr += sizeof(ATTRIBUTE) + get_attrib_len(attr); //attr->ulValueLen; // p_attrib->value_length;
   }


   req_len  = sizeof(CopyObject_Args) + tmpl_len;
   repl_len = sizeof(CK_OBJECT_HANDLE);

#if __64BIT__
{
   CK_OBJECT_HANDLE_32   nObject;
   
   rc = communicate( C_COPYOBJECT, slot_id,
                      args,         req_len,
                      &nObject, &repl_len,
                      NULL,         0,
                      NULL,         0 );
   *phNewObject = nObject;
}
#else
   rc = communicate( C_COPYOBJECT, slot_id,
                      args,         req_len,
                      phNewObject, &repl_len,
                      NULL,         0,
                      NULL,         0 );
#endif

   free( args );
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, old handle = %d, new handle = %d\n", "C_CopyObject", rc, hObject, *phNewObject );
#endif


   return rc;
}


//
//
CK_RV SC_DestroyObject( ST_SESSION_HANDLE  sSession,
                       CK_OBJECT_HANDLE   hObject )
{
   DestroyObject_Args      args;
   HOST_SESSION_HANDLE   * node = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;



   slot_id = SLOTID;

   args.session_handle = HTOCL( SESSION );
   args.object_handle  = ( hObject      );

   req_len  = sizeof(args);
   repl_len = 0;

   rc = communicate( C_DESTROYOBJECT, slot_id,
                     &args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, handle = %d\n", "C_DestroyObject", rc, hObject );
#endif

   return rc;
}


//
//
CK_RV SC_GetObjectSize( ST_SESSION_HANDLE  sSession,
                       CK_OBJECT_HANDLE   hObject,
                       CK_ULONG_PTR       pulSize )
{
   GetObjectSize_Args      args;
   HOST_SESSION_HANDLE   * node = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_ULONG_32                size;
   CK_RV                   rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;

   if (!pulSize) {
      return CKR_ARGUMENTS_BAD;
   }


   slot_id = SLOTID;

   args.session_handle = HTOCL( SESSION );
   args.object_handle  = ( hObject      );

   req_len  = sizeof(args);
   repl_len = sizeof(size);

   rc = communicate( C_GETOBJECTSIZE, slot_id,
                     &args,  req_len,
                     &size, &repl_len,
                      NULL,  0,
                      NULL,  0 );

   if (rc == CKR_OK)
      *pulSize = CTOHL( size );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, handle = %d\n", "C_GetObjectSize", rc, hObject );
#endif

   return rc;
}


// This routine is just temporary.  It will be redesigned after Sept 15 release
//

#ifdef PKCS64

CK_RV SC_GetAttributeValue( ST_SESSION_HANDLE  sSession,
                           CK_OBJECT_HANDLE   hObject,
                           CK_ATTRIBUTE_PTR   pTemplate,
                           CK_ULONG           ulCount )
{
   GetAttributeValue_Args  * args = NULL;
   HOST_SESSION_HANDLE     * node = NULL;
   CK_BYTE                 * buffer = NULL;
   CK_SLOT_ID                slot_id;
   CK_ULONG                  req_len, repl_len;
#if __64BIT__
   CK_ULONG_32                  size; // SAB FIXME   64Bit
#else
   CK_ULONG                  size; 
#endif
   CK_ULONG                  i;
   CK_RV                     rc;
   SESS_SET

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;

   if ( !pTemplate ){
      return CKR_ARGUMENTS_BAD;
   }

   if ( ulCount == 0 ){
      return CKR_ARGUMENTS_BAD;
   }


   slot_id = SLOTID;

   // request data is GetAttributeValue_Args + array of CK_ATTRIBUTE_TYPE
   //
   req_len   = sizeof(GetAttributeValue_Args) + (ulCount * sizeof(CK_ATTRIBUTE_TYPE_32));

   args = (GetAttributeValue_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;
   else {
      CK_ATTRIBUTE_PTR     attr = NULL;
      CK_ATTRIBUTE_TYPE_32  * attrib_block = NULL;

      args->session_handle      = HTOCL( SESSION );
      args->object_handle       = ( hObject      );
      args->attribute_count     = HTOCL( ulCount      );
      args->size_only           = TRUE;
      args->attribute_block_len = HTOCL( ulCount * sizeof(CK_ATTRIBUTE_TYPE_32) );

      // set the attribute block pointer to point to the extra space we allocated
      //
      attrib_block = (CK_ATTRIBUTE_TYPE_32 *)((CK_BYTE*)args + sizeof(GetAttributeValue_Args));

      // build the new attribute block
      //
      attr = pTemplate;
      for (i = 0; i < ulCount; i++, attr++) {
         CK_ULONG_32 tmp = HTOCL( attr->type );

         // We are only dealing with the ATTRIBUTE types
         memcpy( (CK_BYTE *)attrib_block, &tmp, sizeof(CK_ATTRIBUTE_TYPE_32) );
         attrib_block++;
      }
   }

   repl_len = sizeof(size);
   rc = communicate( C_GETATTRIBUTEVALUE, slot_id,
                      args,  req_len,
                     &size, &repl_len,
                      NULL,  0,
                      NULL,  0 );

#ifdef _BIG_ENDIAN
   // XXX do we really need to reverse this size value... Since we are
   // I think so, since this is an unsigned long value returned from the Leeds
   // adapter and therefore it is in Little_endian format
   size = CTOHL(size);
#endif

   // the coprocessor should never return CKR_BUFFER_TOO_SMALL
   //
   if (rc != CKR_OK && rc != CKR_ATTRIBUTE_SENSITIVE && rc != CKR_ATTRIBUTE_TYPE_INVALID) {
      free( args );
      return rc;
   }

   // now, allocate the proper-sized reply block and issue the request again
   //
   buffer = (CK_BYTE *)malloc(size);
   if (!buffer) {
      free( args );
      return CKR_HOST_MEMORY;
   }

   args->size_only = FALSE;
   repl_len = size;

   rc = communicate( C_GETATTRIBUTEVALUE, slot_id,
                      args,    req_len,
                      buffer, &repl_len,
                      NULL,    0,
                      NULL,    0 );


   // Cryptoki allows for C_GetAttributeValue to return CKR_BUFFER_TOO_SMALL but the
   // coprocessor should never return that
   //
   if (rc == CKR_OK ||
       rc == CKR_ATTRIBUTE_SENSITIVE ||
       rc == CKR_ATTRIBUTE_TYPE_INVALID)
   {
      CK_ATTRIBUTE_PTR   ck_attr;
      CK_BYTE          * ptr = (CK_BYTE *)buffer;

      // walk through the reply and update the template.  it's safe to assume the
      // elements in the template and the reply have the same ordering.
      //
      ck_attr = pTemplate;

      // SAB XXX  the below handling of attributes for 32bit is probably 
      // wrong.... We really need to only swap the attributes which are of
      // type CK_ULONG...
#if __64BIT__
      for (i=0;i< ulCount; i++){
         ATTRIBUTE *attr = (ATTRIBUTE *)ptr; // Attribute from the card..
         CK_BYTE   *val  = ptr + sizeof(ATTRIBUTE); // actual value of the attribute
         CK_ULONG_32  val_len = CTOHL(attr->value_length);

         // Each attribute needs to bhe handled according
         // to the type...  

         if (val_len == (CK_ULONG_32)(-1)){
             ck_attr->ulValueLen = val_len;
         } else if ( ck_attr->pValue == NULL) {
            ck_attr->ulValueLen = val_len;
         } else if (ck_attr->ulValueLen < val_len){
            ck_attr->ulValueLen = (CK_ULONG_32)(-1);
            if (rc == CKR_OK)
               rc = CKR_BUFFER_TOO_SMALL;
         } else {
            switch(ck_attr->type){
               case CKA_CLASS:
               case CKA_KEY_TYPE:
               case CKA_MODULUS_BITS:
               case CKA_VALUE_BITS:
               case CKA_VALUE_LEN:
               case CKA_CERTIFICATE_TYPE:  // SAB XXX 64bit
                  {
                  CK_ULONG *tval = (CK_ULONG *)(ck_attr->pValue);

                  ck_attr->ulValueLen = sizeof(CK_ULONG);
                  if ( ck_attr->pValue) {
                     *tval =  HTOCL((CK_ULONG_32)*val);
                  }

                  }
                  break;
               default:
                  ck_attr->ulValueLen = val_len;
                  if ( ck_attr->pValue){
                     memcpy(ck_attr->pValue,val,val_len);
                  }
                  break;
            }
         }

         ck_attr++; // Next attribute in the template from the caler

         if (val_len == (CK_ULONG_32)(-1))
            ptr += sizeof(ATTRIBUTE);
         else
            ptr += sizeof(ATTRIBUTE) + val_len;

      }
#else
      for (i=0; i < ulCount; i++) {
         ATTRIBUTE * attr    = (ATTRIBUTE *)ptr;
         CK_BYTE   * val     = ptr + sizeof(ATTRIBUTE);
         CK_ULONG_32    val_len = CTOHL( attr->value_length );

         if (val_len == (CK_ULONG_32)(-1)) {
            ck_attr->ulValueLen = val_len;
         }
         else if (ck_attr->pValue == NULL) {
            ck_attr->ulValueLen = val_len;
         }
         else if (ck_attr->ulValueLen < val_len) {
            ck_attr->ulValueLen = (CK_ULONG_32)(-1);
            if (rc == CKR_OK)
               rc = CKR_BUFFER_TOO_SMALL;
         }
         else {
            ck_attr->ulValueLen = val_len;
            if ( ck_attr->pValue ){
               memcpy( ck_attr->pValue, val, val_len );
#ifdef _BIG_ENDIAN
               {
                  CK_ULONG_PTR_32  pd;
                  
                  pd = (CK_ULONG_PTR_32)ck_attr->pValue;
                  if ( val_len == sizeof(CK_ULONG_32) ) {
                     ModifyAttribute(ck_attr->type,pd);
                  }
               }
#endif
            } // check for a valid pointer in the template.
         }

         ck_attr++;

         if (val_len == (CK_ULONG_32)(-1))
            ptr += sizeof(ATTRIBUTE);
         else
            ptr += sizeof(ATTRIBUTE) + val_len;
      }
#endif
   }

   if (args)
      free( args );

   if (buffer)
      free( buffer );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, handle = %d\n", "C_GetAttributeValue", rc, hObject );

   {
      CK_ATTRIBUTE  *attr = NULL;
      CK_BYTE       *ptr  = NULL;

      attr = pTemplate;
      for (i=0; i < ulCount; i++, attr++) {
         ptr = (CK_BYTE *)attr->pValue;

         logit(LOG_DEBUG, "   %3d:  Attribute type:  0x%08x\n", i, attr->type );
         logit(LOG_DEBUG, "         Value Length:    %08d\n",   attr->ulValueLen );

         if (attr->ulValueLen != (CK_ULONG)(-1) && (ptr != NULL))
            logit(LOG_DEBUG, "         First 4 bytes:   %02x %02x %02x %02x", ptr[0], ptr[1], ptr[2], ptr[3] );

         logit(LOG_DEBUG, "\n\n");
      }
   }

#endif

   return rc;

}

#else

CK_RV SC_GetAttributeValue( ST_SESSION_HANDLE  sSession,
                           CK_OBJECT_HANDLE   hObject,
                           CK_ATTRIBUTE_PTR   pTemplate,
                           CK_ULONG           ulCount )
{
   GetAttributeValue_Args  * args = NULL;
   HOST_SESSION_HANDLE     * node = NULL;
   CK_BYTE                 * buffer = NULL;
   CK_SLOT_ID                slot_id;
   CK_ULONG                  req_len, repl_len;
   CK_ULONG_32                  size; // SAB FIXME  64Bit
   CK_ULONG                  i;
   CK_RV                     rc;
   SESS_SET

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;

   if ( !pTemplate ){
      return CKR_ARGUMENTS_BAD;
   }

   if ( ulCount == 0 ){
      return CKR_ARGUMENTS_BAD;
   }


   slot_id = SLOTID;

   // request data is GetAttributeValue_Args + array of CK_ATTRIBUTE_TYPE
   //
   req_len   = sizeof(GetAttributeValue_Args) + (ulCount * sizeof(CK_ATTRIBUTE_TYPE));

   args = (GetAttributeValue_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;
   else {
      CK_ATTRIBUTE_PTR     attr = NULL;
      CK_ATTRIBUTE_TYPE  * attrib_block = NULL;

      args->session_handle      = HTOCL( SESSION );
      args->object_handle       = ( hObject      );
      args->attribute_count     = HTOCL( ulCount      );
      args->size_only           = TRUE;
      args->attribute_block_len = HTOCL( ulCount * sizeof(CK_ATTRIBUTE_TYPE) );

      // set the attribute block pointer to point to the extra space we allocated
      //
      attrib_block = (CK_ATTRIBUTE_TYPE *)((CK_BYTE*)args + sizeof(GetAttributeValue_Args));

      // build the new attribute block
      //
      attr = pTemplate;
      for (i = 0; i < ulCount; i++, attr++) {
         CK_ULONG tmp = HTOCL( attr->type );

         // We are only dealing with the ATTRIBUTE types
         memcpy( (CK_BYTE *)attrib_block, &tmp, sizeof(CK_ATTRIBUTE_TYPE) );
         attrib_block++;
      }
   }

   repl_len = sizeof(size);
   rc = communicate( C_GETATTRIBUTEVALUE, slot_id,
                      args,  req_len,
                     &size, &repl_len,
                      NULL,  0,
                      NULL,  0 );

#ifdef _BIG_ENDIAN
   // XXX do we really need to reverse this size value... Since we are
   // I think so, since this is an unsigned long value returned from the Leeds
   // adapter and therefore it is in Little_endian format
   size = CTOHL(size);
#endif

   // the coprocessor should never return CKR_BUFFER_TOO_SMALL
   //
   if (rc != CKR_OK && rc != CKR_ATTRIBUTE_SENSITIVE && rc != CKR_ATTRIBUTE_TYPE_INVALID) {
      free( args );
      return rc;
   }

   // now, allocate the proper-sized reply block and issue the request again
   //
   buffer = (CK_BYTE *)malloc(size);
   if (!buffer) {
      free( args );
      return CKR_HOST_MEMORY;
   }

   args->size_only = FALSE;
   repl_len = size;

   rc = communicate( C_GETATTRIBUTEVALUE, slot_id,
                      args,    req_len,
                      buffer, &repl_len,
                      NULL,    0,
                      NULL,    0 );


   // Cryptoki allows for C_GetAttributeValue to return CKR_BUFFER_TOO_SMALL but the
   // coprocessor should never return that
   //
   if (rc == CKR_OK ||
       rc == CKR_ATTRIBUTE_SENSITIVE ||
       rc == CKR_ATTRIBUTE_TYPE_INVALID)
   {
      CK_ATTRIBUTE_PTR   ck_attr;
      CK_BYTE          * ptr = (CK_BYTE *)buffer;

      // walk through the reply and update the template.  it's safe to assume the
      // elements in the template and the reply have the same ordering.
      //
      ck_attr = pTemplate;

      for (i=0; i < ulCount; i++) {
         ATTRIBUTE * attr    = (ATTRIBUTE *)ptr;
         CK_BYTE   * val     = ptr + sizeof(ATTRIBUTE);
         CK_ULONG    val_len = CTOHL( attr->value_length );

         if (val_len == (CK_ULONG)(-1)) {
            ck_attr->ulValueLen = val_len;
         }
         else if (ck_attr->pValue == NULL) {
            ck_attr->ulValueLen = val_len;
         }
         else if (ck_attr->ulValueLen < val_len) {
            ck_attr->ulValueLen = (CK_ULONG)(-1);
            if (rc == CKR_OK)
               rc = CKR_BUFFER_TOO_SMALL;
         }
         else {
            ck_attr->ulValueLen = val_len;
            if ( ck_attr->pValue ){
               memcpy( ck_attr->pValue, val, val_len );
#ifdef _BIG_ENDIAN
               {
                  CK_ULONG_PTR  pd;
                  
                  pd = (CK_ULONG_PTR)ck_attr->pValue;
                  if ( val_len == sizeof(CK_ULONG) ) {
                     ModifyAttribute(ck_attr->type,pd);
                  }
               }
#endif
            } // check for a valid pointer in the template.
         }

         ck_attr++;

         if (val_len == (CK_ULONG)(-1))
            ptr += sizeof(ATTRIBUTE);
         else
            ptr += sizeof(ATTRIBUTE) + val_len;
      }
   }

   if (args)
      free( args );

   if (buffer)
      free( buffer );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, handle = %d\n", "C_GetAttributeValue", rc, hObject );

   {
      CK_ATTRIBUTE  *attr = NULL;
      CK_BYTE       *ptr  = NULL;

      attr = pTemplate;
      for (i=0; i < ulCount; i++, attr++) {
         ptr = (CK_BYTE *)attr->pValue;

         logit(LOG_DEBUG, "   %3d:  Attribute type:  0x%08x\n", i, attr->type );
         logit(LOG_DEBUG, "         Value Length:    %08d\n",   attr->ulValueLen );

         if (attr->ulValueLen != (CK_ULONG)(-1) && (ptr != NULL))
            logit(LOG_DEBUG, "         First 4 bytes:   %02x %02x %02x %02x", ptr[0], ptr[1], ptr[2], ptr[3] );

         logit(LOG_DEBUG, "\n\n");
      }
   }

#endif

   return rc;

}

#endif

//
//
CK_RV  SC_SetAttributeValue( ST_SESSION_HANDLE    sSession,
                            CK_OBJECT_HANDLE     hObject,
                            CK_ATTRIBUTE_PTR     pTemplate,
                            CK_ULONG             ulCount )
{
   SetAttributeValue_Args   * args = NULL;
   HOST_SESSION_HANDLE      * node = NULL;
   ATTRIBUTE                * attrib_block = NULL;
   CK_BYTE                  * ptr = NULL;
   CK_SLOT_ID                 slot_id;
   CK_ATTRIBUTE_PTR           attr;
   CK_ULONG                   req_len, repl_len;
   CK_ULONG                   tmpl_len;
   CK_ULONG                   i;
   CK_RV                      rc;

   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;


   if ( !pTemplate ){
      return CKR_ARGUMENTS_BAD;
   }

   if ( ulCount == 0 ){
      return CKR_ARGUMENTS_BAD;
   }


   slot_id = SLOTID;

   // compute the total template size
   //
   tmpl_len = 0;
#if __64BIT__
   for (attr = pTemplate, i = 0; i < ulCount; i++, attr++)
      tmpl_len += sizeof(ATTRIBUTE) + get_attrib_len(attr); // attr->ulValueLen;
#else
   for (attr = pTemplate, i = 0; i < ulCount; i++, attr++)
      tmpl_len += sizeof(ATTRIBUTE) + attr->ulValueLen;
#endif


   args = (SetAttributeValue_Args *)malloc(sizeof(SetAttributeValue_Args) + tmpl_len);
   if (!args)
      return CKR_HOST_MEMORY;

   args->session_handle      = HTOCL( SESSION );
   args->object_handle       = ( hObject      );
   args->attribute_count     = HTOCL( ulCount      );
   args->attribute_block_len = HTOCL( tmpl_len     );


   // set the attribute block pointer to point to the extra space we allocated
   //
   attrib_block = (ATTRIBUTE *)((CK_BYTE*)args + sizeof(SetAttributeValue_Args));


   // build the new attribute block
   //
   attr = pTemplate;
   ptr  = (CK_BYTE *)attrib_block;

   for (i = 0; i < ulCount; i++, attr++) {
      ATTRIBUTE *p_attrib = (ATTRIBUTE *)ptr;

      p_attrib->type         = HTOCL( attr->type       );
#if __64BIT__
      p_attrib->value_length = HTOCL(get_attrib_len(attr)); //attr->ulValueLen);
#else
      p_attrib->value_length = HTOCL( attr->ulValueLen );
#endif

      // WARNING:  on BIG-ENDIAN machines, it is important to ensure that
      // the value of the attribute has the appropriate endianness if it will
      // be used by the coprocessor.  For instance, CKA_VALUE for a data_object
      // is ignored.  But CKA_KEY_TYPE attribute is used by the coprocessor
      // so it must be in LITTLE-ENDIAN format before the call to CreateObject.
      //
#ifndef _BIG_ENDIAN
      memcpy( (ptr + sizeof(ATTRIBUTE)), attr->pValue, attr->ulValueLen );
#else
{
      unsigned char  *pd,*ps;
      unsigned long *pl;

      // We need to swap the values.
      pd = (unsigned char *)(ptr + sizeof(ATTRIBUTE));
      ps = (unsigned char *)(attr->pValue);


#if __64BIT__
      copy_attribute_value(ps,pd,attr);
#else
      memcpy(pd, ps, attr->ulValueLen);
#endif

#if __64BIT__
      if ( attr->ulValueLen == 8 ) {
#else
      if ( attr->ulValueLen == 4 ) {
#endif

         pl = (unsigned long *)attr->pValue;
         pl = (unsigned long *)ps;

#ifdef PKCS64
         ModifyAttribute(attr->type,(CK_ULONG_PTR_32)pd);
#else
         ModifyAttribute(attr->type,(CK_ULONG_PTR)pd);
#endif

      }

}
#endif


      //ptr += sizeof(ATTRIBUTE) + p_attrib->value_length;  p_attrib is swapped
#if __64BIT__
      ptr += sizeof(ATTRIBUTE) + get_attrib_len(attr); //attr->ulValueLen;
#else
      ptr += sizeof(ATTRIBUTE) + attr->ulValueLen;
#endif
   }


   req_len  = sizeof(SetAttributeValue_Args) + tmpl_len;
   repl_len = 0;

   rc = communicate( C_SETATTRIBUTEVALUE, slot_id,
                      args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

   free( args );
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, handle = %d\n", "C_SetAttributeValue", rc, hObject );

   attr = pTemplate;
   for (i=0; i < ulCount; i++, attr++) {
      ptr = (CK_BYTE *)attr->pValue;

      logit(LOG_DEBUG, "   %3d:  Attribute type:  0x%08x\n", i, attr->type );
      logit(LOG_DEBUG, "         Value Length:    %08d\n",   attr->ulValueLen );

      if (attr->ulValueLen != (CK_ULONG)(-1) && (ptr != NULL))
         logit(LOG_DEBUG, "         First 4 bytes:   %02x %02x %02x %02x", ptr[0], ptr[1], ptr[2], ptr[3] );

      logit(LOG_DEBUG, "\n\n");
   }
#endif


   return rc;
}


//
//
CK_RV SC_FindObjectsInit( ST_SESSION_HANDLE   sSession,
                         CK_ATTRIBUTE_PTR    pTemplate,
                         CK_ULONG            ulCount )
{
   FindObjectsInit_Args   * args = NULL;

   HOST_SESSION_HANDLE    * node = NULL;
   ATTRIBUTE              * attrib_block = NULL;
   CK_BYTE                * ptr = NULL;
   CK_SLOT_ID               slot_id;
   CK_ATTRIBUTE_PTR         attr;
   CK_ULONG                 req_len, repl_len;
   CK_ULONG                 tmpl_len;
   CK_ULONG                 i;
   CK_RV                    rc;
   SESS_SET

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;



   slot_id = SLOTID;


   // compute the total template size
   //
   tmpl_len = 0;
#if __64BIT__
   for (attr = pTemplate, i = 0; i < ulCount; i++, attr++)
      tmpl_len += sizeof(ATTRIBUTE) + get_attrib_len(attr); // attr->ulValueLen;
#else
   for (attr = pTemplate, i = 0; i < ulCount; i++, attr++)
      tmpl_len += sizeof(ATTRIBUTE) + attr->ulValueLen;
#endif

   args = (FindObjectsInit_Args *)malloc(sizeof(FindObjectsInit_Args) + tmpl_len);
   if (!args)
      return CKR_HOST_MEMORY;

   args->session_handle      = HTOCL( SESSION );
   args->attribute_count     = HTOCL( ulCount      );
   args->attribute_block_len = HTOCL( tmpl_len     );


   // set the attribute block pointer to point to the extra space we allocated
   //
   attrib_block = (ATTRIBUTE *)((CK_BYTE*)args + sizeof(FindObjectsInit_Args));


   // build the new attribute block
   //
   attr = pTemplate;
   ptr  = (CK_BYTE *)attrib_block;

   for (i = 0; i < ulCount; i++, attr++) {
      ATTRIBUTE *p_attrib = (ATTRIBUTE *)ptr;

      p_attrib->type         = HTOCL( attr->type       );
#if __64BIT__
      p_attrib->value_length = HTOCL(get_attrib_len(attr)); // attr->ulValueLen );
#else
      p_attrib->value_length = HTOCL( attr->ulValueLen );
#endif

      // WARNING:  on BIG-ENDIAN machines, it is important to ensure that
      // the value of the attribute has the appropriate endianness if it will
      // be used by the coprocessor.  For instance, CKA_VALUE for a data_object
      // is ignored.  But CKA_KEY_TYPE attribute is used by the coprocessor
      // so it must be in LITTLE-ENDIAN format before the call to CreateObject.
      //
#ifndef _BIG_ENDIAN
      memcpy( (ptr + sizeof(ATTRIBUTE)), attr->pValue, attr->ulValueLen );
#else
{
      unsigned char  *pd,*ps;
      unsigned long *pl;

      // We need to swap the values.
      pd = (unsigned char *)(ptr + sizeof(ATTRIBUTE));
      ps = (unsigned char *)(attr->pValue);

#if __64BIT__
      copy_attribute_value(ps,pd,attr);
#else
      memcpy(pd, ps, attr->ulValueLen);
#endif

#if __64BIT__
      if ( attr->ulValueLen == 8 ) {
#else
      if ( attr->ulValueLen == 4 ) {
#endif
         pl = (unsigned long *)attr->pValue;
         pl = (unsigned long *)ps;

#ifdef PKCS64
         ModifyAttribute(attr->type,(CK_ULONG_PTR_32)pd);
#else
         ModifyAttribute(attr->type,(CK_ULONG_PTR)pd);
#endif

      }

}
#endif


#if __64BIT__
      ptr += sizeof(ATTRIBUTE) + get_attrib_len(attr);
#else
      ptr += sizeof(ATTRIBUTE) + attr->ulValueLen; // Swapped p_attrib->value_length;
#endif
   }


   req_len  = sizeof(FindObjectsInit_Args) + tmpl_len;
   repl_len = 0;

   rc = communicate( C_FINDOBJECTSINIT, slot_id,
                      args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );


   free( args );
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x\n", "C_FindObjectsInit", rc );

   attr = pTemplate;
   for (i=0; i < ulCount; i++, attr++) {
      ptr = (CK_BYTE *)attr->pValue;

      logit(LOG_DEBUG, "   %3d:  Attribute type:  0x%08x\n", i, attr->type );
      logit(LOG_DEBUG, "         Value Length:    %08d\n",   attr->ulValueLen );

      if (attr->ulValueLen != (CK_ULONG)(-1) && (ptr != NULL))
         logit(LOG_DEBUG, "         First 4 bytes:   %02x %02x %02x %02x", ptr[0], ptr[1], ptr[2], ptr[3] );

      logit(LOG_DEBUG, "\n\n");
   }
#endif

   return rc;
}


#ifdef PKCS64

//
//
CK_RV SC_FindObjects( ST_SESSION_HANDLE     sSession,
                     CK_OBJECT_HANDLE_PTR  phObject,
                     CK_ULONG              ulMaxObjectCount,
                     CK_ULONG_PTR          pulObjectCount )
{
   FindObjects_Args        args;

   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * reply = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_ULONG                i;
   CK_RV                   rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;

   if (!phObject || !pulObjectCount)
      return CKR_ARGUMENTS_BAD;



   slot_id = SLOTID;

   args.session_handle = HTOCL( SESSION     );
   args.max_count      = HTOCL( ulMaxObjectCount );

   req_len  = sizeof(args);
   repl_len = sizeof(CK_ULONG_32) + 
                     (ulMaxObjectCount * sizeof(CK_OBJECT_HANDLE_32));

   reply = (CK_BYTE *)malloc(repl_len);
   if (!reply)
      return CKR_HOST_MEMORY;

   rc = communicate( C_FINDOBJECTS, slot_id,
                     &args,  req_len,
                     reply, &repl_len,
                     NULL,   0,
                     NULL,   0 );

   if (rc == CKR_OK) {
#if __64BIT__
      *pulObjectCount = *(CK_ULONG_32*)reply;
#else
      memcpy( pulObjectCount, reply, sizeof(CK_ULONG) );
#endif

      *pulObjectCount = CTOHL( *pulObjectCount ); // Failure to swap causes real problems


#ifdef __64BIT__
      { CK_OBJECT_HANDLE_32 *hp;

       hp = (CK_OBJECT_HANDLE_32 *)( (char *)reply + sizeof (CK_ULONG_32));

       for (i=0; i < *pulObjectCount; i++)
         phObject[i] = ( hp[i] );

      } 

#else
      memcpy( phObject, reply + sizeof(CK_ULONG_32), 
                        *pulObjectCount * sizeof(CK_OBJECT_HANDLE_32) );

      // XXX WJH - Hmmm ....

      for (i=0; i < *pulObjectCount; i++)
         phObject[i] = ( phObject[i] );
#endif
   }

   free( reply );
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, returned %d objects\n", "C_FindObjects", rc, *pulObjectCount );
#endif

   return rc;
}

#else

//
//
CK_RV SC_FindObjects( ST_SESSION_HANDLE     sSession,
                     CK_OBJECT_HANDLE_PTR  phObject,
                     CK_ULONG              ulMaxObjectCount,
                     CK_ULONG_PTR          pulObjectCount )
{
   FindObjects_Args        args;

   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * reply = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_ULONG                i;
   CK_RV                   rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;

   if (!phObject || !pulObjectCount)
      return CKR_ARGUMENTS_BAD;



   slot_id = SLOTID;

   args.session_handle = HTOCL( SESSION     );
   args.max_count      = HTOCL( ulMaxObjectCount );

   req_len  = sizeof(args);
   repl_len = sizeof(CK_ULONG) + (ulMaxObjectCount * sizeof(CK_OBJECT_HANDLE));

   reply = (CK_BYTE *)malloc(repl_len);
   if (!reply)
      return CKR_HOST_MEMORY;

   rc = communicate( C_FINDOBJECTS, slot_id,
                     &args,  req_len,
                     reply, &repl_len,
                     NULL,   0,
                     NULL,   0 );

   if (rc == CKR_OK) {
      memcpy( pulObjectCount, reply, sizeof(CK_ULONG) );

      *pulObjectCount = CTOHL( *pulObjectCount ); // Failure to swap causes real problems

      memcpy( phObject, reply + sizeof(CK_ULONG), *pulObjectCount * sizeof(CK_OBJECT_HANDLE) );


      for (i=0; i < *pulObjectCount; i++)
         phObject[i] = ( phObject[i] );
   }

   free( reply );
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, returned %d objects\n", "C_FindObjects", rc, *pulObjectCount );
#endif

   return rc;
}

#endif

//
//
CK_RV SC_FindObjectsFinal( ST_SESSION_HANDLE  sSession )
{
   FindObjectsFinal_Args   args;

   HOST_SESSION_HANDLE   * node = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;



   slot_id = SLOTID;

   args.session_handle = HTOCL( SESSION );

   req_len  = sizeof(args);
   repl_len = 0;

   rc = communicate( C_FINDOBJECTSFINAL, slot_id,
                     &args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x\n", "C_FindObjectsFinal", rc );
#endif

   return rc;
}



//
//
CK_RV SC_SeedRandom( ST_SESSION_HANDLE  sSession,
                    CK_BYTE_PTR        pSeed,
                    CK_ULONG           ulSeedLen )
{
   SESS_SET

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   return CKR_OK;
}


//
//
CK_RV SC_GenerateRandom( ST_SESSION_HANDLE  sSession,
                        CK_BYTE_PTR        pRandomData,
                        CK_ULONG           ulRandomLen )
{
   GenerateRandom_Args     args;
   HOST_SESSION_HANDLE   * node = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len,len;
   CK_ULONG                total = 0;
   CK_ULONG                amt;
   CK_ULONG                rc = CKR_OK;

   SESS_SET

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;



   slot_id = SLOTID;


   // for now, the coprocessor is restricted to returning data in LEEDS_PACKETS
   // which limits each call to the card to 4096 bytes of random data...
   //
   len = ulRandomLen;
   while (len > 0 && (rc == CKR_OK)) {
      amt = MIN( len, LEEDS_MAX_REQ_LEN );

      args.session_handle = HTOCL( SESSION );
      args.num_bytes      = HTOCL( amt          );

      req_len   = sizeof(GenerateRandom_Args);
      repl_len  = amt;

      rc = communicate( C_GENERATERANDOM, slot_id,
               &args,                 req_len,
                pRandomData + total, &repl_len,
                NULL,                 0,
                NULL,                 0 );


      if (rc != CKR_OK)
         return rc;

      total += amt;
      len -= amt;
   }

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, %d bytes\n", "C_GenerateRandom", rc, ulRandomLen );
#endif


   return rc;
}


//
//
CK_RV SC_GenerateKey( ST_SESSION_HANDLE     sSession,
                     CK_MECHANISM_PTR      pMechanism,
                     CK_ATTRIBUTE_PTR      pTemplate,
                     CK_ULONG              ulCount,
                     CK_OBJECT_HANDLE_PTR  phKey )
{
   GenerateKey_Args     * args;
   HOST_SESSION_HANDLE  * node = NULL;
   CK_ATTRIBUTE         * attr = NULL;
   CK_BYTE              * ptr  = NULL;
   CK_SLOT_ID             slot_id;
   CK_ULONG               req_len, repl_len;
   CK_ULONG               tmpl_len, i;
   CK_RV                  rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;

   if (!pMechanism || !phKey)
      return CKR_ARGUMENTS_BAD;



   slot_id = SLOTID;

   //
   // figure out how much memory to allocate for the request block
   //

   // compute the total template size
   //
   tmpl_len = 0;
#if __64BIT__
   for (attr = pTemplate, i = 0; i < ulCount; i++, attr++)
      tmpl_len += sizeof(ATTRIBUTE) + get_attrib_len(attr); // attr->ulValueLen;
#else
   for (attr = pTemplate, i = 0; i < ulCount; i++, attr++)
      tmpl_len += sizeof(ATTRIBUTE) + attr->ulValueLen;
#endif

#if __64BIT__
   req_len = sizeof(GenerateKey_Args) +  tmpl_len + get_mech_parameter_len(pMechanism);
#else
   req_len = sizeof(GenerateKey_Args) + pMechanism->ulParameterLen + tmpl_len;
#endif

   args = (GenerateKey_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   args->session_handle      = HTOCL( SESSION               );
   args->mech_type           = HTOCL( pMechanism->mechanism      );
#if __64BIT__
   args->mech_param_len      = HTOCL(get_mech_parameter_len(pMechanism)); // pMechanism->ulParameterLen );
#else
   args->mech_param_len      = HTOCL( pMechanism->ulParameterLen );
#endif
   args->attribute_count     = HTOCL( ulCount                    );
   args->attribute_block_len = HTOCL( tmpl_len                   );


   ptr = (CK_BYTE *)args + sizeof(GenerateKey_Args);


   if (pMechanism->ulParameterLen != 0) {
      // WARNING:  again, for BIG-ENDIAN machines, it might be necessary
      // to ensure the parameter has the correct endianness if it is to
      // be interpretted as something other than a byte array
      //
#ifdef BIG_ENDIAN
      ADJUSTMECHPTR();
#else
      memcpy( ptr, pMechanism->pParameter, pMechanism->ulParameterLen );
#endif


#if __64BIT__
      ptr += get_mech_parameter_len(pMechanism); //->ulParameterLen;
#else
      ptr += pMechanism->ulParameterLen;
#endif
   }

   // insert the attribute template into the request
   //
   attr = pTemplate;

   for (i=0; i < ulCount; i++, attr++) {
      ATTRIBUTE *p_attrib = (ATTRIBUTE *)ptr;
      unsigned char  *pd,*ps;
      unsigned long *pl;


      p_attrib->type         = HTOCL(attr->type);
#if __64BIT__
      p_attrib->value_length = HTOCL(get_attrib_len(attr)); //attr->ulValueLen);
#else
      p_attrib->value_length = HTOCL(attr->ulValueLen);
#endif

      // BIG-ENDIAN warning.  Same here...
      //
#ifndef _BIG_ENDIAN
      memcpy( (ptr + sizeof(ATTRIBUTE)), attr->pValue, attr->ulValueLen );
#else
      // We need to swap the values.
      pd = (unsigned char *)(ptr + sizeof(ATTRIBUTE));
      ps = (unsigned char *)(attr->pValue);

#if __64BIT__
      copy_attribute_value(ps,pd,attr);
#else
      memcpy(pd, ps, attr->ulValueLen);
#endif

#if __64BIT__
      if ( attr->ulValueLen == 8 ) {
#else
      if ( attr->ulValueLen == 4 ) {
#endif
         pl = (unsigned long *)attr->pValue;
         pl = (unsigned long *)ps;

#ifdef PKCS64
         ModifyAttribute(attr->type,(CK_ULONG_PTR_32)pd);
#else
         ModifyAttribute(attr->type,(CK_ULONG_PTR)pd);
#endif

      }

#endif

#if __64BIT__
      ptr += sizeof(ATTRIBUTE) + get_attrib_len(attr); //attr->ulValueLen; // p_attrib->value_length;
#else
      ptr += sizeof(ATTRIBUTE) + attr->ulValueLen; // p_attrib->value_length;
#endif
   }

#if __64BIT__
   repl_len = sizeof(CK_OBJECT_HANDLE_32);
#else
   repl_len = sizeof(CK_OBJECT_HANDLE);
#endif

   //hex_dump("GEN_KEY",(CK_BYTE_PTR)args,req_len);
#if __64BIT__
   {
   CK_ULONG_32   val;


   rc = communicate( C_GENERATEKEY, slot_id,
                      args,   req_len,
                      &val, &repl_len,
                      NULL,   0,
                      NULL,   0 );
   *phKey = val;
   }
#else
   rc = communicate( C_GENERATEKEY, slot_id,
                      args,   req_len,
                      phKey, &repl_len,
                      NULL,   0,
                      NULL,   0 );
#endif

   free( args );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, handle = %d, mech = 0x%X\n", "C_GenerateKey", rc, SESSION, *phKey, pMechanism->mechanism );

   attr = pTemplate;
   for (i=0; i < ulCount; i++, attr++) {
      ptr = (CK_BYTE *)attr->pValue;

      logit(LOG_DEBUG, "   %3d:  Attribute type:  0x%08x\n", i, attr->type );
      logit(LOG_DEBUG, "         Value Length:    %08d\n",   attr->ulValueLen );

      if (attr->ulValueLen != (CK_ULONG)(-1) && (ptr != NULL))
         logit(LOG_DEBUG, "         First 4 bytes:   %02x %02x %02x %02x", ptr[0], ptr[1], ptr[2], ptr[3] );

      logit(LOG_DEBUG, "\n\n");
   }

#endif

   return rc;
}



//
//
CK_RV SC_EncryptInit( ST_SESSION_HANDLE  sSession,
                     CK_MECHANISM_PTR   pMechanism,
                     CK_OBJECT_HANDLE   hKey )
{
   EncryptInit_Args      * args = NULL;
   HOST_SESSION_HANDLE   * node = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;



   slot_id = SLOTID;

   if (pMechanism->ulParameterLen != 0)
#if __64BIT__
      req_len = sizeof(EncryptInit_Args) + get_mech_parameter_len(pMechanism); //->ulParameterLen;
#else
      req_len = sizeof(EncryptInit_Args) + pMechanism->ulParameterLen;
#endif
   else
      req_len = sizeof(EncryptInit_Args);

   args = (EncryptInit_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   memset( args, 0x0, req_len );

   if (pMechanism->ulParameterLen != 0) {
      CK_BYTE *ptr = (CK_BYTE *)args + sizeof(EncryptInit_Args);
#ifdef _BIG_ENDIAN
      ADJUSTMECHPTR();
#else
      memcpy( ptr, pMechanism->pParameter, pMechanism->ulParameterLen );
#endif
   }

   args->session_handle = HTOCL( SESSION               );
   args->key            = ( hKey                       ); // Don't swap
   args->mech_type      = HTOCL( pMechanism->mechanism      );
#if __64BIT__
   args->param_len      = HTOCL( get_mech_parameter_len(pMechanism)); //->ulParameterLen );
#else
   args->param_len      = HTOCL( pMechanism->ulParameterLen );
#endif

   repl_len = 0;

   rc = communicate( C_ENCRYPTINIT, slot_id,
                      args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );


   free( args );
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, key = %d, mech = 0x%X\n", "C_EncryptInit", rc, SESSION, hKey, pMechanism->mechanism );
#endif

   return rc;
}


//  12-09  added because of card/host interface changes
CK_RV SC_Encrypt( ST_SESSION_HANDLE  sSession,
                 CK_BYTE_PTR        pData,
                 CK_ULONG           ulDataLen,
                 CK_BYTE_PTR        pEncryptedData,
                 CK_ULONG_PTR       pulEncryptedDataLen )
{
   Encrypt_Args            args;

   HOST_SESSION_HANDLE   * node  = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;


   if (!pData || !pulEncryptedDataLen)
      return CKR_ARGUMENTS_BAD;


   slot_id = SLOTID;

   args.session_handle = HTOCL( SESSION );
   args.cleartext_len  = HTOCL( ulDataLen    );

   if (pEncryptedData == NULL)
      args.length_only = TRUE;
   else
      args.length_only = FALSE;

   req_len  = sizeof(args);

#ifdef PKCS64
   repl_len = sizeof(CK_ULONG_32);
#else
   repl_len = sizeof(CK_ULONG);
#endif

// SAB FIXME  changed for 64bit
#if __64BIT__
{
  CK_ULONG_32   tdata;
   rc = communicate( C_ENCRYPT,            slot_id,
                     &args,                 req_len,
                      &tdata, &repl_len,
                      pData,                ulDataLen,
                      pEncryptedData,      *pulEncryptedDataLen );
   *pulEncryptedDataLen = tdata;
}
#else
   rc = communicate( C_ENCRYPT,            slot_id,
                     &args,                 req_len,
                      pulEncryptedDataLen, &repl_len,
                      pData,                ulDataLen,
                      pEncryptedData,      *pulEncryptedDataLen );

#endif

// SAB XXX FIXME   really need to swap the pulEncryptedDataLen??
// SAB  LOOK
// does communicate replace that value.   repl_len won't get swapped .

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, amount = %d\n", "C_Encrypt", rc, SESSION, ulDataLen );
#endif

#ifdef _BIG_ENDIAN
   {

#ifdef PKCS64
         CK_ULONG_32  td;
#else
         CK_ULONG  td;
#endif

         td = HTOCL(*pulEncryptedDataLen);
         *pulEncryptedDataLen = td;

   }
#endif

   return rc;
}







//
//
CK_RV SC_EncryptUpdate( ST_SESSION_HANDLE  sSession,
                       CK_BYTE_PTR        pPart,
                       CK_ULONG           ulPartLen,
                       CK_BYTE_PTR        pEncryptedPart,
                       CK_ULONG_PTR       pulEncryptedPartLen )
{
   EncryptUpdate_Args    * args  = NULL;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * ptr   = NULL;
   CK_BYTE               * reply = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;

   if (!pPart || !pulEncryptedPartLen)
      return CKR_ARGUMENTS_BAD;


   slot_id = SLOTID;

   req_len  = sizeof(EncryptUpdate_Args) + ulPartLen;
   args = (EncryptUpdate_Args *)malloc( req_len );

   if (!args)
      return CKR_HOST_MEMORY;
   else {
      args->session_handle = HTOCL( SESSION );
      args->cleartext_len  = HTOCL( ulPartLen    );

      ptr = (CK_BYTE *)args + sizeof(EncryptUpdate_Args);
      memcpy( ptr, pPart, ulPartLen );

      if (pEncryptedPart == NULL) {
         args->length_only = TRUE;

#ifdef PKCS64         
         repl_len = sizeof(CK_ULONG_32);

#else
         repl_len = sizeof(CK_ULONG);
#endif

      }
      else {
         args->length_only = FALSE;

#ifdef PKCS64
         repl_len = sizeof(CK_ULONG_32) + *pulEncryptedPartLen;
#else
         repl_len = sizeof(CK_ULONG) + *pulEncryptedPartLen;
#endif

      }

      reply = (CK_BYTE *)malloc( repl_len );
      if (!reply)
         rc = CKR_HOST_MEMORY;
      else {
         rc = communicate( C_ENCRYPTUPDATE, slot_id,
                            args,   req_len,
                            reply, &repl_len,
                            NULL,   0,
                            NULL,   0 );

         if (rc == CKR_OK || rc == CKR_BUFFER_TOO_SMALL) {
#ifdef PKCS64
            {
               CK_ULONG_32  tmp;
               memcpy( &tmp, reply, sizeof(CK_ULONG_32) );
               *pulEncryptedPartLen = CTOHL( tmp );
            }
#else
            memcpy( pulEncryptedPartLen, reply, sizeof(CK_ULONG) );
            *pulEncryptedPartLen = CTOHL( *pulEncryptedPartLen );
#endif


            if (rc == CKR_OK && args->length_only == FALSE)

#ifdef PKCS64
               memcpy( pEncryptedPart, reply + sizeof(CK_ULONG_32), 
                       *pulEncryptedPartLen );
#else
               memcpy( pEncryptedPart, reply + sizeof(CK_ULONG), *pulEncryptedPartLen );
#endif

         }
      }
   }

   if (args)
      free( args );

   if (reply)
      free( reply );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, amount = %d\n", "C_EncryptUpdate", rc, SESSION, ulPartLen );
#endif

   return rc;

}



// I think RSA goofed when designing the specification for C_EncryptFinal.
// This function is supposed to follow the Cryptoki standard that if
// pLastEncryptedPart == NULL then the user is requesting only the length
// of the output.
//
// But it's quite possible that no output will be returned (say the user
// specifies a total of 64 bytes of input data throughout the multi-part
// encryption).  The same thing can happen during an EncryptUpdate.
//
// ie:
//
//    1) user calls C_EncryptFinal to get the needed length
//       --> we return "0 bytes required"
//    2) user passes in a NULL pointer for pLastEncryptedPart
//       --> we think the user is requesting the length again <--
//
// So the user needs to pass in a non-NULL pointer even though we're not
// going to return anything in it.  It would have been cleaner if RSA would
// have simply included a "give-me-the-length-only flag" as an argument.
//
CK_RV SC_EncryptFinal( ST_SESSION_HANDLE  sSession,
                      CK_BYTE_PTR        pLastEncryptedPart,
                      CK_ULONG_PTR       pulLastEncryptedPartLen )
{
   EncryptFinal_Args     * args  = NULL;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * reply = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;

   SESS_SET

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;


   slot_id = SLOTID;

   req_len  = sizeof(EncryptFinal_Args);
   args = (EncryptFinal_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   args->session_handle = HTOCL( SESSION );

   if (pLastEncryptedPart == NULL) {
      args->length_only = TRUE;

#ifdef PKCS64
      repl_len = sizeof(CK_ULONG_32);
#else
      repl_len = sizeof(CK_ULONG);
#endif

   }
   else {
      args->length_only = FALSE;

#ifdef PKCS64
      repl_len = sizeof(CK_ULONG_32) + *pulLastEncryptedPartLen;
#else
      repl_len = sizeof(CK_ULONG) + *pulLastEncryptedPartLen;
#endif

   }


   reply = (CK_BYTE *)malloc( repl_len );
   if (!reply)
      return CKR_HOST_MEMORY;

   rc = communicate( C_ENCRYPTFINAL, slot_id,
                     args,   req_len,
                      reply, &repl_len,
                      NULL,   0,
                      NULL,   0 );

   if (rc == CKR_OK) {
      if (args->length_only == TRUE) {

#ifdef PKCS64
	*pulLastEncryptedPartLen = *(CK_ULONG_32 *)reply;
#else
         memcpy( pulLastEncryptedPartLen, reply, sizeof(CK_ULONG) );
#endif

         *pulLastEncryptedPartLen = CTOHL( *pulLastEncryptedPartLen );
      }
      else {

#ifdef PKCS64
	*pulLastEncryptedPartLen = *(CK_ULONG_32 *)reply;
#else
         memcpy( pulLastEncryptedPartLen, reply, sizeof(CK_ULONG) );
#endif
         *pulLastEncryptedPartLen = CTOHL( *pulLastEncryptedPartLen );

#ifdef PKCS64
         memcpy( pLastEncryptedPart, reply + sizeof(CK_ULONG_32), 
                 *pulLastEncryptedPartLen );
#else
         memcpy( pLastEncryptedPart,      reply + sizeof(CK_ULONG), *pulLastEncryptedPartLen );
#endif

      }
   }

   free( args );
   free( reply );
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d\n", "C_EncryptFinal", rc, SESSION );
#endif

   return rc;
}



//
//
CK_RV SC_DecryptInit( ST_SESSION_HANDLE  sSession,
                     CK_MECHANISM_PTR   pMechanism,
                     CK_OBJECT_HANDLE   hKey )
{
   DecryptInit_Args      * args = NULL;
   HOST_SESSION_HANDLE   * node = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;



   slot_id = SLOTID;

   if (pMechanism->ulParameterLen != 0)
#if __64BIT__
      req_len = sizeof(DecryptInit_Args) + get_mech_parameter_len(pMechanism); //->ulParameterLen;
#else
      req_len = sizeof(DecryptInit_Args) + pMechanism->ulParameterLen;
#endif
   else
      req_len = sizeof(DecryptInit_Args);

   args = (DecryptInit_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   memset( args, 0x0, req_len );

   if (pMechanism->ulParameterLen != 0) {
      CK_BYTE *ptr = (CK_BYTE *)args + sizeof(DecryptInit_Args);
#ifdef _BIG_ENDIAN
      ADJUSTMECHPTR();
#else
      memcpy( ptr, pMechanism->pParameter, pMechanism->ulParameterLen );
#endif
   }

   args->session_handle = HTOCL( SESSION               );
   args->key            = ( hKey                       ); // Don't swap
   args->mech_type      = HTOCL( pMechanism->mechanism      );
#if __64BIT__
   args->param_len      = HTOCL( get_mech_parameter_len(pMechanism)); //->ulParameterLen );
#else
   args->param_len      = HTOCL( pMechanism->ulParameterLen );
#endif

   repl_len = 0;

   rc = communicate( C_DECRYPTINIT, slot_id,
                      args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

   free( args );
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, key = %d, mech = 0x%X\n", "C_DecryptInit", rc, SESSION, hKey, pMechanism->mechanism );
#endif

   return rc;
}


//
//
CK_RV SC_Decrypt( ST_SESSION_HANDLE  sSession,
                 CK_BYTE_PTR        pEncryptedData,
                 CK_ULONG           ulEncryptedDataLen,
                 CK_BYTE_PTR        pData,
                 CK_ULONG_PTR       pulDataLen )
{
   Decrypt_Args            args;

   HOST_SESSION_HANDLE   * node  = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pEncryptedData || !pulDataLen)
      return CKR_ARGUMENTS_BAD;


   slot_id = SLOTID;


   args.session_handle  = HTOCL( SESSION       );
   args.ciphertext_len  = HTOCL( ulEncryptedDataLen );

   if (pData == NULL)
      args.length_only = TRUE;
   else
      args.length_only = FALSE;

   req_len  = sizeof(Decrypt_Args);

#ifdef PKCS64
   repl_len = sizeof(CK_ULONG_32);
#else
   repl_len = sizeof(CK_ULONG);
#endif

#if __64BIT__
{
   CK_ULONG_32 nLen;
   rc = communicate( C_DECRYPT,       slot_id,
                      &args,           req_len,
                      &nLen,     &repl_len,
                      pEncryptedData,  ulEncryptedDataLen,
                      pData,          *pulDataLen );
   *pulDataLen = nLen;
}
#else
   rc = communicate( C_DECRYPT,       slot_id,
                      &args,           req_len,
                      pulDataLen,     &repl_len,
                      pEncryptedData,  ulEncryptedDataLen,
                      pData,          *pulDataLen );
#endif

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, amount = %d\n", "C_Decrypt", rc, SESSION, ulEncryptedDataLen );
#endif
#ifdef _BIG_ENDIAN
   {
      *pulDataLen = CTOHL(*pulDataLen);
   }
#endif

   return rc;

}


//
//
CK_RV SC_DecryptUpdate( ST_SESSION_HANDLE  sSession,
                       CK_BYTE_PTR        pEncryptedPart,
                       CK_ULONG           ulEncryptedPartLen,
                       CK_BYTE_PTR        pPart,
                       CK_ULONG_PTR       pulPartLen )
{
   DecryptUpdate_Args    * args  = NULL;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * ptr   = NULL;
   CK_BYTE               * reply = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pEncryptedPart || !pulPartLen)
      return CKR_ARGUMENTS_BAD;


   slot_id = SLOTID;

   req_len  = sizeof(DecryptUpdate_Args) + ulEncryptedPartLen;
   args = (DecryptUpdate_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;
   else {
      args->session_handle = HTOCL( SESSION       );
      args->ciphertext_len = HTOCL( ulEncryptedPartLen );

      ptr = (CK_BYTE *)args + sizeof(DecryptUpdate_Args);
      memcpy( ptr, pEncryptedPart, ulEncryptedPartLen );

      if (pPart == NULL) {
         args->length_only = TRUE;

#ifdef PKCS64
         repl_len = sizeof(CK_ULONG_32);
#else
         repl_len = sizeof(CK_ULONG);
#endif

      }
      else {
         args->length_only = FALSE;

#ifdef PKCS64
         repl_len = sizeof(CK_ULONG_32) + *pulPartLen;
#else
         repl_len = sizeof(CK_ULONG) + *pulPartLen;
#endif

      }

      reply = (CK_BYTE *)malloc( repl_len );
      if (!reply)
         rc = CKR_HOST_MEMORY;
      else {
         rc = communicate( C_DECRYPTUPDATE, slot_id,
                            args,   req_len,
                            reply, &repl_len,
                            NULL,   0,
                            NULL,   0 );

         if (rc == CKR_OK || rc == CKR_BUFFER_TOO_SMALL) {

#ifdef PKCS64
	   *pulPartLen = *(CK_ULONG_32 *)reply;
#else
            memcpy( pulPartLen, reply, sizeof(CK_ULONG) );
#endif

            *pulPartLen = CTOHL( *pulPartLen );

            if (rc == CKR_OK && args->length_only == FALSE)

#ifdef PKCS64
               memcpy( pPart, reply + sizeof(CK_ULONG_32), *pulPartLen );
#else
               memcpy( pPart, reply + sizeof(CK_ULONG), *pulPartLen );
#endif

         }
      }
   }

   if (args)
      free( args );

   if (reply)
      free( reply );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, amount = %d\n", "C_DecryptUpdate", rc, SESSION, ulEncryptedPartLen );
#endif

   return rc;

}


//
//
CK_RV SC_DecryptFinal( ST_SESSION_HANDLE  sSession,
                      CK_BYTE_PTR        pLastPart,
                      CK_ULONG_PTR       pulLastPartLen )
{
   DecryptFinal_Args     * args  = NULL;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * reply = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pulLastPartLen)
      return CKR_ARGUMENTS_BAD;



   slot_id = SLOTID;

   req_len  = sizeof(DecryptFinal_Args);
   args = (DecryptFinal_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;
   else {
      args->session_handle = HTOCL( SESSION );

      if (pLastPart == NULL) {
         args->length_only = TRUE;

#ifdef PKCS64
         repl_len = sizeof(CK_ULONG_32);
#else
         repl_len = sizeof(CK_ULONG);
#endif

      }
      else {
         args->length_only = FALSE;

#ifdef PKCS64
         repl_len = sizeof(CK_ULONG_32) + *pulLastPartLen;
#else
         repl_len = sizeof(CK_ULONG) + *pulLastPartLen;
#endif

      }

      reply = (CK_BYTE *)malloc( repl_len );
      if (!reply)
         rc = CKR_HOST_MEMORY;
      else {
         rc = communicate( C_DECRYPTFINAL, slot_id,
                            args,   req_len,
                            reply, &repl_len,
                            NULL,   0,
                            NULL,   0 );

         if (rc == CKR_OK || rc == CKR_BUFFER_TOO_SMALL) {

#ifdef PKCS64
	    *pulLastPartLen = *(CK_ULONG_32 *)reply;
#else
            memcpy( pulLastPartLen, reply, sizeof(CK_ULONG) );
#endif
            *pulLastPartLen = CTOHL( *pulLastPartLen );

            if (rc == CKR_OK && args->length_only == FALSE)

#ifdef PKCS64
               memcpy( pLastPart, reply + sizeof(CK_ULONG_32), *pulLastPartLen );
#else
               memcpy( pLastPart, reply + sizeof(CK_ULONG), *pulLastPartLen );
#endif

         }
      }
   }

   if (args)
      free( args );

   if (reply)
      free( reply );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d\n", "C_DecryptFinal", rc, SESSION );
#endif

   return rc;

}


//
//
CK_RV SC_WrapKey( ST_SESSION_HANDLE  sSession,
                 CK_MECHANISM_PTR   pMechanism,
                 CK_OBJECT_HANDLE   hWrappingKey,
                 CK_OBJECT_HANDLE   hKey,
                 CK_BYTE_PTR        pWrappedKey,
                 CK_ULONG_PTR       pulWrappedKeyLen )
{
   WrapKey_Args          * args  = NULL;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * reply = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;
   SESS_SET


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pulWrappedKeyLen)
      return CKR_ARGUMENTS_BAD;


   slot_id = SLOTID;

#if __64BIT__
   req_len = sizeof(WrapKey_Args) + get_mech_parameter_len(pMechanism); //->ulParameterLen;
#else
   req_len = sizeof(WrapKey_Args) + pMechanism->ulParameterLen;
#endif

   args = (WrapKey_Args *)malloc(req_len);
   if (!args)
      return CKR_HOST_MEMORY;
   else {
      args->session_handle  = HTOCL( SESSION               );
      args->mech_type       = HTOCL( pMechanism->mechanism      );
#if __64BIT__
      args->mech_param_len  = HTOCL( get_mech_parameter_len(pMechanism)); 
#else
      args->mech_param_len  = HTOCL( pMechanism->ulParameterLen );
#endif
      args->wrapping_key    = ( hWrappingKey               );
      args->key             = ( hKey                       );

      if (pMechanism->ulParameterLen != 0) {
         CK_BYTE *ptr = (CK_BYTE *)args + sizeof(WrapKey_Args);
#ifdef _BIG_ENDIAN
         ADJUSTMECHPTR();
#else
         memcpy( ptr, pMechanism->pParameter, pMechanism->ulParameterLen );
#endif
      }

      if (!pWrappedKey) {
         args->length_only = TRUE;

#ifdef PKCS64
         repl_len = sizeof(CK_ULONG_32);
#else
         repl_len = sizeof(CK_ULONG);
#endif

      }
      else {
         args->length_only = FALSE;

#ifdef PKCS64
         repl_len = sizeof(CK_ULONG_32) + *pulWrappedKeyLen;
#else
         repl_len = sizeof(CK_ULONG) + *pulWrappedKeyLen;
#endif

      }

      reply = (CK_BYTE *)malloc(repl_len);
      if (!reply)
         rc = CKR_HOST_MEMORY;
      else {
         rc = communicate( C_WRAPKEY, slot_id,
                            args,   req_len,
                            reply, &repl_len,
                            NULL,   0,
                            NULL,   0 );

         if (rc == CKR_OK || rc == CKR_BUFFER_TOO_SMALL) {

#ifdef PKCS64
            *pulWrappedKeyLen = *(CK_ULONG_32 *) reply;
#else
            memcpy( pulWrappedKeyLen, reply, sizeof(CK_ULONG) );
#endif

            *pulWrappedKeyLen = CTOHL( *pulWrappedKeyLen );

            if (rc == CKR_OK && args->length_only == FALSE) {

#ifdef PKCS64
               memcpy( pWrappedKey, reply + sizeof(CK_ULONG_32), *pulWrappedKeyLen );
#else
               memcpy( pWrappedKey, reply + sizeof(CK_ULONG), *pulWrappedKeyLen );
#endif

            }
         }
      }
   }

   if (args)
      free( args );

   if (reply)
      free( reply );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, encrypting key = %d, wrapped key = %d\n", "C_WrapKey", rc, SESSION, hWrappingKey, hKey );
#endif

   return rc;

}


//
//
CK_RV SC_UnwrapKey( ST_SESSION_HANDLE     sSession,
                   CK_MECHANISM_PTR      pMechanism,
                   CK_OBJECT_HANDLE      hUnwrappingKey,
                   CK_BYTE_PTR           pWrappedKey,
                   CK_ULONG              ulWrappedKeyLen,
                   CK_ATTRIBUTE_PTR      pTemplate,
                   CK_ULONG              ulAttributeCount,
                   CK_OBJECT_HANDLE_PTR  phKey )
{
   UnWrapKey_Args        * args  = NULL;
   CK_ATTRIBUTE          * attr  = NULL;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * ptr   = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_ULONG                tmpl_len;
   CK_ULONG                i;
   CK_RV                   rc;

   SESS_SET

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (hSession == 0)
      return CKR_SESSION_HANDLE_INVALID;

   if ((ulWrappedKeyLen == 0) || !phKey || !pWrappedKey)
      return CKR_ARGUMENTS_BAD;

   if ((ulAttributeCount != 0) && !pTemplate)
      return CKR_ARGUMENTS_BAD;


   slot_id = SLOTID;


   // compute the total template size
   //
   tmpl_len = 0;
#if __64BIT__
   for (attr = pTemplate, i = 0; i < ulAttributeCount; i++, attr++)
      tmpl_len += sizeof(ATTRIBUTE) + get_attrib_len(attr); // attr->ulValueLen;
#else
   for (attr = pTemplate, i = 0; i < ulAttributeCount; i++, attr++)
      tmpl_len += sizeof(ATTRIBUTE) + attr->ulValueLen;
#endif

#if __64BIT__
   req_len = sizeof(UnWrapKey_Args) + get_mech_parameter_len(pMechanism) //->ulParameterLen
                                    + ulWrappedKeyLen
                                    + tmpl_len;
#else
   req_len = sizeof(UnWrapKey_Args) + pMechanism->ulParameterLen
                                    + ulWrappedKeyLen
                                    + tmpl_len;
#endif

   args = (UnWrapKey_Args *)malloc(req_len);
   if (!args)
      return CKR_HOST_MEMORY;

   memset( args, 0x0, req_len );


   args->session_handle      = HTOCL( SESSION               );
   args->mech_type           = HTOCL( pMechanism->mechanism      );
#if __64BIT__
   args->mech_param_len      = HTOCL( get_mech_parameter_len(pMechanism));
#else
   args->mech_param_len      = HTOCL( pMechanism->ulParameterLen );
#endif
   args->unwrapping_key      = ( hUnwrappingKey             );
   args->wrapped_key_len     = HTOCL( ulWrappedKeyLen            );
   args->attribute_count     = HTOCL( ulAttributeCount           );
   args->attribute_block_len = HTOCL( tmpl_len                   );


   ptr = (CK_BYTE *)args + sizeof(UnWrapKey_Args);

   if (pMechanism->ulParameterLen != 0) {
#ifdef _BIG_ENDIAN
      ADJUSTMECHPTR();
#else
      memcpy( ptr, pMechanism->pParameter, pMechanism->ulParameterLen );
#endif
#if __64BIT__
      ptr += get_mech_parameter_len(pMechanism); //->ulParameterLen;
#else
      ptr += pMechanism->ulParameterLen;
#endif
   }

   if (ulWrappedKeyLen != 0) {
      memcpy( ptr, pWrappedKey, ulWrappedKeyLen );
      ptr += ulWrappedKeyLen;
   }

   // build the attribute block
   //
   attr = pTemplate;
   for (i = 0; i < ulAttributeCount; i++, attr++) {
      ATTRIBUTE *p_attrib = (ATTRIBUTE *)ptr;

      p_attrib->type         = HTOCL( attr->type       );
#if __64BIT__
      p_attrib->value_length = HTOCL(get_attrib_len(attr)); //attr->ulValueLen);
#else
      p_attrib->value_length = HTOCL( attr->ulValueLen );
#endif

#ifndef _BIG_ENDIAN
      memcpy( (ptr + sizeof(ATTRIBUTE)), attr->pValue, attr->ulValueLen );
#else
{
      unsigned char  *pd,*ps;

#ifdef PKCS64
      unsigned int  *pl;
#else
      unsigned long *pl;
#endif

      // We need to swap the values.
      pd = (unsigned char *)(ptr + sizeof(ATTRIBUTE));
      ps = (unsigned char *)(attr->pValue);

#if __64BIT__
      copy_attribute_value(ps,pd,attr);
#else
      memcpy(pd, ps, attr->ulValueLen);
#endif


#if __64BIT__
      if ( attr->ulValueLen == 8 ) {
#else
      if ( attr->ulValueLen == 4 ) {
#endif
	 pl = (unsigned int *)attr->pValue;
         pl = (unsigned int *)ps;

#ifdef PKCS64
         ModifyAttribute(attr->type,(CK_ULONG_PTR_32)pd);
#else         
         ModifyAttribute(attr->type,(CK_ULONG_PTR)pd);
#endif

      }

}
#endif


#if __64BIT__
      ptr += sizeof(ATTRIBUTE) + get_attrib_len(attr); //attr->ulValueLen; // p_attrib->value_length;
#else
      ptr += sizeof(ATTRIBUTE) + attr->ulValueLen; // p_attrib->value_length;
#endif
   }

#ifdef PKCS64
   repl_len = sizeof(CK_OBJECT_HANDLE_32);
#else
   repl_len = sizeof(CK_OBJECT_HANDLE);
#endif

#if __64BIT__
{
   CK_OBJECT_HANDLE_32  nHandle;
   rc = communicate( C_UNWRAPKEY, slot_id,
                      args,   req_len,
                      &nHandle, &repl_len,
                      NULL,   0,
                      NULL,   0 );
   *phKey = nHandle;
}
#else
   rc = communicate( C_UNWRAPKEY, slot_id,
                      args,   req_len,
                      phKey, &repl_len,
                      NULL,   0,
                      NULL,   0 );
#endif

   free( args );
#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, decrypting key = %d, unwrapped key = %d mech 0x%X\n", "C_UnwrapKey", rc, SESSION, hUnwrappingKey, *phKey,pMechanism->mechanism );

   attr = pTemplate;
   for (i=0; i < ulAttributeCount; i++, attr++) {
      ptr = (CK_BYTE *)attr->pValue;

      logit(LOG_DEBUG, "   %3d:  Attribute type:  0x%08x\n", i, attr->type );
      logit(LOG_DEBUG, "         Value Length:    %08d\n",   attr->ulValueLen );

      if (attr->ulValueLen != (CK_ULONG)(-1) && (ptr != NULL))
         logit(LOG_DEBUG, "         First 4 bytes:   %02x %02x %02x %02x", ptr[0], ptr[1], ptr[2], ptr[3] );

      logit(LOG_DEBUG, "\n\n");
   }
#endif

   return rc;
}



//
//
CK_RV SC_DigestInit( ST_SESSION_HANDLE  sSession,
                    CK_MECHANISM_PTR   pMechanism )
{
   DigestInit_Args      * args = NULL;
   HOST_SESSION_HANDLE  * node = NULL;
   CK_SLOT_ID             slot_id;
   CK_ULONG               req_len, repl_len;
   CK_RV                  rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;



   slot_id = SLOTID;

   if (pMechanism->ulParameterLen != 0)
#if __64BIT__
      req_len = sizeof(DigestInit_Args) + get_mech_parameter_len(pMechanism);
#else
      req_len = sizeof(DigestInit_Args) + pMechanism->ulParameterLen;
#endif

   else
      req_len = sizeof(DigestInit_Args);

   args = (DigestInit_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   memset( args, 0x0, req_len );

   if (pMechanism->ulParameterLen != 0) {
      CK_BYTE *ptr = (CK_BYTE *)args + sizeof(DigestInit_Args);
#ifdef _BIG_ENDIAN
      ADJUSTMECHPTR();
#else
      memcpy( ptr, pMechanism->pParameter, pMechanism->ulParameterLen );
#endif
   }

   args->session_handle = HTOCL( SESSION               );
   args->mech_type      = HTOCL( pMechanism->mechanism      );
#if __64BIT__
   args->param_len      = HTOCL( get_mech_parameter_len(pMechanism) );
#else
   args->param_len      = HTOCL( pMechanism->ulParameterLen );
#endif

   repl_len = 0;

   rc = communicate( C_DIGESTINIT, slot_id,
                      args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

   free( args );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, mech = 0x%X\n", "C_DigestInit", rc, SESSION, pMechanism->mechanism );
#endif

   return rc;
}


//
//
CK_RV SC_Digest( ST_SESSION_HANDLE  sSession,
                CK_BYTE_PTR        pData,
                CK_ULONG           ulDataLen,
                CK_BYTE_PTR        pDigest,
                CK_ULONG_PTR       pulDigestLen )
{
   Digest_Args             args;

   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * reply = NULL;
   CK_BYTE                 nullstring[] = { 0 };
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;
   SESS_SET    // this must be at the end of the local variable defs


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pData || !pulDigestLen)
      return CKR_ARGUMENTS_BAD;


   slot_id = SLOTID;

   args.session_handle  = HTOCL( SESSION );

   if (pDigest == NULL) {
      args.length_only = TRUE;

#ifdef PKCS64
      repl_len = sizeof(CK_ULONG_32);
#else
      repl_len = sizeof(CK_ULONG);
#endif

   }
   else {
      args.length_only = FALSE;

#ifdef PKCS64
      repl_len = sizeof(CK_ULONG_32) + *pulDigestLen;
#else
      repl_len = sizeof(CK_ULONG) + *pulDigestLen;
#endif

   }

   req_len  = sizeof(args);

   reply = (CK_BYTE *)malloc( repl_len );
   if (!reply)
      return CKR_HOST_MEMORY;

   if (ulDataLen == 0) {
      args.data_len = HTOCL( 1 );

      rc = communicate( C_DIGEST,      slot_id,
                        &args,          req_len,
                         reply,        &repl_len,
                         nullstring,    1,
                         NULL,          0 );
   }
   else {
      args.data_len = HTOCL( ulDataLen );

      rc = communicate( C_DIGEST,      slot_id,
                        &args,          req_len,
                         reply,        &repl_len,
                         pData,         ulDataLen,
                         NULL,          0 );
   }

   if (rc == CKR_OK || rc == CKR_BUFFER_TOO_SMALL) {

#ifdef PKCS64
      *pulDigestLen = *(CK_ULONG_32 *)reply;
#else
      memcpy( pulDigestLen, reply, sizeof(CK_ULONG) );
#endif

      *pulDigestLen = CTOHL( *pulDigestLen );

      if (rc == CKR_OK && args.length_only == FALSE)

#ifdef PKCS64
         memcpy( pDigest, reply + sizeof(CK_ULONG_32), *pulDigestLen );
#else
         memcpy( pDigest, reply + sizeof(CK_ULONG), *pulDigestLen );
#endif

   }

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, datalen = %d\n", "C_Digest", rc, SESSION, ulDataLen );
#endif

   return rc;

}


//
//
CK_RV SC_DigestUpdate( ST_SESSION_HANDLE  sSession,
                      CK_BYTE_PTR        pPart,
                      CK_ULONG           ulPartLen )
{
   DigestUpdate_Args     * args  = NULL;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * ptr   = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;
   SESS_SET    // this must be at the end of the local variable defs


   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;


   slot_id = SLOTID;


   req_len  = sizeof(DigestUpdate_Args) + ulPartLen;
   args = (DigestUpdate_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   args->session_handle  = HTOCL( SESSION );
   args->data_len        = HTOCL( ulPartLen    );

   if (ulPartLen > 0) {
      ptr = (CK_BYTE *)args + sizeof(DigestUpdate_Args);
      memcpy( ptr, pPart, ulPartLen );
   }

   repl_len = 0;

   rc = communicate( C_DIGESTUPDATE, slot_id,
                      args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

   free( args );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, datalen = %d\n", "C_DigestUpdate", rc, SESSION, ulPartLen );
#endif

   return rc;
}


//
//
CK_RV SC_DigestKey( ST_SESSION_HANDLE  sSession,
                   CK_OBJECT_HANDLE   hKey )
{
   DigestKey_Args          args;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;


   slot_id = SLOTID;


   args.session_handle  = HTOCL( SESSION );
   args.key             = (hKey );  // object handles do not get byte-reversed

   req_len  = sizeof(DigestKey_Args);
   repl_len = 0;

   rc = communicate( C_DIGESTKEY, slot_id,
                     &args,   req_len,
                     NULL,   &repl_len,
                     NULL,    0,
                     NULL,    0 );


#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, key = %d\n", "C_DigestKey", rc, SESSION, hKey );
#endif

   return rc;
}


//
//
CK_RV SC_DigestFinal( ST_SESSION_HANDLE  sSession,
                     CK_BYTE_PTR        pDigest,
                     CK_ULONG_PTR       pulDigestLen )
{
   DigestFinal_Args        args;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * reply = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pulDigestLen)
      return CKR_ARGUMENTS_BAD;


   slot_id = SLOTID;


   args.session_handle = HTOCL(SESSION);

   if (!pDigest) {
      args.length_only = TRUE;

#ifdef PKCS64
      repl_len = sizeof(CK_ULONG_32);
#else
      repl_len = sizeof(CK_ULONG);
#endif

   }
   else {
      args.length_only = FALSE;

#ifdef PKCS64
      repl_len = sizeof(CK_ULONG_32) + *pulDigestLen;
#else
      repl_len = sizeof(CK_ULONG) + *pulDigestLen;
#endif

   }

   req_len = sizeof(DigestFinal_Args);

   reply = (CK_BYTE *)malloc(repl_len);
   if (!reply)
      return CKR_HOST_MEMORY;

   rc = communicate( C_DIGESTFINAL, slot_id,
                     &args,  req_len,
                     reply, &repl_len,
                     NULL,   0,
                     NULL,   0 );

   if (rc == CKR_OK || rc == CKR_BUFFER_TOO_SMALL) {

#ifdef PKCS64
      memcpy( pulDigestLen, reply, sizeof(CK_ULONG_32) );
#else
      memcpy( pulDigestLen, reply, sizeof(CK_ULONG) );
#endif

      *pulDigestLen = CTOHL( *pulDigestLen );

      if (rc == CKR_OK || rc == CKR_BUFFER_TOO_SMALL) {

#ifdef PKCS64
	*pulDigestLen = *(CK_ULONG_32 *)reply;
#else
         memcpy( pulDigestLen, reply, sizeof(CK_ULONG) );
#endif

         *pulDigestLen = CTOHL( *pulDigestLen );

         if (rc == CKR_OK && args.length_only == FALSE)

#ifdef PKCS64
            memcpy( pDigest, reply + sizeof(CK_ULONG_32), *pulDigestLen );
#else
            memcpy( pDigest, reply + sizeof(CK_ULONG), *pulDigestLen );
#endif
      }    

   }


   free( reply );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d\n", "C_DigestFinal", rc, SESSION );
#endif

   return rc;
}


//
//
CK_RV SC_GenerateKeyPair( ST_SESSION_HANDLE     sSession,
                         CK_MECHANISM_PTR      pMechanism,
                         CK_ATTRIBUTE_PTR      pPublicKeyTemplate,
                         CK_ULONG              ulPublicKeyAttributeCount,
                         CK_ATTRIBUTE_PTR      pPrivateKeyTemplate,
                         CK_ULONG              ulPrivateKeyAttributeCount,
                         CK_OBJECT_HANDLE_PTR  phPublicKey,
                         CK_OBJECT_HANDLE_PTR  phPrivateKey )
{
   GenKeyPair_Args       * args = NULL;
   HOST_SESSION_HANDLE   * node = NULL;
   CK_ATTRIBUTE          * attr = NULL;
   CK_BYTE               * ptr  = NULL;

#ifdef PKCS64
   CK_OBJECT_HANDLE_32     reply[2];
#else
   CK_OBJECT_HANDLE        reply[2];
#endif

   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_ULONG                i, publ_tmpl_len, priv_tmpl_len;
   CK_RV                   rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pMechanism || !phPublicKey || !phPrivateKey)
      return CKR_ARGUMENTS_BAD;


   slot_id = SLOTID;

   //
   // figure out how much memory to allocate for the request
   //

   publ_tmpl_len = 0;
#if __64BIT__
   for (attr=pPublicKeyTemplate, i=0; i < ulPublicKeyAttributeCount; i++, attr++)
      publ_tmpl_len += sizeof(ATTRIBUTE) + get_attrib_len(attr);
#else
   for (attr=pPublicKeyTemplate, i=0; i < ulPublicKeyAttributeCount; i++, attr++)
      publ_tmpl_len += sizeof(ATTRIBUTE) + attr->ulValueLen;
#endif

   priv_tmpl_len = 0;
#if __64BIT__
   for (attr=pPrivateKeyTemplate, i=0; i < ulPrivateKeyAttributeCount; i++, attr++)
      priv_tmpl_len += sizeof(ATTRIBUTE) + get_attrib_len(attr);
#else
   for (attr=pPrivateKeyTemplate, i=0; i < ulPrivateKeyAttributeCount; i++, attr++)
      priv_tmpl_len += sizeof(ATTRIBUTE) + attr->ulValueLen;
#endif


#if __64BIT__
   req_len = sizeof(GenKeyPair_Args) + get_mech_parameter_len(pMechanism);
#else
   req_len = sizeof(GenKeyPair_Args) + pMechanism->ulParameterLen;
#endif
   req_len += publ_tmpl_len + priv_tmpl_len;

   args = (GenKeyPair_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   args->session_handle       = HTOCL (SESSION);
   args->mech_type            = HTOCL( pMechanism->mechanism );
#if __64BIT__
   args->mech_param_len       = HTOCL( get_mech_parameter_len(pMechanism));
#else
   args->mech_param_len       = HTOCL( pMechanism->ulParameterLen );
#endif
   args->publ_key_attr_count  = HTOCL( ulPublicKeyAttributeCount );
   args->publ_key_tmpl_len    = HTOCL( publ_tmpl_len );
   args->priv_key_attr_count  = HTOCL( ulPrivateKeyAttributeCount );
   args->priv_key_tmpl_len    = HTOCL( priv_tmpl_len );

   // append the variable-length fields to the request
   //
   ptr = (CK_BYTE *)args + sizeof(GenKeyPair_Args);


   if (pMechanism->ulParameterLen != 0) {
      // WARNING:  again, for BIG-ENDIAN machines, it might be necessary
      // to ensure the parameter has the correct endianness if it is to
      // be interpretted as something other than a byte array
#ifdef _BIG_ENDIAN
      ADJUSTMECHPTR();
#else
      memcpy( ptr, pMechanism->pParameter, pMechanism->ulParameterLen );
#endif
#if __64BIT__
      ptr += get_mech_parameter_len(pMechanism);
#else
      ptr += pMechanism->ulParameterLen;
#endif
   }

   // append the public key template
   //
   attr = pPublicKeyTemplate;
   for (i=0; i < ulPublicKeyAttributeCount; i++, attr++) {
      ATTRIBUTE *p_attrib = (ATTRIBUTE *)ptr;
      unsigned char  *pd,*ps;

#ifdef PKCS64
      unsigned int *pl;
#else
      unsigned long *pl;
#endif

      p_attrib->type         = HTOCL( attr->type );
#if __64BIT__
      p_attrib->value_length = HTOCL(get_attrib_len(attr)); //attr->ulValueLen);
#else
      p_attrib->value_length = HTOCL( attr->ulValueLen );
#endif

      // BIG-ENDIAN warning:  attribute values
#ifndef _BIG_ENDIAN
      memcpy( (ptr + sizeof(ATTRIBUTE)), attr->pValue, attr->ulValueLen );
#else
      // We need to swap the values.
      pd = (unsigned char *)(ptr + sizeof(ATTRIBUTE));
      ps = (unsigned char *)(attr->pValue);


#if __64BIT__
      copy_attribute_value(ps,pd,attr);
#else
      memcpy(pd, ps, attr->ulValueLen);
#endif

#if __64BIT__
      if ( attr->ulValueLen == 8 ) {
#else
      if ( attr->ulValueLen == 4 ) {
#endif

         pl = (unsigned int *)attr->pValue;
         pl = (unsigned int *)ps;

#ifdef PKCS64
         ModifyAttribute(attr->type,(CK_ULONG_PTR_32)pd);
#else
         ModifyAttribute(attr->type,(CK_ULONG_PTR)pd);
#endif

      }

#endif


#if __64BIT__
      ptr += sizeof(ATTRIBUTE) + get_attrib_len(attr); // attr->ulValueLen;
#else
      ptr += sizeof(ATTRIBUTE) + attr->ulValueLen;
#endif
   }


   // append the private key template
   //
   attr = pPrivateKeyTemplate;
   for (i=0; i < ulPrivateKeyAttributeCount; i++, attr++) {
      ATTRIBUTE *p_attrib = (ATTRIBUTE *)ptr;
      unsigned char  *pd,*ps;

#ifdef PKCS64
      unsigned int *pl;
#else
      unsigned long *pl;
#endif

      p_attrib->type         = HTOCL( attr->type );
#if __64BIT__
      p_attrib->value_length = HTOCL(get_attrib_len(attr)); //attr->ulValueLen);
#else
      p_attrib->value_length = HTOCL( attr->ulValueLen );
#endif

      // BIG-ENDIAN warning:  attribute values
      //
#ifndef _BIG_ENDIAN
      memcpy( (ptr + sizeof(ATTRIBUTE)), attr->pValue, attr->ulValueLen );
#else
      // We need to swap the values.
      pd = (unsigned char *)(ptr + sizeof(ATTRIBUTE));
      ps = (unsigned char *)(attr->pValue);

#if __64BIT__
      copy_attribute_value(ps,pd,attr);
#else
      memcpy(pd, ps, attr->ulValueLen);
#endif

#if __64BIT__
      if ( attr->ulValueLen == 8 ) {
#else
      if ( attr->ulValueLen == 4 ) {
#endif

         pl = (unsigned int *)attr->pValue;
         pl = (unsigned int *)ps;

#ifdef PKCS64
         ModifyAttribute(attr->type,(CK_ULONG_PTR_32)pd);
#else
         ModifyAttribute(attr->type,(CK_ULONG_PTR)pd);
#endif

      }

#endif

#if __64BIT__
      ptr += sizeof(ATTRIBUTE) + get_attrib_len(attr); // attr->ulValueLen;
#else
      ptr += sizeof(ATTRIBUTE) + attr->ulValueLen;
#endif

   }


   repl_len = sizeof(reply);

   rc = communicate( C_GENERATEKEYPAIR, slot_id,
                      args,   req_len,
                      reply, &repl_len,
                      NULL,   0,
                      NULL,   0 );

   if (rc == CKR_OK) {
      *phPublicKey  = reply[0];
      *phPrivateKey = reply[1];
   }

   free( args );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, mech = 0x%X\n", "C_GenerateKeyPair", rc, SESSION, pMechanism->mechanism );

   if (rc == CKR_OK) {
      logit(LOG_DEBUG, "   Public  handle:  %d\n", *phPublicKey );
      logit(LOG_DEBUG, "   Private handle:  %d\n", *phPrivateKey );
   }

   logit(LOG_DEBUG, "   Public Template:\n");

   attr = pPublicKeyTemplate;
   for (i=0; i < ulPublicKeyAttributeCount; i++, attr++) {
      ptr = (CK_BYTE *)attr->pValue;

      logit(LOG_DEBUG, "   %3d:  Attribute type:  0x%08x\n", i, attr->type );
      logit(LOG_DEBUG, "         Value Length:    %08d\n",   attr->ulValueLen );

      if (attr->ulValueLen != (CK_ULONG)(-1) && (ptr != NULL))
         logit(LOG_DEBUG, "         First 4 bytes:   %02x %02x %02x %02x", ptr[0], ptr[1], ptr[2], ptr[3] );

      logit(LOG_DEBUG, "\n\n");
   }

   logit(LOG_DEBUG, "   Private Template:\n");

   attr = pPrivateKeyTemplate;
   for (i=0; i < ulPrivateKeyAttributeCount; i++, attr++) {
      ptr = (CK_BYTE *)attr->pValue;

      logit(LOG_DEBUG, "   %3d:  Attribute type:  0x%08x\n", i, attr->type );
      logit(LOG_DEBUG, "         Value Length:    %08d\n",   attr->ulValueLen );

      if (attr->ulValueLen != (CK_ULONG)(-1) && (ptr != NULL))
         logit(LOG_DEBUG, "         First 4 bytes:   %02x %02x %02x %02x", ptr[0], ptr[1], ptr[2], ptr[3] );

      logit(LOG_DEBUG, "\n\n");
   }

#endif

   return rc;
}


//
//
CK_RV SC_SignInit( ST_SESSION_HANDLE  sSession,
                  CK_MECHANISM_PTR   pMechanism,
                  CK_OBJECT_HANDLE   hKey )
{
   SignInit_Args         * args = NULL;
   HOST_SESSION_HANDLE   * node = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;



   slot_id = SLOTID;

   if (pMechanism->ulParameterLen != 0) {
#if __64BIT__
      req_len = sizeof(SignInit_Args) + get_mech_parameter_len(pMechanism); //->ulParameterLen;
#else
      req_len = sizeof(SignInit_Args) + pMechanism->ulParameterLen;
#endif
   }else
      req_len = sizeof(SignInit_Args);

   args = (SignInit_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   memset( args, 0x0, req_len );

   if (pMechanism->ulParameterLen != 0) {

      CK_BYTE *ptr = (CK_BYTE *)args + sizeof(SignInit_Args);

#ifdef _BIG_ENDIAN
      ADJUSTMECHPTR();
#else
      // FIXME  Intel 64Bit this will not work..
      memcpy( ptr, pMechanism->pParameter, pMechanism->ulParameterLen );
#endif

   }

   args->session_handle = HTOCL( SESSION               );
   args->key            = ( hKey                       );
   args->mech_type      = HTOCL( pMechanism->mechanism      );
#if __64BIT__
   args->param_len      = HTOCL( get_mech_parameter_len(pMechanism)); //->ulParameterLen );
#else
   args->param_len      = HTOCL( pMechanism->ulParameterLen );
#endif

   repl_len = 0;

   rc = communicate( C_SIGNINIT, slot_id,
                      args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

   free( args );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, mech = 0x%X\n", "C_SignInit", rc, SESSION, pMechanism->mechanism );
   logit(LOG_DEBUG, "%-25s:  hKey %d \n", "C_SignInit", hKey);
#endif

   return rc;
}


//
//
CK_RV SC_Sign( ST_SESSION_HANDLE  sSession,
              CK_BYTE_PTR        pData,
              CK_ULONG           ulDataLen,
              CK_BYTE_PTR        pSignature,
              CK_ULONG_PTR       pulSignatureLen )
{
   Sign_Args             * args  = NULL;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * ptr   = NULL;
   CK_BYTE               * reply = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pData || !pulSignatureLen)
      return CKR_ARGUMENTS_BAD;



   slot_id = SLOTID;

   req_len  = sizeof(Sign_Args) + ulDataLen;
   args = (Sign_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;
   else {
      args->session_handle = HTOCL( SESSION );
      args->data_len       = HTOCL( ulDataLen    );

      ptr = (CK_BYTE *)args + sizeof(Sign_Args);
      memcpy( ptr, pData, ulDataLen );

      if (pSignature == NULL) {
         args->length_only = TRUE;

#ifdef PKCS64
         repl_len = sizeof(CK_ULONG_32);
#else
         repl_len = sizeof(CK_ULONG);
#endif

      }
      else {
         args->length_only = FALSE;

#ifdef PKCS64
         repl_len = sizeof(CK_ULONG_32) + *pulSignatureLen;
#else
         repl_len = sizeof(CK_ULONG) + *pulSignatureLen;
#endif

      }

      reply = (CK_BYTE *)malloc( repl_len );
      if (!reply)
         rc = CKR_HOST_MEMORY;
      else {
         rc = communicate( C_SIGN, slot_id,
                            args,   req_len,
                            reply, &repl_len,
                            NULL,   0,
                            NULL,   0 );

         if (rc == CKR_OK || rc == CKR_BUFFER_TOO_SMALL) {

#ifdef PKCS64
	   *pulSignatureLen = *(CK_ULONG_32 *)reply;
#else
            memcpy( pulSignatureLen, reply, sizeof(CK_ULONG) );
#endif

            *pulSignatureLen = CTOHL( *pulSignatureLen );

            if (rc == CKR_OK && args->length_only == FALSE)

#ifdef PKCS64
	      memcpy( pSignature, reply + sizeof(CK_ULONG_32), 
                      *pulSignatureLen );
#else
               memcpy( pSignature, reply + sizeof(CK_ULONG), *pulSignatureLen );
#endif

         }
      }
   }

   if (args)
      free( args );

   if (reply)
      free( reply );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, datalen = %d\n", "C_Sign", rc, SESSION, ulDataLen );
#endif

   return rc;
}


//
//
CK_RV SC_SignUpdate ( ST_SESSION_HANDLE  sSession,
                     CK_BYTE_PTR        pPart,
                     CK_ULONG           ulPartLen )
{
   SignUpdate_Args       * args  = NULL;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * ptr   = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pPart)
      return CKR_ARGUMENTS_BAD;


   slot_id = SLOTID;

   req_len  = sizeof(SignUpdate_Args) + ulPartLen;
   args = (SignUpdate_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   args->session_handle = HTOCL( SESSION );
   args->data_len       = HTOCL( ulPartLen    );

   ptr = (CK_BYTE *)args + sizeof(SignUpdate_Args);
   memcpy( ptr, pPart, ulPartLen );

   repl_len = 0;

   rc = communicate( C_SIGNUPDATE, slot_id,
                      args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

   free( args );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, datalen = %d\n", "C_SignUpdate", rc, SESSION, ulPartLen );
#endif

   return rc;
}


//
//
CK_RV SC_SignFinal ( ST_SESSION_HANDLE  sSession,
                    CK_BYTE_PTR        pSignature,
                    CK_ULONG_PTR       pulSignatureLen )
{
   SignFinal_Args          args;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * reply = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pulSignatureLen)
      return CKR_ARGUMENTS_BAD;



   slot_id = SLOTID;

   req_len  = sizeof(SignFinal_Args);

   args.session_handle = HTOCL( SESSION );

   if (pSignature == NULL) {
      args.length_only = TRUE;

#ifdef PKCS64
      repl_len = sizeof(CK_ULONG_32);
#else
      repl_len = sizeof(CK_ULONG);
#endif

   }
   else {
      args.length_only = FALSE;

#ifdef PKCS64
      repl_len = sizeof(CK_ULONG_32) + *pulSignatureLen;
#else
      repl_len = sizeof(CK_ULONG) + *pulSignatureLen;
#endif

   }

   reply = (CK_BYTE *)malloc( repl_len );
   if (!reply)
      return CKR_HOST_MEMORY;

   rc = communicate( C_SIGNFINAL, slot_id,
                     &args,   req_len,
                     reply,  &repl_len,
                     NULL,    0,
                     NULL,    0 );

   if (rc == CKR_OK || rc == CKR_BUFFER_TOO_SMALL) {

#ifdef PKCS64
      *pulSignatureLen = *(CK_ULONG_32 *)reply;
#else
      memcpy( pulSignatureLen, reply, sizeof(CK_ULONG) );
#endif

      *pulSignatureLen = CTOHL( *pulSignatureLen );

      if (rc == CKR_OK && args.length_only == FALSE)

#ifdef PKCS64
        memcpy( pSignature, reply + sizeof(CK_ULONG_32), *pulSignatureLen );
#else
         memcpy( pSignature, reply + sizeof(CK_ULONG), *pulSignatureLen );
#endif

   }

   free( reply );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d\n", "C_SignFinal", rc, SESSION );
#endif

   return rc;
}


//
//
CK_RV SC_VerifyInit( ST_SESSION_HANDLE  sSession,
                    CK_MECHANISM_PTR   pMechanism,
                    CK_OBJECT_HANDLE   hKey )
{
   VerifyInit_Args       * args = NULL;
   HOST_SESSION_HANDLE   * node = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;



   slot_id = SLOTID;

   if (pMechanism->ulParameterLen != 0)
#if __64BIT__
      req_len = sizeof(VerifyInit_Args) + get_mech_parameter_len(pMechanism);
#else
      req_len = sizeof(VerifyInit_Args) + pMechanism->ulParameterLen;
#endif
   else
      req_len = sizeof(VerifyInit_Args);

   args = (VerifyInit_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   memset( args, 0x0, req_len );

   if (pMechanism->ulParameterLen != 0) {
      CK_BYTE *ptr = (CK_BYTE *)args + sizeof(VerifyInit_Args);
#ifdef _BIG_ENDIAN
      ADJUSTMECHPTR();
#else
      memcpy( ptr, pMechanism->pParameter, pMechanism->ulParameterLen );
#endif
   }

   args->session_handle = HTOCL( SESSION               );
   args->key            = ( hKey                       );
   args->mech_type      = HTOCL( pMechanism->mechanism      );
#if __64BIT__
   args->param_len      = HTOCL( get_mech_parameter_len(pMechanism));
#else
   args->param_len      = HTOCL( pMechanism->ulParameterLen );
#endif

   repl_len = 0;

   rc = communicate( C_VERIFYINIT, slot_id,
                      args,   req_len,
                      NULL,  &repl_len,
                      NULL,   0,
                      NULL,   0 );

   free( args );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, mech = 0x%X\n", "C_VerifyInit", rc, SESSION, pMechanism->mechanism );
#endif

   return rc;
}


//
//
CK_RV SC_Verify( ST_SESSION_HANDLE  sSession,
                CK_BYTE_PTR        pData,
                CK_ULONG           ulDataLen,
                CK_BYTE_PTR        pSignature,
                CK_ULONG           ulSignatureLen )
{
   Verify_Args           * args  = NULL;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * ptr   = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pData || !pSignature)
      return CKR_ARGUMENTS_BAD;



   slot_id = SLOTID;

   req_len  = sizeof(Verify_Args) + ulDataLen + ulSignatureLen;
   args = (Verify_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   args->session_handle = HTOCL( SESSION   );
   args->data_len       = HTOCL( ulDataLen      );
   args->signature_len  = HTOCL( ulSignatureLen );

   ptr = (CK_BYTE *)args + sizeof(Verify_Args);
   memcpy( ptr, pData, ulDataLen );

   ptr += ulDataLen;
   memcpy( ptr, pSignature, ulSignatureLen );

   repl_len = 0;

   rc = communicate( C_VERIFY, slot_id,
                      args,   req_len,
                      NULL,  &repl_len,
                      NULL,   0,
                      NULL,   0 );

   free( args );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, datalen = %d, siglen = %d\n", "C_Verify", rc, SESSION, ulDataLen, ulSignatureLen );
#endif

   return rc;
}


//
//
CK_RV SC_VerifyUpdate( ST_SESSION_HANDLE  sSession,
                      CK_BYTE_PTR        pPart,
                      CK_ULONG           ulPartLen )
{
   VerifyUpdate_Args     * args  = NULL;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * ptr   = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pPart)
      return CKR_ARGUMENTS_BAD;




   slot_id = SLOTID;

   req_len  = sizeof(VerifyUpdate_Args) + ulPartLen;
   args = (VerifyUpdate_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   args->session_handle = HTOCL( SESSION );
   args->data_len       = HTOCL( ulPartLen    );

   ptr = (CK_BYTE *)args + sizeof(VerifyUpdate_Args);
   memcpy( ptr, pPart, ulPartLen );

   repl_len = 0;

   rc = communicate( C_VERIFYUPDATE, slot_id,
                      args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

   free( args );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, datalen = %d\n", "C_VerifyUpdate", rc, SESSION, ulPartLen );
#endif

   return rc;
}


//
//
CK_RV SC_VerifyFinal( ST_SESSION_HANDLE  sSession,
                     CK_BYTE_PTR        pSignature,
                     CK_ULONG           ulSignatureLen )
{
   VerifyFinal_Args      * args;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * ptr   = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pSignature)
      return CKR_ARGUMENTS_BAD;



   req_len  = sizeof(VerifyFinal_Args) + ulSignatureLen;
   args = (VerifyFinal_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   slot_id = SLOTID;

   args->session_handle = HTOCL( SESSION   );
   args->signature_len  = HTOCL( ulSignatureLen );

   ptr = (CK_BYTE *)args + sizeof(VerifyFinal_Args);
   memcpy( ptr, pSignature, ulSignatureLen );

   repl_len = 0;
   rc = communicate( C_VERIFYFINAL, slot_id,
                      args,   req_len,
                      NULL,  &repl_len,
                      NULL,   0,
                      NULL,   0 );

   free( args );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d\n", "C_VerifyFinal", rc, SESSION );
#endif

   return rc;
}


//
//
CK_RV SC_SignRecoverInit( ST_SESSION_HANDLE  sSession,
                         CK_MECHANISM_PTR   pMechanism,
                         CK_OBJECT_HANDLE   hKey )
{
   SignRecoverInit_Args  * args = NULL;
   HOST_SESSION_HANDLE   * node = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;




   if (pMechanism->ulParameterLen != 0)
#if __64BIT__
      req_len = sizeof(SignRecoverInit_Args) + get_mech_parameter_len(pMechanism);
#else
      req_len = sizeof(SignRecoverInit_Args) + pMechanism->ulParameterLen;
#endif
   else
      req_len = sizeof(SignRecoverInit_Args);

   args = (SignRecoverInit_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   slot_id = SLOTID;

   args->session_handle = HTOCL( SESSION               );
   args->key            = ( hKey                       );
   args->mech_type      = HTOCL( pMechanism->mechanism      );
#if __64BIT__
   args->param_len      = HTOCL( get_mech_parameter_len(pMechanism));
#else
   args->param_len      = HTOCL( pMechanism->ulParameterLen );
#endif

   if (pMechanism->ulParameterLen != 0) {
      CK_BYTE *ptr = (CK_BYTE *)args + sizeof(SignRecoverInit_Args);
#ifdef _BIG_ENDIAN
      ADJUSTMECHPTR();
#else
      memcpy( ptr, pMechanism->pParameter, pMechanism->ulParameterLen );
#endif
   }

   repl_len = 0;
   rc = communicate( C_SIGNRECOVERINIT, slot_id,
                      args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

   free( args );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, mech = 0x%X\n", "C_SignRecoverInit", rc, SESSION, pMechanism->mechanism );
#endif

   return rc;
}


//
//
CK_RV SC_SignRecover( ST_SESSION_HANDLE  sSession,
                     CK_BYTE_PTR        pData,
                     CK_ULONG           ulDataLen,
                     CK_BYTE_PTR        pSignature,
                     CK_ULONG_PTR       pulSignatureLen )
{
   SignRecover_Args      * args  = NULL;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * ptr   = NULL;
   CK_BYTE               * reply = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pData || !pulSignatureLen)
      return CKR_ARGUMENTS_BAD;



   req_len  = sizeof(SignRecover_Args) + ulDataLen;
   args = (SignRecover_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   slot_id = SLOTID;

   args->session_handle = HTOCL( SESSION );
   args->data_len       = HTOCL( ulDataLen    );

   ptr = (CK_BYTE *)args + sizeof(SignRecover_Args);
   memcpy( ptr, pData, ulDataLen );

   if (pSignature == NULL) {
      args->length_only = TRUE;

#ifdef PKCS64
      repl_len = sizeof(CK_ULONG_32);
#else
      repl_len = sizeof(CK_ULONG);
#endif

   }
   else {
      args->length_only = FALSE;

#ifdef PKCS64
      repl_len = sizeof(CK_ULONG_32) + *pulSignatureLen;
#else
      repl_len = sizeof(CK_ULONG) + *pulSignatureLen;
#endif

   }

   reply = (CK_BYTE *)malloc( repl_len );
   if (!reply) {
      rc = CKR_HOST_MEMORY;
   }
   else {
      rc = communicate( C_SIGNRECOVER, slot_id,
                         args,   req_len,
                         reply, &repl_len,
                         NULL,   0,
                         NULL,   0 );

      if (rc == CKR_OK || rc == CKR_BUFFER_TOO_SMALL) {

#ifdef PKCS64
         *pulSignatureLen = *(CK_ULONG_32 *)reply;
#else
         memcpy( pulSignatureLen, reply, sizeof(CK_ULONG) );
#endif

         *pulSignatureLen = CTOHL( *pulSignatureLen );

         if (rc == CKR_OK && args->length_only == FALSE)

#ifdef PKCS64
            memcpy( pSignature, reply + sizeof(CK_ULONG_32), *pulSignatureLen );
#else
            memcpy( pSignature, reply + sizeof(CK_ULONG), *pulSignatureLen );
#endif

      }
   }

   if (args)
      free( args );

   if (reply)
      free( reply );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, datalen = %d\n", "C_SignRecover", rc, SESSION, ulDataLen );
#endif

   return rc;
}


//
//
CK_RV SC_VerifyRecoverInit( ST_SESSION_HANDLE  sSession,
                           CK_MECHANISM_PTR   pMechanism,
                           CK_OBJECT_HANDLE   hKey )
{
   VerifyRecoverInit_Args  * args = NULL;
   HOST_SESSION_HANDLE     * node = NULL;
   CK_SLOT_ID                slot_id;
   CK_ULONG                  req_len, repl_len;
   CK_RV                     rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;



   if (pMechanism->ulParameterLen != 0)
#if __64BIT__
      req_len = sizeof(VerifyRecoverInit_Args) + get_mech_parameter_len(pMechanism);
#else
      req_len = sizeof(VerifyRecoverInit_Args) + pMechanism->ulParameterLen;
#endif
   else
      req_len = sizeof(VerifyRecoverInit_Args);

   args = (VerifyRecoverInit_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   args->session_handle = HTOCL( SESSION               );
   args->key            = ( hKey                       );
   args->mech_type      = HTOCL( pMechanism->mechanism      );
#if __64BIT__
   args->param_len      = HTOCL( get_mech_parameter_len(pMechanism));
#else
   args->param_len      = HTOCL( pMechanism->ulParameterLen );
#endif

   slot_id = SLOTID;

   if (pMechanism->ulParameterLen != 0) {
      CK_BYTE *ptr = (CK_BYTE *)args + sizeof(VerifyRecoverInit_Args);
#ifdef _BIG_ENDIAN
      ADJUSTMECHPTR();
#else
      memcpy( ptr, pMechanism->pParameter, pMechanism->ulParameterLen );
#endif

   }

   repl_len = 0;
   rc = communicate( C_VERIFYRECOVERINIT, slot_id,
                      args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

   free( args );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, mech = 0x%X\n", "C_VerifyRecoverInit", rc, SESSION, pMechanism->mechanism );
#endif

   return rc;
}


//
//
CK_RV SC_VerifyRecover( ST_SESSION_HANDLE  sSession,
                       CK_BYTE_PTR        pSignature,
                       CK_ULONG           ulSignatureLen,
                       CK_BYTE_PTR        pData,
                       CK_ULONG_PTR       pulDataLen )
{
   VerifyRecover_Args    * args  = NULL;
   HOST_SESSION_HANDLE   * node  = NULL;
   CK_BYTE               * ptr   = NULL;
   CK_BYTE               * reply = NULL;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len, repl_len;
   CK_RV                   rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pSignature || !pulDataLen)
      return CKR_ARGUMENTS_BAD;


   req_len  = sizeof(VerifyRecover_Args) + ulSignatureLen;
   args = (VerifyRecover_Args *)malloc( req_len );
   if (!args) {
      rc = CKR_HOST_MEMORY;
   }
   else {
      slot_id = SLOTID;

      args->session_handle = HTOCL( SESSION   );
      args->signature_len  = HTOCL( ulSignatureLen );

      ptr = (CK_BYTE *)args + sizeof(VerifyRecover_Args);
      memcpy( ptr, pSignature, ulSignatureLen );


      if (!pData) {
         args->length_only = TRUE;

#ifdef PKCS64
         repl_len = sizeof(CK_ULONG_32);
#else
         repl_len = sizeof(CK_ULONG);
#endif

      }
      else {
         args->length_only = FALSE;

#ifdef PKCS64
         repl_len = sizeof(CK_ULONG_32) + *pulDataLen;
#else
         repl_len = sizeof(CK_ULONG) + *pulDataLen;
#endif

      }

      reply = (CK_BYTE *)malloc( repl_len );
      if (!reply) {
         rc = CKR_HOST_MEMORY;
      }
      else {
         rc = communicate( C_VERIFYRECOVER, slot_id,
                            args,  req_len,
                            reply, &repl_len,
                            NULL,   0,
                            NULL,   0 );

         if (rc == CKR_OK || rc == CKR_BUFFER_TOO_SMALL) {

#ifdef PKCS64
	   *pulDataLen = *(CK_ULONG_32 *)reply;
#else
            memcpy( pulDataLen, reply, sizeof(CK_ULONG) );
#endif

            *pulDataLen = CTOHL( *pulDataLen );

            if (rc == CKR_OK && args->length_only == FALSE)

#ifdef PKCS64
               memcpy( pData, reply + sizeof(CK_ULONG_32), *pulDataLen );
#else
               memcpy( pData, reply + sizeof(CK_ULONG), *pulDataLen );
#endif

         }
      }
   }


   if (args)
      free( args );

   if (reply)
      free( reply );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, recover len = %d\n", "C_VerifyRecover", rc, SESSION, *pulDataLen );
#endif

   return rc;
}


//
//
CK_RV SC_GetOperationState( ST_SESSION_HANDLE  sSession,
                           CK_BYTE_PTR        pOperationState,
                           CK_ULONG_PTR       pulOperationStateLen )
{
   GetOperationState_Args  args;
   HOST_SESSION_HANDLE     *node = NULL;
   CK_BYTE                 *reply;
   CK_SLOT_ID              slot_id;
   CK_ULONG                req_len;
   CK_ULONG                repl_len;
   CK_RV                   rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pulOperationStateLen)
      return CKR_ARGUMENTS_BAD;


   slot_id = SLOTID;

   args.session_handle = HTOCL( SESSION );

   if (pOperationState == NULL) {
      args.length_only = TRUE;

#ifdef PKCS64
      repl_len = sizeof(CK_ULONG_32);
#else
      repl_len = sizeof(CK_ULONG);
#endif

   }
   else {
      args.length_only = FALSE;

#ifdef PKCS64
      repl_len = sizeof(CK_ULONG_32) + *pulOperationStateLen;
#else
      repl_len = sizeof(CK_ULONG) + *pulOperationStateLen;
#endif

   }

   reply = (CK_BYTE *)malloc(repl_len);
   if (!reply)
      return CKR_HOST_MEMORY;

   req_len = sizeof(args);


   rc = communicate( C_GETOPERATIONSTATE, slot_id,
                      &args,  req_len,
                      reply, &repl_len,
                      NULL,   0,
                      NULL,   0 );


   if (rc == CKR_OK) {
#ifndef _BIG_ENDIAN
      memcpy( pulOperationStateLen, reply, sizeof(CK_ULONG) );
#else
      {

#ifdef PKCS64
         CK_ULONG_32 tLen; 
         
         tLen = *(CK_ULONG_32 *)reply;
#else                  
         CK_ULONG tLen; 
         
         memcpy( &tLen, reply, sizeof(CK_ULONG) );
#endif

         tLen = CTOHL(tLen);
         *pulOperationStateLen = tLen;
      }
#endif

      if (args.length_only == FALSE) 

#ifdef PKCS64
         memcpy( pOperationState, reply + sizeof(CK_ULONG_32), *pulOperationStateLen );
#else
         memcpy( pOperationState, reply + sizeof(CK_ULONG), *pulOperationStateLen );
#endif

   }

   free( reply );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d\n", "C_GetOperationState", rc, SESSION );
#endif

   return rc;
}


//
//
CK_RV SC_SetOperationState( ST_SESSION_HANDLE  sSession,
                           CK_BYTE_PTR        pOperationState,
                           CK_ULONG           ulOperationStateLen,
                           CK_OBJECT_HANDLE   hEncryptionKey,
                           CK_OBJECT_HANDLE   hAuthenticationKey )
{
   SetOperationState_Args  *args = NULL;
   HOST_SESSION_HANDLE     *node = NULL;
   CK_SLOT_ID               slot_id;
   CK_ULONG                 req_len, repl_len;
   CK_RV                    rc;

   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pOperationState)
      return CKR_ARGUMENTS_BAD;


   slot_id = SLOTID;

   req_len  = sizeof(SetOperationState_Args) + ulOperationStateLen;
   repl_len = 0;

   args = (SetOperationState_Args *)malloc( req_len );
   if (!args)
      return CKR_HOST_MEMORY;

   args->session_handle = HTOCL( SESSION );
   args->encr_key       = (hEncryptionKey);
   args->auth_key       = (hAuthenticationKey);
   args->data_len       = HTOCL( ulOperationStateLen );

   memcpy( (CK_BYTE *)args + sizeof(SetOperationState_Args), pOperationState, ulOperationStateLen );

   rc = communicate( C_SETOPERATIONSTATE, slot_id,
                      args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

   free( args );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d\n", "C_SetOperationState", rc, SESSION );
#endif

   return rc;
}


//
//
CK_RV SC_InitToken( CK_SLOT_ID   sid,
                   CK_CHAR_PTR  pPin,
                   CK_ULONG     ulPinLen,
                   CK_CHAR_PTR  pLabel )
{
   InitToken_Args    *args = NULL;
   CK_ULONG           req_len, repl_len;
   CK_RV              rc;

   // Normalize to stdll slot index
   CK_SLOT_ID   slotID;
   SLT_CHECK;

   slotID = slot_id;



   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pPin || !pLabel)
      return CKR_FUNCTION_FAILED;

   req_len  = sizeof(InitToken_Args) + ulPinLen;
   repl_len = 0;

   args = (InitToken_Args *)malloc(req_len);
   if (!args)
      return CKR_HOST_MEMORY;

   memcpy( args->label, pLabel, 32 );

   args->so_pin_len = HTOCL( ulPinLen );

   memcpy( (CK_BYTE *)args + sizeof(InitToken_Args), pPin, ulPinLen );

   rc = communicate( C_INITTOKEN, slotID,
                      args,  req_len,
                      NULL, &repl_len,
                      NULL,  0,
                      NULL,  0 );

   free( args );

#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x\n", "C_InitToken", rc );
#endif

   return rc;
}



//
//
//CK_RV C_DeriveKey( CK_SESSION_HANDLE     hSession,
//                   CK_MECHANISM_PTR      pMechanism,
//                   CK_OBJECT_HANDLE      hBaseKey,
//                   CK_ATTRIBUTE_PTR      pTemplate,
//                   CK_ULONG              ulAttributeCount,
//                   CK_OBJECT_HANDLE_PTR  phKey )
//{
//   DeriveKey_Args       * args;
//   HOST_SESSION_HANDLE  * node = NULL;
//   CK_ATTRIBUTE         * attr = NULL;
//   CK_BYTE              * ptr  = NULL;
//   CK_SLOT_ID             slot_id;
//   CK_ULONG               req_len, repl_len;
//   CK_ULONG               tmpl_len, i;
//   CK_RV                  rc;
//   CK_BYTE              * reply = NULL;
//
//
//   if (Initialized() == FALSE)
//      return CKR_CRYPTOKI_NOT_INITIALIZED;
//
//   if (!pMechanism || !phKey)
//      return CKR_ARGUMENTS_BAD;
//
//   node = findSession( hSession );
//   if (!node)
//      return CKR_SESSION_HANDLE_INVALID;
//
//
//   slot_id = node->slot_id;
//
//   //
//   // figure out how much memory to allocate for the request block
//   //
//
//   // compute the total template size
//   //
//   tmpl_len = 0;
//   for (attr = pTemplate, i = 0; i < ulAttributeCount; i++, attr++)
//      tmpl_len += sizeof(ATTRIBUTE) + attr->ulValueLen;
//
//   req_len = sizeof(DeriveKey_Args) + pMechanism->ulParameterLen + tmpl_len;
//
//   // The mechanism parameter for certain mechanisms contains pointers to
//   // other things; in those cases, we have to add those things to the
//   // request and adjust the request length accordingly, then copy those
//   // things to the request...
//   //
//   // Simlarly, the information returned for certain mechanisms consists of
//   // more than just a key handle.  We have to anticipate this when we
//   // allocate space to hold the reply...
//   //
//   // CKM_SSL3_MASTER_KEY_DERIVE -
//   //
//   // Parameter block (CK_SSL3_MASTER_KEY_DERIVE_PARAMS):
//   //    space for remote copy of pClientRandom  <-+
//   //    ulClientRandomLen                         |
//   //    space for remote copy of pServerRandom    +- ulParameterLen
//   //    ulServerRandomLen                         |
//   //    space for remote copy of pVersion       <-+
//   //    buffer[ulClientRandomLen] (client random data)
//   //    buffer[ulServerRandomLen] (server random data)
//   //
//   // Reply block:
//   //    object handle for master key
//   //    updated version information (sizeof(CK_VERSION))//   //
//   // CKM_SSL3_KEY_AND_MAC_DERIVE -
//   //
//   // Parameter block (CK_SSL3_KEY_MAT_PARAMS):
//   //    ulMacSizeInBits                               <-+
//   //    ulKeySizeInBits                                 |
//   //    ulIVSizeInBits                                  |
//   //    bIsExport                                       |
//   //    space for remote copy of pClientRandom          +- ulParameterLen
//   //    ulClientRandomLen                               |
//   //    space for remote copy of pServerRandom          |
//   //    ulServerRandomLen                               |
//   //    space for remote copy of pReturnedKeyMaterial <-+
//   //    buffer[ulClientRandomLen] (client random data)
//   //    buffer[ulServerRandomLen] (server random data)
//   //
//   // Reply block (CK_SSL3_KEY_MAT_OUT):
//   //    object handle for client MAC secret key
//   //    object handle for server MAC secret key
//   //    object handle for client secret key
//   //    object handle for server secret key
//   //    space for remote copy of pIVClient
//   //    space for remote copy of pIVServer
//   //    buffer[(ulIVSizeInBits + 7)/8] (client IV)
//   //    buffer[(ulIVSizeInBits + 7)/8] (server IV)
//   //
//   switch( pMechanism->mechanism )
//   {
//      case CKM_SSL3_MASTER_KEY_DERIVE:
//      {
//         CK_SSL3_MASTER_KEY_DERIVE_PARAMS * pPtr =
//            (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *)pMechanism->pParameter;
//
//         req_len += pPtr->RandomInfo.ulClientRandomLen
//                  + pPtr->RandomInfo.ulServerRandomLen;
//
//         repl_len = sizeof(CK_OBJECT_HANDLE) + sizeof(CK_VERSION);
//         break;
//      }
//
//      case CKM_SSL3_KEY_AND_MAC_DERIVE:
//      {
//         CK_SSL3_KEY_MAT_PARAMS * pPtr =
//            (CK_SSL3_KEY_MAT_PARAMS *)pMechanism->pParameter;
//
//         req_len += pPtr->RandomInfo.ulClientRandomLen
//                  + pPtr->RandomInfo.ulServerRandomLen;
//
//         repl_len = 4*sizeof(CK_OBJECT_HANDLE)
//                  + 2*sizeof(CK_BYTE_PTR)
//                  + 2*((pPtr->ulIVSizeInBits + 7)/8);
//         break;
//      }
//      default:
//         repl_len = sizeof(CK_OBJECT_HANDLE);
//         break;
//   }
//
//   args = (DeriveKey_Args *)malloc( req_len );
//   if (!args)
//      return CKR_HOST_MEMORY;
//
//   reply = (CK_BYTE *)malloc( repl_len );
//   if (!reply) {
//      free( args );
//      return CKR_HOST_MEMORY;
//   }
//
//   args->session_handle      = HTOCL( node->handle               );
//   args->mech_type           = HTOCL( pMechanism->mechanism      );
//   args->mech_param_len      = HTOCL( pMechanism->ulParameterLen );
//   args->base_key            = hBaseKey;
//   args->attribute_count     = HTOCL( ulAttributeCount           );
//   args->attribute_block_len = HTOCL( tmpl_len                   );
//
//   ptr = (CK_BYTE *)args + sizeof(DeriveKey_Args);
//
//   if (pMechanism->ulParameterLen != 0) {
//      // WARNING:  again, for BIG-ENDIAN machines, it might be necessary
//      // to ensure the parameter has the correct endianness if it is to
//      // be interpretted as something other than a byte array
//      //
//      memcpy( ptr, pMechanism->pParameter, pMechanism->ulParameterLen );
//      ptr += pMechanism->ulParameterLen;
//   }
//
//   // Insert mechanism-specific "flattened" pointer info...
//   //
//   switch( pMechanism->mechanism )
//   {
//      case CKM_SSL3_MASTER_KEY_DERIVE:
//      {
//         CK_SSL3_MASTER_KEY_DERIVE_PARAMS * pPtr =
//            (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *)pMechanism->pParameter;
//
//         memcpy( ptr,
//                 pPtr->RandomInfo.pClientRandom,
//                 pPtr->RandomInfo.ulClientRandomLen );
//
//         ptr += pPtr->RandomInfo.ulClientRandomLen;
//
//         memcpy( ptr,
//                 pPtr->RandomInfo.pServerRandom,
//                 pPtr->RandomInfo.ulServerRandomLen );
//
//         ptr += pPtr->RandomInfo.ulServerRandomLen;
//
//         break;
//      }
//      case CKM_SSL3_KEY_AND_MAC_DERIVE:
//      {
//         CK_SSL3_KEY_MAT_PARAMS * pPtr =
//            (CK_SSL3_KEY_MAT_PARAMS *)pMechanism->pParameter;
//
//         memcpy( ptr,
//                 pPtr->RandomInfo.pClientRandom,
//                 pPtr->RandomInfo.ulClientRandomLen );
//
//         ptr += pPtr->RandomInfo.ulClientRandomLen;
//
//         memcpy( ptr,
//                 pPtr->RandomInfo.pServerRandom,
//                 pPtr->RandomInfo.ulServerRandomLen );
//
//         ptr += pPtr->RandomInfo.ulServerRandomLen;
//
//         break;
//      }
//      default:
//         break;
//   }
//
//   // insert the attribute template into the request
//   //
//   attr = pTemplate;
//
//   for (i=0; i < ulAttributeCount; i++, attr++) {
//      ATTRIBUTE *p_attrib = (ATTRIBUTE *)ptr;
//
//      p_attrib->type         = HTOCL( attr->type );
//      p_attrib->value_length = HTOCL( attr->ulValueLen );
//
//      // BIG-ENDIAN warning.  Same here...
//      //
//      memcpy( (ptr + sizeof(ATTRIBUTE)), attr->pValue, attr->ulValueLen );
//
//      ptr += sizeof(ATTRIBUTE) + attr->ulValueLen;
//   }
//
//   rc = communicate( C_DERIVEKEY, slot_id,
//                      args,   req_len,
//                      reply, &repl_len,
//                      NULL,   0,
//                      NULL,   0 );
//
//   free( args );
//
//   // Copy returned information to appropriate destination
//   //
//   switch( pMechanism->mechanism )
//   {
//      case CKM_SSL3_MASTER_KEY_DERIVE:
//      {
//         CK_SSL3_MASTER_KEY_DERIVE_PARAMS * pPtr =
//            (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *)pMechanism->pParameter;
//
//         // Update version information in mechanism parameter
//         //
//         memcpy( pPtr->pVersion,
//                 reply + sizeof(CK_OBJECT_HANDLE),
//                 sizeof(CK_VERSION) );
//
//         // Return handle of derived key
//         //
//         memcpy( phKey, reply, sizeof(CK_OBJECT_HANDLE) );
//
//         break;
//      }
//
//      case CKM_SSL3_KEY_AND_MAC_DERIVE:
//      {
//        CK_SSL3_KEY_MAT_OUT *pPtr =
//           ((CK_SSL3_KEY_MAT_PARAMS *)
//           (pMechanism->pParameter))->pReturnedKeyMaterial;
//
//        CK_ULONG IVlen =
//           (repl_len - 2*sizeof(CK_BYTE_PTR) - 4*sizeof(CK_OBJECT_HANDLE))/2;
//
//        // Copy object handles from reply to user's buffer
//        //
//        memcpy( pPtr,
//                reply,
//                4*sizeof(CK_OBJECT_HANDLE) );
//
//        // If IV length was nonzero, copy IVs from reply to
//        // user's buffer
//        //
//        if (IVlen != 0)
//        {
//          memcpy( pPtr->pIVClient,
//                  reply + 4*sizeof(CK_OBJECT_HANDLE),
//                  IVlen );
//          memcpy( pPtr->pIVServer,
//                  reply + 4*sizeof(CK_OBJECT_HANDLE) + IVlen,
//                  IVlen );
//        }
//
//        break;
//      }
//
//      default:
//         break;
//   }
//
//   free( reply );
//
//#ifdef DEBUGON
//   LOG_DEBUG = fopen( DEBUGFILEPATH, "a" );
//   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, handle = %d, mech = %x\n", "C_DeriveKey", rc, node->handle, *phKey, pMechanism->mechanism );
//
//   attr = pTemplate;
//   for (i=0; i < ulAttributeCount; i++, attr++) {
//      ptr = (CK_BYTE *)attr->pValue;
//
//      logit(LOG_DEBUG, "   %3d:  Attribute type:  0x%08x\n", i, attr->type );
//      logit(LOG_DEBUG, "         Value Length:    %08d\n",   attr->ulValueLen );
//
//      if (attr->ulValueLen != (CK_ULONG)(-1) && (ptr != NULL))
//         logit(LOG_DEBUG, "         First 4 bytes:   %02x %02x %02x %02x", ptr[0], ptr[1], ptr[2], ptr[3] );
//
//      logit(LOG_DEBUG, "\n\n");
//   }
//
//   fflush(LOG_DEBUG);
//   fclose(LOG_DEBUG);
//#endif
//
//   return rc;
//}



CK_RV SC_DeriveKey( ST_SESSION_HANDLE     sSession,
                   CK_MECHANISM_PTR      pMechanism,
                   CK_OBJECT_HANDLE      hBaseKey,
                   CK_ATTRIBUTE_PTR      pTemplate,
                   CK_ULONG              ulAttributeCount,
                   CK_OBJECT_HANDLE_PTR  phKey )
{
   DeriveKey_Args       * args  = NULL;
   HOST_SESSION_HANDLE  * node  = NULL;
   CK_ATTRIBUTE         * attr  = NULL;
   CK_BYTE              * reply = NULL;
   CK_BYTE              * param = NULL;
   CK_BYTE              * ptr   = NULL;
   CK_SLOT_ID             slot_id;
   CK_ULONG               req_len, repl_len, param_len;
   CK_ULONG               tmpl_len, i;
   CK_RV                  rc;
   SESS_SET    // this must be at the end of the local variable defs

   if (Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (!pMechanism )
      return CKR_ARGUMENTS_BAD;

   // pHkey can be null if the mechanism is SSL3_KEY_AND_MAC_DERIVE
   if ( !phKey && (pMechanism->mechanism != CKM_SSL3_KEY_AND_MAC_DERIVE))
      return CKR_ARGUMENTS_BAD;



   slot_id = SLOTID;


   // compute the total template size
   //
   tmpl_len = 0;
#if __64BIT__
   for (attr = pTemplate, i = 0; i < ulAttributeCount; i++, attr++)
      tmpl_len += sizeof(ATTRIBUTE) + get_attrib_len(attr); // attr->ulValueLen;
#else
   for (attr = pTemplate, i = 0; i < ulAttributeCount; i++, attr++)
      tmpl_len += sizeof(ATTRIBUTE) + attr->ulValueLen;
#endif

   //
   // some of the SSL3 mechanisms have mechanism parameters complicated by
   // pointers to other structures.  we need to flatten these out before we
   // can send it to the card.  we do this in two steps.  first step is to
   // compute the length of the overall request block sent to the card.
   // second step fills in the mechanism-specific data
   //

   // step 1 -- get the request block length and the expected reply block length
   //
   switch (pMechanism->mechanism) {

#if defined(ENABLE_DH)
      case CKM_DH_PKCS_DERIVE:
         {
            param_len = pMechanism->ulParameterLen;
            param = (CK_BYTE *)malloc( param_len );
            if (!param) {
               rc = CKR_HOST_MEMORY;
               goto error;
            }

            memcpy( param, pMechanism->pParameter, param_len );

            req_len = sizeof(DeriveKey_Args) + param_len + tmpl_len;

#ifdef PKCS64
            repl_len = sizeof(CK_OBJECT_HANDLE_32);
#else
            repl_len = sizeof(CK_OBJECT_HANDLE);
#endif
         }
         break;
#endif

      case CKM_MD2_KEY_DERIVATION:
      case CKM_MD5_KEY_DERIVATION:
      case CKM_SHA1_KEY_DERIVATION:
         // no mechanism-specific parameters 
         //
         param_len = 0;
         req_len = sizeof(DeriveKey_Args) + tmpl_len;
#ifdef PKCS64
         repl_len = sizeof(CK_OBJECT_HANDLE_32);
#else
         repl_len = sizeof(CK_OBJECT_HANDLE);
#endif
         break;

      case CKM_SSL3_MASTER_KEY_DERIVE:
         {
            SSL3_MASTER_KEY_DERIVE_PARAMS    *p;
            CK_SSL3_MASTER_KEY_DERIVE_PARAMS *ptr;

            ptr = (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *)pMechanism->pParameter;

            // SAB  XXX XXX 64BIT... 
            // noting special needed since the 
            // Random len is length of a byte string
            param_len = sizeof(SSL3_MASTER_KEY_DERIVE_PARAMS) +
                        ptr->RandomInfo.ulClientRandomLen +
                        ptr->RandomInfo.ulServerRandomLen;
            

            param = (CK_BYTE *)malloc( param_len );
            if (!param) {
               rc = CKR_HOST_MEMORY;
               goto error;
            }

            // XXX  64BIT
            // No special 64 bit stuff since this is not a CK_ structure
            //  
            p = (SSL3_MASTER_KEY_DERIVE_PARAMS *)param;

            p->version.major   = 3; // this is ignored by the card
            p->version.minor   = 0; // this is ignored by the card
            p->client_data_len = HTOCL( ptr->RandomInfo.ulClientRandomLen );
            p->server_data_len = HTOCL( ptr->RandomInfo.ulServerRandomLen );

            memcpy( param + sizeof(SSL3_MASTER_KEY_DERIVE_PARAMS),
                    ptr->RandomInfo.pClientRandom,
                    ptr->RandomInfo.ulClientRandomLen );

            memcpy( param + sizeof(SSL3_MASTER_KEY_DERIVE_PARAMS) +
                            ptr->RandomInfo.ulClientRandomLen,
                    ptr->RandomInfo.pServerRandom,
                    ptr->RandomInfo.ulServerRandomLen );

            req_len  = sizeof(DeriveKey_Args) + tmpl_len + param_len;

#ifdef PKCS64
            repl_len = sizeof(CK_OBJECT_HANDLE_32) + sizeof(CK_VERSION);
#else
            repl_len = sizeof(CK_OBJECT_HANDLE) + sizeof(CK_VERSION);
#endif

         }
         break;

      case CKM_SSL3_KEY_AND_MAC_DERIVE:
         {
            CK_SSL3_KEY_MAT_PARAMS *ptr;
            SSL3_KEY_MAT_PARAMS    *p;
            CK_ULONG                iv_len;

            ptr = (CK_SSL3_KEY_MAT_PARAMS *)pMechanism->pParameter;

            param_len = sizeof(SSL3_KEY_MAT_PARAMS) +
                        ptr->RandomInfo.ulClientRandomLen +
                        ptr->RandomInfo.ulServerRandomLen;

            iv_len   = (ptr->ulIVSizeInBits + 7) / 8;

            param = (CK_BYTE *)malloc( param_len );
            if (!param) {
               rc = CKR_HOST_MEMORY;
               goto error;
            }

            p = (SSL3_KEY_MAT_PARAMS *)param;

            p->mac_size_bits   = HTOCL( ptr->ulMacSizeInBits );
            p->key_size_bits   = HTOCL( ptr->ulKeySizeInBits );
            p->iv_size_bits    = HTOCL( ptr->ulIVSizeInBits  );
            p->export          = ptr->bIsExport;
            p->client_data_len = HTOCL( ptr->RandomInfo.ulClientRandomLen );
            p->server_data_len = HTOCL( ptr->RandomInfo.ulServerRandomLen );

            memcpy( param + sizeof(SSL3_KEY_MAT_PARAMS),
                    ptr->RandomInfo.pClientRandom,
                    ptr->RandomInfo.ulClientRandomLen);

            memcpy( param + sizeof(SSL3_KEY_MAT_PARAMS) +
                            ptr->RandomInfo.ulClientRandomLen,
                    ptr->RandomInfo.pServerRandom,
                    ptr->RandomInfo.ulServerRandomLen );

            req_len  = sizeof(DeriveKey_Args) + tmpl_len + param_len;
            repl_len = sizeof(SSL3_KEY_MAT_OUT) + (2 * iv_len);
         }
         break;

      default:
         rc = CKR_MECHANISM_INVALID;
         goto error;
   }

   args = (DeriveKey_Args *)malloc( req_len );
   if (!args) {
      rc = CKR_HOST_MEMORY;
      goto error;
   }

   reply = (CK_BYTE *)malloc( repl_len );
   if (!reply) {
      rc = CKR_HOST_MEMORY;
      goto error;
   }

   args->session_handle      = HTOCL( SESSION               );
   args->mech_type           = HTOCL( pMechanism->mechanism      );
#if __64BIT__
   args->mech_param_len      = HTOCL( get_mech_parameter_len(pMechanism)); // XXX 64Bit
#else
   args->mech_param_len      = HTOCL( pMechanism->ulParameterLen );
#endif
   args->base_key            = hBaseKey;
   args->attribute_count     = HTOCL( ulAttributeCount           );
   args->attribute_block_len = HTOCL( tmpl_len                   );

   ptr = (CK_BYTE *)args + sizeof(DeriveKey_Args);

   // insert the mechanism parameter
   //
   memcpy( ptr, param, param_len );
   ptr += param_len;

   free( param );
   param = NULL;
   // insert the attribute template into the request
   //
   attr = pTemplate;
   for (i=0; i < ulAttributeCount; i++, attr++) {
      ATTRIBUTE *p_attrib = (ATTRIBUTE *)ptr;

      p_attrib->type         = HTOCL( attr->type );

#if __64BIT__
      p_attrib->value_length = HTOCL(get_attrib_len(attr)); //attr->ulValueLen);
#else
      p_attrib->value_length = HTOCL( attr->ulValueLen );
#endif

      // BIG-ENDIAN warning.  Same here...
      //
#ifndef _BIG_ENDIAN
      memcpy( (ptr + sizeof(ATTRIBUTE)), attr->pValue, attr->ulValueLen );
#else
{
      unsigned char  *pd,*ps;
      unsigned long *pl;

      // We need to swap the values.
      pd = (unsigned char *)(ptr + sizeof(ATTRIBUTE));
      ps = (unsigned char *)(attr->pValue);


#if __64BIT__
      copy_attribute_value(ps,pd,attr);
#else
      memcpy(pd, ps, attr->ulValueLen);
#endif

#if __64BIT__
      if ( attr->ulValueLen == 8 ) {
#else
      if ( attr->ulValueLen == 4 ) {
#endif
         pl = (unsigned long *)attr->pValue;
         pl = (unsigned long *)ps;

#ifdef PKCS64
         ModifyAttribute(attr->type,(CK_ULONG_PTR_32)pd);
#else
         ModifyAttribute(attr->type,(CK_ULONG_PTR)pd);
#endif

      }

}
#endif


#if __64BIT__
      ptr += sizeof(ATTRIBUTE) + get_attrib_len(attr); //attr->ulValueLen;
#else
      ptr += sizeof(ATTRIBUTE) + attr->ulValueLen;
#endif
   }

   rc = communicate( C_DERIVEKEY,  slot_id,
                      args,         req_len,
                      reply,       &repl_len,
                      NULL,         0,
                      NULL,         0 );

   free( args );
   args = NULL;

   if (rc != CKR_OK)
      goto error;

   // copy returned information to appropriate destination
   //
   switch (pMechanism->mechanism) {
      case CKM_SSL3_MASTER_KEY_DERIVE:
         {
            CK_SSL3_MASTER_KEY_DERIVE_PARAMS *pPtr =
                  (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *)pMechanism->pParameter;

#ifdef PKCS64
#if __64BIT__
          *phKey = (CK_ULONG_32)*reply;
#else
           memcpy( phKey, reply, sizeof(CK_OBJECT_HANDLE_32) );
#endif

#else
            memcpy( phKey, reply, sizeof(CK_OBJECT_HANDLE) );
#endif

            // Netscape's regression tests sometimes set the version pointer
            // to NULL...
            //
            if (pPtr->pVersion != NULL) {
               memcpy( pPtr->pVersion,

#ifdef PKCS64
                       reply + sizeof(CK_OBJECT_HANDLE_32),
#else
                       reply + sizeof(CK_OBJECT_HANDLE),
#endif
                       sizeof(CK_VERSION) );
            }
         }
         break;

      case CKM_SSL3_KEY_AND_MAC_DERIVE:
         {
            CK_SSL3_KEY_MAT_PARAMS *pReq;
            CK_SSL3_KEY_MAT_OUT    *pPtr;
            SSL3_KEY_MAT_OUT       *pReply;
#if __64BIT__
            CK_ULONG_32                iv_len;
#else
            CK_ULONG                iv_len;
#endif

            pReq = (CK_SSL3_KEY_MAT_PARAMS *)pMechanism->pParameter;
            iv_len = (pReq->ulIVSizeInBits + 7) / 8;

            pPtr = pReq->pReturnedKeyMaterial;

            pReply = (SSL3_KEY_MAT_OUT *)reply;

            // pReply comes from the Card, therefore it MUST
            // be endian adjusted.
            pReply->iv_len = CTOHL(pReply->iv_len);
            if (pReply->iv_len != iv_len) {
               rc = CKR_FUNCTION_FAILED;
               goto error;
            }

            pPtr->hClientMacSecret = pReply->client_mac_secret;
            pPtr->hServerMacSecret = pReply->server_mac_secret;
            pPtr->hClientKey       = pReply->client_key;
            pPtr->hServerKey       = pReply->server_key;

            ptr = (CK_BYTE *)pReply + sizeof(SSL3_KEY_MAT_OUT);

            if (iv_len) {
               memcpy( pPtr->pIVClient, ptr, iv_len );
               ptr += iv_len;
               memcpy( pPtr->pIVServer, ptr, iv_len );
            }
         }
         break;

      default:
         // any illegal mechanisms have already been filtered out by now
         //
         // JRM - please sanity check this for 64-bit correctness...
         //
#ifdef PKCS64
#if __64BIT__
         *phKey = (CK_ULONG_32)*reply;
#else
         memcpy( phKey, reply, sizeof(CK_OBJECT_HANDLE_32) );
#endif

#else
         memcpy( phKey, reply, sizeof(CK_OBJECT_HANDLE) );
#endif
         break;
   }
   free( reply );
   reply = NULL;

error:
   if (param)  free( param );
   if (args)   free( args  );
   if (reply)  free( reply );


#ifdef DEBUGON
   logit(LOG_DEBUG, "%-25s:  rc = %08x, sess = %d, base key = %d, mech = %x\n", "C_DeriveKey", rc, SESSION, hBaseKey, pMechanism->mechanism );
   logit(LOG_DEBUG, "%-25s:  requestlen %d mechparmlen %d  sizeof(DeriveKey_Args) %d passedparm %d\n", "C_DeriveKey", req_len,pMechanism->ulParameterLen,sizeof(DeriveKey_Args), param_len);

   if (rc == CKR_OK)
   switch (pMechanism->mechanism) {
      case CKM_SSL3_KEY_AND_MAC_DERIVE:
         {
            CK_SSL3_KEY_MAT_PARAMS *pReq;
            CK_SSL3_KEY_MAT_OUT    *pPtr;
            pReq = (CK_SSL3_KEY_MAT_PARAMS *)pMechanism->pParameter;
            pPtr = pReq->pReturnedKeyMaterial;

            logit(LOG_DEBUG, "   Client MAC key:  %d\n", pPtr->hClientMacSecret );
            logit(LOG_DEBUG, "   Server MAC key:  %d\n", pPtr->hServerMacSecret );
            logit(LOG_DEBUG, "   Client Key:      %d\n", pPtr->hClientKey );
            logit(LOG_DEBUG, "   Server Key:      %d\n", pPtr->hServerKey );
         }
         break;

      default:
         logit(LOG_DEBUG, "   Derived key:     %d\n", *phKey );
   }


   attr = pTemplate;
   for (i=0; i < ulAttributeCount; i++, attr++) {
      ptr = (CK_BYTE *)attr->pValue;

      logit(LOG_DEBUG, "   %3d:  Attribute type:  0x%08x\n", i, attr->type );
      logit(LOG_DEBUG, "         Value Length:    %08d\n",   attr->ulValueLen );

      if (attr->ulValueLen != (CK_ULONG)(-1) && (ptr != NULL))
         logit(LOG_DEBUG, "         First 4 bytes:   %02x %02x %02x %02x", ptr[0], ptr[1], ptr[2], ptr[3] );

      logit(LOG_DEBUG, "\n\n");
   }
#endif

   return rc;

}

#define FCV_ENABLED
#ifdef FCV_ENABLED
// This function sends a Function Control Vector to the card
//
CK_RV FCVFunction( CK_SLOT_ID sid, CK_BYTE *FCV, CK_ULONG len )
{
   CK_ULONG   req_len, repl_len, expected_repl_len;
   CK_RV      rc;
   SLT_CHECK;

   if (slot_id == 0 && Initialized() == FALSE)
      return CKR_CRYPTOKI_NOT_INITIALIZED;

   if (slot_id > MAX_SLOT_ID)
      return CKR_SLOT_ID_INVALID;

   req_len  = len;
   repl_len = expected_repl_len = 0;

   rc = communicate( FCVFUNCTION, slot_id,
                     FCV,   req_len,
                     NULL, &repl_len,
                     NULL,  0,
                     NULL,  0 );
   if (rc == CKR_OK)
   {
      if ( repl_len != expected_repl_len )
         rc = CKR_GENERAL_ERROR;
   }

#ifdef DEBUGON
	logit(LOG_DEBUG, "%-25s:  rc = %08x\n", "FCVFUNCTION", rc );
#endif

   return rc;
}
#endif

#if LINUX
void
_init()
{
printf("Initialization of leeds STDLL \n");

}
#endif
