Hi,
I have made changes to pycsc to fit my short term needs (SP Verify +
SCardControl) . The project owner JL Giraud has made a few comments and I
need to clean up the code. Still it works (Windows & Linux, not sure about
MAC) ... so I'm publishing it:
Regards,
Philippe
/***********************************************************
* Title: pycsc.c
* Author: Jean-Luc Giraud <[EMAIL PROTECTED]>
* Compiler: gcc
* Platform: Mac OS X, Linux and Windows2000
* Purpose: Python class to communicate with smart cards
* License: See file COPYING
* $Id: pycsc.c,v 1.2 2005/06/23 22:27:47 philippe Exp $
*
* Copyright (c) 2003 - Jean-Luc Giraud.
*
* MODIFIED SEPT 2004 - Philippe C. Martin - SnakeCard, LLC (T=1)
* MODIFIED APRIL 2006 - Philippe C. Martin - SnakeCard, LLC (SCardControl
+ PIN verify support)
************************************************************/
#include <Python.h>
/* Include the header files */
#ifdef __APPLE__
#include <wintypes.h>
#include <PCSC/winscard.h>
#else
#include <winscard.h>
#endif
#ifndef _WINDOWS_
#include <reader.h>
#else
#ifdef _WINDOWS_
#pragma pack(push,old_value,1)
#else
#pragma pack(push,1)
#endif
typedef struct tag_PIN_VERIFY_STRUCTURE
{
UCHAR bTimerOut;
UCHAR bTimerOut2;
UCHAR bmFormatString;
UCHAR bmPINBlockString;
UCHAR bmPINLengthFormat;
USHORT wPINMaxExtraDigit;
UCHAR bEntryValidationCondition;
UCHAR bNumberMessage;
USHORT wLangId;
UCHAR bMsgIndex;
UCHAR bTeoPrologue[3];
ULONG ulDataLength;
UCHAR abData[1];
} PIN_VERIFY_STRUCTURE;
#endif
#ifdef _WINDOWS_
#pragma pack(pop,old_value)
#else
#pragma pack(pop)
#endif
#undef DEBUG
/* Internal tool */
static LONG getReaderList(SCARDCONTEXT hContext, LPSTR* pmszReaders, DWORD
*pdwReaders);
#ifdef _WINDOWS_
/* Windows does not provide the pcsc_stringify_error function */
char ErrorString[200];
char *pcsc_stringify_error(LONG rv)
{
char strErrorCode[50];
switch(rv)
{
case SCARD_E_CANCELLED:
strcpy(strErrorCode, "SCARD_E_CANCELLED");
break;
case SCARD_E_CANT_DISPOSE:
strcpy(strErrorCode, "SCARD_E_CANT_DISPOSE");
break;
case SCARD_E_CARD_UNSUPPORTED:
strcpy(strErrorCode, "SCARD_E_CARD_UNSUPPORTED");
break;
case SCARD_E_DUPLICATE_READER:
strcpy(strErrorCode, "SCARD_E_DUPLICATE_READER");
break;
case SCARD_E_INSUFFICIENT_BUFFER:
strcpy(strErrorCode, "SCARD_E_INSUFFICIENT_BUFFER");
break;
case SCARD_E_INVALID_ATR:
strcpy(strErrorCode, "SCARD_E_INVALID_ATR");
break;
case SCARD_E_INVALID_HANDLE:
strcpy(strErrorCode, "SCARD_E_INVALID_HANDLE");
break;
case SCARD_E_INVALID_PARAMETER:
strcpy(strErrorCode, "SCARD_E_INVALID_PARAMETER");
break;
case SCARD_E_INVALID_TARGET:
strcpy(strErrorCode, "SCARD_E_INVALID_TARGET");
break;
case SCARD_E_INVALID_VALUE:
strcpy(strErrorCode, "SCARD_E_INVALID_VALUE");
break;
case SCARD_E_NOT_READY:
strcpy(strErrorCode, "SCARD_E_NOT_READY");
break;
case SCARD_E_NOT_TRANSACTED:
strcpy(strErrorCode, "SCARD_E_NOT_TRANSACTED");
break;
case SCARD_E_NO_MEMORY:
strcpy(strErrorCode, "SCARD_E_NO_MEMORY");
break;
case SCARD_E_NO_SERVICE:
strcpy(strErrorCode, "SCARD_E_NO_SERVICE");
break;
case SCARD_E_NO_SMARTCARD:
strcpy(strErrorCode, "SCARD_E_NO_SMARTCARD");
break;
case SCARD_E_PCI_TOO_SMALL:
strcpy(strErrorCode, "SCARD_E_PCI_TOO_SMALL");
break;
case SCARD_E_PROTO_MISMATCH:
strcpy(strErrorCode, "SCARD_E_PROTO_MISMATCH");
break;
case SCARD_E_READER_UNAVAILABLE:
strcpy(strErrorCode, "SCARD_E_READER_UNAVAILABLE");
break;
case SCARD_E_READER_UNSUPPORTED:
strcpy(strErrorCode, "SCARD_E_READER_UNSUPPORTED");
break;
case SCARD_E_SERVICE_STOPPED:
strcpy(strErrorCode, "SCARD_E_SERVICE_STOPPED");
break;
case SCARD_E_SHARING_VIOLATION:
strcpy(strErrorCode, "SCARD_E_SHARING_VIOLATION");
break;
case SCARD_E_SYSTEM_CANCELLED:
strcpy(strErrorCode, "SCARD_E_SYSTEM_CANCELLED");
break;
case SCARD_E_TIMEOUT:
strcpy(strErrorCode, "SCARD_E_TIMEOUT");
break;
case SCARD_E_UNKNOWN_CARD:
strcpy(strErrorCode, "SCARD_E_UNKNOWN_CARD");
break;
case SCARD_E_UNKNOWN_READER:
strcpy(strErrorCode, "SCARD_E_UNKNOWN_READER");
break;
case SCARD_F_COMM_ERROR:
strcpy(strErrorCode, "SCARD_F_COMM_ERROR");
break;
case SCARD_F_INTERNAL_ERROR:
strcpy(strErrorCode, "SCARD_F_INTERNAL_ERROR");
break;
case SCARD_F_UNKNOWN_ERROR:
strcpy(strErrorCode, "SCARD_F_UNKNOWN_ERROR");
break;
case SCARD_F_WAITED_TOO_LONG:
strcpy(strErrorCode, "SCARD_F_WAITED_TOO_LONG");
break;
case SCARD_S_SUCCESS:
strcpy(strErrorCode, "SCARD_S_SUCCESS");
break;
case SCARD_W_REMOVED_CARD:
strcpy(strErrorCode, "SCARD_W_REMOVED_CARD");
break;
case SCARD_W_RESET_CARD:
strcpy(strErrorCode, "SCARD_W_RESET_CARD");
break;
case SCARD_W_UNPOWERED_CARD:
strcpy(strErrorCode, "SCARD_W_UNPOWERED_CARD");
break;
case SCARD_W_UNRESPONSIVE_CARD:
strcpy(strErrorCode, "SCARD_W_UNRESPONSIVE_CARD");
break;
case SCARD_W_UNSUPPORTED_CARD:
strcpy(strErrorCode, "SCARD_W_UNSUPPORTED_CARD");
break;
default:
strcpy(strErrorCode, "Unknown");
}
sprintf(ErrorString, "Error returned by PCSC: 0x%08X (%s)", rv,
strErrorCode);
return ErrorString;
}
#endif
/* define MAX_ATR_SIZE for all platforms */
#ifndef MAX_ATR_SIZE
#define MAX_ATR_SIZE 300
#endif
/***********************************************************
* pycsc object structure
***********************************************************/
typedef struct
{
PyObject_HEAD
SCARDHANDLE hCard;
SCARDCONTEXT hContext;
DWORD sMode;
DWORD dwProtocol;
} pycscobject;
/* Exception used by this object */
static PyObject *PycscException;
/* Forward declaration of type descriptor */
staticforward PyTypeObject PycscType;
/***********************************************************
* Intance methods:
*
* reconnect()
* disconnect()
* status()
* control()
* transmit()
* cancel()
* beginTransaction()
* endTransaction()
* cancelTransaction()
*
***********************************************************/
static PyObject * pycsc_reconnect( PyObject *self, PyObject *args, PyObject
*keywds)
{
pycscobject *object = (pycscobject *)self;
LONG rv;
DWORD dwPreferredProtocol = SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1;
DWORD dwInitialization = SCARD_LEAVE_CARD;
DWORD pdwActiveProtocol;
static char *kwlist[] = {"smode", "protocol", "init", NULL};
object->sMode = SCARD_SHARE_SHARED; /* default value */
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|lll", kwlist,
&object->sMode, &dwPreferredProtocol,
&dwInitialization))
return NULL;
#ifdef DEBUG
printf("sMode = %ld\n",object->sMode);
printf("pProt = %ld\n",dwPreferredProtocol);
printf("init = %ld\n",dwInitialization);
printf("IN RECONNECT\n");
printf("object->sMode %d\n",object->sMode);
printf("object->dwPreferredProtocol %d\n",dwPreferredProtocol);
printf("object->dwInitialization %d\n",dwInitialization);
#endif
rv = SCardReconnect(object->hCard, object->sMode, dwPreferredProtocol,
dwInitialization, &pdwActiveProtocol);
if ( rv != SCARD_S_SUCCESS )
{
PyErr_SetString(PycscException, pcsc_stringify_error(rv));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject * pycsc_disconnect(PyObject *self, PyObject * args)
{
pycscobject *object = (pycscobject *)self;
DWORD dwDisposition = SCARD_LEAVE_CARD;
LONG rv;
if (!PyArg_ParseTuple(args,"|l", &dwDisposition))
return NULL;
rv = SCardDisconnect(object->hCard, dwDisposition);
if ( rv != SCARD_S_SUCCESS )
{
PyErr_SetString(PycscException, pcsc_stringify_error(rv));
return NULL;
}
#ifdef DEBUG
printf("pycsc_disconnect : OK\n");
#endif
Py_INCREF(Py_None);
return Py_None;
}
/* Returns a dictionary with keys as follows:
"ReaderName"
"State"
"Protocol"
"ATR"
*/
static PyObject * pycsc_status(PyObject *self, PyObject * args)
{
pycscobject *object = (pycscobject *)self;
BYTE pbAtr[MAX_ATR_SIZE];
DWORD dwAtrLen, dwProt=0, dwState=0;
DWORD dwReaderLen;
LPSTR pcReaders;
LONG rv;
PyObject *ret_value;
dwReaderLen = 10000;
dwAtrLen = 0;
/* Dry run to get the length of the reader name */
rv = SCardStatus( object->hCard, (LPSTR) NULL, &dwReaderLen,
&dwState, &dwProt, NULL, &dwAtrLen );
if ( rv != SCARD_S_SUCCESS )
{
PyErr_SetString(PycscException, pcsc_stringify_error(rv));
return NULL;
}
#ifdef DEBUG
printf("SCardStatus dry run returned dwReaderLen= %ld, dwAtrLen= %ld\n",
dwReaderLen, dwAtrLen);
#endif
pcReaders = (char *)PyMem_Malloc(sizeof(char)*dwReaderLen);
if (!pcReaders)
{
return PyErr_NoMemory();
}
/* Get values */
dwAtrLen = sizeof(pbAtr);
rv = SCardStatus( object->hCard, pcReaders, &dwReaderLen,
&dwState, &dwProt, pbAtr, &dwAtrLen );
if ( rv != SCARD_S_SUCCESS )
{
PyErr_SetString(PycscException, pcsc_stringify_error(rv));
PyMem_Free((void *)pcReaders);
return NULL;
}
#ifdef DEBUG
printf("pycsc_status : OK up to build value\n");
#endif
ret_value = Py_BuildValue("{s:s, s:i, s:i, s:s#}",
"ReaderName", pcReaders,
"State", dwState,
"Protocol", dwProt,
"ATR", pbAtr, dwAtrLen);
#ifdef DEBUG
printf("pycsc_status : OK\n");
#endif
PyMem_Free((void *)pcReaders);
return ret_value;
}
/* Retrieve SCARD_PCI_XX address from SCARD_PROTOCOL_XX constant */
static SCARD_IO_REQUEST *protocoltoPCI(DWORD dwProtocol)
{
switch (dwProtocol)
{
case SCARD_PROTOCOL_T0:
return (SCARD_IO_REQUEST *)SCARD_PCI_T0;
case SCARD_PROTOCOL_T1:
return (SCARD_IO_REQUEST *)SCARD_PCI_T1;
case SCARD_PROTOCOL_RAW:
return (SCARD_IO_REQUEST *)SCARD_PCI_RAW;
default:
PyErr_SetString(PycscException, "Unknow value of io request");
return NULL;
}
}
/* args : a string representing data to send */
static PyObject * pycsc_transmit(PyObject *self, PyObject * args,
PyObject *keywds)
{
pycscobject *object = (pycscobject *)self;
LONG rv;
unsigned long len;
unsigned char *sendBuffer;
DWORD bSendPci;
SCARD_IO_REQUEST *pioSendPci;
BYTE resparray[1024];
DWORD resplength = sizeof(resparray);
static char *kwlist[] = {"com","sendPCI", NULL};
/* Default values */
bSendPci = object->dwProtocol;
if (!PyArg_ParseTupleAndKeywords(args, keywds, "s#|l", kwlist,
&sendBuffer, &len, &bSendPci))
{
#ifdef DEBUG
printf ("ERROR PARSING PYTHON KEYWORDS\n");
#endif
return NULL;
}
pioSendPci = protocoltoPCI(bSendPci);
if (pioSendPci == NULL)
{
#ifdef DEBUG
printf ("ERROR SETTING PROTOCOL\n");
#endif
return NULL;
}
rv = SCardTransmit( object->hCard, pioSendPci, sendBuffer, len,
NULL, resparray, &resplength);
if ( rv != SCARD_S_SUCCESS )
{
#ifdef DEBUG
printf ("ERROR SCardTransmit\n");
#endif
PyErr_SetString(PycscException, pcsc_stringify_error(rv));
return NULL;
}
#ifdef DEBUG
printf ("TRANSMIT RETURNING RESULTS\n");
#endif
return Py_BuildValue("s#", resparray, resplength);
}
static PyObject * pycsc_cancel(PyObject *self, PyObject * args)
{
PyErr_SetString(PycscException, "Not implemented");
return NULL;
}
static PyObject * pycsc_beginTransaction(PyObject *self, PyObject * args)
{
PyErr_SetString(PycscException, "Not implemented");
return NULL;
}
static PyObject * pycsc_endTransaction(PyObject *self, PyObject * args)
{
PyErr_SetString(PycscException, "Not implemented");
return NULL;
}
static PyObject * pycsc_cancelTransaction(PyObject *self, PyObject * args)
{
PyErr_SetString(PycscException, "Not implemented");
return NULL;
}
//******************************************************************
static PyObject * pycsc_control(PyObject *p_self, PyObject * p_args)
{
int l_ok;
pycscobject *l_object = (pycscobject *)p_self;
unsigned long l_dwControlcode;
unsigned char * l_pbSendBuffer=NULL;
unsigned long l_cbSendLength=0;
#define B_SIZE 1024
unsigned char l_bRecvBuffer[B_SIZE];
unsigned long l_pcbRecvLength=0;
unsigned long l_lpBytesReturned=0;
long l_rv;
int i;
for (i = 0; i < B_SIZE; i += 1)
{
l_bRecvBuffer[i] = 0;
}
//#define DEBUG
// printf("SCARD_CTL_CODE(3400) = %X\n",SCARD_CTL_CODE(3400));
l_ok = PyArg_ParseTuple(p_args, "ll|s#",
&l_dwControlcode,
&l_pcbRecvLength,
&l_pbSendBuffer,
&l_cbSendLength
);
if (! l_ok)
{
PyErr_SetString(PycscException, "pycsc_control: parameters parsing
failed");
#ifdef DEBUG
printf("L_OK = %d\n",l_ok);
#endif
return NULL;
}
#ifdef DEBUG
printf("card=%x code=%x sendbuffer=%x send length=%d rec length=%d\n",
l_object->hCard,
l_dwControlcode,
l_pbSendBuffer,
l_cbSendLength,
l_pcbRecvLength);
for (i=0; i < l_cbSendLength; i += 1)
{
printf("%X ", l_pbSendBuffer[i]);
}
printf("\n");
#endif
l_rv= SCardControl (
l_object->hCard,
l_dwControlcode,
l_pbSendBuffer,
l_cbSendLength,
l_bRecvBuffer,
l_pcbRecvLength,
&l_lpBytesReturned);
if ( l_rv != SCARD_S_SUCCESS )
{
#ifdef DEBUG
printf("L_RV = %x\n",l_rv);
#endif
PyErr_SetString(PycscException, pcsc_stringify_error(l_rv));
return NULL;
}
else
{
#ifdef DEBUG
printf("REC LENGTH = %d\n", l_lpBytesReturned);
#endif
}
#ifdef DEBUG
for (i = 0; i < l_lpBytesReturned; i += 1)
{
printf("0x%x ",l_bRecvBuffer[i]);
}
#endif
return Py_BuildValue("s#", l_bRecvBuffer, l_lpBytesReturned);
//return Py_BuildValue("s", l_bRecvBuffer);
}
//******************************************************************
static PyObject * pycsc_verify(PyObject *p_self, PyObject * p_args)
{
int l_ok;
pycscobject *l_object = (pycscobject *)p_self;
unsigned long l_cbSendLength=0;
#define B_SIZE 1024
// unsigned char l_bSendBuffer[B_SIZE];
unsigned char l_bRecvBuffer[B_SIZE];
unsigned long l_pcbRecvLength=0;
unsigned long l_lpBytesReturned=0;
unsigned long l_dwControlCode=0;
#define APDU_LENGTH 0x09
unsigned char l_apdu[] = {0,0x20,0,0,4,0x20,0x20,0x20,0x20};
union
{
PIN_VERIFY_STRUCTURE l_verify;
unsigned char l_bSendBuffer[B_SIZE];
}l_u;
#define STRUCT_SIZE (sizeof(PIN_VERIFY_STRUCTURE) - 1)
long l_rv;
int i;
#define DEBUG
// printf("SCARD_CTL_CODE(3400) = %X\n",SCARD_CTL_CODE(3400));
l_ok = PyArg_ParseTuple(p_args, "l",
&l_dwControlCode
);
if (! l_ok)
{
PyErr_SetString(PycscException, "pycsc_control: parameters parsing
failed");
#ifdef DEBUG
printf("L_OK = %d\n",l_ok);
#endif
return NULL;
}
l_u.l_verify.bTimerOut = 0x18; /* timeout is seconds (00 means use
default
timeout) */
l_u.l_verify.bTimerOut2 = 0x18; /* timeout in seconds after first key
stroke
*/
l_u.l_verify.bmFormatString = 0x80; /* formatting options */
l_u.l_verify.bmPINBlockString = 0x0;/* bits 7-4 bit size of PIN length
in
APDU,
* bits 3-0 PIN block size in
bytes after
* justification and formatting
*/
l_u.l_verify.bmPINLengthFormat = 0; /* bits 7-5 RFU,
* bit 4 set if system
units are bytes, clear if
* system units are
bits,
* bits 3-0 PIN length
position in system units */
l_u.l_verify.wPINMaxExtraDigit = 0x0404;/* 0xXXYY where XX is minimum
PIN
size in digits,
and YY is maximum PIN size in digits */
l_u.l_verify.bEntryValidationCondition = 3; /* Conditions under which
PIN
entry should
* be considered complete */
l_u.l_verify.bNumberMessage = 0x0; /* Number of messages to display for
PIN
verification */
l_u.l_verify.wLangId = 0x0409; /* Language for messages */
l_u.l_verify.bMsgIndex=0; /* Message index (should be 00) */
l_u.l_verify.bTeoPrologue[0]= 0; /* T=1 block prologue field to use
(fill
with 00) */
l_u.l_verify.bTeoPrologue[1]= 0; /* T=1 block prologue field to use
(fill
with 00) */
l_u.l_verify.bTeoPrologue[2]= 0; /* T=1 block prologue field to use
(fill
with 00) */
l_u.l_verify.ulDataLength = APDU_LENGTH; /* length of Data to be sent
to the
ICC */
// strncpy(l_bSendBuffer, (unsigned char *) &l_verify,
STRUCT_SIZE);
// strncpy(&l_bSendBuffer[STRUCT_SIZE], l_apdu, APDU_LENGTH);
// strncpy(&l_u.l_verify.abData[0], l_apdu, APDU_LENGTH);
for (i = 0; i < APDU_LENGTH; i += 1)
{
l_u.l_verify.abData[i] = l_apdu[i];
}
l_cbSendLength = STRUCT_SIZE + APDU_LENGTH;
#ifdef DEBUG
printf(" SENDING: (LEN + %x) ", l_cbSendLength);
for (i=0; i < l_cbSendLength; i += 1)
{
printf("%X ", l_u.l_bSendBuffer[i]);
}
printf("\n");
#endif
l_pcbRecvLength = B_SIZE;
l_rv= SCardControl (
l_object->hCard,
l_dwControlCode,
l_u.l_bSendBuffer,
l_cbSendLength,
&l_bRecvBuffer[0],
l_pcbRecvLength,
&l_lpBytesReturned);
if ( l_rv != SCARD_S_SUCCESS )
{
#ifdef DEBUG
printf("L_RV = %x\n",l_rv);
#endif
PyErr_SetString(PycscException, pcsc_stringify_error(l_rv));
return NULL;
}
else
{
#ifdef DEBUG
printf("REC LENGTH = %d\n", l_lpBytesReturned);
#endif
}
#ifdef DEBUG
for (i = 0; i < l_lpBytesReturned; i += 1)
{
printf("0x%x ",l_bRecvBuffer[i]);
}
#endif
return Py_BuildValue("s#", l_bRecvBuffer, l_lpBytesReturned);
//return Py_BuildValue("s", l_bRecvBuffer);
}
/* Declaration of methods */
static struct PyMethodDef pycsc_methods[] =
{
{"reconnect",(PyCFunction)pycsc_reconnect, METH_VARARGS|METH_KEYWORDS},
{"disconnect", pycsc_disconnect, METH_VARARGS},
{"status", pycsc_status, METH_VARARGS},
{"control", pycsc_control, METH_VARARGS},
{"verify", pycsc_verify, METH_VARARGS},
{"transmit",(PyCFunction)pycsc_transmit, METH_VARARGS|METH_KEYWORDS},
{"cancel", pycsc_cancel, METH_VARARGS},
{"beginTransaction", pycsc_beginTransaction, METH_VARARGS},
{"endTransaction", pycsc_endTransaction, METH_VARARGS},
{"cancelTransaction", pycsc_cancelTransaction, METH_VARARGS},
{NULL, NULL}
};
/***********************************************************
* Type methods
*
* dealloc() (Destructor)
* getattr()
* repr()
*
***********************************************************/
static void pycsc_dealloc(PyObject *self)
{
pycscobject *object = (pycscobject *)self;
#ifdef DEBUG
SCARDCONTEXT hContext;
SCARDHANDLE hCard;
hContext = ((pycscobject *)self)->hContext;
hCard = ((pycscobject *)self)->hCard;
#endif
//+ Disconnect leaving card untouched, any better idea?
SCardDisconnect( object->hCard, SCARD_LEAVE_CARD );
SCardReleaseContext( object->hContext );
PyObject_Del(object);
#ifdef DEBUG
printf("pycsc_dealloc successful for hContext = %08X, hCard = %08X\n",
hContext, hCard);
#endif
}
static PyObject * pycsc_getattr(PyObject *self, char* name)
{
pycscobject *object = (pycscobject *)self;
return Py_FindMethod(pycsc_methods, (PyObject *) object, name);
}
static PyObject * pycsc_repr(PyObject *self)
{
pycscobject *object = (pycscobject *)self;
char buffer[1024];
snprintf(buffer, sizeof(buffer),
"< pycsc, hContext = 0x%08lX, hCard = 0x%08lX at %lx >",
object->hContext, object->hCard, (LONG) object);
return PyString_FromString(buffer);
}
statichere PyTypeObject PycscType =
{
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"pycsc", /* tp_name */
sizeof(pycscobject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
pycsc_dealloc, /* tp_dealloc */
0, /* tp_print */
(getattrfunc) pycsc_getattr,/* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc) pycsc_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc) 0, /* tp_hash */
0, /* tp_call */
(reprfunc) 0, /* tp_str */
};
/***********************************************************
* Class methods
*
* pycsc()
* listReader()
* listReaderGroups()
* getStatusChange()
*
***********************************************************/
/* This is the "creator" for a new pycsc object */
static PyObject * pycscobject_pycsc(PyObject *self, PyObject * args, PyObject
*keywds)
{
/* No reader name in args, connect to the first reader */
LPSTR mszReaders = NULL;
LPSTR szRequestedReader = "";
DWORD dwReaders;
DWORD dwMode = SCARD_SHARE_SHARED;
DWORD eProtocol; /* effective protocol */
DWORD dwPreferredProtocol = SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1;
SCARDCONTEXT hContext;
SCARDHANDLE hCard;
LONG rv;
pycscobject *newself;
static char *kwlist[] = {"reader", "mode", "protocol", NULL};
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|s#ll", kwlist,
&szRequestedReader, &dwReaders,
&dwMode,
&dwPreferredProtocol))
return NULL;
#ifdef DEBUG
printf("pycsc called with: ");
if (szRequestedReader)
printf("Reader name: %s\n", szRequestedReader);
else
printf("Reader name not specified\n");
printf("Mode: %ld\n", dwMode);
printf("Preferred protocol: %ld\n", dwPreferredProtocol);
#endif
/* Initialise context */
rv = SCardEstablishContext( SCARD_SCOPE_SYSTEM, NULL, NULL,
&hContext);
if ( rv != SCARD_S_SUCCESS )
{
PyErr_SetString(PycscException, pcsc_stringify_error(rv));
return NULL;
}
#ifdef DEBUG
printf("SCardEstablishContext successful\n");
#endif
if (strlen(szRequestedReader) > 0)
{
// malloc a buffer to copy the reader name to have the same behiaviour
// as when selecting the first one
mszReaders = (char *)PyMem_Malloc(sizeof(char)*
(strlen(szRequestedReader)+1));
if (!mszReaders)
{
SCardReleaseContext( hContext );
return PyErr_NoMemory();
}
strncpy(mszReaders, szRequestedReader, strlen(szRequestedReader)+1);
}
else
{
// No reader specified, need to locate the first one
rv = getReaderList(hContext, &mszReaders, &dwReaders);
if ( rv != SCARD_S_SUCCESS )
{
SCardReleaseContext( hContext );
PyErr_SetString(PycscException, pcsc_stringify_error(rv));
return NULL;
}
}
if (*mszReaders == '\0')
{
SCardReleaseContext( hContext );
PyErr_SetString(PycscException, "No reader connected");
return NULL;
}
/* Connect */
rv = SCardConnect(hContext, mszReaders, dwMode,
dwPreferredProtocol, &hCard, &eProtocol);
/* Free the memory now */
PyMem_Free((void *)mszReaders);
if ( rv != SCARD_S_SUCCESS )
{
SCardReleaseContext( hContext );
PyErr_SetString(PycscException, pcsc_stringify_error(rv));
return NULL;
}
/* Now that everything worked, alloc new object */
/* replace self from class with the new instance */
newself = PyObject_New(pycscobject, & PycscType);
if (newself == NULL)
{
SCardReleaseContext( hContext );
PyErr_SetString(PycscException, "Could not allocate new object");
return NULL;
}
newself->hContext = hContext;
newself->hCard = hCard;
newself->sMode = dwMode;
newself->dwProtocol = eProtocol;
#ifdef DEBUG
printf("Active protocol: 0xld\n", eProtocol);
printf("pycsc_pycsc: OK with hContext = 0x%08X, hCard = 0x%08X\n",
hContext, hCard);
#endif
return (PyObject *) newself;
}
/***********************************************************************/
static PyObject * pycscobject_getCtlCode(PyObject *self, PyObject * args)
{
return Py_BuildValue("l", SCARD_CTL_CODE(3400));
}
/***********************************************************************/
static PyObject * pycscobject_listReader(PyObject *self, PyObject * args)
{
SCARDCONTEXT hContext;
LPSTR mszReaders = NULL;
LPSTR mszReadersScan;
DWORD dwReaders;
LONG rv;
PyObject *ret_value;
rv = SCardEstablishContext( SCARD_SCOPE_SYSTEM, NULL, NULL,
&hContext);
if ( rv != SCARD_S_SUCCESS )
{
PyErr_SetString(PycscException, pcsc_stringify_error(rv));
return NULL;
}
rv = getReaderList(hContext, &mszReaders, &dwReaders);
if ( rv != SCARD_S_SUCCESS )
{
PyErr_SetString(PycscException, pcsc_stringify_error(rv));
return NULL;
}
// Build output from mszReaders
ret_value = Py_BuildValue("[]");
if (!ret_value)
{
PyErr_SetString(PycscException, "Could not create list");
SCardReleaseContext(hContext);
PyMem_Free((void *)mszReaders);
return NULL;
}
mszReadersScan = mszReaders;
while (*mszReadersScan != '\0')
{
//+ Does that free memomry properly in case of error with the append
//+ probably Py_BuildValue("s", mszReadersScan) needs a DECREF
//+ and so does ret_value
if (PyList_Append(ret_value, Py_BuildValue("s", mszReadersScan)))
{
PyErr_SetString(PycscException, "Could not append reader name");
SCardReleaseContext(hContext);
PyMem_Free((void *)mszReaders);
return NULL;
}
mszReadersScan += strlen(mszReadersScan)+1;
}
SCardReleaseContext(hContext);
PyMem_Free((void *)mszReaders);
return ret_value;
}
static PyObject * pycscobject_listReaderGroups(PyObject *self, PyObject *
args)
{
PyErr_SetString(PycscException, "Not implemented");
return NULL;
}
static PyObject * pycscobject_getStatusChange(PyObject *self, PyObject * args,
PyObject *keywds)
{
SCARDCONTEXT hContext;
PyObject *ret_value = NULL;
SCARD_READERSTATE *pstReaderStates;
DWORD timeout = INFINITE;
PyObject *pyReaderStates = NULL;
PyObject *tmpSeq;
int readerstatesLength = 0;
int i;
LONG rv;
static char *kwlist[] = {"Timeout", "ReaderStates", NULL};
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|lO", kwlist,
&timeout, &pyReaderStates))
{
PyErr_SetString(PycscException, "Error parsing arguments");
return NULL;
}
/*printf("TIMEOUT = %d\n",timeout);*/
// Create an empty sequence in case pyReaderStates was not given as arg
tmpSeq = Py_BuildValue("[]");
if (pyReaderStates==NULL)
{
pyReaderStates = tmpSeq;
}
// Parse the readerstate argument
pyReaderStates = PySequence_Fast(pyReaderStates, "pycsc: getStatusChange:
Expecting sequence argument for readerstates");
Py_DECREF(tmpSeq);
if ( ! pyReaderStates )
{
PyErr_SetString(PycscException, "Error in call to PySequence_Fast");
return NULL;
}
readerstatesLength = PySequence_Fast_GET_SIZE(pyReaderStates);
pstReaderStates =
PyMem_Malloc(sizeof(SCARD_READERSTATE)*readerstatesLength);
if (!pstReaderStates)
{
Py_DECREF(pyReaderStates);
return PyErr_NoMemory();
}
// Iterate on the sequence. Each element should be a mapping reflecting the
content of the struct
for (i=0; i<readerstatesLength; i++)
{
PyObject *pyReaderState;
pyReaderState = PySequence_Fast_GET_ITEM(pyReaderStates, i);
if ( (!pyReaderState) || (! PyMapping_Check(pyReaderState)) )
{
// Release memory
for (;i>0; i--)
{
PyMem_Free((void *)pstReaderStates[i-1].szReader);
}
PyMem_Free((void *)pstReaderStates);
Py_DECREF(pyReaderStates);
PyErr_SetString(PycscException, "pycsc: getStatusChange: Expecting
mapping argument for each readerstate");
return NULL;
}
// Parse the content of the mapping to set the structure
// The keys of the mapping are:
// "reader" for the reader name
// "currentState" for the set of state information to watch for
// Missing value values will be replaced by default values ("" for
reader, SCARD_STATE_EMPTY for currentState)
pstReaderStates[0].szReader = "";
pstReaderStates[0].dwCurrentState = SCARD_STATE_EMPTY;
// First deal with dwCurrentState as the szReader free loop on error
will be the same as below
if (PyMapping_HasKeyString(pyReaderState, "CurrentState"))
{
PyObject *pycurrentState = NULL;
pycurrentState = PyMapping_GetItemString(pyReaderState,
"CurrentState");
if (!PyInt_Check(pycurrentState))
{
for (;i>0; i--)
{
PyMem_Free((void *)pstReaderStates[i-1].szReader);
}
PyMem_Free((void *)pstReaderStates);
Py_DECREF(pyReaderStates);
PyErr_SetString(PycscException, "pycsc: getStatusChange:
Expecting \"CurrentState\" key to reference an integer");
return NULL;
}
pstReaderStates[i].dwCurrentState = PyInt_AsLong(pycurrentState);
}
if (PyMapping_HasKeyString(pyReaderState, "Reader"))
{
PyObject *pyReader = NULL;
char *pcReaderName;
int length;
pyReader = PyMapping_GetItemString(pyReaderState, "Reader");
if (!PyString_Check(pyReader))
{
for (;i>0; i--)
{
PyMem_Free((void *)pstReaderStates[i-1].szReader);
}
PyMem_Free((void *)pstReaderStates);
Py_DECREF(pyReaderStates);
PyErr_SetString(PycscException, "pycsc: getStatusChange:
Expecting \"Reader\" key to reference a string");
return NULL;
}
// Make a copy of the string.
length = sizeof(char)*(strlen(PyString_AsString(pyReader))+1);
pcReaderName = PyMem_Malloc(length);
if (!pcReaderName)
{
for (;i>0; i--)
{
PyMem_Free((void *)pstReaderStates[i-1].szReader);
}
PyMem_Free((void *)pstReaderStates);
Py_DECREF(pyReaderStates);
PyErr_SetString(PycscException, "pycsc: getStatusChange: Memory
allocation error");
return NULL;
}
strncpy(pcReaderName, PyString_AsString(pyReader), length);
pcReaderName[length-1] = '\0';
pstReaderStates[i].szReader = pcReaderName;
pstReaderStates[i].pvUserData = NULL;
}
}
// Input is not required anymore.
Py_DECREF(pyReaderStates);
// Connect to pcsc.
rv = SCardEstablishContext( SCARD_SCOPE_SYSTEM, NULL, NULL,
&hContext);
if ( rv != SCARD_S_SUCCESS )
{
for (i=0;i<readerstatesLength; i++)
{
PyMem_Free((void *)pstReaderStates[i].szReader);
}
PyMem_Free((void *)pstReaderStates);
PyErr_SetString(PycscException, pcsc_stringify_error(rv));
return NULL;
}
rv = SCardGetStatusChange(hContext, timeout, pstReaderStates,
readerstatesLength);
SCardReleaseContext(hContext);
if ( rv != SCARD_S_SUCCESS )
{
for (i=0;i<readerstatesLength; i++)
{
PyMem_Free((void *)pstReaderStates[i].szReader);
}
PyMem_Free((void *)pstReaderStates);
PyErr_SetString(PycscException, pcsc_stringify_error(rv));
return NULL;
}
// Construct the response sequence of mappings
ret_value = Py_BuildValue("[]");
if (!ret_value)
{
for (i=0;i<readerstatesLength; i++)
{
PyMem_Free((void *)pstReaderStates[i].szReader);
}
PyMem_Free((void *)pstReaderStates);
PyErr_SetString(PycscException, "Could not create list");
return NULL;
}
for (i=0;i<readerstatesLength; i++)
{
PyObject *pyreaderstate;
pyreaderstate = Py_BuildValue("{s:s, s:s, s:i, s:i, s:s#}",
"Reader", pstReaderStates[i].szReader,
"UserData", "",
"CurrentState",
pstReaderStates[i].dwCurrentState,
"EventState",
pstReaderStates[i].dwEventState,
"Atr", pstReaderStates[i].rgbAtr,
pstReaderStates[i].cbAtr);
if (!pyreaderstate)
{
Py_DECREF(ret_value);
// Up to the value of i (non inclusive), the memory has already been
released
for (;i<readerstatesLength; i++)
{
PyMem_Free((void *)pstReaderStates[i].szReader);
}
PyMem_Free((void *)pstReaderStates);
PyErr_SetString(PycscException, "Could not create dictionnary");
return NULL;
}
if (PyList_Append(ret_value, Py_BuildValue("O", pyreaderstate)))
{
PyErr_SetString(PycscException, "Could not append dictionnary to
sequence");
Py_DECREF(ret_value);
Py_DECREF(pyreaderstate);
// Up to the value of i (non inclusive), the memory has already been
released
for (;i<readerstatesLength; i++)
{
PyMem_Free((void *)pstReaderStates[i].szReader);
}
PyMem_Free((void *)pstReaderStates);
PyErr_SetString(PycscException, "Could not create dictionnary");
return NULL;
}
// Release memory as soon as we don't need it anymore
PyMem_Free((void *)pstReaderStates[i].szReader);
}
// Release memory
PyMem_Free((void *)pstReaderStates);
return ret_value;
}
/* Declaration of methods */
static struct PyMethodDef pycsctype_methods[] =
{
{"pycsc",(PyCFunction)pycscobject_pycsc, METH_VARARGS|
METH_KEYWORDS},
{"listReader", pycscobject_listReader, METH_VARARGS},
{"getCtlCode", pycscobject_getCtlCode, METH_VARARGS},
{"listReaderGroups", pycscobject_listReaderGroups, METH_VARARGS},
{"getStatusChange",(PyCFunction) pycscobject_getStatusChange,
METH_VARARGS|METH_KEYWORDS},
{(char*)NULL, (PyCFunction)NULL, (int)NULL}
};
/* Module initialisation */
void initpycsc(void)
{
PyObject *m, *d;
/* patch object type for building dll on windows... */
PycscType.ob_type = &PyType_Type;
m = Py_InitModule("pycsc", pycsctype_methods);
d = PyModule_GetDict(m);
//+ Add error code and constants definitions
PyDict_SetItemString(d, "SCARD_LEAVE_CARD",
PyInt_FromLong(SCARD_LEAVE_CARD));
PyDict_SetItemString(d, "SCARD_RESET_CARD",
PyInt_FromLong(SCARD_RESET_CARD));
PyDict_SetItemString(d, "SCARD_SHARE_SHARED",
PyInt_FromLong(SCARD_SHARE_SHARED));
PyDict_SetItemString(d, "SCARD_SHARE_EXCLUSIVE",
PyInt_FromLong(SCARD_SHARE_EXCLUSIVE));
PyDict_SetItemString(d, "SCARD_SHARE_DIRECT",
PyInt_FromLong(SCARD_SHARE_DIRECT));
PyDict_SetItemString(d, "SCARD_PROTOCOL_T0",
PyInt_FromLong(SCARD_PROTOCOL_T0));
PyDict_SetItemString(d, "SCARD_PROTOCOL_T1",
PyInt_FromLong(SCARD_PROTOCOL_T1));
PyDict_SetItemString(d, "SCARD_PROTOCOL_RAW",
PyInt_FromLong(SCARD_PROTOCOL_RAW));
#ifdef _WINDOWS_
PyDict_SetItemString(d, "SCARD_PROTOCOL_UNDEFINED",
PyInt_FromLong(SCARD_PROTOCOL_UNDEFINED));
#endif
PyDict_SetItemString(d, "SCARD_ABSENT", PyInt_FromLong(SCARD_ABSENT));
PyDict_SetItemString(d, "SCARD_PRESENT", PyInt_FromLong(SCARD_PRESENT));
PyDict_SetItemString(d, "SCARD_SWALLOWED", PyInt_FromLong(SCARD_SWALLOWED));
PyDict_SetItemString(d, "SCARD_POWERED", PyInt_FromLong(SCARD_POWERED));
PyDict_SetItemString(d, "SCARD_NEGOTIABLE",
PyInt_FromLong(SCARD_NEGOTIABLE));
PyDict_SetItemString(d, "SCARD_SPECIFIC", PyInt_FromLong(SCARD_SPECIFIC));
#ifndef _WINDOWS_
// PCSC-lite specific
PyDict_SetItemString(d, "SCARD_PROTOCOL_ANY",
PyInt_FromLong(SCARD_PROTOCOL_ANY));
#endif
PyDict_SetItemString(d, "SCARD_STATE_UNAWARE",
PyInt_FromLong(SCARD_STATE_UNAWARE));
PyDict_SetItemString(d, "SCARD_STATE_IGNORE",
PyInt_FromLong(SCARD_STATE_IGNORE));
PyDict_SetItemString(d, "SCARD_STATE_CHANGED",
PyInt_FromLong(SCARD_STATE_CHANGED));
PyDict_SetItemString(d, "SCARD_STATE_UNKNOWN",
PyInt_FromLong(SCARD_STATE_UNKNOWN));
PyDict_SetItemString(d, "SCARD_STATE_UNAVAILABLE",
PyInt_FromLong(SCARD_STATE_UNAVAILABLE));
PyDict_SetItemString(d, "SCARD_STATE_EMPTY",
PyInt_FromLong(SCARD_STATE_EMPTY));
PyDict_SetItemString(d, "SCARD_STATE_PRESENT",
PyInt_FromLong(SCARD_STATE_PRESENT));
PyDict_SetItemString(d, "SCARD_STATE_ATRMATCH",
PyInt_FromLong(SCARD_STATE_ATRMATCH));
PyDict_SetItemString(d, "SCARD_STATE_EXCLUSIVE",
PyInt_FromLong(SCARD_STATE_EXCLUSIVE));
PyDict_SetItemString(d, "SCARD_STATE_INUSE",
PyInt_FromLong(SCARD_STATE_INUSE));
PyDict_SetItemString(d, "SCARD_STATE_MUTE",
PyInt_FromLong(SCARD_STATE_MUTE));
//+ Define the PycscException
PycscException = PyErr_NewException("pycsc.PycscException", NULL, NULL);
PyDict_SetItemString(d, "PycscException", PycscException);
}
/* Internal tool */
static LONG getReaderList(SCARDCONTEXT hContext, LPSTR* pmszReaders, DWORD
*pdwReaders)
{
LPTSTR mszGroups = 0;
LPSTR mszReaders = NULL;
LONG dwReaders;
LONG rv;
/* Read size of reader list */
rv = SCardListReaders( hContext, mszGroups, 0, &dwReaders );
if ( rv != SCARD_S_SUCCESS )
{
return rv;
}
#ifdef DEBUG
printf("SCardListReaders dry run successful\n");
#endif
/* malloc a buffer to store reader names */
mszReaders = (char *)PyMem_Malloc(sizeof(char)*dwReaders);
if (!mszReaders)
{
return SCARD_E_NO_MEMORY;
}
/* Get the list of readers*/
rv = SCardListReaders(hContext, mszGroups,
mszReaders, &dwReaders );
if ( rv != SCARD_S_SUCCESS )
{
PyMem_Free((void *)mszReaders);
return rv;
}
#ifdef DEBUG
printf("SCardListReaders successful\n");
#endif
*pmszReaders = mszReaders;
*pdwReaders = dwReaders;
return SCARD_S_SUCCESS;
}
--
_________________________
Philippe C. Martin
www.snakecard.com
_________________________
_______________________________________________
Muscle mailing list
[email protected]
http://lists.drizzle.com/mailman/listinfo/muscle