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
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 );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|