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.
 
 
 
 
 
 

4011 lines
70 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
iiscmr.cxx
Abstract:
Classes to handle IIS client cert wildcard mappings
Author:
Philippe Choquier (phillich) 17-oct-1996
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#define _CRYPT32_
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <wincrypt.h>
#include <iis64.h>
#include <locks.h>
#define DLL_IMPLEMENTATION
#include <iismap.hxx>
#include "iismaprc.h"
#include "mapmsg.h"
#include <iiscmr.hxx>
#include <icrypt.hxx>
#include <dbgutil.h>
#include <lmcons.h>
typedef
WINCRYPT32API
BOOL
(WINAPI* PFNCryptDecodeObject)(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT void *pvStructInfo,
IN OUT DWORD *pcbStructInfo
);
//
// GLOBALS
//
//
// definition of ASN.1 <> X.509 name conversion
//
MAP_ASN aMapAsn[] = {
{ szOID_COUNTRY_NAME, "", IDS_CMR_ASN_C },
{ szOID_ORGANIZATION_NAME, "", IDS_CMR_ASN_O },
{ szOID_ORGANIZATIONAL_UNIT_NAME, "", IDS_CMR_ASN_OU },
{ szOID_COMMON_NAME, "", IDS_CMR_ASN_CN },
{ szOID_LOCALITY_NAME, "", IDS_CMR_ASN_L },
{ szOID_STATE_OR_PROVINCE_NAME, "", IDS_CMR_ASN_S },
{ szOID_TITLE, "", IDS_CMR_ASN_T },
{ szOID_GIVEN_NAME, "", IDS_CMR_ASN_GN },
{ szOID_INITIALS, "", IDS_CMR_ASN_I },
{ "1.2.840.113549.1.9.1", "", IDS_CMR_ASN_Email },
{ "1.2.840.113549.1.9.8", "", IDS_CMR_ASN_Addr }, // warning: can include CR/LF
} ;
HINSTANCE hCapi2Lib = NULL;
PFNCryptDecodeObject
pfnCryptDecodeObject = NULL;
char HEXTOA[] = "0123456789abcdef";
MAP_FIELD aMapField[] = {
{ CERT_FIELD_ISSUER, IDS_CMR_X509FLD_IS, "" },
{ CERT_FIELD_SUBJECT, IDS_CMR_X509FLD_SU, "" },
{ CERT_FIELD_SERIAL_NUMBER, IDS_CMR_X509FLD_SN, "" },
} ;
DWORD adwFieldFlags[]={
CERT_FIELD_FLAG_CONTAINS_SUBFIELDS,
CERT_FIELD_FLAG_CONTAINS_SUBFIELDS,
0,
};
//
// Global functions
//
BOOL
Unserialize(
LPBYTE* ppB,
LPDWORD pC,
LPDWORD pU
)
/*++
Routine Description:
Unserialize a DWORD
pU is updated with DWORD from *ppB, ppB & pC are updated
Arguments:
ppB - ptr to addr of buffer
pC - ptr to byte count in buffer
pU - ptr to DWORD where to unserialize
Return Value:
TRUE if successful, FALSE on error
--*/
{
DWORD dwTemp; // added to handle 64 bit alignment problems
if ( *pC >= sizeof( DWORD ) )
{
dwTemp = **ppB;
*pU = dwTemp;
*ppB += sizeof(DWORD);
*pC -= sizeof(DWORD);
return TRUE;
}
return FALSE;
}
BOOL
Unserialize(
LPBYTE* ppB,
LPDWORD pC,
LPBOOL pU
)
/*++
Routine Description:
Unserialize a BOOL
pU is updated with BOOL from *ppB, ppB & pC are updated
Arguments:
ppB - ptr to addr of buffer
pC - ptr to byte count in buffer
pU - ptr to BOOL where to unserialize
Return Value:
TRUE if successful, FALSE on error
--*/
{
BOOL bTemp; // added to handle 64 bit alignment problems
if ( *pC >= sizeof( BOOL ) )
{
bTemp = **ppB;
*pU = bTemp;
*ppB += sizeof(BOOL);
*pC -= sizeof(BOOL);
return TRUE;
}
return FALSE;
}
//
// Extensible buffer class
//
BOOL
CStoreXBF::Need(
DWORD dwNeed
)
/*++
Routine Description:
Insure that CStoreXBF can store at least dwNeed bytes
including bytes already stored.
Arguments:
dwNeed - minimum of bytes available for storage
Return Value:
TRUE if successful, FALSE on error
--*/
{
if ( dwNeed > m_cAllocBuff )
{
dwNeed = ((dwNeed + m_cGrain)/m_cGrain)*m_cGrain;
LPBYTE pN = (LPBYTE)LocalAlloc( LMEM_FIXED, dwNeed );
if ( pN == NULL )
{
return FALSE;
}
if ( m_cUsedBuff )
{
// expanding buffer
// copy existing data into new buffer
//
DBG_ASSERT( m_cUsedBuff <= dwNeed );
memcpy( pN, m_pBuff, m_cUsedBuff );
}
m_cAllocBuff = dwNeed;
LocalFree( m_pBuff );
m_pBuff = pN;
}
return TRUE;
}
BOOL
CStoreXBF::Save(
HANDLE hFile
)
/*++
Routine Description:
Save to file
Arguments:
hFile - file handle
Return Value:
TRUE if successful, FALSE on error
--*/
{
DWORD dwWritten;
return WriteFile( hFile, GetBuff(), GetUsed(), &dwWritten, NULL ) &&
dwWritten == GetUsed();
}
BOOL
CStoreXBF::Load(
HANDLE hFile
)
/*++
Routine Description:
Load from file
Arguments:
hFile - file handle
Return Value:
TRUE if successful, FALSE on error
--*/
{
DWORD dwS = GetFileSize( hFile, NULL );
DWORD dwRead;
if ( dwS != 0xffffffff &&
Need( dwS ) &&
ReadFile( hFile, GetBuff(), dwS, &dwRead, NULL ) &&
dwRead == dwS )
{
m_cUsedBuff = dwRead;
return TRUE;
}
m_cUsedBuff = 0;
return FALSE;
}
BOOL
Serialize(
CStoreXBF* pX,
DWORD dw
)
/*++
Routine Description:
Serialize a DWORD in CStoreXBF
Arguments:
pX - ptr to CStoreXBF where to add serialized DWORD
dw - DWORD to serialize
Return Value:
TRUE if successful, FALSE on error
--*/
{
return pX->Append( (LPBYTE)&dw, sizeof(dw) );
}
//
// extensible array of LPVOID
//
BOOL
Serialize(
CStoreXBF* pX,
BOOL f
)
/*++
Routine Description:
Serialize a BOOL in CStoreXBF
Arguments:
pX - ptr to CStoreXBF where to add serialized BOOL
f - BOOL to serialize
Return Value:
TRUE if successful, FALSE on error
--*/
{
return pX->Append( (LPBYTE)&f, sizeof(f) );
}
DWORD
CPtrXBF::AddPtr(
LPVOID pV
)
/*++
Routine Description:
Add a ptr to array
Arguments:
pV - ptr to be added at end of array
Return Value:
index ( 0-based ) in array where added or INDEX_ERROR if error
--*/
{
DWORD i = GetNbPtr();
if ( Append( (LPBYTE)&pV, sizeof(pV)) )
{
return i;
}
return INDEX_ERROR;
}
DWORD
CPtrXBF::InsertPtr(
DWORD iBefore,
LPVOID pV
)
/*++
Routine Description:
Insert a ptr to array
Arguments:
iBefore - index where to insert entry, or 0xffffffff if add to array
pV - ptr to be inserted
Return Value:
index ( 0-based ) in array where added or INDEX_ERROR if error
--*/
{
if ( iBefore == INDEX_ERROR || iBefore >= GetNbPtr() )
{
return AddPtr( pV );
}
if ( AddPtr( NULL ) != INDEX_ERROR )
{
//
// AddPtr has taken care of expanding
// moving all the pointer passed the insertion point
// using memmove is thus safe
//
memmove( GetBuff()+(iBefore+1)*sizeof(LPVOID),
GetBuff()+iBefore*sizeof(LPVOID),
GetUsed()-(iBefore+1)*sizeof(LPVOID) );
SetPtr( iBefore, pV );
return iBefore;
}
return INDEX_ERROR;
}
BOOL
CPtrXBF::DeletePtr(
DWORD i
)
/*++
Routine Description:
Delete a ptr from array
Arguments:
i - index of ptr to delete
Return Value:
TRUE if success, otherwise FALSE
--*/
{
//
// shrinking is safe
//
memmove( GetBuff()+i*sizeof(LPVOID),
GetBuff()+(i+1)*sizeof(LPVOID),
GetUsed()-(i+1)*sizeof(LPVOID) );
DecreaseUse( sizeof(LPVOID) );
return TRUE;
}
BOOL
CPtrXBF::Unserialize(
LPBYTE* ppB,
LPDWORD pC,
DWORD cNbEntry
)
/*++
Routine Description:
Unserialize a ptr array
Arguments:
ppB - ptr to addr of buffer to unserialize from
pC - ptr to count of bytes in buffer
cNbEntry - # of ptr to unserialize from buffer
Return Value:
TRUE if success, otherwise FALSE
--*/
{
Reset();
if ( *pC >= cNbEntry * sizeof(LPVOID) &&
Append( *ppB, cNbEntry * sizeof(LPVOID) ) )
{
*ppB += cNbEntry * sizeof(LPVOID);
*pC -= cNbEntry * sizeof(LPVOID);
return TRUE;
}
return FALSE;
}
BOOL
CPtrXBF::Serialize(
CStoreXBF* pX
)
/*++
Routine Description:
Serialize a ptr array
Arguments:
pX - ptr to CStoreXBF to serialize to
Return Value:
TRUE if success, otherwise FALSE
--*/
{
return pX->Append( (LPBYTE)GetBuff(), (DWORD)GetUsed() );
}
//
// extensible array of DWORDS
// Added to make win64 stuff work
//
DWORD
CPtrDwordXBF::AddPtr(
DWORD pV
)
/*++
Routine Description:
Add a ptr to array
Arguments:
pV - ptr to be added at end of array
Return Value:
index ( 0-based ) in array where added or INDEX_ERROR if error
--*/
{
DWORD i = GetNbPtr();
if ( Append( (LPBYTE)&pV, sizeof(pV)) )
{
return i;
}
return INDEX_ERROR;
}
DWORD
CPtrDwordXBF::InsertPtr(
DWORD iBefore,
DWORD pV
)
/*++
Routine Description:
Insert a ptr to array
Arguments:
iBefore - index where to insert entry, or 0xffffffff if add to array
pV - ptr to be inserted
Return Value:
index ( 0-based ) in array where added or INDEX_ERROR if error
--*/
{
if ( iBefore == INDEX_ERROR || iBefore >= GetNbPtr() )
{
return AddPtr( pV );
}
if ( AddPtr( NULL ) != INDEX_ERROR )
{
//
// AddPtr has taken care of adding additional memory
// It is safe now to shift array passed the insertion point by one
//
memmove( GetBuff()+(iBefore+1)*sizeof(DWORD),
GetBuff()+iBefore*sizeof(DWORD),
GetUsed()-(iBefore+1)*sizeof(DWORD) );
SetPtr( iBefore, pV );
return iBefore;
}
return INDEX_ERROR;
}
BOOL
CPtrDwordXBF::DeletePtr(
DWORD i
)
/*++
Routine Description:
Delete a ptr from array
Arguments:
i - index of ptr to delete
Return Value:
TRUE if success, otherwise FALSE
--*/
{
//
// shrinking is safe, no risk of buffer overflow
//
memmove( GetBuff()+i*sizeof(DWORD),
GetBuff()+(i+1)*sizeof(DWORD),
GetUsed()-(i+1)*sizeof(DWORD) );
DecreaseUse( sizeof(LPVOID) );
return TRUE;
}
BOOL
CPtrDwordXBF::Unserialize(
LPBYTE* ppB,
LPDWORD pC,
DWORD cNbEntry
)
/*++
Routine Description:
Unserialize a ptr array
Arguments:
ppB - ptr to addr of buffer to unserialize from
pC - ptr to count of bytes in buffer
cNbEntry - # of ptr to unserialize from buffer
Return Value:
TRUE if success, otherwise FALSE
--*/
{
Reset();
if ( *pC >= cNbEntry * sizeof(DWORD))
{
if (Append( *ppB, cNbEntry * sizeof(DWORD) ))
{
*ppB += cNbEntry * sizeof(DWORD);
*pC -= cNbEntry * sizeof(DWORD);
return TRUE;
}
}
return FALSE;
}
BOOL
CPtrDwordXBF::Serialize(
CStoreXBF* pX
)
/*++
Routine Description:
Serialize a ptr array
Arguments:
pX - ptr to CStoreXBF to serialize to
Return Value:
TRUE if success, otherwise FALSE
--*/
{
return pX->Append( (LPBYTE)GetBuff(), (DWORD)GetUsed() );
}
//
// string storage class
//
BOOL
CAllocString::Set(
LPSTR pS
)
/*++
Routine Description:
Set a string content, freeing prior content if any
Arguments:
pS - string to copy
Return Value:
TRUE if successful, FALSE on error
--*/
{
size_t l;
Reset();
if ( ( m_pStr = (LPSTR)LocalAlloc( LMEM_FIXED, l = strlen(pS)+1 ) ) != NULL )
{
memcpy( m_pStr, pS, l );
return TRUE;
}
return FALSE;
}
BOOL
CAllocString::Append(
LPSTR pS
)
/*++
Routine Description:
Append a string content
Arguments:
pS - string to append
Return Value:
TRUE if successful, FALSE on error
--*/
{
size_t l = m_pStr ? strlen(m_pStr ) : 0;
size_t nl;
LPSTR pStr;
if ( (pStr = (LPSTR)LocalAlloc( LMEM_FIXED, l + (nl = strlen(pS)+1 ))) != NULL )
{
memcpy( pStr, m_pStr, l );
memcpy( pStr+l, pS, nl );
//
// Free the old block before we blow it away.
//
Reset();
m_pStr = pStr;
return TRUE;
}
return FALSE;
}
BOOL
CAllocString::Unserialize(
LPBYTE* ppb,
LPDWORD pc
)
/*++
Routine Description:
Unserialize a string
Arguments:
ppB - ptr to addr of buffer to unserialize from
pC - ptr to count of bytes in buffer
Return Value:
TRUE if success, otherwise FALSE
--*/
{
DWORD dwL;
if ( ::Unserialize( ppb, pc, &dwL ) &&
(m_pStr = (LPSTR)LocalAlloc( LMEM_FIXED, dwL + 1)) != NULL )
{
memcpy( m_pStr, *ppb, dwL );
m_pStr[dwL] = '\0';
*ppb += dwL;
*pc -= dwL;
return TRUE;
}
return FALSE;
}
BOOL
CAllocString::Serialize(
CStoreXBF* pX
)
/*++
Routine Description:
Serialize a string
Arguments:
pX - ptr to CStoreXBF to serialize to
Return Value:
TRUE if success, otherwise FALSE
--*/
{
LPSTR pS = m_pStr ? m_pStr : "";
return ::Serialize( pX, (DWORD)strlen(pS) ) && pX->Append( pS );
}
//
// binary object, contains ptr & size
//
BOOL
CBlob::Set(
LPBYTE pStr,
DWORD cStr
)
/*++
Routine Description:
Store a buffer in a blob object
buffer is copied inside blob
blob is reset before copy
Arguments:
pStr - ptr to buffer to copy
cStr - length of buffer
Return Value:
TRUE if success, otherwise FALSE
--*/
{
Reset();
return InitSet( pStr, cStr);
}
BOOL
CBlob::InitSet(
LPBYTE pStr,
DWORD cStr
)
/*++
Routine Description:
Store a buffer in a blob object
buffer is copied inside blob
blob is not reset before copy, initial blob content ignored
Arguments:
pStr - ptr to buffer to copy
cStr - length of buffer
Return Value:
TRUE if success, otherwise FALSE
--*/
{
if ( (m_pStr = (LPBYTE)LocalAlloc( LMEM_FIXED, cStr )) != NULL )
{
memcpy( m_pStr, pStr, cStr );
m_cStr = cStr;
return TRUE;
}
return FALSE;
}
BOOL
CBlob::Unserialize(
LPBYTE* ppB,
LPDWORD pC
)
/*++
Routine Description:
Unserialize a blob
Arguments:
ppB - ptr to addr of buffer to unserialize from
pC - ptr to count of bytes in buffer
Return Value:
TRUE if success, otherwise FALSE
--*/
{
Reset();
if ( ::Unserialize( ppB, pC, &m_cStr ) &&
*pC >= m_cStr &&
( m_pStr = (LPBYTE)LocalAlloc( LMEM_FIXED, m_cStr ) ) != NULL )
{
memcpy( m_pStr, *ppB, m_cStr );
*ppB += m_cStr;
*pC -= m_cStr;
}
else
{
m_cStr = 0;
return FALSE;
}
return TRUE;
}
BOOL
CBlob::Serialize(
CStoreXBF* pX
)
/*++
Routine Description:
Serialize a blob
Arguments:
pX - ptr to CStoreXBF to serialize to
Return Value:
TRUE if success, otherwise FALSE
--*/
{
return ::Serialize( pX, m_cStr ) &&
pX->Append( m_pStr, m_cStr );
}
//
// extensible array of strings
//
CStrPtrXBF::~CStrPtrXBF(
)
/*++
Routine Description:
CStrPtrXBF destructor
Arguments:
None
Return Value:
Nothing
--*/
{
DWORD iM = GetNbPtr();
UINT i;
for ( i = 0 ; i < iM ; ++i )
{
((CAllocString*)GetPtrAddr(i))->Reset();
}
}
DWORD
CStrPtrXBF::AddEntry(
LPSTR pS
)
/*++
Routine Description:
Add a string to array
string content is copied in array
Arguments:
pS - string to be added at end of array
Return Value:
index ( 0-based ) in array where added or INDEX_ERROR if error
--*/
{
DWORD i;
if ( (i = AddPtr( NULL )) != INDEX_ERROR )
{
return ((CAllocString*)GetPtrAddr(i))->Set( pS ) ? i : INDEX_ERROR;
}
return INDEX_ERROR;
}
DWORD
CStrPtrXBF::InsertEntry(
DWORD iBefore,
LPSTR pS
)
/*++
Routine Description:
Insert a string in array
string content is copied in array
Arguments:
iBefore - index where to insert entry, or 0xffffffff if add to array
pS - string to be inserted in array
Return Value:
index ( 0-based ) in array where added or INDEX_ERROR if error
--*/
{
DWORD i;
if ( (i = InsertPtr( iBefore, NULL )) != INDEX_ERROR )
{
return ((CAllocString*)GetPtrAddr(i))->Set( pS ) ? i : INDEX_ERROR;
}
return INDEX_ERROR;
}
BOOL
CStrPtrXBF::DeleteEntry(
DWORD i
)
/*++
Routine Description:
Delete a string from array
Arguments:
i - index of string to delete
Return Value:
TRUE if success, otherwise FALSE
--*/
{
if ( i < GetNbPtr() )
{
((CAllocString*)GetPtrAddr(i))->Reset();
DeletePtr( i );
return TRUE;
}
return FALSE;
}
BOOL
CStrPtrXBF::Unserialize(
LPBYTE* ppB,
LPDWORD pC,
DWORD cNbEntry
)
/*++
Routine Description:
Unserialize a string array
Arguments:
ppB - ptr to addr of buffer
pC - ptr to byte count in buffer
cNbEntry - # of entry to unserialize
Return Value:
TRUE if successful, FALSE on error
--*/
{
UINT i;
Reset();
CAllocString empty;
for ( i = 0 ; i < cNbEntry ; ++i )
{
if ( !Append( (LPBYTE)&empty, sizeof(empty)) ||
!((CAllocString*)GetPtrAddr(i))->Unserialize( ppB, pC ) )
{
return FALSE;
}
}
return TRUE;
}
BOOL
CStrPtrXBF::Serialize(
CStoreXBF* pX
)
/*++
Routine Description:
Serialize a string array
Arguments:
pX - ptr to CStoreXBF where to add serialized DWORD
Return Value:
TRUE if successful, FALSE on error
--*/
{
UINT i;
for ( i = 0 ; i < GetNbEntry() ; ++i )
{
if ( !((CAllocString*)GetPtrAddr(i))->Serialize( pX ) )
{
return FALSE;
}
}
return TRUE;
}
//
// extensible array of binary object
// ptr & size are stored for each entry
//
CBlobXBF::~CBlobXBF(
)
/*++
Routine Description:
CBlobXBF destructor
Arguments:
None
Return Value:
Nothing
--*/
{
DWORD iM = GetUsed()/sizeof(CBlob);
UINT i;
for ( i = 0 ; i < iM ; ++i )
{
GetBlob(i)->Reset();
}
}
VOID CBlobXBF::Reset(
)
/*++
Routine Description:
Reset the blob content to NULL
Arguments:
None
Return Value:
Nothing
--*/
{
DWORD iM = GetUsed()/sizeof(CBlob);
UINT i;
for ( i = 0 ; i < iM ; ++i )
{
GetBlob(i)->Reset();
}
CStoreXBF::Reset();
}
DWORD
CBlobXBF::AddEntry(
LPBYTE pS,
DWORD cS
)
/*++
Routine Description:
Add a buffer to blob array
buffer content is copied in array
Arguments:
pS - buffer to be added at end of array
cS - length of buffer
Return Value:
index ( 0-based ) in array where added or INDEX_ERROR if error
--*/
{
DWORD i = GetNbEntry();
if ( Append( (LPBYTE)&pS, sizeof(CBlob) ) )
{
return GetBlob(i)->InitSet( pS, cS ) ? i : INDEX_ERROR;
}
return INDEX_ERROR;
}
DWORD
CBlobXBF::InsertEntry(
DWORD iBefore,
LPSTR pS,
DWORD cS )
/*++
Routine Description:
Insert a buffer in blob array
buffer content is copied in array
Arguments:
iBefore - index where to insert entry, or 0xffffffff if add to array
pS - buffer to be inserted in array
cS - length of buffer
Return Value:
index ( 0-based ) in array where added or INDEX_ERROR if error
--*/
{
if ( iBefore == INDEX_ERROR || iBefore >= GetNbEntry() )
{
return AddEntry( (LPBYTE)pS, cS );
}
if ( iBefore < GetNbEntry() && Append( (LPBYTE)&pS, sizeof(CBlob) ) )
{
//
// Append has taken care of expanding memory
// safe to memmove by one entry
//
memmove( GetBuff()+(iBefore+1)*sizeof(CBlob),
GetBuff()+iBefore*sizeof(CBlob),
GetUsed()-(iBefore+1)*sizeof(CBlob) );
return GetBlob(iBefore)->InitSet( (LPBYTE)pS, cS ) ? iBefore : INDEX_ERROR;
}
return INDEX_ERROR;
}
BOOL
CBlobXBF::DeleteEntry(
DWORD i
)
/*++
Routine Description:
Delete a entry from blob array
Arguments:
i - index of string to delete
Return Value:
TRUE if success, otherwise FALSE
--*/
{
if ( i < GetNbEntry() )
{
GetBlob(i)->Reset();
// shrinking is safe, no risk of buffer overflow
//
memmove( GetBuff()+i*sizeof(CBlob),
GetBuff()+(i+1)*sizeof(CBlob),
GetUsed()-(i+1)*sizeof(CBlob) );
DecreaseUse( sizeof(CBlob) );
return TRUE;
}
return FALSE;
}
BOOL
CBlobXBF::Unserialize(
LPBYTE* ppB,
LPDWORD pC,
DWORD cNbEntry )
/*++
Routine Description:
Unserialize a blob array
Arguments:
ppB - ptr to addr of buffer to unserialize from
pC - ptr to count of bytes in buffer
cNbEntry - # of ptr to unserialize from buffer
Return Value:
TRUE if success, otherwise FALSE
--*/
{
UINT i;
Reset();
CBlob empty;
for ( i = 0 ; i < cNbEntry ; ++i )
{
if ( !Append( (LPBYTE)&empty, sizeof(empty) ) ||
!GetBlob(i)->Unserialize( ppB, pC ) )
{
return FALSE;
}
}
return TRUE;
}
BOOL
CBlobXBF::Serialize(
CStoreXBF* pX
)
/*++
Routine Description:
Serialize a blob array
Arguments:
pX - ptr to CStoreXBF where to add serialized blob
Return Value:
TRUE if successful, FALSE on error
--*/
{
UINT i;
for ( i = 0 ; i < GetNbEntry() ; ++i )
{
if ( !GetBlob(i)->Serialize( pX ) )
{
return FALSE;
}
}
return TRUE;
}
CDecodedCert::CDecodedCert(
PCERT_CONTEXT pCert
)
/*++
Routine Description:
Constructor
Store a reference to cert ( cert data is NOT copied )
Arguments:
pCert - cert
Return Value:
Nothing
--*/
{
UINT i;
for ( i = 0 ; i < CERT_FIELD_LAST ; ++i )
{
aniFields[i] = NULL;
}
pCertCtx = (PCCERT_CONTEXT)pCert;
}
CDecodedCert::~CDecodedCert(
)
/*++
Routine Description:
Destructor
Arguments:
None
Return Value:
Nothing
--*/
{
UINT i;
for ( i = 0 ; i < CERT_FIELD_LAST ; ++i )
{
if ( aniFields[i] != NULL )
{
LocalFree( aniFields[i] );
}
}
}
BOOL
CDecodedCert::GetIssuer(
LPVOID* ppCert,
LPDWORD pcCert
)
/*++
Routine Description:
Get the issuer portion of a cert
Returns a reference : issuer is NOT copied
Arguments:
ppCert - updated with ptr to issuer
pcCert - updated with issuer byte count
Return Value:
TRUE if successful, FALSE on error
--*/
{
if ( pCertCtx == NULL )
{
return FALSE;
}
*ppCert = pCertCtx->pCertInfo->Issuer.pbData;
*pcCert = pCertCtx->pCertInfo->Issuer.cbData;
return TRUE;
}
PCERT_RDN_ATTR *
CDecodedCert::GetSubField(
CERT_FIELD_ID fi,
LPSTR pszAsnName,
LPDWORD pcElements
)
/*++
Routine Description:
Returns a cert sub-field ( e.g. Issuer.O ). There may be multiple entries
for a given subfield. This functions returns an array of attribute values
Arguments:
fi - cert field where sub-field is located
pszAsnName - ASN.1 name of sub-field inside fi
pcElements - Number of elements returned in array
Return Value:
ptr to array of pointers to attribute blobs if success, otherwise NULL
--*/
{
CERT_NAME_BLOB* pBlob;
DWORD cbNameInfo;
PCERT_NAME_INFO pNameInfo;
DWORD cRDN;
DWORD cAttr;
PCERT_RDN pRDN;
PCERT_RDN_ATTR pAttr;
PCERT_RDN_ATTR* pAttrValues = NULL;
DWORD cRet = 0;
DWORD cMaxRet = 0;
if ( pfnCryptDecodeObject == NULL )
{
SetLastError(ERROR_PROC_NOT_FOUND);
return NULL;
}
*pcElements = 0;
switch( fi )
{
case CERT_FIELD_ISSUER:
pBlob = &pCertCtx->pCertInfo->Issuer;
break;
case CERT_FIELD_SUBJECT:
pBlob = &pCertCtx->pCertInfo->Subject;
break;
case CERT_FIELD_SERIAL_NUMBER:
pAttrValues = (PCERT_RDN_ATTR*)
LocalAlloc( LPTR, sizeof( PCERT_RDN_ATTR ) );
if ( pAttrValues == NULL )
{
return NULL;
}
*pcElements = 1;
//
// Setup a CERT_RDN_ATTR so that GetSubField() can always return a
// pointer to an array of CERT_RDN_ATTRs
//
SerialNumber.dwValueType = CERT_RDN_OCTET_STRING;
SerialNumber.Value = pCertCtx->pCertInfo->SerialNumber;
pAttrValues[ 0 ] = &SerialNumber;
return pAttrValues;
default:
return NULL;
}
if ( pszAsnName == NULL )
{
return NULL;
}
if ( (pNameInfo = aniFields[fi]) == NULL )
{
if (!(*pfnCryptDecodeObject)(X509_ASN_ENCODING,
(LPCSTR)X509_NAME,
pBlob->pbData,
pBlob->cbData,
0,
NULL,
&cbNameInfo))
{
return NULL;
}
if (NULL == (pNameInfo = (PCERT_NAME_INFO)LocalAlloc(LMEM_FIXED,cbNameInfo)))
{
return NULL;
}
if (!(*pfnCryptDecodeObject)(X509_ASN_ENCODING,
(LPCSTR)X509_NAME,
pBlob->pbData,
pBlob->cbData,
0,
pNameInfo,
&cbNameInfo))
{
LocalFree( pNameInfo );
return NULL;
}
aniFields[fi] = pNameInfo;
}
for (cRDN = pNameInfo->cRDN, pRDN = pNameInfo->rgRDN; cRDN > 0; cRDN--, pRDN++)
{
for ( cAttr = pRDN->cRDNAttr, pAttr = pRDN->rgRDNAttr ; cAttr > 0 ; cAttr--, ++pAttr )
{
if ( !strcmp( pAttr->pszObjId, pszAsnName ) )
{
if ( ( cRet + 1 ) > cMaxRet )
{
cMaxRet += 10;
if ( pAttrValues )
{
PCERT_RDN_ATTR* pReallocatedAttrValues = (PCERT_RDN_ATTR*)
LocalReAlloc( pAttrValues,
sizeof( PCERT_RDN_ATTR ) * cMaxRet,
LMEM_MOVEABLE );
if ( pReallocatedAttrValues == NULL )
{
LocalFree( pAttrValues );
return NULL;
}
pAttrValues = pReallocatedAttrValues;
}
else
{
pAttrValues = (PCERT_RDN_ATTR*)
LocalAlloc( LPTR,
sizeof( PCERT_RDN_ATTR ) * cMaxRet );
if ( pAttrValues == NULL )
{
return NULL;
}
}
}
pAttrValues[ cRet ] = pAttr;
cRet++;
}
}
}
*pcElements = cRet;
return pAttrValues;
}
CIssuerStore::CIssuerStore(
)
/*++
Routine Description:
Constructor
Arguments:
None
Return Value:
Nothing
--*/
{
m_fValid = TRUE;
}
CIssuerStore::~CIssuerStore(
)
/*++
Routine Description:
Destructor
Arguments:
None
Return Value:
Nothing
--*/
{
}
VOID
CIssuerStore::Reset(
)
/*++
Routine Description:
Reset issuer list
Arguments:
None
Return Value:
None
--*/
{
m_pIssuerNames.Reset();
m_IssuerCerts.Reset();
m_fValid = TRUE;
}
BOOL
CIssuerStore::Unserialize(
CStoreXBF* pX
)
/*++
Routine Description:
Unserialize issuer list
Arguments:
pX - CStoreXBF to unserialize from
Return Value:
TRUE if success, otherwise FALSE
--*/
{
LPBYTE pb = pX->GetBuff();
DWORD dw = pX->GetUsed();
return Unserialize( &pb, &dw );
}
BOOL
CIssuerStore::Unserialize(
LPBYTE* ppb,
LPDWORD pc
)
/*++
Routine Description:
Unserialize issuer list
Arguments:
ppB - ptr to addr of buffer to unserialize from
pC - ptr to count of bytes in buffer
Return Value:
TRUE if success, otherwise FALSE
--*/
{
DWORD dwC;
Reset();
if ( ::Unserialize( ppb, pc, &dwC ) &&
m_pIssuerNames.Unserialize( ppb, pc, dwC ) &&
m_IssuerCerts.Unserialize( ppb, pc, dwC ) )
{
return TRUE;
}
m_fValid = FALSE;
return FALSE;
}
BOOL
CIssuerStore::Serialize(
CStoreXBF* pX
)
/*++
Routine Description:
Serialize issuer list
Arguments:
pX - CStoreXBF to serialize to
Return Value:
TRUE if success, otherwise FALSE
--*/
{
if ( !m_fValid )
{
return FALSE;
}
return ::Serialize( pX, (DWORD)GetNbIssuers() ) &&
m_pIssuerNames.Serialize( pX ) &&
m_IssuerCerts.Serialize( pX );
}
CCertGlobalRuleInfo::CCertGlobalRuleInfo(
)
/*++
Routine Description:
Constructor
Arguments:
None
Return Value:
Nothing
--*/
{
m_fValid = TRUE;
m_fEnabled = TRUE;
}
CCertGlobalRuleInfo::~CCertGlobalRuleInfo(
)
/*++
Routine Description:
Destructor
Arguments:
None
Return Value:
Nothing
--*/
{
}
BOOL
CCertGlobalRuleInfo::Reset(
)
/*++
Routine Description:
Reset to default values
Arguments:
None
Return Value:
Nothing
--*/
{
m_Order.Reset();
m_fValid = TRUE;
m_fEnabled = TRUE;
return TRUE;
}
BOOL
CCertGlobalRuleInfo::AddRuleOrder(
)
/*++
Routine Description:
Add a rule at end of rule order array
Arguments:
None
Return Value:
TRUE if success, otherwise FALSE
--*/
{
DWORD i;
if ( (i = m_Order.AddPtr( NULL )) != INDEX_ERROR )
{
// m_Order.SetPtr( i, (LPVOID) i );
m_Order.SetPtr( i, i );
return TRUE;
}
m_fValid = FALSE;
return FALSE;
}
BOOL
CCertGlobalRuleInfo::DeleteRuleById(
DWORD dwId,
BOOL DecrementAbove
)
/*++
Routine Description:
Delete a rule based on index in rules array
Arguments:
dwId - index in rules array
DecrementAbove - flag indicating if items with a index above dwID need
to be decremented. This is usually caused by the item being removed
from the main array.
Return Value:
TRUE if success, otherwise FALSE
--*/
{
UINT iO;
UINT iMax = m_Order.GetNbPtr();
DWORD id;
for ( iO = 0 ; iO < iMax ; ++iO )
{
// if it equals dwID, remove it
if ( (DWORD_PTR)m_Order.GetPtr( iO ) == dwId )
{
m_Order.DeletePtr( iO );
if ( DecrementAbove )
{
// if we have been asked to decrement the remaining items,
// need to do this in another loop here. Yuck. - Boyd
iMax = m_Order.GetNbPtr();
for ( iO = 0 ; iO < iMax ; ++iO )
{
// the id in question
id = (DWORD)((DWORD_PTR)m_Order.GetPtr( iO ));
// if it is bigger, decrement by one
if ( id > dwId )
{
id--;
// put it back in place
// m_Order.SetPtr( iO, (LPVOID) id ); //SUNDOWN ALERT
m_Order.SetPtr( iO, id ); //SUNDOWN ALERT
}
}
}
// return early
return TRUE;
}
}
m_fValid = FALSE;
return FALSE;
}
BOOL
CCertGlobalRuleInfo::SerializeGlobalRuleInfo(
CStoreXBF* pX
)
/*++
Routine Description:
Serialize mapper global information
Arguments:
pX - ptr to CStoreXBF to serialize to
Return Value:
TRUE if success, otherwise FALSE
--*/
{
return ::Serialize( pX, GetRuleOrderCount() ) &&
pX->Append( (LPBYTE)GetRuleOrderArray(),
sizeof(DWORD)*GetRuleOrderCount() ) &&
::Serialize( pX, m_fEnabled );
}
BOOL
CCertGlobalRuleInfo::UnserializeGlobalRuleInfo(
LPBYTE* ppB,
LPDWORD pC
)
/*++
Routine Description:
Unserialize mapper global info
Arguments:
ppB - ptr to addr of buffer to unserialize from
pC - ptr to count of bytes in buffer
Return Value:
TRUE if success, otherwise FALSE
--*/
{
DWORD dwO;
Reset();
return ::Unserialize( ppB, pC, &dwO ) &&
m_Order.Unserialize( ppB, pC, dwO ) &&
::Unserialize( ppB, pC, &m_fEnabled );
}
CCertMapRule::CCertMapRule(
)
/*++
Routine Description:
Constructor
Arguments:
None
Return Value:
Nothing
--*/
{
m_fEnabled = TRUE;
m_fDenyAccess = FALSE;
m_fMatchAllIssuers = TRUE;
m_fValid = TRUE;
}
CCertMapRule::~CCertMapRule(
)
/*++
Routine Description:
Desctructor
Arguments:
None
Return Value:
Nothing
--*/
{
}
VOID
CCertMapRule::Reset(
)
/*++
Routine Description:
Reset to default values
Arguments:
None
Return Value:
Nothing
--*/
{
m_fEnabled = TRUE;
m_fDenyAccess = FALSE;
m_fMatchAllIssuers = TRUE;
m_fValid = TRUE;
m_asRuleName.Reset();
m_asAccount.Reset();
m_asPassword.Reset();
m_ElemsContent.Reset();
m_ElemsSubfield.Reset();
m_ElemsField.Reset();
m_ElemsFlags.Reset();
m_Issuers.Reset();
m_IssuersAcceptStatus.Reset();
}
BOOL
CCertMapRule::Unserialize(
CStoreXBF* pX
)
/*++
Routine Description:
Unserialize a mapping rule
Arguments:
pX - ptr to CStoreXBF to unserialize from
Return Value:
TRUE if successful, FALSE on error
--*/
{
LPBYTE pb = pX->GetBuff();
DWORD dw = pX->GetUsed();
return Unserialize( &pb, &dw );
}
BOOL
CCertMapRule::Unserialize(
LPBYTE* ppb,
LPDWORD pc
)
/*++
Routine Description:
Unserialize a mapping rule
Arguments:
ppB - ptr to addr of buffer
pC - ptr to byte count in buffer
Return Value:
TRUE if successful, FALSE on error
--*/
{
DWORD dwEl;
DWORD dwIs;
Reset();
if ( m_asRuleName.Unserialize( ppb, pc ) &&
m_asAccount.Unserialize( ppb, pc ) &&
m_asPassword.Unserialize( ppb, pc ) &&
::Unserialize( ppb, pc, &m_fEnabled ) &&
::Unserialize( ppb, pc, &m_fDenyAccess ) &&
::Unserialize( ppb, pc, &dwEl ) &&
m_ElemsContent.Unserialize( ppb, pc, dwEl ) &&
m_ElemsSubfield.Unserialize( ppb, pc, dwEl ) &&
m_ElemsField.Unserialize( ppb, pc, dwEl ) &&
m_ElemsFlags.Unserialize( ppb, pc, dwEl ) &&
::Unserialize( ppb, pc, &dwIs ) &&
m_Issuers.Unserialize( ppb, pc, dwIs ) &&
m_IssuersAcceptStatus.Unserialize( ppb, pc, dwIs ) &&
::Unserialize( ppb, pc, &m_fMatchAllIssuers ) )
{
return TRUE;
}
m_fValid = FALSE;
return FALSE;
}
BOOL
CCertMapRule::Serialize(
CStoreXBF* pX
)
/*++
Routine Description:
Serialize a rule mapping in CStoreXBF
Arguments:
pX - ptr to CStoreXBF where to add serialized DWORD
Return Value:
TRUE if successful, FALSE on error
--*/
{
if ( m_fValid &&
m_asRuleName.Serialize( pX ) &&
m_asAccount.Serialize( pX ) &&
m_asPassword.Serialize( pX ) &&
::Serialize( pX, m_fEnabled ) &&
::Serialize( pX, m_fDenyAccess ) &&
::Serialize( pX, GetRuleElemCount() ) &&
m_ElemsContent.Serialize( pX ) &&
m_ElemsSubfield.Serialize( pX ) &&
m_ElemsField.Serialize( pX ) &&
m_ElemsFlags.Serialize( pX ) &&
::Serialize( pX, m_Issuers.GetNbEntry() ) &&
m_Issuers.Serialize( pX ) &&
m_IssuersAcceptStatus.Serialize( pX ) &&
::Serialize( pX, m_fMatchAllIssuers ) )
{
return TRUE;
}
return FALSE;
}
BOOL
CCertMapRule::SetRuleAccount(
LPSTR pszAcct
)
/*++
Routine Description:
Set NT account returned by this rule if match
Arguments:
pszAcct - NT account to use
Return Value:
TRUE if successful, FALSE on error
error ERROR_INVALID_NAME if replacement name ( %subfield% ) invalid
--*/
{
LPSTR pR;
LPSTR pD;
//
// Check replacement field valid
//
if ( ( pR = strchr( pszAcct, '%' ) ) != NULL )
{
++pR;
if ( (pD = strchr( pR, '%' )) == NULL )
{
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
*pD = '\0';
if ( !MapSubFieldToAsn1( pR ) )
{
*pD = '%';
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
*pD = '%';
}
return m_asAccount.Set( pszAcct );
}
//static
LPBYTE
CCertMapRule::CertMapMemstr(
LPBYTE pStr,
UINT cStr,
LPBYTE pSub,
UINT cSub,
BOOL fCaseInsensitive
)
/*++
Routine Description:
Find 1st occurence of block of memory inside buffer
Arguments:
pStr - buffer where to search
cStr - length of pStr
pSub - buffer to search for in pStr
cSub - length of pSub
fCaseInsensitive - TRUE is case insensitive search
Return Value:
Ptr to 1st occurence of pSub in pStr or NULL if not found
--*/
{
LPBYTE p;
LPBYTE pN;
if ( cSub > cStr )
{
return NULL;
}
UINT ch = *pSub;
if ( fCaseInsensitive )
{
if ( cStr >= cSub &&
cSub )
{
cStr -= cSub - 1;
for ( p = pStr ; cStr ; ++p, --cStr )
{
if ( !_memicmp( p, pSub, cSub ) )
{
return p;
}
}
}
}
else
{
for ( p = pStr ; ( pN = (LPBYTE)memchr( p, ch, cStr ) ) != NULL ; )
{
if ( !memcmp( pN, pSub, cSub ) )
{
return pN;
}
cStr -= (UINT)(pN - p + 1);
p = pN + 1;
}
}
return NULL;
}
// return ERROR_INVALID_NAME if no match
BOOL
CCertMapRule::Match(
CDecodedCert* pC,
CDecodedCert* /*pAuth*/,
LPSTR pszAcct,
LPSTR pszPwd,
LPBOOL pfDenied
)
/*++
Routine Description:
Check if rule match certificate
Arguments:
pC - client certificate
pAuth - certifying authority (not used),
pszAcct - updated with NT account on success,
assumed to be at longer then UNLEN+IIS_DNLEN+1
pszPwd - updated with NT password on success,
assumed to be longer then PWLEN long
pfDenied - updated with deny access status for this match on success
TRUE if access is denied for this match, otherwise FALSE
Return Value:
TRUE if successful, FALSE on error
Errors:
ERROR_ARENA_TRASHED if rule internal state is invalid
ERROR_INVALID_NAME if no match
--*/
{
UINT i;
UINT iMax;
DWORD cObjLen;
DWORD cMatch = 0;
BOOL fSt = FALSE;
LPBYTE pMatch = NULL;
INT iRet;
BOOL fCaseInsensitive;
PCERT_RDN_ATTR * pAttrValues;
DWORD cAttrValues;
DWORD cAttr;
PBYTE pContent;
BOOL fConverted = FALSE;
PBYTE pConverted = NULL;
if ( !m_fEnabled )
{
return FALSE;
}
if ( !m_fValid )
{
SetLastError( ERROR_ARENA_TRASHED );
return FALSE;
}
iMax = GetRuleElemCount();
for ( i = 0 ; i < iMax ; ++i )
{
m_ElemsContent.GetEntry( i, &pMatch, &cMatch );
--cMatch;
if( ( pAttrValues = pC->GetSubField(
(CERT_FIELD_ID)((UINT_PTR)m_ElemsField.GetPtr(i)),
m_ElemsSubfield.GetEntry( i ), &cAttrValues ) ) != NULL )
{
fCaseInsensitive = (DWORD)((DWORD_PTR)m_ElemsFlags.GetPtr(i) & CMR_FLAGS_CASE_INSENSITIVE);
for ( cAttr = 0;
cAttr < cAttrValues;
cAttr++ )
{
fConverted = FALSE;
pContent = pAttrValues[ cAttr ]->Value.pbData;
cObjLen = pAttrValues[ cAttr ]->Value.cbData;
if ( pAttrValues[ cAttr ]->dwValueType == CERT_RDN_UNICODE_STRING )
{
cObjLen /= sizeof( WCHAR );
//
// Convert UNICODE cert value to multibyte
//
iRet = WideCharToMultiByte( CP_ACP,
0,
(WCHAR*) pContent,
cObjLen,
NULL,
0,
NULL,
NULL );
if ( !iRet )
{
fSt = FALSE;
break;
}
pConverted = (PBYTE) LocalAlloc( LPTR, iRet );
if ( pConverted == NULL )
{
fSt = FALSE;
break;
}
iRet = WideCharToMultiByte( CP_ACP,
0,
(WCHAR*) pContent,
cObjLen,
(CHAR*) pConverted,
iRet,
NULL,
NULL );
if ( !iRet )
{
fSt = FALSE;
LocalFree( pConverted );
break;
}
fConverted = TRUE;
pContent = (PBYTE) pConverted;
cObjLen = iRet;
}
switch ( pMatch[0] )
{
case MATCH_ALL:
fSt = cObjLen == cMatch &&
( fCaseInsensitive ?
!_memicmp( pMatch+1, pContent, cObjLen ) :
!memcmp( pMatch+1, pContent, cObjLen ) );
break;
case MATCH_FIRST:
fSt = cObjLen >= cMatch &&
( fCaseInsensitive ?
!_memicmp( pMatch+1, pContent, cMatch ) :
!memcmp( pMatch+1, pContent, cMatch ) );
break;
case MATCH_LAST:
fSt = cObjLen >= cMatch &&
( fCaseInsensitive ?
!_memicmp( pMatch+1, pContent+cObjLen-cMatch, cMatch ) :
!memcmp( pMatch+1, pContent+cObjLen-cMatch, cMatch ) );
break;
case MATCH_IN:
fSt = CertMapMemstr( pContent, cObjLen, pMatch + 1, cMatch, fCaseInsensitive ) != NULL;
break;
default:
fSt = FALSE;
}
if ( fConverted )
{
LocalFree( pConverted );
pConverted = NULL;
}
if ( fSt )
{
break;
}
}
LocalFree( pAttrValues );
pAttrValues = NULL;
if ( !fSt )
{
break;
}
}
else if ( cMatch )
{
// non empty rule on n/a subfield : stop looking other matches
break;
}
}
//
// if client cert match, check issuers
//
if ( i == iMax )
{
fSt = TRUE;
if ( fSt )
{
*pfDenied = m_fDenyAccess;
if ( GetRuleAccount() != NULL &&
GetRulePassword() != NULL )
{
//
// Truncate account and password
// if they don't fit.
// It will render the output data useless
// but will prevent buffer overflow
// if invalid too long accounts and pwds
// happen to be stored in mappings
strncpy( pszAcct,
GetRuleAccount(),
UNLEN + IIS_DNLEN + 1 );
pszAcct[ UNLEN + IIS_DNLEN + 1 ] = '\0';
strncpy( pszPwd,
GetRulePassword(),
PWLEN );
pszAcct[ PWLEN ] = '\0';
}
else
{
SetLastError( ERROR_INVALID_PARAMETER );
fSt = FALSE;
}
}
return fSt;
}
SetLastError( ERROR_INVALID_NAME );
return FALSE;
}
BOOL
CCertMapRule::GetRuleElem(
DWORD i,
CERT_FIELD_ID* pfiField,
LPSTR* ppContent,
LPDWORD pcContent,
LPSTR* ppSubField,
LPDWORD pdwFlags
)
/*++
Routine Description:
Access a rule element
Arguments:
i - index ( 0-based ) of element to access
pfiField - updated with CERT_FIELD_ID of this element
ppContent - updated with ptr to match binary form
pcContent - updated with length of match binary form
ppSubField - updated with ASN.1 name of cert sub-field for match
pdwFlags - updated with flags
Return Value:
TRUE if successful, FALSE on error
--*/
{
if ( !m_fValid )
{
SetLastError( ERROR_ARENA_TRASHED );
return FALSE;
}
if ( (*ppSubField = m_ElemsSubfield.GetEntry( i )) != NULL &&
m_ElemsContent.GetEntry( i, (LPBYTE*)ppContent, pcContent ) )
{
*pfiField = (CERT_FIELD_ID)((UINT_PTR)m_ElemsField.GetPtr( i ));
if ( pdwFlags )
{
*pdwFlags = (DWORD)((DWORD_PTR)m_ElemsFlags.GetPtr( i ));
}
return TRUE;
}
return FALSE;
}
BOOL
CCertMapRule::DeleteRuleElem(
DWORD i
)
/*++
Routine Description:
Delete a rule element
Arguments:
i - index ( 0-based ) of element to delete
Return Value:
TRUE if successful, FALSE on error
--*/
{
if ( !m_fValid )
{
SetLastError( ERROR_ARENA_TRASHED );
return FALSE;
}
if ( m_ElemsContent.DeleteEntry( i ) &&
m_ElemsSubfield.DeleteEntry( i ) &&
m_ElemsField.DeletePtr( i ) &&
m_ElemsFlags.DeletePtr( i ) )
{
return TRUE;
}
m_fValid = FALSE;
return FALSE;
}
BOOL
CCertMapRule::DeleteRuleElemsByField(
CERT_FIELD_ID fiField
)
/*++
Routine Description:
Delete rule elements based on CERT_FIELD_ID
Arguments:
fiField - CERT_FIELD_ID of elements to delete
Return Value:
TRUE if successful ( even if no element deleted ), FALSE on error
--*/
{
UINT i;
UINT iMax;
if ( !m_fValid )
{
SetLastError( ERROR_ARENA_TRASHED );
return FALSE;
}
iMax = GetRuleElemCount();
for ( i = 0 ; i < iMax ; ++i )
{
if ( fiField == (CERT_FIELD_ID)((UINT_PTR)m_ElemsField.GetPtr(i) ))
{
if ( !DeleteRuleElem( i ) )
{
m_fValid = FALSE;
return FALSE;
}
--i;
}
}
return TRUE;
}
DWORD
CCertMapRule::AddRuleElem(
DWORD iBefore,
CERT_FIELD_ID fiField,
LPSTR pszSubField,
LPBYTE pContent,
DWORD cContent,
DWORD dwFlags
)
/*++
Routine Description:
Add a rule element
Arguments:
iBefore - index ( 0-based ) of where to insert in list,
0xffffffff to append to list
fiField - CERT_FIELD_ID of this element
pSubField - ASN.1 name of cert sub-field for match
pContent - ptr to match binary form
cContent - length of match binary form
dwFlags - flags ( CMR_FLAGS_* )
Return Value:
TRUE if successful, FALSE on error
--*/
{
if ( !m_fValid )
{
SetLastError( ERROR_ARENA_TRASHED );
return FALSE;
}
if ( m_ElemsContent.InsertEntry( iBefore, (LPSTR)pContent, cContent ) != INDEX_ERROR &&
m_ElemsSubfield.InsertEntry( iBefore, pszSubField ) != INDEX_ERROR &&
m_ElemsField.InsertPtr( iBefore, (LPVOID)fiField ) != INDEX_ERROR &&
m_ElemsFlags.InsertPtr( iBefore, ULongToPtr(dwFlags) ) != INDEX_ERROR )
{
return TRUE;
}
m_fValid = FALSE;
return FALSE;
}
BOOL
CCertMapRule::GetIssuerEntry(
DWORD i,
LPBOOL pfS,
LPSTR* ppszI
)
/*++
Routine Description:
Get issuer entry from issuer list
Arguments:
i - index ( 0-based ) of element to delete
pfS - updated with issuer accept status
ppszI - updated with ptr to issuer ID
Return Value:
TRUE if successful ( even if no element deleted ), FALSE on error
--*/
{
if ( i < m_Issuers.GetNbEntry() )
{
*ppszI = m_Issuers.GetEntry( i );
*pfS = (BOOL) ((DWORD_PTR)m_IssuersAcceptStatus.GetPtr( i ));
return TRUE;
}
return FALSE;
}
BOOL
CCertMapRule::GetIssuerEntryByName(
LPSTR pszName,
LPBOOL pfS
)
/*++
Routine Description:
Get issuer entry from issuer list
Arguments:
pszName - issuer ID
pfS - updated with issuer accept status
Return Value:
TRUE if successful ( even if no element deleted ), FALSE on error
--*/
{
UINT i;
UINT iMx = m_Issuers.GetNbEntry();
for ( i = 0 ; i < iMx ; ++i )
{
if ( !strcmp( m_Issuers.GetEntry( i ), pszName ) )
{
*pfS = (BOOL) ((DWORD_PTR)m_IssuersAcceptStatus.GetPtr( i ));
return TRUE;
}
}
return FALSE;
}
BOOL
CCertMapRule::SetIssuerEntryAcceptStatus(
DWORD i,
BOOL fAcceptStatus
)
/*++
Routine Description:
Set issuer entry accept status
Arguments:
i - index ( 0-based ) of element to update
fAcceptStatus - issuer accept status
Return Value:
TRUE if successful, FALSE on error
--*/
{
return m_IssuersAcceptStatus.SetPtr( i, ULongToPtr(fAcceptStatus) );
}
BOOL
CCertMapRule::AddIssuerEntry(
LPSTR pszName,
BOOL fAcceptStatus
)
/*++
Routine Description:
Add issuer entry to issuer list
Arguments:
pszName - issuer ID
fAcceptStatus - issuer accept status
Return Value:
TRUE if success, otherwise FALSE
--*/
{
if ( m_Issuers.AddEntry( pszName ) != INDEX_ERROR &&
m_IssuersAcceptStatus.AddPtr( ULongToPtr((ULONG)fAcceptStatus) ) != INDEX_ERROR )
{
return TRUE;
}
m_fValid = FALSE;
return FALSE;
}
BOOL
CCertMapRule::DeleteIssuerEntry(
DWORD i
)
/*++
Routine Description:
Delete an issuer entry
Arguments:
i - index ( 0-based ) of element to delete
Return Value:
TRUE if successful, FALSE on error
--*/
{
if ( m_Issuers.DeleteEntry( i ) &&
m_IssuersAcceptStatus.DeletePtr( i ) )
{
return TRUE;
}
return FALSE;
}
CIisRuleMapper::CIisRuleMapper(
)
/*++
Routine Description:
Constructor
Arguments:
None
Return Value:
Nothing
--*/
{
m_pRWLock = new CReaderWriterLock3();
m_fValid = ( m_pRWLock != NULL );
}
CIisRuleMapper::~CIisRuleMapper(
)
/*++
Routine Description:
Destructor
Arguments:
None
Return Value:
Nothing
--*/
{
UINT i;
UINT iMax = GetRuleCount();
for ( i = 0 ; i < iMax ; ++i )
{
delete (CCertMapRule*)GetRule( i );
}
if ( m_pRWLock != NULL )
{
delete m_pRWLock;
m_pRWLock = NULL;
}
}
BOOL
CIisRuleMapper::Reset(
)
/*++
Routine Description:
Reset to default values
Arguments:
None
Return Value:
Nothing
--*/
{
m_GlobalRuleInfo.Reset();
UINT i;
UINT iMax = GetRuleCount();
for ( i = 0 ; i < iMax ; ++i )
{
delete (CCertMapRule*)GetRule( i );
}
m_Rules.Reset();
m_fValid = TRUE;
return TRUE;
}
VOID
CIisRuleMapper::WriteLockRules()
{
m_pRWLock->WriteLock();
}
VOID
CIisRuleMapper::ReadLockRules()
{
m_pRWLock->ReadLock();
}
VOID
CIisRuleMapper::WriteUnlockRules()
{
m_pRWLock->WriteUnlock();
}
VOID
CIisRuleMapper::ReadUnlockRules()
{
m_pRWLock->ReadUnlock();
}
BOOL
CIisRuleMapper::Unserialize(
CStoreXBF* pX
)
/*++
Routine Description:
Unserialize rule mapper
Arguments:
pX - CStoreXBF to unserialize from
Return Value:
TRUE if success, otherwise FALSE
--*/
{
LPBYTE pb = pX->GetBuff();
DWORD dw = pX->GetUsed();
return Unserialize( &pb, &dw );
}
BOOL
CIisRuleMapper::Unserialize(
LPBYTE* ppb,
LPDWORD pc
)
/*++
Routine Description:
Unserialize rule mapper
Arguments:
ppB - ptr to addr of buffer
pC - ptr to byte count in buffer
Return Value:
TRUE if success, otherwise FALSE
--*/
{
DWORD dwMx;
CCertMapRule * pR;
DWORD ir;
UINT i;
BOOL fSt = FALSE;
WriteLockRules();
Reset();
if ( m_GlobalRuleInfo.UnserializeGlobalRuleInfo( ppb, pc ) &&
::Unserialize( ppb, pc, &dwMx ) )
{
fSt = TRUE;
for ( i = 0 ; i < dwMx ; ++i )
{
if ( (pR = new CCertMapRule()) == NULL ||
(ir = m_Rules.AddPtr( (LPVOID)pR )) == INDEX_ERROR ||
!pR->Unserialize( ppb, pc ) )
{
fSt = FALSE;
m_fValid = FALSE;
if ( pR != NULL )
{
delete pR;
}
break;
}
}
}
else
{
m_fValid = FALSE;
}
WriteUnlockRules();
return fSt;
}
BOOL
CIisRuleMapper::Serialize(
CStoreXBF* psxSer
)
/*++
Routine Description:
Serialize all rules
Arguments:
psxSer - ptr to CStoreXBF where to serialize
Return Value:
TRUE if successful, FALSE on error
--*/
{
BOOL fSt = FALSE;
UINT i;
DWORD dwMx;
ReadLockRules();
if ( m_fValid )
{
dwMx = m_Rules.GetNbPtr();
if ( m_GlobalRuleInfo.SerializeGlobalRuleInfo( psxSer ) &&
::Serialize( psxSer, dwMx ) )
{
fSt = TRUE;
for ( i = 0 ; i < dwMx ; ++i )
{
if ( !GetRule(i)->Serialize( psxSer ) )
{
fSt = FALSE;
break;
}
}
}
}
ReadUnlockRules();
return fSt;
}
BOOL
CIisRuleMapper::DeleteRule(
DWORD dwI
)
/*++
Routine Description:
Delete a rule
Arguments:
dwI - index ( 0-based ) of rule to delete
Return Value:
TRUE if successful, FALSE on error
--*/
{
if ( dwI < GetRuleCount() )
{
if ( m_Rules.DeletePtr( dwI ) &&
m_GlobalRuleInfo.DeleteRuleById( dwI, TRUE ) )
{
return TRUE;
}
m_fValid = FALSE;
}
return FALSE;
}
DWORD
CIisRuleMapper::AddRule(
)
/*++
Routine Description:
Add an empty rule
Arguments:
None
Return Value:
index of added rule or INDEX_ERROR if error
--*/
{
CCertMapRule *pR;
DWORD i;
if ( ( pR = new CCertMapRule() ) != NULL )
{
if ( (i = m_Rules.AddPtr( (LPVOID)pR )) != INDEX_ERROR )
{
if ( m_GlobalRuleInfo.AddRuleOrder() )
{
return i;
}
m_fValid = FALSE;
/* INTRINSA suppress = leaks */
return INDEX_ERROR;
}
m_fValid = FALSE;
delete pR;
}
return INDEX_ERROR;
}
DWORD
CIisRuleMapper::AddRule(
CCertMapRule *pR
)
/*++
Routine Description:
Add a rule
Arguments:
pR - rule to add
Return Value:
index of added rule or INDEX_ERROR if error
--*/
{
DWORD i;
if ( (i = m_Rules.AddPtr( (LPVOID)pR )) != INDEX_ERROR )
{
if ( m_GlobalRuleInfo.AddRuleOrder() )
{
return i;
}
}
m_fValid = FALSE;
return INDEX_ERROR;
}
BOOL
CIisRuleMapper::Match(
PCERT_CONTEXT pCert,
PCERT_CONTEXT pAuth,
LPWSTR pszAcctW,
LPWSTR pszPwdW
)
/*++
Routine Description:
Check if rule match certificate
WARNING: must be called inside lock
Arguments:
pCert - client cert
pAuth - Certifying Authority or NULL if not recognized
cbLen - ptr to DER encoded cert
pszAcctW - updated with NT account on success,
assumed to be at least UNLEN+IIS_DNLEN+1+1 long
pszPwdW - updated with NT password on success,
assumed to be at least PWLEN+1 long
Return Value:
TRUE if successful, FALSE on error
Errors:
ERROR_ARENA_TRASHED if rule internal state is invalid
ERROR_INVALID_NAME if no match
ERROR_ACCESS_DENIED if match and denied access
--*/
{
UINT iR;
UINT iMax;
LPDWORD pdwOrder;
CDecodedCert dcCert( pCert );
CDecodedCert dcAuth( pAuth );
BOOL fSt = FALSE;
BOOL fDenied;
CHAR achAcct[ UNLEN + IIS_DNLEN + 1 + 1 ];
CHAR achPwd[ PWLEN + 1 ];
ReadLockRules();
if ( !IsValid() || !m_GlobalRuleInfo.IsValid() )
{
SetLastError( ERROR_ARENA_TRASHED );
goto ex;
}
if ( !m_GlobalRuleInfo.GetRulesEnabled() )
{
SetLastError( ERROR_INVALID_NAME );
goto ex;
}
iMax = GetRuleCount();
if ( iMax == 0 )
{
SetLastError( ERROR_INVALID_NAME );
goto ex;
}
pdwOrder = m_GlobalRuleInfo.GetRuleOrderArray();
for ( iR = 0 ; iR < iMax ; ++iR )
{
if ( ((CCertMapRule*)m_Rules.GetPtr(pdwOrder[iR]))->Match(
&dcCert, &dcAuth, achAcct, achPwd, &fDenied ) )
{
if ( fDenied )
{
SetLastError( ERROR_ACCESS_DENIED );
fSt = FALSE;
}
else
{
fSt = TRUE;
}
break;
}
}
ex:
ReadUnlockRules();
if ( fSt )
{
if ( !MultiByteToWideChar( CP_ACP,
MB_PRECOMPOSED,
achAcct,
-1,
pszAcctW,
UNLEN+IIS_DNLEN+1+1 ) )
{
return FALSE;
}
if ( !MultiByteToWideChar( CP_ACP,
MB_PRECOMPOSED,
achPwd,
-1,
pszPwdW,
PWLEN+1 ) )
{
return FALSE;
}
}
return fSt;
}
CERT_FIELD_ID
MapFieldToId(
LPSTR pField
)
/*++
Routine Description:
Map field name ( "Issuer", ... ) to ID
Arguments:
pField - field name
Return Value:
CERT_FIELD_ID of field or CERT_FIELD_ERROR if error
--*/
{
UINT x;
for ( x = 0 ; x < sizeof(aMapField)/sizeof(MAP_FIELD) ; ++x )
{
if ( !_stricmp( pField, aMapField[x].pTextName ) )
{
return aMapField[x].dwId;
}
}
return CERT_FIELD_ERROR;
}
LPSTR
MapIdToField(
CERT_FIELD_ID dwId
)
/*++
Routine Description:
Map ID to field name ( "Issuer", ... )
Arguments:
dwId - field ID
Return Value:
TRUE if successful, FALSE on error
--*/
{
UINT x;
for ( x = 0 ; x < sizeof(aMapField)/sizeof(MAP_FIELD) ; ++x )
{
if ( dwId == aMapField[x].dwId )
{
return aMapField[x].pTextName;
}
}
return NULL;
}
DWORD
GetIdFlags(
CERT_FIELD_ID dwId
)
/*++
Routine Description:
Get flags for specified ID
Arguments:
dwId - field ID
Return Value:
ID flags if success, otherwise 0xffffffff
--*/
{
if ( dwId < CERT_FIELD_LAST )
{
return adwFieldFlags[dwId];
}
return 0xffffffff;
}
LPSTR
MapSubFieldToAsn1(
LPSTR pszSubField
)
/*++
Routine Description:
Map field name ( "OU", ... ) to ASN.1 name
Arguments:
pszSubField - subfield name
Return Value:
ptr to ASN.1 name or NULL if error
--*/
{
UINT x;
for ( x = 0 ; x < sizeof(aMapAsn)/sizeof(MAP_ASN) ; ++x )
{
if ( !strcmp( pszSubField, aMapAsn[x].pTextName ) )
{
return aMapAsn[x].pAsnName;
}
}
return NULL;
}
LPSTR
MapAsn1ToSubField(
LPSTR pszAsn1
)
/*++
Routine Description:
Map ID to field name ( "OU", ... )
Arguments:
pszAsn1 - ASN.1 name
Return Value:
sub field name or ASN.1 name if conversion not found
--*/
{
UINT x;
for ( x = 0 ; x < sizeof(aMapAsn)/sizeof(MAP_ASN) ; ++x )
{
if ( !strcmp( pszAsn1, aMapAsn[x].pAsnName ) )
{
return aMapAsn[x].pTextName;
}
}
return pszAsn1;
}
LPSTR
EnumerateKnownSubFields(
DWORD dwIndex
)
/*++
Routine Description:
Get subfield name from index (0-based )
Arguments:
dwIndex - enumerator ( 0-based )
Return Value:
sub field name or NULL if no more subfields
--*/
{
if ( dwIndex < sizeof(aMapAsn)/sizeof(MAP_ASN) )
{
return aMapAsn[dwIndex].pTextName;
}
return NULL;
}
VOID
InitializeWildcardMapping(
HANDLE hModule
)
/*++
Routine Description:
Initialize wildcard mapping
Arguments:
hModule - module handle of this DLL
Return Value:
Nothing
--*/
{
if ( ( hCapi2Lib = LoadLibrary("crypt32.dll") ) != NULL )
{
pfnCryptDecodeObject = (PFNCryptDecodeObject)GetProcAddress(hCapi2Lib, "CryptDecodeObject");
}
LPVOID p;
UINT i;
UINT l;
CHAR achTmp[128];
for ( i = 0 ; i < sizeof(aMapAsn)/sizeof(MAP_ASN) ; ++ i )
{
if ( (l = LoadString( (HINSTANCE)hModule, aMapAsn[i].dwResId, achTmp, sizeof(achTmp) )) == NULL ||
(p = LocalAlloc( LMEM_FIXED, l+1 )) == NULL )
{
p = (LPVOID)"";
}
else
{
memcpy( p, achTmp, l+1 );
}
aMapAsn[i].pTextName = (LPSTR)p;
}
for ( i = 0 ; i < sizeof(aMapField)/sizeof(MAP_FIELD) ; ++ i )
{
if ( (l = LoadString( (HINSTANCE)hModule, aMapField[i].dwResId, achTmp, sizeof(achTmp) )) == NULL ||
(p = LocalAlloc( LMEM_FIXED, l+1 )) == NULL )
{
p = (LPVOID)"";
}
else
{
memcpy( p, achTmp, l+1 );
}
aMapField[i].pTextName = (LPSTR)p;
}
}
VOID
TerminateWildcardMapping(
)
/*++
Routine Description:
Terminate wildcard mapping
Arguments:
None
Return Value:
Nothing
--*/
{
UINT i;
if ( hCapi2Lib != NULL )
{
FreeLibrary( hCapi2Lib );
}
for ( i = 0 ; i < sizeof(aMapAsn)/sizeof(MAP_ASN) ; ++ i )
{
if ( aMapAsn[i].pTextName[0] )
{
LocalFree( aMapAsn[i].pTextName );
}
}
for ( i = 0 ; i < sizeof(aMapField)/sizeof(MAP_FIELD) ; ++ i )
{
if ( aMapField[i].pTextName[0] )
{
LocalFree( aMapField[i].pTextName );
}
}
}
BOOL
MatchRequestToBinary(
LPSTR pszReq,
LPBYTE* ppbBin,
LPDWORD pdwBin )
/*++
Routine Description:
Convert from match request user format ( e.g. "*msft*"
to internal binary format
Arguments:
pszReq - match in user format
ppbBin - updated with ptr to alloced binary format,
to be freed by calling FreeMatchConversion()
pdwBin - updated with binary format length
Return Value:
TRUE if success, otherwise FALSE
--*/
{
LPSTR pReq;
DWORD cReq;
LPBYTE pBin;
MATCH_TYPES mt;
if ( !pszReq)
{
*ppbBin = NULL;
*pdwBin = 0;
return FALSE;
}
pReq = pszReq;
cReq = (DWORD) strlen( pReq );
if ( !cReq )
{
mt = MATCH_ALL;
}
else
{
if ( pReq[0] == '*' )
{
if ( pReq[cReq-1] == '*' && cReq > 1 )
{
mt = MATCH_IN;
cReq -= 2;
}
else
{
mt = MATCH_LAST;
cReq -= 1;
}
++pReq;
}
else if ( pReq[cReq-1] == '*' )
{
mt = MATCH_FIRST;
cReq -= 1;
}
else
{
mt = MATCH_ALL;
}
}
if ( (pBin = (LPBYTE)LocalAlloc( LMEM_FIXED, cReq + 1 )) == NULL )
{
return FALSE;
}
pBin[0] = (BYTE)mt;
memcpy( pBin+1, pReq, cReq );
*ppbBin = pBin;
*pdwBin = cReq + 1;
return TRUE;
}
BOOL
BinaryToMatchRequest(
LPBYTE pbBin,
DWORD dwBin,
LPSTR* ppszReq
)
/*++
Routine Description:
Convert from internal binary format to
match request user format ( e.g. "*msft*"
Arguments:
pbBin - ptr to binary format,
dwBin - binary format length
ppszReq - updated with ptr to alloced match in user format
to be freed by calling FreeMatchConversion()
Return Value:
TRUE if success, otherwise FALSE
--*/
{
BOOL fPre;
BOOL fPost;
UINT cMatch = dwBin + 1;
LPSTR pMatch;
if ( !pbBin || !dwBin )
{
*ppszReq = NULL;
return FALSE;
}
switch ( (MATCH_TYPES)(UINT)pbBin[0] )
{
case MATCH_ALL:
fPre = FALSE;
fPost = FALSE;
break;
case MATCH_LAST:
fPre = TRUE;
fPost = FALSE;
++cMatch;
break;
case MATCH_FIRST:
fPre = FALSE;
fPost = TRUE;
++cMatch;
break;
case MATCH_IN:
fPre = TRUE;
fPost = TRUE;
cMatch += 2;
break;
default:
return FALSE;
}
if ( (pMatch = (LPSTR)LocalAlloc( LMEM_FIXED, cMatch )) == NULL )
{
return FALSE;
}
*ppszReq = pMatch;
if ( fPre )
{
*pMatch++ = '*';
}
DBG_ASSERT( cMatch >= dwBin - 1 );
memcpy( pMatch, pbBin + 1, dwBin - 1 );
pMatch += dwBin - 1;
if ( fPost )
{
*pMatch++ = '*';
}
*pMatch = '\0';
return TRUE;
}
VOID
FreeMatchConversion(
LPVOID pvFree
)
/*++
Routine Description:
Free result of binary to/from user format conversion
Arguments:
pvFree - buffer to free
Return Value:
Nothing
--*/
{
if ( pvFree != NULL )
{
LocalFree( pvFree );
}
}