Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2884 lines
66 KiB

/*++
Copyright (C) Microsoft Corporation, 1996 - 1999
Module Name:
Context
Abstract:
This module implements the CSCardUserContext and CSCardSubcontext classes.
These classes are responsible for establishing and maintaining the
connection to the Calais Server application, and for tracking the context
under which related operations are performed.
Author:
Doug Barlow (dbarlow) 11/21/1996
Environment:
Win32, C++ w/ Excpetions
Notes:
?Notes?
--*/
#define __SUBROUTINE__
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include "client.h"
#ifdef DBG
#include <stdio.h>
#endif
//
//==============================================================================
//
// CSCardUserContext
//
/*++
CSCardUserContext:
This is the default constructor for the user context.
Arguments:
None
Return Value:
None
Throws:
None
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 4/22/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardUserContext::CSCardUserContext")
CSCardUserContext::CSCardUserContext(
IN DWORD dwScope)
: m_csUsrCtxLock(CSID_USER_CONTEXT),
m_hContextHeap(DBGT("User Context Heap Handle")),
m_rgpSubContexts()
{
m_dwScope = dwScope;
m_hRedirContext = NULL;
}
/*++
CSCardUserContext::~CSCardUserContext:
This is the destructor for a User Context.
Arguments:
None
Return Value:
None
Throws:
None
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 4/22/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardUserContext::~CSCardUserContext")
CSCardUserContext::~CSCardUserContext()
{
DWORD dwIndex;
CSCardSubcontext *pSubCtx;
LockSection(&m_csUsrCtxLock, DBGT("Destructing User Level Context"));
for (dwIndex = m_rgpSubContexts.Count(); 0 < dwIndex;)
{
{
pSubCtx = m_rgpSubContexts[--dwIndex];
if (NULL != pSubCtx)
m_rgpSubContexts.Set(dwIndex, NULL);
}
if (NULL != pSubCtx)
delete pSubCtx;
}
m_rgpSubContexts.Empty();
if (m_hContextHeap.IsValid())
HeapDestroy(m_hContextHeap.Relinquish());
}
/*++
EstablishContext:
This method establishes the context by connecting to the Calais Server
application.
Arguments:
dwScope supplies an indication of the scope of the context. Possible values
are:
SCARD_SCOPE_USER - The context is a user context, and any database
operations are performed within the domain of the user.
SCARD_SCOPE_TERMINAL - The context is that of the current terminal, and
any database operations are performed within the domain of that
terminal. (The calling application must have appropriate access
permissions for any database actions.)
SCARD_SCOPE_SYSTEM - The context is the system context, and any database
operations are performed within the domain of the system. (The
calling application must have appropriate access permissions for any
database actions.)
Return Value:
None
Throws:
Error conditions are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 11/21/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardUserContext::EstablishContext")
void
CSCardUserContext::EstablishContext(
void)
{
//
// Make sure we can access the server.
//
CSCardSubcontext *pSubCtx = AcquireSubcontext();
ASSERT(NULL != pSubCtx);
if (NULL == pSubCtx)
throw (DWORD)SCARD_E_NO_MEMORY;
pSubCtx->ReleaseSubcontext();
}
/*++
ReleaseContext:
This method requests the ReleaseContext service on behalf of the client.
Arguments:
None
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardUserContext::ReleaseContext")
void
CSCardUserContext::ReleaseContext(
void)
{
DWORD dwIndex;
CSCardSubcontext *pSubCtx;
LockSection(&m_csUsrCtxLock, DBGT("Releasing subcontexts"));
for (dwIndex = m_rgpSubContexts.Count(); 0 < dwIndex;)
{
pSubCtx = m_rgpSubContexts[--dwIndex];
if (NULL != pSubCtx)
{
m_rgpSubContexts.Set(dwIndex, NULL);
if (NULL != pSubCtx->m_hReaderHandle)
{
try
{
g_phlReaders->Close(pSubCtx->m_hReaderHandle);
}
catch (...) {}
}
try
{
pSubCtx->ReleaseContext();
}
catch (...) {}
delete pSubCtx;
}
}
}
/*++
ClosePipes:
This method closes the pipes to SCardSvr.
Arguments:
None
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Sermet Iskin (SermetI) 1/3/2001
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardUserContext::ClosePipes")
void
CSCardUserContext::ClosePipes(
void)
{
DWORD dwIndex;
CSCardSubcontext *pSubCtx;
LockSection(&m_csUsrCtxLock, DBGT("Closing pipes"));
for (dwIndex = m_rgpSubContexts.Count(); 0 < dwIndex;)
{
pSubCtx = m_rgpSubContexts[--dwIndex];
if (NULL != pSubCtx)
{
try
{
pSubCtx->ClosePipe();
}
catch (...) {}
}
}
}
/*++
AllocateMemory:
Allocate memory for the user through this user context.
Arguments:
cbLength supplies the length of the buffer to be allocated, in bytes.
Return Value:
The address of the allocated buffer, or NULL if an error occurred.
Throws:
None
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 4/21/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardUserContext::AllocateMemory")
LPVOID
CSCardUserContext::AllocateMemory(
DWORD cbLength)
{
LockSection(&m_csUsrCtxLock, DBGT("Locking memory heap"));
if (!m_hContextHeap.IsValid())
{
m_hContextHeap = HeapCreate(0, 0, 0);
if (!m_hContextHeap.IsValid())
{
CalaisWarning(
__SUBROUTINE__,
DBGT("Failed to create context heap: "),
m_hContextHeap.GetLastError());
goto ErrorExit;
}
}
if (cbLength)
{
return HeapAlloc(
m_hContextHeap,
HEAP_ZERO_MEMORY,
cbLength);
}
ErrorExit:
return NULL;
}
/*++
FreeMemory:
Free memory for the user through this user context.
Arguments:
pvBuffer supplies the address of the previously allocated buffer.
Return Value:
None.
Throws:
None
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 4/21/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardUserContext::FreeMemory")
DWORD
CSCardUserContext::FreeMemory(
LPCVOID pvBuffer)
{
BOOL fSts;
LockSection(&m_csUsrCtxLock, DBGT("Freeing heap memory"));
ASSERT(m_hContextHeap.IsValid());
fSts = HeapFree(m_hContextHeap, 0, (LPVOID)pvBuffer);
return fSts ? ERROR_SUCCESS : GetLastError();
}
/*++
AcquireSubcontext:
A User Context manages one or more underlying subcontexts. Subcontexts
exist to facilitate multiple operations simoultaneously. This method
obtains a subcontext for temporary use.
Arguments:
None
Return Value:
The address of the newly created subcontext object.
Throws:
Errors are thrown as DWORD status codes.
Remarks:
Subcontexts are managed by the main context, so when the main context is
closed, all the subcontexts are closed too.
Author:
Doug Barlow (dbarlow) 9/4/1998
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardUserContext::AcquireSubcontext")
CSCardSubcontext *
CSCardUserContext::AcquireSubcontext(
BOOL fAndAllocate)
{
CSCardSubcontext *pSubCtx = NULL;
LockSection(&m_csUsrCtxLock, DBGT("Acquiring a subcontext"));
try
{
DWORD dwIndex;
//
// See if we've got an unused subcontext laying around.
//
for (dwIndex = m_rgpSubContexts.Count(); 0 < dwIndex;)
{
pSubCtx = m_rgpSubContexts[--dwIndex];
if (NULL != pSubCtx)
{
LockSection2(&pSubCtx->m_csSubCtxLock, DBGT("Reusing subcontext"));
if (fAndAllocate)
{
if (CSCardSubcontext::Idle == pSubCtx->m_nInUse)
{
ASSERT(pSubCtx->m_hCancelEvent.IsValid());
pSubCtx->Allocate();
pSubCtx->SetBusy();
break;
}
}
else
{
if (CSCardSubcontext::Busy > pSubCtx->m_nInUse)
{
ASSERT(pSubCtx->m_hCancelEvent.IsValid());
pSubCtx->SetBusy();
break;
}
}
pSubCtx = NULL;
}
}
//
// If not, make a new one.
//
if (NULL == pSubCtx)
{
pSubCtx = new CSCardSubcontext;
if (NULL == pSubCtx)
{
CalaisWarning(
__SUBROUTINE__,
DBGT("Client can't allocate a new subcontext"));
return NULL; // SCARD_E_NO_MEMORY;
}
if (pSubCtx->InitFailed())
{
delete pSubCtx;
pSubCtx = NULL;
return NULL; // SCARD_E_NO_MEMORY;
}
if (fAndAllocate)
pSubCtx->Allocate();
pSubCtx->SetBusy();
pSubCtx->EstablishContext(m_dwScope);
m_rgpSubContexts.Add(pSubCtx);
pSubCtx->m_pParentCtx = this;
}
//
// Make sure the cancel event is clear.
//
ASSERT(pSubCtx->m_hCancelEvent.IsValid());
if (!ResetEvent(pSubCtx->m_hCancelEvent))
{
DWORD dwErr = GetLastError();
CalaisWarning(
__SUBROUTINE__,
DBGT("Subcontext Allocate Failed to clear cancel event: %1"),
dwErr);
}
//
// All done. Return to caller.
//
ASSERT(pSubCtx->m_pParentCtx == this);
}
catch (...)
{
if (NULL != pSubCtx)
{
if (NULL == pSubCtx->m_pParentCtx)
delete pSubCtx;
else
{
if (fAndAllocate)
pSubCtx->Deallocate();
pSubCtx->ReleaseSubcontext();
}
}
throw;
}
return pSubCtx;
}
/*++
IsValidContext:
This method requests the ReleaseContext service on behalf of the client.
Arguments:
None
Return Value:
None
Throws:
If the call cannot be completed, a DWORD status code is thrown.
Remarks:
If the context is determined to not be valid, it is automatically released.
Author:
Doug Barlow (dbarlow) 11/2/1998
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardUserContext::IsValidContext")
BOOL
CSCardUserContext::IsValidContext(
void)
{
DWORD dwIndex;
BOOL fIsValid = TRUE;
CSCardSubcontext *pSubCtx;
LockSection(&m_csUsrCtxLock, DBGT("Valid context check"));
for (dwIndex = m_rgpSubContexts.Count(); 0 < dwIndex;)
{
pSubCtx = m_rgpSubContexts[--dwIndex];
if (NULL != pSubCtx)
{
CSCardSubcontext::State nState;
{
LockSection2(
&pSubCtx->m_csSubCtxLock,
DBGT("IsValidContext Checking validity state"));
nState = pSubCtx->m_nInUse;
}
switch (nState)
{
case CSCardSubcontext::Idle:
case CSCardSubcontext::Allocated:
try
{
CSubctxLock ctxLock(pSubCtx);
pSubCtx->IsValidContext();
fIsValid = TRUE;
}
catch (...)
{
m_rgpSubContexts.Set(dwIndex, NULL);
delete pSubCtx;
fIsValid = FALSE;
}
break;
case CSCardSubcontext::Busy:
// Don't bother it.
break;
default:
CalaisWarning(
__SUBROUTINE__,
DBGT("Subcontext state is invalid"));
throw (DWORD)SCARD_F_INTERNAL_ERROR;
}
}
}
return fIsValid;
}
/*++
LocateCards:
This method requests the LocateCards service on behalf of the client.
Arguments:
mszReaders supplies the names of readers to look in, as a multistring.
mszCards supplies the names of the cards to search for, as a multi-string.
rgReaderStates supplies an array of SCARD_READERSTATE structures controlling
the search, and receives the result. Reader names are taken from the
mszReaders parameter, not from here.
cReaders supplies the number of elements in the rgReaderStates array.
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardUserContext::LocateCards")
void
CSCardUserContext::LocateCards(
IN LPCTSTR mszReaders,
IN LPSCARD_ATRMASK rgAtrMasks,
IN DWORD cAtrs,
IN OUT LPSCARD_READERSTATE rgReaderStates,
IN DWORD cReaders)
{
CSCardSubcontext *pSubCtx = NULL;
try
{
pSubCtx = AcquireSubcontext();
if (NULL == pSubCtx)
throw (DWORD)SCARD_E_NO_MEMORY;
pSubCtx->LocateCards(
mszReaders,
rgAtrMasks,
cAtrs,
rgReaderStates,
cReaders);
pSubCtx->ReleaseSubcontext();
}
catch (...)
{
if (NULL != pSubCtx)
pSubCtx->ReleaseSubcontext();
throw;
}
}
/*++
GetStatusChange:
This method requests the GetStatusChange service on behalf of the client.
Arguments:
rgReaderStates supplies an array of SCARD_READERSTATE structures controlling
the search, and receives the result.
cReaders supplies the number of elements in the rgReaderStates array.
Return Value:
None
Remarks:
We don't have to clean up the cancel event, since this is a one-time usage
of this sub-context. Typically, if the subcontext were to be continued
to be used, we'd have to make sure the cancel event got cleared eventually.
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardUserContext::GetStatusChange")
void
CSCardUserContext::GetStatusChange(
IN LPCTSTR mszReaders,
IN OUT LPSCARD_READERSTATE rgReaderStates,
IN DWORD cReaders,
IN DWORD dwTimeout)
{
CSCardSubcontext *pSubCtx = NULL;
try
{
pSubCtx = AcquireSubcontext(TRUE);
if (NULL == pSubCtx)
throw (DWORD) SCARD_E_NO_MEMORY;
pSubCtx->GetStatusChange(
mszReaders,
rgReaderStates,
cReaders,
dwTimeout);
pSubCtx->Deallocate();
pSubCtx->ReleaseSubcontext();
}
catch (DWORD dwStatus)
{
DWORD dwError;
dwError = dwStatus;
if (NULL != pSubCtx)
{
pSubCtx->Deallocate();
pSubCtx->ReleaseSubcontext();
}
// Catch & convert the Cancel I threw myself
if ((SCARD_E_CANCELLED == dwError) && (IsBad()))
{
dwError = SCARD_E_SYSTEM_CANCELLED;
}
throw dwError;
}
catch (...)
{
if (NULL != pSubCtx)
{
pSubCtx->Deallocate();
pSubCtx->ReleaseSubcontext();
}
throw;
}
}
/*++
Cancel:
This method requests the Cancel service on behalf of the client.
Arguments:
None
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardUserContext::Cancel")
void
CSCardUserContext::Cancel(
void)
{
DWORD dwIndex;
CSCardSubcontext *pSubCtx;
LockSection(&m_csUsrCtxLock, DBGT("Cancelling outstanding operations"));
for (dwIndex = m_rgpSubContexts.Count(); 0 < dwIndex;)
{
pSubCtx = m_rgpSubContexts[--dwIndex];
if (NULL != pSubCtx)
pSubCtx->Cancel();
}
}
/*++
StripInactiveReaders:
This routine scans the supplied list of readers, and shortens it to exclude
any readers that aren't currently active.
Arguments:
bfReaders supplies a list of readers by friendly name. This list is pruned
to remove all names that refer to inactive readers.
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Remarks:
All the listed readers must be introduced. This routine does not filter
undefined readers.
Author:
Doug Barlow (dbarlow) 5/7/1998
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardUserContext::StripInactiveReaders")
void
CSCardUserContext::StripInactiveReaders(
IN OUT CBuffer &bfReaders)
{
CSCardSubcontext *pSubCtx = NULL;
try
{
pSubCtx = AcquireSubcontext();
if (NULL == pSubCtx)
throw (DWORD) SCARD_E_NO_MEMORY;
pSubCtx->StripInactiveReaders(bfReaders);
pSubCtx->ReleaseSubcontext();
}
catch (...)
{
if (NULL != pSubCtx)
pSubCtx->ReleaseSubcontext();
throw;
}
}
//
//==============================================================================
//
// CSCardSubcontext
//
/*++
CONSTRUCTOR and DESTRUCTOR:
These are the simple constructor and destructor for the CSCardSubcontext
class.
Arguments:
None
Return Value:
None
Throws:
None
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/8/1998
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardSubcontext::CSCardSubcontext")
CSCardSubcontext::CSCardSubcontext(void)
: m_csSubCtxLock(CSID_SUBCONTEXT),
m_hBusy(DBGT("Subcontext busy mutex")),
m_hCancelEvent(DBGT("Subcontext cancel event"))
{
DWORD dwSts;
m_hReaderHandle = NULL;
m_pParentCtx = NULL;
m_pChannel = NULL;
m_nInUse = Idle;
m_nLastState = Invalid;
m_hBusy = CreateEvent(NULL, TRUE, TRUE, NULL);
if (!m_hBusy.IsValid())
{
dwSts = m_hBusy.GetLastError();
CalaisWarning(
__SUBROUTINE__,
DBGT("Failed to create busy event flag: %1"),
dwSts);
throw dwSts;
}
CSecurityDescriptor acl;
acl.InitializeFromProcessToken();
acl.AllowOwner(
EVENT_ALL_ACCESS);
acl.Allow(
&acl.SID_LocalService,
EVENT_ALL_ACCESS);
m_hCancelEvent = CreateEvent(acl, TRUE, FALSE, NULL);
if (!m_hCancelEvent.IsValid())
{
dwSts = m_hCancelEvent.GetLastError();
CalaisWarning(
__SUBROUTINE__,
DBGT("Card context cannot create cancel event: %1"),
dwSts);
throw dwSts;
}
}
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardSubcontext::~CSCardSubcontext")
CSCardSubcontext::~CSCardSubcontext()
{
if (NULL != m_pChannel)
delete m_pChannel;
if (m_hBusy.IsValid())
m_hBusy.Close();
if (m_hCancelEvent.IsValid())
m_hCancelEvent.Close();
}
/*++
Allocate:
This method raises the state of the subcontext to 'Allocated'. This means
it is in use as an SCARDHANDLE.
Arguments:
None
Return Value:
None
Throws:
Errors are thrown as DWORD status codes
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 4/23/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardSubcontext::Allocate")
void
CSCardSubcontext::Allocate(
void)
{
LockSection(&m_csSubCtxLock, DBGT("Mark subcontext as allocated"));
ASSERT(Idle == m_nInUse);
ASSERT(Invalid == m_nLastState);
m_nInUse = Allocated;
}
/*++
Deallocate:
This method releases the subcontext from the allocated state.
If the device is still busy, it sets things up to be deallocated
when it is released.
Arguments:
None
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 4/23/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardSubcontext::Deallocate")
void
CSCardSubcontext::Deallocate(
void)
{
LockSection(&m_csSubCtxLock, DBGT("Deallocate subcontext"));
switch (m_nInUse)
{
case Idle:
ASSERT(FALSE); // Why are we here?
break;
case Allocated:
m_nInUse = Idle;
m_nLastState = Invalid;
break;
case Busy:
ASSERT(Allocated == m_nLastState);
m_nLastState = Idle;
break;
default:
CalaisWarning(
__SUBROUTINE__,
DBGT("Subcontext deallocation state corruption detected."));
throw (DWORD)SCARD_F_INTERNAL_ERROR;
}
}
/*++
SetBusy:
This method marks the subcontext as busy.
Arguments:
None
Return Value:
None
Throws:
None (It tries to limp along)
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 11/10/1998
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardSubcontext::SetBusy")
void
CSCardSubcontext::SetBusy(
void)
{
LockSection(&m_csSubCtxLock, DBGT("Mark subcontext busy"));
ASSERT(Busy != m_nInUse);
ASSERT(Invalid == m_nLastState);
ASSERT(m_hBusy.IsValid());
m_nLastState = m_nInUse;
m_nInUse = Busy;
ASSERT(m_nLastState < m_nInUse);
ASSERT(Invalid != m_nLastState);
if (!ResetEvent(m_hBusy))
CalaisWarning(
__SUBROUTINE__,
DBGT("Failed to mark context busy: %1"),
GetLastError());
}
/*++
SendRequest:
This method sends the given Communications Object to the server application.
Arguments:
pCom supplies the Communications Object to be sent.
Return Value:
None
Throws:
None
Author:
Doug Barlow (dbarlow) 12/16/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardSubcontext::SendRequest")
void
CSCardSubcontext::SendRequest(
CComObject *pCom)
{
ASSERT(Busy == m_nInUse);
try
{
DWORD dwSts = pCom->Send(m_pChannel);
if (ERROR_SUCCESS != dwSts)
throw dwSts;
}
catch (DWORD dwErr)
{
switch (dwErr)
{
case ERROR_NO_DATA:
case ERROR_PIPE_NOT_CONNECTED:
case ERROR_BAD_PIPE:
case ERROR_BROKEN_PIPE:
throw (DWORD)SCARD_E_SERVICE_STOPPED;
break;
default:
throw;
}
}
}
//
// Attempts to restore the impersonation token of the current thread.
// Assumes that failure to restore the impersonation token is catastrophic.
//
// If this function is called, we assume we're currently running as Local
// System and attempting to restore our impersonation token. That shouldn't
// fail, but if it does, something is really wrong and we must not continue
// to execute code in this state.
//
void MySetThreadToken(HANDLE hThreadToken)
{
if (FALSE == SetThreadToken(NULL, hThreadToken))
{
ASSERT(FALSE);
TerminateThread(GetCurrentThread(), 0);
}
}
/*++
EstablishContext:
This method establishes the context by connecting to the Calais Server
application.
Arguments:
dwScope supplies an indication of the scope of the context. Possible values
are:
SCARD_SCOPE_USER - The context is a user context, and any database
operations are performed within the domain of the user.
SCARD_SCOPE_TERMINAL - The context is that of the current terminal, and
any database operations are performed within the domain of that
terminal. (The calling application must have appropriate access
permissions for any database actions.)
SCARD_SCOPE_SYSTEM - The context is the system context, and any database
operations are performed within the domain of the system. (The
calling application must have appropriate access permissions for any
database actions.)
Return Value:
None
Throws:
Error conditions are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 11/21/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardSubcontext::EstablishContext")
void
CSCardSubcontext::EstablishContext(
IN DWORD dwScope)
{
CComChannel *pCom = NULL;
DWORD dwVersion = CALAIS_COMM_CURRENT;
HANDLE hThreadToken = NULL;
try
{
CComInitiator comInit;
ComEstablishContext comEstablishContext;
ComEstablishContext::CObjEstablishContext_request *pReq;
ComEstablishContext::CObjEstablishContext_response *pRsp;
DWORD dwSts;
HANDLE hServerCancelEvent = NULL;
ASSERT(Busy == m_nInUse);
pCom = comInit.Initiate(
CalaisString(CALSTR_COMMPIPENAME),
&dwVersion);
ASSERT(dwVersion == CALAIS_COMM_CURRENT);
pReq = comEstablishContext.InitRequest(0);
pReq->dwProcId = GetCurrentProcessId();
pReq->hptrCancelEvent = (HANDLE_PTR) m_hCancelEvent.Value();
comEstablishContext.Send(pCom);
comEstablishContext.InitResponse(0);
pRsp = comEstablishContext.Receive(pCom);
if (SCARD_S_SUCCESS != pRsp->dwStatus)
throw pRsp->dwStatus;
hServerCancelEvent = (HANDLE) pRsp->hptrCancelEvent;
if (NULL != hServerCancelEvent)
{
CHandleObject hTargetProc(DBGT("Target Process in EstablishContext"));
HANDLE h = NULL;
BOOL fSts = FALSE;
//
// The Resource Manager doesn't have access to our Cancel event.
// It's proposed an event to use instead. Switch over.
//
// Get the process handle for scardsvr. We require Duplicate
// Handle rights.
//
// Assume that the only reason scardsvr would have sent back a new
// event handle is that we're impersonating a lesser account that
// doesn't own the current process. That account will likely not
// have the appropriate rights to scardsvr either, so we need to
// revert to self before doing the following work.
//
if (FALSE == OpenThreadToken(
GetCurrentThread(), MAXIMUM_ALLOWED, TRUE, &hThreadToken))
throw GetLastError();
if (FALSE == RevertToSelf())
throw GetLastError();
hTargetProc = OpenProcess(
PROCESS_DUP_HANDLE | EVENT_ALL_ACCESS,
FALSE, // handle inheritance flag
pRsp->dwProcId); // process identifier
if (!hTargetProc.IsValid())
throw GetLastError();
fSts = DuplicateHandle(
hTargetProc, // handle to process
hServerCancelEvent,
GetCurrentProcess(),// handle to process to duplicate to
&h, // pointer to duplicate handle
EVENT_ALL_ACCESS, // access for duplicate handle
FALSE, // handle inheritance flag
0); // optional actions
if (!fSts)
{
dwSts = GetLastError();
CalaisWarning(
__SUBROUTINE__,
DBGT("EstablishContext could not dup offered cancel event: %1"),
dwSts);
ASSERT(NULL == h);
throw dwSts;
}
// Restore the impersonation token
MySetThreadToken(hThreadToken);
CloseHandle(hThreadToken);
hThreadToken = NULL;
ASSERT(m_hCancelEvent.IsValid());
m_hCancelEvent.Close();
m_hCancelEvent = h;
}
m_pChannel = pCom;
}
catch (...)
{
if (NULL != hThreadToken)
{
MySetThreadToken(hThreadToken);
CloseHandle(hThreadToken);
}
if (NULL != pCom)
delete pCom;
throw;
}
}
/*++
ReleaseSubcontext:
This method releases the subcontext for use by other requests.
Arguments:
None
Return Value:
None
Throws:
Errors are thrown as DWORD status codes
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 4/22/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardSubcontext::ReleaseSubcontext")
void
CSCardSubcontext::ReleaseSubcontext(
void)
{
LockSection(&m_csSubCtxLock, DBGT("Mark subcontext available"));
// Check to see if winscard.dll is currently being unloaded. If
// so, skip the asserts.
if (FALSE == g_fInClientRundown)
{
ASSERT(Idle != m_nInUse);
ASSERT(Busy != m_nLastState);
ASSERT(Invalid != m_nLastState);
ASSERT(m_nInUse > m_nLastState);
ASSERT(m_hBusy.IsValid());
}
m_nInUse = m_nLastState;
if (FALSE == g_fInClientRundown)
{
ASSERT(Busy != m_nInUse);
}
m_nLastState = Invalid;
if (!SetEvent(m_hBusy))
CalaisWarning(
__SUBROUTINE__,
DBGT("Failed to mark context Available: %1"),
GetLastError());
}
/*++
ReleaseContext:
This method requests the ReleaseContext service on behalf of the client.
Arguments:
None
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardSubcontext::ReleaseContext")
void
CSCardSubcontext::ReleaseContext(
void)
{
ComReleaseContext comRel;
ComReleaseContext::CObjReleaseContext_request *pReq;
ComReleaseContext::CObjReleaseContext_response *pRsp;
if (WaitForSingleObject(m_hBusy, 0) != WAIT_TIMEOUT) // Subcontext not busy
{
CSubctxLock csCtxLock(this);
pReq = comRel.InitRequest(0);
SendRequest(&comRel);
comRel.InitResponse(0);
pRsp = comRel.Receive(m_pChannel);
if (SCARD_S_SUCCESS != pRsp->dwStatus)
throw pRsp->dwStatus;
}
}
/*++
ClosePipe:
This method closes the pipe to SCardSvr.
Arguments:
None
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Sermet Iskin (SermetI) 1/4/2001
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardSubcontext::ClosePipe")
void
CSCardSubcontext::ClosePipe(
void)
{
if (WaitForSingleObject(m_hBusy, 0) != WAIT_TIMEOUT) // Subcontext not busy
{
CSubctxLock csCtxLock(this);
m_pChannel->ClosePipe() ;
}
}
/*++
WaitForAvailable:
This method waits for a given connection to go not busy, then locks it.
Arguments:
None
Return Value:
None
Throws:
Errors are thrown as DWORD status codes
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 4/22/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardSubcontext::WaitForAvailable")
void
CSCardSubcontext::WaitForAvailable(
void)
{
DWORD dwSts;
BOOL fNotDone = TRUE;
ASSERT(m_hBusy.IsValid());
while (fNotDone)
{
{
LockSection(&m_csSubCtxLock, DBGT("Checking availability"));
switch (m_nInUse)
{
case Idle:
ASSERT(Invalid == m_nLastState);
// Fall through intentionally
case Allocated:
ASSERT(Allocated != m_nLastState);
SetBusy();
fNotDone = FALSE;
continue;
break;
case Busy:
ASSERT(Busy > m_nLastState);
ASSERT(Invalid != m_nLastState);
break;
default:
CalaisWarning(
__SUBROUTINE__,
DBGT("Subcontext availability state is corrupted."));
throw (DWORD)SCARD_F_INTERNAL_ERROR;
}
}
dwSts = WaitForSingleObject(m_hBusy, CALAIS_LOCK_TIMEOUT);
switch (dwSts)
{
case WAIT_ABANDONED:
CalaisWarning(
__SUBROUTINE__,
DBGT("Wait for context busy received wait abandoned."));
break;
case WAIT_OBJECT_0:
break;
case WAIT_TIMEOUT:
CalaisWarning(
__SUBROUTINE__,
DBGT("Wait for context busy timed out."),
GetLastError());
break;
case WAIT_FAILED:
CalaisWarning(
__SUBROUTINE__,
DBGT("Wait for context busy failed: %1"),
GetLastError());
break;
default:
CalaisWarning(
__SUBROUTINE__,
DBGT("Wait for context busy received invalid return: %1"),
GetLastError());
}
}
}
/*++
IsValidContext:
This method requests the ReleaseContext service on behalf of the client.
Arguments:
None
Return Value:
None
Throws:
If the call cannot be completed, a DWORD status code is thrown.
Remarks:
If the context is determined to not be valid, it is automatically released.
Author:
Doug Barlow (dbarlow) 11/2/1998
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardSubcontext::IsValidContext")
void
CSCardSubcontext::IsValidContext(
void)
{
ComIsValidContext comObj;
ComIsValidContext::CObjIsValidContext_request *pReq;
ComIsValidContext::CObjIsValidContext_response *pRsp;
pReq = comObj.InitRequest(0);
SendRequest(&comObj);
comObj.InitResponse(0);
pRsp = comObj.Receive(m_pChannel);
if (SCARD_S_SUCCESS != pRsp->dwStatus)
throw pRsp->dwStatus;
}
/*++
LocateCards:
This method requests the LocateCards service on behalf of the client.
Arguments:
mszReaders supplies the names of readers to look in, as a multistring.
mszCards supplies the names of the cards to search for, as a multi-string.
rgReaderStates supplies an array of SCARD_READERSTATE structures controlling
the search, and receives the result. Reader names are taken from the
mszReaders parameter, not from here.
cReaders supplies the number of elements in the rgReaderStates array.
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardSubcontext::LocateCards")
void
CSCardSubcontext::LocateCards(
IN LPCTSTR mszReaders,
IN LPSCARD_ATRMASK rgAtrMasks,
IN DWORD cAtrs,
IN OUT LPSCARD_READERSTATE rgReaderStates,
IN DWORD cReaders)
{
ComLocateCards comObj;
ComLocateCards::CObjLocateCards_request *pReq;
ComLocateCards::CObjLocateCards_response *pRsp;
CBuffer bfReaders;
CBuffer bfStatus;
CBuffer bfAtrs;
CBuffer bfMasks;
CBuffer bfXlate1(36); // Rough guess of name & ATR lengths
LPDWORD rgdwStatus;
DWORD dwIndex, dwChkLen;
BYTE cbAtrLen;
DWORD dwAtrLen;
LPCBYTE pbAtr;
LPCTSTR szReader;
if (0 == cReaders)
return;
if (0 == *mszReaders)
throw (DWORD)SCARD_E_UNKNOWN_READER;
bfStatus.Resize(sizeof(DWORD) * cReaders);
rgdwStatus = (LPDWORD)bfStatus.Access();
//
// List the smartcard ATRs and masks we're interested in.
//
for (dwIndex = 0;
dwIndex < cAtrs;
dwIndex++)
{
bfAtrs.Presize(bfAtrs.Length() + rgAtrMasks[dwIndex].cbAtr + 1, TRUE);
bfMasks.Presize(bfMasks.Length() + rgAtrMasks[dwIndex].cbAtr + 1, TRUE);
ASSERT(33 >= rgAtrMasks[dwIndex].cbAtr); // Biggest an ATR can be.
cbAtrLen = (BYTE)rgAtrMasks[dwIndex].cbAtr;
bfAtrs.Append(&cbAtrLen, 1);
bfAtrs.Append(rgAtrMasks[dwIndex].rgbAtr, cbAtrLen);
bfMasks.Append(&cbAtrLen, 1);
bfMasks.Append(rgAtrMasks[dwIndex].rgbMask, cbAtrLen);
}
//
// List the reader devices we're interested in.
//
for (szReader = FirstString(mszReaders), dwIndex = 0;
NULL != szReader;
szReader = NextString(szReader), dwIndex += 1)
{
ASSERT(cReaders > dwIndex);
BOOL fSts = GetReaderInfo(
Scope(),
szReader,
NULL,
&bfXlate1);
if (!fSts)
throw (DWORD)SCARD_E_UNKNOWN_READER;
bfReaders.Append(
bfXlate1.Access(),
bfXlate1.Length());
rgdwStatus[dwIndex] = rgReaderStates[dwIndex].dwCurrentState;
}
ASSERT(cReaders == dwIndex);
bfReaders.Append((LPCBYTE)TEXT("\000"), sizeof(TCHAR));
//
// Put it all into the request.
//
pReq = comObj.InitRequest(
bfAtrs.Length() + bfMasks.Length() + bfReaders.Length()
+ bfStatus.Length() + 4 * sizeof(DWORD));
pReq = (ComLocateCards::CObjLocateCards_request *)comObj.Append(
pReq->dscAtrs, bfAtrs.Access(), bfAtrs.Length());
pReq = (ComLocateCards::CObjLocateCards_request *)comObj.Append(
pReq->dscAtrMasks, bfMasks.Access(), bfMasks.Length());
pReq = (ComLocateCards::CObjLocateCards_request *)comObj.Append(
pReq->dscReaders, bfReaders.Access(), bfReaders.Length());
pReq = (ComLocateCards::CObjLocateCards_request *)comObj.Append(
pReq->dscReaderStates, bfStatus.Access(), bfStatus.Length());
//
// Send in the request.
//
SendRequest(&comObj);
comObj.InitResponse(cReaders * sizeof(DWORD));
pRsp = comObj.Receive(m_pChannel);
if (SCARD_S_SUCCESS != pRsp->dwStatus)
throw pRsp->dwStatus;
//
// Parse the response.
//
rgdwStatus = (LPDWORD)comObj.Parse(pRsp->dscReaderStates, &dwChkLen);
if (dwChkLen != cReaders * sizeof(DWORD))
{
CalaisWarning(
__SUBROUTINE__,
DBGT("Client locate cards array size mismatch"));
throw (DWORD)SCARD_F_COMM_ERROR;
}
pbAtr = (LPCBYTE)comObj.Parse(pRsp->dscAtrs, &dwChkLen);
for (dwIndex = 0; dwIndex < cReaders; dwIndex += 1)
{
rgReaderStates[dwIndex].dwEventState = rgdwStatus[dwIndex];
dwAtrLen = *pbAtr++;
ASSERT(33 >= dwAtrLen);
if (dwAtrLen >= dwChkLen)
{
CalaisWarning(
__SUBROUTINE__,
DBGT("Client locate cards ATR size mismatch"));
throw (DWORD)SCARD_F_COMM_ERROR;
}
ZeroMemory(
rgReaderStates[dwIndex].rgbAtr,
sizeof(SCARD_READERSTATE) - FIELD_OFFSET(SCARD_READERSTATE, rgbAtr));
CopyMemory(rgReaderStates[dwIndex].rgbAtr, pbAtr, dwAtrLen);
rgReaderStates[dwIndex].cbAtr = dwAtrLen;
dwChkLen -= dwAtrLen + 1;
pbAtr += dwAtrLen;
}
}
/*++
GetStatusChange:
This method requests the GetStatusChange service on behalf of the client.
Arguments:
rgReaderStates supplies an array of SCARD_READERSTATE structures controlling
the search, and receives the result.
cReaders supplies the number of elements in the rgReaderStates array.
Return Value:
None
Remarks:
We don't have to clean up the cancel event, since this is a one-time usage
of this sub-context. Typically, if the subcontext were to be continued
to be used, we'd have to make sure the cancel event got cleared eventually.
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardSubcontext::GetStatusChange")
void
CSCardSubcontext::GetStatusChange(
IN LPCTSTR mszReaders,
IN OUT LPSCARD_READERSTATE rgReaderStates,
IN DWORD cReaders,
IN DWORD dwTimeout)
{
ComGetStatusChange comObj;
ComGetStatusChange::CObjGetStatusChange_request *pReq;
ComGetStatusChange::CObjGetStatusChange_response *pRsp;
CBuffer bfReaders;
CBuffer bfStatus;
LPDWORD rgdwStatus;
CBuffer bfXlate(16); // Rough guess of device name length
DWORD dwIndex, dwChkLen;
BOOL fSts;
LPCBYTE pbAtr;
DWORD dwAtrLen;
LPCTSTR szReader;
if (0 == cReaders)
return;
bfStatus.Resize(sizeof(DWORD) * cReaders);
rgdwStatus = (LPDWORD)bfStatus.Access();
if (0 == *mszReaders)
throw (DWORD)SCARD_E_UNKNOWN_READER;
//
// List the reader devices we're interested in.
//
for (szReader = FirstString(mszReaders), dwIndex = 0;
NULL != szReader;
szReader = NextString(szReader), dwIndex += 1)
{
ASSERT(cReaders > dwIndex);
fSts = GetReaderInfo(
Scope(),
szReader,
NULL,
&bfXlate);
if (fSts)
{
bfReaders.Append(
bfXlate.Access(),
bfXlate.Length());
}
else if (0 == _tcsncicmp(
CalaisString(CALSTR_SPECIALREADERHEADER),
szReader,
_tcslen(CalaisString(CALSTR_SPECIALREADERHEADER))))
{
bfReaders.Append(
(LPCBYTE)szReader,
(_tcslen(szReader) + 1) * sizeof(TCHAR));
}
else
throw (DWORD)SCARD_E_UNKNOWN_READER;
rgdwStatus[dwIndex] = rgReaderStates[dwIndex].dwCurrentState;
}
ASSERT(cReaders == dwIndex);
bfReaders.Append((LPCBYTE)TEXT("\000"), sizeof(TCHAR));
//
// Put it all into the request.
//
pReq = comObj.InitRequest(
bfReaders.Length() + bfStatus.Length()
+ 2 * sizeof(DWORD));
pReq->dwTimeout = dwTimeout;
pReq = (ComGetStatusChange::CObjGetStatusChange_request *)
comObj.Append(
pReq->dscReaders,
bfReaders.Access(),
bfReaders.Length());
pReq = (ComGetStatusChange::CObjGetStatusChange_request *)
comObj.Append(
pReq->dscReaderStates,
bfStatus.Access(),
bfStatus.Length());
SendRequest(&comObj);
comObj.InitResponse(cReaders * sizeof(DWORD));
pRsp = comObj.Receive(m_pChannel);
if (SCARD_S_SUCCESS != pRsp->dwStatus)
throw pRsp->dwStatus;
rgdwStatus = (LPDWORD)comObj.Parse(pRsp->dscReaderStates, &dwChkLen);
if (dwChkLen != cReaders * sizeof(DWORD))
{
CalaisWarning(
__SUBROUTINE__,
DBGT("Client locate cards array size mismatch"));
throw (DWORD)SCARD_F_COMM_ERROR;
}
pbAtr = (LPCBYTE)comObj.Parse(pRsp->dscAtrs, &dwChkLen);
for (dwIndex = 0; dwIndex < cReaders; dwIndex += 1)
{
rgReaderStates[dwIndex].dwEventState = rgdwStatus[dwIndex];
dwAtrLen = *pbAtr++;
ASSERT(33 >= dwAtrLen);
if (dwAtrLen >= dwChkLen)
{
CalaisWarning(
__SUBROUTINE__,
DBGT("Client locate cards ATR size mismatch"));
throw (DWORD)SCARD_F_COMM_ERROR;
}
ZeroMemory(
rgReaderStates[dwIndex].rgbAtr,
sizeof(SCARD_READERSTATE) - FIELD_OFFSET(SCARD_READERSTATE, rgbAtr));
CopyMemory(rgReaderStates[dwIndex].rgbAtr, pbAtr, dwAtrLen);
rgReaderStates[dwIndex].cbAtr = dwAtrLen;
dwChkLen -= dwAtrLen + 1;
pbAtr += dwAtrLen;
}
}
/*++
Cancel:
This method requests the Cancel service on behalf of the client.
Arguments:
None
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardSubcontext::Cancel")
void
CSCardSubcontext::Cancel(
void)
{
ASSERT(m_hCancelEvent.IsValid());
if (!SetEvent(m_hCancelEvent))
CalaisWarning(
__SUBROUTINE__,
DBGT("Cancel request Failed to set context cancel event: %1"),
GetLastError());
}
/*++
StripInactiveReaders:
This routine scans the supplied list of readers, and shortens it to exclude
any readers that aren't currently active.
Arguments:
bfReaders supplies a list of readers by friendly name. This list is pruned
to remove all names that refer to inactive readers.
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Remarks:
All the listed readers must be introduced. This routine does not filter
undefined readers.
Author:
Doug Barlow (dbarlow) 5/7/1998
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CSCardSubcontext::StripInactiveReaders")
void
CSCardSubcontext::StripInactiveReaders(
IN OUT CBuffer &bfReaders)
{
ComListReaders comObj;
ComListReaders::CObjListReaders_request *pReq;
ComListReaders::CObjListReaders_response *pRsp;
CBuffer bfDeviceName, bfDevices;
LPCTSTR szReader;
BOOL fSts;
LPBOOL pfDeviceActive;
DWORD dwReaderCount;
//
// Build the corresponding list of device names.
//
if (0 == *(LPCTSTR)bfReaders.Access())
throw (DWORD)SCARD_E_NO_READERS_AVAILABLE;
for (szReader = FirstString((LPCTSTR)bfReaders.Access());
NULL != szReader;
szReader = NextString(szReader))
{
fSts = GetReaderInfo(Scope(), szReader, NULL, &bfDeviceName);
if (!fSts)
throw (DWORD)SCARD_E_UNKNOWN_READER;
MStrAdd(bfDevices, (LPCTSTR)bfDeviceName.Access());
}
//
// Ask the resource manager which ones are active.
//
pReq = comObj.InitRequest(bfDevices.Length());
pReq = (ComListReaders::CObjListReaders_request *)comObj.Append(
pReq->dscReaders, bfDevices.Access(), bfDevices.Length());
SendRequest(&comObj);
comObj.InitResponse(0);
pRsp = comObj.Receive(m_pChannel);
if (SCARD_S_SUCCESS != pRsp->dwStatus)
throw pRsp->dwStatus;
pfDeviceActive = (LPBOOL)comObj.Parse(pRsp->dscReaders, &dwReaderCount);
dwReaderCount /= sizeof(BOOL);
ASSERT(dwReaderCount == MStringCount((LPCTSTR)bfReaders.Access()));
//
// Filter the inactive ones out of the original set.
//
bfDevices.Reset();
for (szReader = FirstString((LPCTSTR)bfReaders.Access());
NULL != szReader;
szReader = NextString(szReader))
{
if (*pfDeviceActive++)
MStrAdd(bfDevices, szReader);
}
//
// Replace the original buffer.
//
bfReaders = bfDevices;
}
//
//==============================================================================
//
// CReaderContext
//
#define INVALID_SCARDHANDLE_VALUE (INTERCHANGEHANDLE)(-1)
/*++
CReaderContext:
~CReaderContext:
These are the constructor and destructor for a client reader context object.
Arguments:
None
Return Value:
None
Throws:
None
Author:
Doug Barlow (dbarlow) 12/7/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CReaderContext::CReaderContext")
CReaderContext::CReaderContext(
void)
{
m_dwActiveProtocol = SCARD_PROTOCOL_UNDEFINED;
m_pCtx = NULL;
m_hCard = (INTERCHANGEHANDLE)INVALID_SCARDHANDLE_VALUE;
m_hRedirCard = NULL;
}
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CReaderContext::~CReaderContext")
CReaderContext::~CReaderContext()
{
try
{
if (NULL != m_pCtx)
{
Context()->Deallocate();
Context()->ReleaseSubcontext();
m_pCtx = NULL;
}
}
catch (...) {}
}
/*++
Connect:
This method requests the Connect service on behalf of the client.
Arguments:
pCtx supplies the Context under which the reader is opened.
szReaderName supplies the name of the reader to connect to.
dwShareMode supplies the form of sharing to be invoked.
dwPreferredProtocols supplies the acceptable protocols.
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CReaderContext::Connect")
void
CReaderContext::Connect(
CSCardSubcontext *pCtx,
LPCTSTR szReaderName,
DWORD dwShareMode,
DWORD dwPreferredProtocols)
{
ComConnect comObj;
ComConnect::CObjConnect_request *pReq;
ComConnect::CObjConnect_response *pRsp;
BOOL fSts;
CBuffer bfDevice;
ASSERT(SCARD_PROTOCOL_UNDEFINED == m_dwActiveProtocol);
ASSERT(NULL == m_pCtx);
if (0 == *szReaderName)
throw (DWORD)SCARD_E_UNKNOWN_READER;
fSts = GetReaderInfo(
pCtx->Scope(),
szReaderName,
NULL,
&bfDevice);
if (!fSts)
throw (DWORD)SCARD_E_UNKNOWN_READER;
pReq = comObj.InitRequest(bfDevice.Length() + sizeof(DWORD));
pReq->dwShareMode = dwShareMode;
pReq->dwPreferredProtocols = dwPreferredProtocols;
pReq = (ComConnect::CObjConnect_request *)comObj.Append(
pReq->dscReader, bfDevice.Access(), bfDevice.Length());
pCtx->SendRequest(&comObj);
comObj.InitResponse(0);
pRsp = comObj.Receive(pCtx->m_pChannel);
if (SCARD_S_SUCCESS != pRsp->dwStatus)
throw pRsp->dwStatus;
m_hCard = pRsp->hCard;
m_dwActiveProtocol = pRsp->dwActiveProtocol;
m_pCtx = pCtx;
}
/*++
Reconnect:
This method requests the Reconnect service on behalf of the client.
Arguments:
dwShareMode supplies the form of sharing to be invoked.
dwPreferredProtocols supplies the acceptable protocols.
dwInitialization supplies the card initialization required.
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CReaderContext::Reconnect")
void
CReaderContext::Reconnect(
DWORD dwShareMode,
DWORD dwPreferredProtocols,
DWORD dwInitialization)
{
ComReconnect comObj;
ComReconnect::CObjReconnect_request *pReq;
ComReconnect::CObjReconnect_response *pRsp;
CSubctxLock ctxLock(Context());
pReq = comObj.InitRequest(0);
pReq->hCard = m_hCard;
pReq->dwShareMode = dwShareMode;
pReq->dwPreferredProtocols = dwPreferredProtocols;
pReq->dwInitialization = dwInitialization;
Context()->SendRequest(&comObj);
comObj.InitResponse(0);
pRsp = comObj.Receive(Context()->m_pChannel);
if (SCARD_S_SUCCESS != pRsp->dwStatus)
throw pRsp->dwStatus;
m_dwActiveProtocol = pRsp->dwActiveProtocol;
}
/*++
Disconnect:
This method requests the Disconnect service on behalf of the client.
Arguments:
dwDisposition - Supplies an indication of what should be done with the card
in the connected reader.
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CReaderContext::Disconnect")
LONG
CReaderContext::Disconnect(
DWORD dwDisposition)
{
ComDisconnect comObj;
ComDisconnect::CObjDisconnect_request *pReq;
ComDisconnect::CObjDisconnect_response *pRsp = NULL;
CSubctxLock ctxLock(Context());
try
{
pReq = comObj.InitRequest(0);
pReq->hCard = m_hCard;
pReq->dwDisposition = dwDisposition;
Context()->SendRequest(&comObj);
comObj.InitResponse(0);
pRsp = comObj.Receive(Context()->m_pChannel);
}
catch (...) {}
if (NULL != m_pCtx)
{
Context()->Deallocate();
m_pCtx = NULL;
}
m_dwActiveProtocol = SCARD_PROTOCOL_UNDEFINED;
m_hCard = INVALID_SCARDHANDLE_VALUE;
return (NULL != pRsp) ? pRsp->dwStatus : SCARD_E_SERVICE_STOPPED;
}
/*++
BeginTransaction:
This method requests the BeginTransaction service on behalf of the client.
Arguments:
None
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CReaderContext::BeginTransaction")
void
CReaderContext::BeginTransaction(
void)
{
ComBeginTransaction comObj;
ComBeginTransaction::CObjBeginTransaction_request *pReq;
ComBeginTransaction::CObjBeginTransaction_response *pRsp;
CSubctxLock ctxLock(Context());
pReq = comObj.InitRequest(0);
pReq->hCard = m_hCard;
Context()->SendRequest(&comObj);
comObj.InitResponse(0);
pRsp = comObj.Receive(Context()->m_pChannel);
if (SCARD_S_SUCCESS != pRsp->dwStatus)
throw pRsp->dwStatus;
}
/*++
EndTransaction:
This method requests the EndTransaction service on behalf of the client.
Arguments:
dwDisposition supplies the disposition of the card.
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CReaderContext::EndTransaction")
void
CReaderContext::EndTransaction(
DWORD dwDisposition)
{
DWORD dw;
if (dwDisposition == SCARD_LEAVE_CARD_FORCE)
{
if (INVALID_SCARDHANDLE_VALUE == m_hCard)
{
return;
}
dw = SCARD_LEAVE_CARD;
}
else
{
dw = dwDisposition;
}
ComEndTransaction comObj;
ComEndTransaction::CObjEndTransaction_request *pReq;
ComEndTransaction::CObjEndTransaction_response *pRsp;
CSubctxLock ctxLock(Context());
pReq = comObj.InitRequest(0);
pReq->hCard = m_hCard;
pReq->dwDisposition = dw;
Context()->SendRequest(&comObj);
comObj.InitResponse(0);
pRsp = comObj.Receive(Context()->m_pChannel);
if (SCARD_S_SUCCESS != pRsp->dwStatus)
throw pRsp->dwStatus;
}
/*++
Status:
This method requests the Status service on behalf of the client.
Arguments:
pdwState - This receives the current state of the reader. Upon success, it
receives one of the following state indicators:
SCARD_ABSENT - This value implies there is no card in the reader.
SCARD_PRESENT - This value implies there is a card is present in the
reader, but that it has not been moved into position for use.
SCARD_SWALLOWED - This value implies there is a card in the reader in
position for use. The card is not powered.
SCARD_POWERED - This value implies there is power is being provided to
the card, but the Reader Driver is unaware of the mode of the card.
SCARD_NEGOTIABLEMODE - This value implies the card has been reset and is
awaiting PTS negotiation.
SCARD_SPECIFICMODE - This value implies the card has been reset and
specific communication protocols have been established.
pdwProtocol - This receives the current protocol, if any. Possible returned
values are listed below. Other values may be added in the future. The
returned value is only meaningful if the returned state is
SCARD_SPECIFICMODE.
SCARD_PROTOCOL_RAW - The Raw Transfer Protocol is in use.
SCARD_PROTOCOL_T0 - The ISO 7816/3 T=0 Protocol is in use.
SCARD_PROTOCOL_T1 - The ISO 7816/3 T=1 Protocol is in use.
bfAtr - This receives the current ATR, if any.
bfReaderNames - This receives the list of friendly names assigned to the
connected reader, as a MultiString.
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 11/14/1997
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CReaderContext::Status")
void
CReaderContext::Status(
OUT LPDWORD pdwState,
OUT LPDWORD pdwProtocol,
OUT CBuffer &bfAtr,
OUT CBuffer &bfReaderNames)
{
ComStatus comObj;
ComStatus::CObjStatus_request *pReq;
ComStatus::CObjStatus_response *pRsp;
CBuffer bfSysName;
LPCBYTE pbAtr;
DWORD cbAtr;
LPCTSTR szSysName;
CSubctxLock ctxLock(Context());
pReq = comObj.InitRequest(0);
pReq->hCard = m_hCard;
Context()->SendRequest(&comObj);
comObj.InitResponse(0);
pRsp = comObj.Receive(Context()->m_pChannel);
if (SCARD_S_SUCCESS != pRsp->dwStatus)
throw pRsp->dwStatus;
*pdwState = pRsp->dwState;
*pdwProtocol = pRsp->dwProtocol;
pbAtr = (LPCBYTE)comObj.Parse(pRsp->dscAtr, &cbAtr);
szSysName = (LPCTSTR)comObj.Parse(pRsp->dscSysName);
bfAtr.Set(pbAtr, cbAtr);
ListReaderNames(
Context()->Scope(),
szSysName,
bfReaderNames);
}
/*++
Transmit:
This method requests the Transmit service on behalf of the client.
Arguments:
pioSendPci - This supplies the protocol header structure for the
instruction.
pbSendBuffer - This supplies the actual data to be written to the card in
conjunction with the command.
cbSendLength - This supplies the length of the pbDataBuffer parameter, in
bytes.
pioRecvPci - This receives the return protocol header structure from the
instruction.
bfRecvData - This receives any data returned from the card in conjunction
with the command.
cbProposedLength - This supplies a maximum length for the received data.
If this value is zero, then the server uses the default max length.
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CReaderContext::Transmit")
void
CReaderContext::Transmit(
IN LPCSCARD_IO_REQUEST pioSendPci,
IN LPCBYTE pbSendBuffer,
IN DWORD cbSendLength,
OUT LPSCARD_IO_REQUEST pioRecvPci,
OUT CBuffer &bfRecvData,
IN DWORD cbProposedLength)
{
static const SCARD_IO_REQUEST ioNullPci = { 0, sizeof(SCARD_IO_REQUEST) };
ComTransmit comObj;
ComTransmit::CObjTransmit_request *pReq;
ComTransmit::CObjTransmit_response *pRsp;
LPSCARD_IO_REQUEST pioIoreq;
DWORD cbIoreq, cbData;
LPCBYTE pbData;
CSubctxLock ctxLock(Context());
if (NULL == pioSendPci)
pioSendPci = &ioNullPci;
pReq = comObj.InitRequest(pioSendPci->cbPciLength + cbSendLength
+ 2 * sizeof(DWORD)
+ 2 * sizeof(DWORD));
pReq->hCard = m_hCard;
pReq->dwPciLength = (NULL == pioRecvPci)
? sizeof(SCARD_IO_REQUEST)
: pioRecvPci->cbPciLength;
pReq->dwRecvLength = cbProposedLength;
pReq = (ComTransmit::CObjTransmit_request *)comObj.Append(
pReq->dscSendPci,
(LPCBYTE)pioSendPci,
pioSendPci->cbPciLength);
pReq = (ComTransmit::CObjTransmit_request *)comObj.Append(
pReq->dscSendBuffer,
pbSendBuffer,
cbSendLength);
Context()->SendRequest(&comObj);
comObj.InitResponse(pReq->dwPciLength + pReq->dwRecvLength
+ 2 * sizeof(DWORD));
pRsp = comObj.Receive(Context()->m_pChannel);
if (SCARD_S_SUCCESS != pRsp->dwStatus)
throw pRsp->dwStatus;
pioIoreq = (LPSCARD_IO_REQUEST)comObj.Parse(pRsp->dscRecvPci, &cbIoreq);
ASSERT(cbIoreq == pioIoreq->cbPciLength);
if (NULL != pioRecvPci)
{
if (cbIoreq > pioRecvPci->cbPciLength)
throw (DWORD)SCARD_E_PCI_TOO_SMALL;
CopyMemory(pioRecvPci, pioIoreq, cbIoreq);
}
pbData = (LPCBYTE)comObj.Parse(pRsp->dscRecvBuffer, &cbData);
bfRecvData.Set(pbData, cbData);
}
/*++
Control:
This method requests the Control service on behalf of the client.
Arguments:
dwControlCode - This supplies the control code for the operation. This value
identifies the specific operation to be performed.
pvInBuffer - This supplies a pointer to a buffer that contains the data
required to perform the operation. This parameter can be NULL if the
dwControlCode parameter specifies an operation that does not require
input data.
cbInBufferSize - This supplies the size, in bytes, of the buffer pointed to
by pvInBuffer.
bfOutBuffer - This buffer receives the operation's output data.
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CReaderContext::Control")
void
CReaderContext::Control(
IN DWORD dwControlCode,
IN LPCVOID pvInBuffer,
IN DWORD cbInBufferSize,
OUT CBuffer &bfOutBuffer)
{
ComControl comObj;
ComControl::CObjControl_request *pReq;
ComControl::CObjControl_response *pRsp;
LPCBYTE pbData;
DWORD cbData;
CSubctxLock ctxLock(Context());
pReq = comObj.InitRequest(cbInBufferSize + sizeof(DWORD));
pReq->hCard = m_hCard;
pReq->dwControlCode = dwControlCode;
pReq->dwOutLength = bfOutBuffer.Space();
pReq = (ComControl::CObjControl_request *)
comObj.Append(pReq->dscInBuffer, (LPCBYTE)pvInBuffer, cbInBufferSize);
Context()->SendRequest(&comObj);
comObj.InitResponse(0);
pRsp = comObj.Receive(Context()->m_pChannel);
if (SCARD_S_SUCCESS != pRsp->dwStatus)
throw pRsp->dwStatus;
pbData = (LPCBYTE)comObj.Parse(pRsp->dscOutBuffer, &cbData);
bfOutBuffer.Set(pbData, cbData);
}
/*++
GetAttrib:
This method requests the GetAttrib service on behalf of the client.
Arguments:
dwAttrId - This supplies the identifier for the attribute to get.
bfAttr - This buffer receives the attribute corresponding to the attribute
id supplied in the dwAttrId parameter.
cbProposedLength - This supplies a maximum length for the received data.
If this value is zero, then the server uses the default max length.
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CReaderContext::GetAttrib")
void
CReaderContext::GetAttrib(
IN DWORD dwAttrId,
OUT CBuffer &bfAttr,
DWORD cbProposedLen)
{
ComGetAttrib comObj;
ComGetAttrib::CObjGetAttrib_request *pReq;
ComGetAttrib::CObjGetAttrib_response *pRsp;
LPCBYTE pbData;
DWORD cbData;
CSubctxLock ctxLock(Context());
pReq = comObj.InitRequest(0);
pReq->hCard = m_hCard;
pReq->dwAttrId = dwAttrId;
pReq->dwOutLength = cbProposedLen;
Context()->SendRequest(&comObj);
comObj.InitResponse(0);
pRsp = comObj.Receive(Context()->m_pChannel);
if (SCARD_S_SUCCESS != pRsp->dwStatus)
throw pRsp->dwStatus;
pbData = (LPCBYTE)comObj.Parse(pRsp->dscAttr, &cbData);
bfAttr.Set(pbData, cbData);
}
/*++
SetAttrib:
This method requests the SetAttrib service on behalf of the client.
Arguments:
dwAttrId - This supplies the identifier for the attribute to get.
pbAttr - This buffer supplies the attribute corresponding to the attribute
id supplied in the dwAttrId parameter.
cbAttrLength - This supplies the length of the attribute value in pbAttr
buffer in bytes.
Return Value:
None
Throws:
Errors are thrown as DWORD status codes.
Author:
Doug Barlow (dbarlow) 12/6/1996
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CReaderContext::SetAttrib")
void
CReaderContext::SetAttrib(
IN DWORD dwAttrId,
IN LPCBYTE pbAttr,
IN DWORD cbAttrLen)
{
ComSetAttrib comObj;
ComSetAttrib::CObjSetAttrib_request *pReq;
ComSetAttrib::CObjSetAttrib_response *pRsp;
CSubctxLock ctxLock(Context());
pReq = comObj.InitRequest(0);
pReq->hCard = m_hCard;
pReq->dwAttrId = dwAttrId;
pReq = (ComSetAttrib::CObjSetAttrib_request *)
comObj.Append(pReq->dscAttr, pbAttr, cbAttrLen);
Context()->SendRequest(&comObj);
comObj.InitResponse(0);
pRsp = comObj.Receive(Context()->m_pChannel);
if (SCARD_S_SUCCESS != pRsp->dwStatus)
throw pRsp->dwStatus;
}