windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/iismap/iismap.cxx
2020-09-26 16:20:57 +08:00

6832 lines
128 KiB
C++

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
iismap.cxx
Abstract:
Classes to handle mapping
Author:
Philippe Choquier (phillich) 17-may-1996
--*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <wincrypt.h>
//#include <crypt32l.h>
#include "xbf.hxx"
extern "C" {
#include "immd5.h"
}
#include <iis64.h>
#include <iismap.hxx>
#include "iismaprc.h"
#include "mapmsg.h"
#include "iiscmr.hxx"
#include <refb.hxx>
#include <icrypt.hxx>
#include "dbgutil.h"
//
// global vars
//
CRITICAL_SECTION g_csIisMap;
DWORD g_dwGuid = 0;
HKEY g_hKey = NULL;
LPSTR g_pszInstallPath = NULL;
DECLARE_DEBUG_PRINTS_OBJECT();
//
//
//
#if defined(DECODE_ASN1)
PRDN_VALUE_BLOB
CertGetNameField(
UINT iEncoding,
IN LPCTSTR pszObjId,
IN PNAME_INFO pInfo
);
UINT DecodeNames(
IN PNAME_BLOB pNameBlob,
IN LPSTR* pFields,
IN LPSTR pStore
);
UINT DecodeCert(
IN PBYTE pbEncodedCert,
IN DWORD cbEncodedCert,
LPSTR* pFields,
LPSTR pStore
);
#endif
//
// global functions
//
extern "C" int __cdecl
QsortIisMappingCmp(
const void *pA,
const void *pB )
/*++
Routine Description:
Compare function for 2 CIisMapping entries
compare using mask, then all fields as defined in
the linked CIisAcctMapper hierarchy
Arguments:
pA -- ptr to 1st element
pB -- ptr tp 2nd elemet
Returns:
-1 if *pA < *pB, 0 if *pA == *pB, 1 if *pA > *pB
--*/
{
return (*(CIisMapping**)pA)->Cmp( *(CIisMapping**)pB, FALSE );
}
extern "C" int __cdecl
MatchIisMappingCmp(
const void *pA,
const void *pB )
/*++
Routine Description:
Compare function for 2 CIisMapping entries
do not uses mask, uses all fields as defined in
the linked CIisAcctMapper hierarchy
Arguments:
pA -- ptr to 1st element
pB -- ptr tp 2nd elemet
Returns:
-1 if *pA < *pB, 0 if *pA == *pB, 1 if *pA > *pB
--*/
{
return ( *(CIisMapping**)pA)->Cmp( *(CIisMapping**)pB, TRUE );
}
HRESULT
GetSecurityDescriptorForMetabaseExtensionFile(
PSECURITY_DESCRIPTOR * ppsdStorage
)
/*++
Routine Description:
Build security descriptor that will be set for the extension file
*.mp (includes Administrators and System )
Arguments:
ppsdStorage - Security Descriptor to be set for extension file
Returns:
HRESULT
--*/
{
HRESULT hr = ERROR_SUCCESS;
BOOL fRet = FALSE;
DWORD dwDaclSize = 0;
SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;
PSID psidSystem = NULL;
PSID psidAdmin = NULL;
PACL paclDiscretionary = NULL;
DBG_ASSERT( ppsdStorage != NULL );
*ppsdStorage = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if ( *ppsdStorage == NULL )
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto exit;
}
//
// Initialize the security descriptor.
//
fRet = InitializeSecurityDescriptor(
*ppsdStorage,
SECURITY_DESCRIPTOR_REVISION
);
if( !fRet )
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto exit;
}
//
// Create the SIDs for the local system and admin group.
//
fRet = AllocateAndInitializeSid(
&ntAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0,
0,
0,
0,
0,
0,
0,
&psidSystem
);
if( !fRet )
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto exit;
}
fRet= AllocateAndInitializeSid(
&ntAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0,
0,
0,
0,
0,
0,
&psidAdmin
);
if( !fRet )
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto exit;
}
//
// Create the DACL containing an access-allowed ACE
// for the local system and admin SIDs.
//
dwDaclSize = sizeof(ACL)
+ sizeof(ACCESS_ALLOWED_ACE)
+ GetLengthSid(psidAdmin)
+ sizeof(ACCESS_ALLOWED_ACE)
+ GetLengthSid(psidSystem)
- sizeof(DWORD);
paclDiscretionary = (PACL)LocalAlloc(LPTR, dwDaclSize );
if ( paclDiscretionary == NULL )
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto exit;
}
fRet = InitializeAcl(
paclDiscretionary,
dwDaclSize,
ACL_REVISION
);
if( !fRet )
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto exit;
}
fRet = AddAccessAllowedAce(
paclDiscretionary,
ACL_REVISION,
FILE_ALL_ACCESS,
psidSystem
);
if ( !fRet )
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto exit;
}
fRet = AddAccessAllowedAce(
paclDiscretionary,
ACL_REVISION,
FILE_ALL_ACCESS,
psidAdmin
);
if ( !fRet )
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto exit;
}
//
// Set the DACL into the security descriptor.
//
fRet = SetSecurityDescriptorDacl(
*ppsdStorage,
TRUE,
paclDiscretionary,
FALSE
);
if ( !fRet ) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto exit;
}
hr = S_OK;
exit:
if ( psidAdmin != NULL )
{
FreeSid( psidAdmin );
psidAdmin = NULL;
}
if ( psidSystem != NULL )
{
FreeSid( psidSystem );
psidSystem = NULL;
}
if ( FAILED( hr ) ) {
if ( paclDiscretionary != NULL )
{
LocalFree( paclDiscretionary );
paclDiscretionary = NULL;
}
if ( *ppsdStorage != NULL )
{
LocalFree( *ppsdStorage );
*ppsdStorage = NULL;
}
}
return hr;
}
HRESULT
FreeSecurityDescriptorForMetabaseExtensionFile(
PSECURITY_DESCRIPTOR psdStorage
)
/*++
Routine Description:
Free security descriptor generated by
GetSecurityDescriptorForMetabaseExtentionFile()
Arguments:
psdStorage - Security Descriptor to be freed
Returns:
HRESULT
--*/
{
HRESULT hr = ERROR_SUCCESS;
BOOL fRet = FALSE;
BOOL fDaclPresent;
PACL paclDiscretionary = NULL;
BOOL fDaclDefaulted;
//
// Get the DACL from the security descriptor.
//
if ( psdStorage == NULL )
{
hr = S_OK;
goto exit;
}
fRet = GetSecurityDescriptorDacl(
psdStorage,
&fDaclPresent,
&paclDiscretionary,
&fDaclDefaulted
);
if ( !fRet )
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto exit;
}
if ( fDaclPresent && paclDiscretionary != NULL )
{
LocalFree( paclDiscretionary );
paclDiscretionary = NULL;
}
LocalFree( psdStorage );
hr = S_OK;
exit:
return hr;
}
INT
Iisfputs(
const char* pBuf,
FILE* fOut
)
{
return (fputs( pBuf, fOut ) == EOF || fputc( '\n', fOut ) == EOF)
? EOF
: 0;
}
LPSTR
Iisfgets(
LPSTR pBuf,
INT cMax,
FILE* fIn
)
{
LPSTR pszWas = pBuf;
INT ch = 0;
while ( cMax > 1 && (ch=fgetc(fIn))!= EOF && ch != '\n' )
{
*pBuf++ = (CHAR)ch;
--cMax;
}
if ( ch != EOF )
{
*pBuf = '\0';
return pszWas;
}
return NULL;
}
//
// Fields for the Certificate mapper
//
IISMDB_Fields IisCertMappingFields[] = {
{IISMDB_TYPE_ISSUER_O, NULL, IDS_IISMAP_FLD0, 40 },
{IISMDB_TYPE_ISSUER_OU, NULL, IDS_IISMAP_FLD1, 40 },
{IISMDB_TYPE_ISSUER_C, NULL, IDS_IISMAP_FLD2, 40 },
{IISMDB_TYPE_SUBJECT_O, NULL, IDS_IISMAP_FLD3, 40 },
{IISMDB_TYPE_SUBJECT_OU, NULL, IDS_IISMAP_FLD4, 40 },
{IISMDB_TYPE_SUBJECT_C, NULL, IDS_IISMAP_FLD5, 40 },
{IISMDB_TYPE_SUBJECT_CN, NULL, IDS_IISMAP_FLD6, 40 },
{IISMDB_TYPE_NTACCT, NULL, IDS_IISMAP_FLD7, 40 },
} ;
//
// default hierarchy for the Certificate mapper
//
IISMDB_HEntry IisCertMappingHierarchy[] = {
{IISMDB_INDEX_ISSUER_O, TRUE},
{IISMDB_INDEX_ISSUER_OU, FALSE},
{IISMDB_INDEX_ISSUER_C, FALSE},
{IISMDB_INDEX_SUBJECT_O, TRUE},
{IISMDB_INDEX_SUBJECT_OU, FALSE},
{IISMDB_INDEX_SUBJECT_C, FALSE},
{IISMDB_INDEX_SUBJECT_CN, TRUE},
} ;
//
// Fields for the Certificate 1:1 mapper
//
IISMDB_Fields IisCert11MappingFields[] = {
#if defined(CERT11_FULL_CERT)
{IISMDB_INDEX_CERT11_CERT, NULL, IDS_IISMAP11_FLDC, 40 },
#else
{IISMDB_INDEX_CERT11_SUBJECT, NULL, IDS_IISMAP11_FLDS, 40 },
{IISMDB_INDEX_CERT11_ISSUER, NULL, IDS_IISMAP11_FLDI, 40 },
#endif
{IISMDB_INDEX_CERT11_NT_ACCT, NULL, IDS_IISMAP11_FLDA, 40 },
#if defined(CERT11_FULL_CERT)
{IISMDB_INDEX_CERT11_NAME, NULL, IDS_IISMAP11_FLDN, 40 },
{IISMDB_INDEX_CERT11_ENABLED, NULL, IDS_IISMAP11_FLDE, 40 },
{IISMDB_INDEX_CERT11_NT_PWD, NULL, IDS_IISMAP11_FLDP, 40 },
#endif
} ;
//
// default hierarchy for the Certificate 1:1 mapper
//
IISMDB_HEntry IisCert11MappingHierarchy[] = {
#if defined(CERT11_FULL_CERT)
{IISMDB_INDEX_CERT11_CERT, TRUE},
#else
{IISMDB_INDEX_CERT11_ISSUER, TRUE},
{IISMDB_INDEX_CERT11_SUBJECT, FALSE},
#endif
} ;
//
// Fields for the Ita mapper
//
IISMDB_Fields IisItaMappingFields[] = {
{IISMDB_TYPE_ITACCT, NULL, IDS_ITAIISMAP_FLD0, 40 },
{IISMDB_TYPE_ITPWD, NULL, IDS_ITAIISMAP_FLD1, 40 },
{IISMDB_TYPE_NTACCT, NULL, IDS_ITAIISMAP_FLD2, 40 },
} ;
//
// default hierarchy for the Ita mapper
//
IISMDB_HEntry IisItaMappingHierarchy[] = {
{IISIMDB_INDEX_IT_ACCT, TRUE},
{IISIMDB_INDEX_IT_PWD, TRUE},
} ;
//
// Fields for the Md5 mapper
//
IISMDB_Fields IisMd5MappingFields[] = {
{IISMDB_TYPE_ITREALM, NULL, IDS_MD5IISMAP_FLD0, 40 },
{IISMDB_TYPE_ITACCT, NULL, IDS_MD5IISMAP_FLD1, 40 },
{IISMDB_TYPE_ITMD5PWD, NULL, IDS_MD5IISMAP_FLD2, 40 },
{IISMDB_TYPE_NTACCT, NULL, IDS_MD5IISMAP_FLD3, 40 },
{IISMMDB_INDEX_IT_CLRPWD, NULL, IDS_MD5IISMAP_FLD4, 40 },
{IISMMDB_INDEX_NT_PWD, NULL, IDS_MD5IISMAP_FLD5, 40 },
} ;
//
// default hierarchy for the Md5 mapper
//
IISMDB_HEntry IisMd5MappingHierarchy[] = {
{IISMMDB_INDEX_IT_REALM, TRUE},
{IISMMDB_INDEX_IT_ACCT, TRUE},
} ;
HINSTANCE g_hModule = (HINSTANCE)INVALID_HANDLE_VALUE;
// CIisAcctMapper
CIisAcctMapper::CIisAcctMapper(
)
/*++
Routine Description:
Constructor for CIisAcctMapper
Arguments:
None
Returns:
Nothing
--*/
{
m_cInit = -1;
m_pMapping = NULL;
m_cMapping = 0;
m_pAltMapping = NULL;
m_cAltMapping = 0;
m_pHierarchy = NULL;
m_cHierarchy = 0;
m_achFileName[0] = '\0';
m_pClasses = NULL;
m_pSesKey = NULL;
m_dwSesKey = 0;
m_hNotifyEvent = NULL;
m_fRequestTerminate = FALSE;
INITIALIZE_CRITICAL_SECTION( &csLock );
}
CIisAcctMapper::~CIisAcctMapper(
)
/*++
Routine Description:
Destructor for CIisAcctMapper
Arguments:
None
Returns:
Nothing
--*/
{
Reset();
if ( m_pHierarchy != NULL )
{
LocalFree( m_pHierarchy );
}
if ( m_pSesKey != NULL )
{
LocalFree( m_pSesKey );
}
DeleteCriticalSection( &csLock );
}
VOID
FreeCIisAcctMapper(
LPVOID pMapper
)
/*++
Routine Description:
Delete a CIisAcctMapper
Arguments:
pMapper - ptr to mapper
Returns:
Nothing
--*/
{
delete (CIisAcctMapper*)pMapper;
}
BOOL
CIisAcctMapper::Create(
VOID
)
/*++
Routine Description:
Create file for CIisAcctMapper with proper SD
Arguments:
None
Returns:
TRUE if success, FALSE if error
--*/
{
// create file name, store in m_achFileName
// from g_dwGuid
// and g_pszInstallPath
UINT cLen;
UINT cIter;
HANDLE hF;
HRESULT hr = E_FAIL;
BOOL fRet = FALSE;
PSECURITY_DESCRIPTOR psdForMetabaseExtensionFile = NULL;
SECURITY_ATTRIBUTES saStorage;
PSECURITY_ATTRIBUTES psaStorage = NULL;
Reset();
if ( g_pszInstallPath )
{
cLen = strlen(g_pszInstallPath);
memcpy( m_achFileName, g_pszInstallPath, cLen );
if ( cLen && m_achFileName[cLen-1] != '\\' )
{
m_achFileName[cLen++] = '\\';
}
}
else
{
cLen = 0;
}
wsprintf( m_achFileName+cLen, "%08x.mp", g_dwGuid );
//
// build security descriptor (Administrators and SYSTEM)
// to be set on metabase extension file
//
hr = GetSecurityDescriptorForMetabaseExtensionFile(
&psdForMetabaseExtensionFile );
if ( SUCCEEDED(hr) && psdForMetabaseExtensionFile != NULL )
{
saStorage.nLength = sizeof(SECURITY_ATTRIBUTES);
saStorage.lpSecurityDescriptor = psdForMetabaseExtensionFile;
saStorage.bInheritHandle = FALSE;
}
else
{
return FALSE;
}
//
// Open file and close it right away
// If file didn't exist, then empty file with good SD (Security Descriptor)
// will be created. That will later be opened using C runtime (fopen)
// in Save() method and good SD will persist.
// Ideally Save() should be using Win32 CreateFile()
// instead fopen and it could set SD itself. But since this is legacy
// source file and rather unsafe for making too many changes, pragmatic
// approach was chosen to set SD here in Create() method
//
if ( (hF = CreateFile( m_achFileName,
GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
&saStorage,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL ) ) != INVALID_HANDLE_VALUE )
{
CloseHandle( hF );
fRet = TRUE;
}
else
{
fRet = FALSE;
}
if ( psdForMetabaseExtensionFile != NULL )
{
FreeSecurityDescriptorForMetabaseExtensionFile(
psdForMetabaseExtensionFile );
psdForMetabaseExtensionFile = NULL;
}
return fRet;
}
BOOL
CIisAcctMapper::Delete(
VOID
)
/*++
Routine Description:
Delete external storage used by this mapper ( i.e. file )
Arguments:
None
Returns:
TRUE if success, FALSE if error
--*/
{
BOOL fSt = TRUE;
Lock();
if ( m_achFileName[0] )
{
fSt = DeleteFile( m_achFileName );
m_achFileName[0] = '\0';
}
Unlock();
return fSt;
}
BOOL
CIisAcctMapper::Serialize(
CStoreXBF* pXbf
)
/*++
Routine Description:
Serialize mapper reference ( NOT mapping info ) to buffer
Save() must be called to save mapping info before calling Serialize()
Arguments:
pXbf - ptr to extensible buffer to serialize to
Returns:
TRUE if success, FALSE if error
--*/
{
return pXbf->Append( (DWORD)strlen(m_achFileName) ) &&
pXbf->Append( (LPBYTE)m_achFileName, (DWORD)strlen(m_achFileName) ) &&
pXbf->Append( (LPBYTE)m_md5.digest, (DWORD)sizeof(m_md5.digest) ) &&
pXbf->Append( (DWORD)m_dwSesKey ) &&
pXbf->Append( (LPBYTE)m_pSesKey, (DWORD)m_dwSesKey ) ;
}
BOOL
CIisAcctMapper::Unserialize(
CStoreXBF* pXBF
)
/*++
Routine Description:
Unserialize mapper reference ( NOT mapping info ) from extensible buffer
Load() must be called to load mapping info
Arguments:
pXBF - ptr to extensible buffer
Returns:
TRUE if success, FALSE if error
--*/
{
LPBYTE pb = pXBF->GetBuff();
DWORD c = pXBF->GetUsed();
return Unserialize( &pb, &c );
}
BOOL
CIisAcctMapper::Unserialize(
LPBYTE* ppb,
LPDWORD pc
)
/*++
Routine Description:
Unserialize mapper reference ( NOT mapping info ) from buffer
Load() must be called to load mapping info
Arguments:
ppb - ptr to buffer
pc - ptr to buffer length
Returns:
TRUE if success, FALSE if error
--*/
{
DWORD cName;
if ( ::Unserialize( ppb, pc, &cName ) &&
cName <= *pc )
{
memcpy( m_achFileName, *ppb, cName );
m_achFileName[ cName ] = '\0';
*ppb += cName;
*pc -= cName;
if ( sizeof(m_md5.digest) <= *pc )
{
memcpy( m_md5.digest, *ppb, sizeof(m_md5.digest) );
*ppb += sizeof(m_md5.digest);
*pc -= sizeof(m_md5.digest);
if ( ::Unserialize( ppb, pc, &m_dwSesKey ) &&
cName <= *pc )
{
if ( m_pSesKey != NULL )
{
LocalFree( m_pSesKey );
}
if ( !(m_pSesKey = (LPBYTE)LocalAlloc( LMEM_FIXED, m_dwSesKey )) )
{
m_dwSesKey = 0;
return FALSE;
}
memcpy( m_pSesKey, *ppb, m_dwSesKey );
*ppb += m_dwSesKey;
*pc -= m_dwSesKey;
return TRUE;
}
}
}
return FALSE;
}
BOOL
CIisAcctMapper::Serialize(
VOID
)
/*++
Routine Description:
Serialize mapper reference ( NOT mapping info ) to registry
Save() must be called to save mapping info before calling Serialize()
Warning : this allow only 1 instance
Arguments:
None
Returns:
TRUE if success, FALSE if error
--*/
{
BOOL fSt = TRUE;
HKEY hKey;
LONG st;
if ( (st = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
GetRegKeyName(),
0,
KEY_WRITE,
&hKey )) != ERROR_SUCCESS )
{
SetLastError( st );
return FALSE;
}
if ( RegSetValueEx( hKey,
FILE_VALIDATOR,
NULL,
REG_BINARY,
(LPBYTE)m_md5.digest,
sizeof(m_md5.digest) ) != ERROR_SUCCESS ||
RegSetValueEx( hKey,
FILE_LOCATION,
NULL,
REG_SZ,
(LPBYTE)m_achFileName,
strlen(m_achFileName) ) != ERROR_SUCCESS )
{
fSt = FALSE;
}
RegCloseKey( hKey );
return fSt;
}
BOOL
CIisAcctMapper::Unserialize(
VOID
)
/*++
Routine Description:
Unserialize mapper reference ( NOT mapping info ) From registry
Load() must be called to load mapping info
Warning : this allow only 1 instance
Arguments:
None
Returns:
TRUE if success, FALSE if error
--*/
{
BOOL fSt = FALSE;
HKEY hKey;
DWORD dwLen;
DWORD dwType;
LONG st;
// Check registry
if ( (st = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
GetRegKeyName(),
0,
KEY_READ,
&hKey )) != ERROR_SUCCESS )
{
SetLastError( st );
return FALSE;
}
dwLen = sizeof(m_md5.digest);
if ( RegQueryValueEx( hKey,
FILE_VALIDATOR,
NULL,
&dwType,
(LPBYTE)m_md5.digest,
&dwLen ) == ERROR_SUCCESS &&
dwType == REG_BINARY &&
(( dwLen = sizeof(m_achFileName) ), TRUE ) &&
RegQueryValueEx( hKey,
FILE_LOCATION,
NULL,
&dwType,
(LPBYTE)m_achFileName,
&dwLen ) == ERROR_SUCCESS &&
dwType == REG_SZ )
{
fSt = TRUE;
}
RegCloseKey( hKey );
return fSt;
}
BOOL
CIisAcctMapper::UpdateClasses(
BOOL fComputeMask
)
/*++
Routine Description:
Constructor for CIisAcctMapper
Arguments:
fComputeMask -- TRUE if mask to be recomputed
Returns:
TRUE if success, FALSE if error
--*/
{
UINT x;
UINT mx = 1 << m_cHierarchy;
if ( fComputeMask )
{
for ( x = 0 ; x < m_cMapping ; ++x )
{
m_pMapping[x]->UpdateMask( m_pHierarchy, m_cHierarchy );
}
}
SortMappings();
if ( m_pClasses == NULL )
{
m_pClasses = (MappingClass*)LocalAlloc(
LMEM_FIXED,
sizeof(MappingClass)*(mx+1) );
if ( m_pClasses == NULL )
{
return FALSE;
}
}
DWORD dwN = 0; // current class index in m_pClasses
DWORD dwLastClass = 0;
DWORD dwFirst = 0; // first entry for current dwLastClass
for ( x = 0 ; x <= m_cMapping ; ++x )
{
DWORD dwCur;
dwCur = (x==m_cMapping) ? dwLastClass+1: m_pMapping[x]->GetMask();
if ( dwCur > dwLastClass )
{
if ( x > dwFirst )
{
m_pClasses[dwN].dwClass = dwLastClass;
m_pClasses[dwN].dwFirst = dwFirst;
m_pClasses[dwN].dwLast = x - 1;
++dwN;
}
dwLastClass = dwCur;
dwFirst = x;
}
}
m_pClasses[dwN].dwClass = 0xffffffff;
return TRUE;
}
BOOL
CIisAcctMapper::SortMappings(
)
/*++
Routine Description:
Sort the mappings. Masks for mapping objects are assumed
to be already computed.
Arguments:
None
Returns:
TRUE if success, FALSE if error
--*/
{
qsort( (LPVOID)m_pMapping,
m_cMapping,
sizeof(CIisMapping*),
QsortIisMappingCmp
);
return TRUE;
}
BOOL
CIisAcctMapper::FindMatch(
CIisMapping* pQuery,
CIisMapping** pResult,
LPDWORD piResult
)
/*++
Routine Description:
Find a match base on field contents in CIisMapping
Arguments:
pQuery -- describe fields to consider for mapping
pResult -- updated with result if found mapping
Returns:
TRUE if mapping found, else FALSE
Lock:
mapper must be locked for ptr to remain valid
--*/
{
// iterate through classes, do bsearch on each
MappingClass *pH = m_pClasses;
if ( pH == NULL )
{
return FALSE;
}
while ( pH->dwClass != 0xffffffff )
{
CIisMapping **pRes = (CIisMapping **)bsearch( (LPVOID)&pQuery,
(LPVOID)(m_pMapping+pH->dwFirst),
pH->dwLast - pH->dwFirst + 1,
sizeof(CIisMapping*),
MatchIisMappingCmp );
if ( piResult != NULL )
{
*piResult = DIFF(pRes - m_pMapping);
}
if ( pRes != NULL )
{
*pResult = *pRes;
return TRUE;
}
++pH;
}
return FALSE;
}
#if 0
DWORD
WINAPI IisMappingUpdateIndication(
LPVOID pV )
/*++
Routine Description:
Shell for registry update notification
Arguments:
pV -- ptr to CIisAcctMapper to be notified
Returns:
NT error code ( 0 if no error )
--*/
{
return ((CIisAcctMapper*)pV)->UpdateIndication();
}
DWORD
CIisAcctMapper::UpdateIndication(
VOID )
/*++
Routine Description:
Thread monitoring authentication methods update in registry
Arguments:
None
Returns:
NT error
--*/
{
for ( ;; )
{
if ( RegNotifyChangeKeyValue( m_hKey,
FALSE,
REG_NOTIFY_CHANGE_LAST_SET,
m_hNotifyEvent,
TRUE ) != ERROR_SUCCESS )
{
break;
}
if ( WaitForSingleObject( m_hNotifyEvent, INFINITE)
!= WAIT_OBJECT_0 )
{
break;
}
if ( m_fRequestTerminate )
{
break;
}
// re-load mapper
Lock();
if ( !Load() && GetLastError() == ERROR_INVALID_ACCESS )
{
Reset();
}
Unlock();
}
return 0;
}
#endif
#if 0
BOOL
CIisAcctMapper::Init(
BOOL *pfFirst,
BOOL fMonitorChange
)
/*++
Routine Description:
Initialize mappings, optionally load map file
Arguments:
fLoad -- TRUE to load mappings from file
Returns:
TRUE if success, FALSE if error
--*/
{
*pfFirst = FALSE;
BOOL fSt = TRUE;
if ( !InterlockedIncrement( &m_cInit ) )
{
*pfFirst = TRUE;
if ( fMonitorChange )
{
m_hNotifyEvent = IIS_CREATE_EVENT(
"CIisAcctMapper::m_hNotifyEvent",
this,
FALSE,
FALSE
);
}
m_fRequestTerminate = FALSE;
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
GetRegKeyName(),
0,
KEY_READ,
&m_hKey ) == ERROR_SUCCESS )
{
DWORD dwLen = sizeof( m_achFileName );
DWORD dwType;
if ( RegQueryValueEx( m_hKey,
FILE_LOCATION,
NULL,
&dwType,
(LPBYTE)m_achFileName,
&dwLen ) != ERROR_SUCCESS
|| dwType != REG_SZ )
{
strcpy( m_achFileName, IIS_CERT_FILENAME );
}
if ( fMonitorChange )
{
// create registry monitoring thread
DWORD dwID;
if ( (m_hThread = CreateThread( NULL,
0,
(LPTHREAD_START_ROUTINE)::IisMappingUpdateIndication,
(LPVOID)this,
0,
&dwID )) == NULL )
{
fSt = FALSE;
goto ex;
}
}
fSt = Reset();
}
else
{
SetLastError( ERROR_CANTOPEN );
fSt = FALSE;
}
}
//
// log event if error
//
if ( !fSt )
{
char achErr[32];
LPCTSTR pA[1];
pA[0] = achErr;
_itoa( GetLastError(), achErr, 10 );
ReportIisMapEvent( EVENTLOG_ERROR_TYPE,
IISMAP_EVENT_INIT_ERROR,
1,
pA );
}
return fSt;
}
BOOL
CIisAcctMapper::Terminate(
BOOL fForce
)
/*++
Routine Description:
Terminate mapping
Arguments:
None
Returns:
TRUE if success, FALSE if error
--*/
{
BOOL fSt = TRUE;
if ( InterlockedDecrement( &m_cInit ) < 0 || fForce )
{
#if 0
if ( m_hNotifyEvent && m_hThread )
{
m_fRequestTerminate = TRUE;
SetEvent( m_hNotifyEvent );
if ( m_hThread != NULL )
{
fSt = WaitForSingleObject( m_hThread, 1000 * 3 )
== WAIT_OBJECT_0;
if ( !fSt )
{
TerminateThread( m_hThread, 0 );
}
CloseHandle( m_hThread );
m_hThread = NULL;
if ( m_hKey != NULL )
{
RegCloseKey( m_hKey );
m_hKey = NULL;
}
if ( m_hNotifyEvent != NULL )
{
CloseHandle( m_hNotifyEvent );
m_hNotifyEvent = NULL;
}
return fSt;
}
}
if ( m_hKey != NULL )
{
RegCloseKey( m_hKey );
m_hKey = NULL;
}
#endif
}
return TRUE;
}
#endif
void
CIisAcctMapper::Lock(
)
/*++
Routine Description:
Prevent access to mapper from other threads
Arguments:
None
Returns:
Nothing
--*/
{
EnterCriticalSection( &csLock );
}
void
CIisAcctMapper::Unlock(
)
/*++
Routine Description:
Re-enabled access to mapper from other threads
Arguments:
None
Returns:
Nothing
--*/
{
LeaveCriticalSection( &csLock );
}
BOOL
CIisAcctMapper::FlushAlternate(
BOOL fApply
)
/*++
Routine Description:
Flush alternate list, optionaly commiting it to the main list
Arguments:
fApply -- TRUE to commit changes made in alternate list
Returns:
TRUE if success, otherwise FALSE
--*/
{
UINT i;
UINT iM;
BOOL fSt = TRUE;
if ( m_pAltMapping )
{
if ( fApply )
{
//
// Transfer non existing objects from regular to alternate list
//
iM = min( m_cMapping, m_cAltMapping );
for ( i = 0 ; i < iM ; ++ i )
{
if ( m_pAltMapping[i] == NULL )
{
m_pAltMapping[i] = m_pMapping[i];
}
else
{
delete m_pMapping[i];
}
}
//
// delete extra objects
//
if ( m_cMapping > m_cAltMapping )
{
for ( i = m_cAltMapping ; i < m_cMapping ; ++i )
{
delete m_pMapping[i];
}
}
if ( m_pMapping )
{
LocalFree( m_pMapping );
}
m_pMapping = m_pAltMapping;
m_cMapping = m_cAltMapping;
fSt = UpdateClasses( TRUE );
}
else
{
for ( i = 0 ; i < m_cAltMapping ; ++i )
{
if ( m_pAltMapping[i] )
{
delete m_pAltMapping;
}
}
LocalFree( m_pAltMapping );
}
}
m_pAltMapping = NULL;
m_cAltMapping = 0;
return fSt;
}
BOOL
CIisAcctMapper::GetMapping(
DWORD iIndex,
CIisMapping** pM,
BOOL fGetFromAlternate,
BOOL fPutOnAlternate
)
/*++
Routine Description:
Get mapping entry based on index
Arguments:
iIndex -- index in mapping array
pM -- updated with pointer to mapping. mapping object
still owned by the mapper object.
fGetFromAlternate -- TRUE if retrieve from alternate list
fPutOnAlternate -- TRUE if put returned mapping on alternate list
Returns:
TRUE if success, FALSE if error
--*/
{
if ( fPutOnAlternate )
{
// create alternate list if not exist
if ( !m_pAltMapping && m_cMapping )
{
m_pAltMapping = (CIisMapping**)LocalAlloc( LMEM_FIXED, sizeof(CIisMapping*)*(m_cMapping) );
if ( m_pAltMapping == NULL )
{
return FALSE;
}
memset( m_pAltMapping, '\0', sizeof(CIisMapping*) * m_cMapping );
m_cAltMapping = m_cMapping;
}
if ( iIndex < m_cAltMapping )
{
if ( m_pAltMapping[iIndex] == NULL &&
m_pMapping != NULL ) // work-around for compiler bug
{
// duplicate mapping to alternate list if not exist
if ( m_pMapping[iIndex]->Clone( pM ) )
{
m_pAltMapping[iIndex] = *pM;
}
else
{
return FALSE;
}
}
else
{
*pM = m_pAltMapping[iIndex];
}
return TRUE;
}
return FALSE;
}
if ( fGetFromAlternate &&
m_pAltMapping &&
iIndex < m_cAltMapping )
{
if ( m_pAltMapping[iIndex] )
{
*pM = m_pAltMapping[iIndex];
}
else
{
*pM = m_pMapping[iIndex];
}
return TRUE;
}
if ( iIndex < m_cMapping )
{
*pM = m_pMapping[iIndex];
return TRUE;
}
return FALSE;
}
BOOL
CIisAcctMapper::GetMappingForUpdate(
DWORD iIndex,
CIisMapping** pM
)
/*++
Routine Description:
Get mapping entry based on index
returns a copy of the mapping so update is cancelable
Arguments:
iIndex -- index in mapping array
pM -- updated with pointer to mapping. mapping object
still owned by the mapper object.
Returns:
TRUE if success, FALSE if error
--*/
{
if ( iIndex < m_cMapping )
{
if ( (*pM = CreateNewMapping()) == NULL )
{
return FALSE;
}
return (*pM)->Copy( m_pMapping[iIndex] );
}
return FALSE;
}
BOOL
CIisAcctMapper::Update(
DWORD iIndex,
CIisMapping* pM
)
/*++
Routine Description:
Update a mapping
Arguments:
iIndex -- index in mapping array
pM -- pointer to mapping.
Returns:
TRUE if success, FALSE if error
--*/
{
if ( iIndex < m_cMapping )
{
pM->UpdateMask( m_pHierarchy, m_cHierarchy);
return m_pMapping[iIndex]->Copy( pM ) && UpdateClasses( FALSE );
}
return FALSE;
}
BOOL
CIisAcctMapper::Update(
DWORD iIndex
)
/*++
Routine Description:
Update a mapping
Arguments:
iIndex -- index in mapping array
Returns:
TRUE if success, FALSE if error
--*/
{
if ( iIndex < m_cMapping )
{
return m_pMapping[iIndex]->UpdateMask( m_pHierarchy, m_cHierarchy);
}
return FALSE;
}
BOOL
CIisAcctMapper::Add(
CIisMapping* pM,
BOOL fAlternate
)
/*++
Routine Description:
Add a mapping entry to mapping array
Transfer ownership of mapping object to mapper
Arguments:
pM -- pointer to mapping to be added to mapper
fAlternate - TRUE if add to alternate list
Returns:
TRUE if success, FALSE if error
--*/
{
CIisMapping **pMapping;
if ( fAlternate )
{
DWORD dwC = m_pAltMapping ? m_cAltMapping : m_cMapping;
CIisMapping** pMap = m_pAltMapping ? m_pAltMapping : m_pMapping;
pMapping = (CIisMapping**)LocalAlloc( LMEM_FIXED, sizeof(CIisMapping*)*(dwC+1) );
if ( pMapping == NULL )
{
return FALSE;
}
if ( m_pAltMapping )
{
memcpy( pMapping, pMap, sizeof(CIisMapping*) * dwC );
LocalFree( m_pAltMapping );
}
else
{
memset( pMapping, '\0', dwC * sizeof(LPVOID) );
}
m_pAltMapping = pMapping;
m_pAltMapping[dwC] = pM;
m_cAltMapping = dwC + 1;
return TRUE;
}
else
{
pMapping = (CIisMapping**)LocalAlloc( LMEM_FIXED, sizeof(CIisMapping*)*(m_cMapping+1) );
if ( pMapping == NULL )
{
return FALSE;
}
if ( m_pMapping )
{
memcpy( pMapping, m_pMapping, sizeof(CIisMapping*) * m_cMapping );
LocalFree( m_pMapping );
}
m_pMapping = pMapping;
pM->UpdateMask( m_pHierarchy, m_cHierarchy );
m_pMapping[m_cMapping] = pM;
++m_cMapping;
SortMappings();
return UpdateClasses( FALSE );
}
}
DWORD
CIisAcctMapper::AddEx(
CIisMapping* pM
)
/*++
Routine Description:
Add a mapping entry to mapping array
Transfer ownership of mapping object to mapper
Arguments:
pM -- pointer to mapping to be added to mapper
Returns:
Index of entry if success, otherwise 0xffffffff
--*/
{
CIisMapping **pMapping = (CIisMapping**)LocalAlloc( LMEM_FIXED, sizeof(CIisMapping*)*(m_cMapping+1) );
if ( pMapping == NULL )
{
return 0xffffffff;
}
if ( m_pMapping )
{
memcpy( pMapping, m_pMapping, sizeof(CIisMapping*) * m_cMapping );
LocalFree( m_pMapping );
}
m_pMapping = pMapping;
pM->UpdateMask( m_pHierarchy, m_cHierarchy );
m_pMapping[m_cMapping] = pM;
++m_cMapping;
SortMappings();
if ( UpdateClasses( FALSE ) )
{
return m_cMapping-1;
}
return 0xffffffff;
}
VOID
CIisAcctMapper::DeleteMappingObject(
CIisMapping *pM
)
/*++
Routine Description:
Delete a mapping object
Arguments:
pM - ptr to mapping object
Returns:
Nothing
--*/
{
delete pM;
}
BOOL
CIisAcctMapper::Delete(
DWORD dwIndex,
BOOL fUseAlternate
)
/*++
Routine Description:
Delete a mapping entry based on index
Arguments:
iIndex -- index in mapping array
fUseAlternate -- TRUE if update alternate list
Returns:
TRUE if success, FALSE if error
--*/
{
UINT i;
UINT iM;
if ( fUseAlternate )
{
//
// clone all entries from main to alternate list
//
if ( !m_pAltMapping )
{
m_pAltMapping = (CIisMapping**)LocalAlloc( LMEM_FIXED, sizeof(CIisMapping*)*(m_cMapping) );
if ( m_pAltMapping == NULL )
{
return FALSE;
}
memset( m_pAltMapping, '\0', sizeof(CIisMapping*) * m_cMapping );
m_cAltMapping = m_cMapping;
}
iM = min( m_cMapping, m_cAltMapping );
for ( i = 0 ; i < iM ; ++i )
{
if ( m_pAltMapping[i] == NULL )
{
if ( !m_pMapping[i]->Clone( &m_pAltMapping[i] ) )
{
return FALSE;
}
}
}
if ( dwIndex < m_cAltMapping )
{
delete m_pAltMapping[dwIndex];
memmove( m_pAltMapping+dwIndex,
m_pAltMapping+dwIndex+1,
(m_cAltMapping - dwIndex - 1) * sizeof(CIisMapping*) );
--m_cAltMapping;
return TRUE;
}
return FALSE;
}
if ( dwIndex < m_cMapping )
{
delete m_pMapping[dwIndex];
memmove( m_pMapping+dwIndex,
m_pMapping+dwIndex+1,
(m_cMapping - dwIndex - 1) * sizeof(CIisMapping*) );
--m_cMapping;
return UpdateClasses( FALSE );
}
return FALSE;
}
BOOL
CIisAcctMapper::Save(
)
/*++
Routine Description:
Save mapper ( mappings, hierarchy, derived class private data )
to a file, updating registry entry with MD5 signature
Arguments:
None
Returns:
TRUE if success, FALSE if error
--*/
{
UINT x;
FILE * fOut = NULL;
BOOL fSt = TRUE;
DWORD dwVal;
DWORD st;
IIS_CRYPTO_STORAGE storage;
PIIS_CRYPTO_BLOB blob;
Lock();
MD5Init( &m_md5 );
if ( FAILED(storage.Initialize()) )
{
fSt = FALSE;
goto cleanup;
}
if ( m_pSesKey != NULL )
{
LocalFree( m_pSesKey );
m_pSesKey = NULL;
m_dwSesKey = 0;
}
if ( FAILED( storage.GetSessionKeyBlob( &blob ) ) )
{
fSt = FALSE;
goto cleanup;
}
m_dwSesKey = IISCryptoGetBlobLength( blob );
if ( (m_pSesKey = (LPBYTE)LocalAlloc( LMEM_FIXED, m_dwSesKey)) == NULL )
{
m_dwSesKey = 0;
fSt = FALSE;
goto cleanup;
}
memcpy( m_pSesKey, (LPBYTE)blob, m_dwSesKey );
if ( (fOut = fopen( m_achFileName, "wb" )) == NULL )
{
fSt = FALSE;
goto cleanup;
}
// magic value & version
dwVal = IISMDB_FILE_MAGIC_VALUE;
if( fwrite( (LPVOID)&dwVal, sizeof(dwVal), 1, fOut ) != 1 )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( &m_md5, (LPBYTE)&dwVal, sizeof(dwVal) );
dwVal = IISMDB_CURRENT_VERSION;
if( fwrite( (LPVOID)&dwVal, sizeof(dwVal), 1, fOut ) != 1 )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( &m_md5, (LPBYTE)&dwVal, sizeof(dwVal) );
// mappings
if( fwrite( (LPVOID)&m_cMapping, sizeof(m_cMapping), 1, fOut ) != 1 )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( &m_md5, (LPBYTE)&m_cMapping, sizeof(m_cMapping) );
for ( x = 0 ; x < m_cMapping ; ++x )
{
if ( !m_pMapping[x]->Serialize( fOut ,(VALID_CTX)&m_md5, (LPVOID)&storage) )
{
fSt = FALSE;
goto cleanup;
}
}
// save hierarchy
if( fwrite( (LPVOID)&m_cHierarchy, sizeof(m_cHierarchy), 1, fOut ) != 1 )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( &m_md5, (LPBYTE)&m_cHierarchy, sizeof(m_cHierarchy) );
if( fwrite( (LPVOID)m_pHierarchy, sizeof(IISMDB_HEntry), m_cHierarchy, fOut ) != m_cHierarchy )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( &m_md5, (LPBYTE)m_pHierarchy, sizeof(IISMDB_HEntry)*m_cHierarchy );
// save private data
fSt = SavePrivate( fOut, (VALID_CTX)&m_md5 );
MD5Final( &m_md5 );
cleanup:
if ( fOut != NULL )
{
fclose( fOut );
}
// update registry
if ( !fSt )
{
memset( m_md5.digest, '\0', sizeof(m_md5.digest) );
}
Unlock();
return fSt;
}
BOOL
CIisAcctMapper::Reset(
)
/*++
Routine Description:
Reset mapper to empty state
Arguments:
None
Returns:
TRUE if success, FALSE if error
--*/
{
UINT x;
// free all mapping
if ( m_pMapping != NULL )
{
for ( x = 0 ; x < m_cMapping ; ++x )
{
delete m_pMapping[x];
}
LocalFree( m_pMapping );
m_pMapping = NULL;
}
m_cMapping = 0;
if ( m_pClasses != NULL )
{
LocalFree( m_pClasses );
m_pClasses = NULL;
}
// default hierarchy
if ( m_pHierarchy == NULL )
{
IISMDB_HEntry *pH = GetDefaultHierarchy( &m_cHierarchy );
m_pHierarchy = (IISMDB_HEntry*)LocalAlloc( LMEM_FIXED, sizeof(IISMDB_HEntry)*m_cHierarchy );
if ( m_pHierarchy == NULL )
{
return FALSE;
}
memcpy( m_pHierarchy, pH, m_cHierarchy * sizeof(IISMDB_HEntry) );
}
return ResetPrivate();
}
BOOL
CIisAcctMapper::Load(
)
/*++
Routine Description:
Load mapper ( mappings, hierarchy, derived class private data )
from a file, checking registry entry for MD5 signature
Arguments:
None
Returns:
TRUE if success, FALSE if error
--*/
{
UINT x;
MD5_CTX md5Check;
FILE * fIn;
BOOL fSt = TRUE;
DWORD dwType;
DWORD dwLen;
DWORD dwVal;
IIS_CRYPTO_STORAGE storage;
Reset();
MD5Init( &md5Check );
if ( FAILED( storage.Initialize( (PIIS_CRYPTO_BLOB)m_pSesKey) ) )
{
return FALSE;
}
if ( (fIn = fopen( m_achFileName, "rb" )) == NULL )
{
return FALSE;
}
// magic value & version
if( fread( (LPVOID)&dwVal, sizeof(dwVal), 1, fIn ) != 1 )
{
fSt = FALSE;
goto cleanup;
}
if ( dwVal != IISMDB_FILE_MAGIC_VALUE )
{
SetLastError( ERROR_BAD_FORMAT );
fSt = FALSE;
goto cleanup;
}
MD5Update( &md5Check, (LPBYTE)&dwVal, sizeof(dwVal) );
if( fread( (LPVOID)&dwVal, sizeof(dwVal), 1, fIn ) != 1 )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( &md5Check, (LPBYTE)&dwVal, sizeof(dwVal) );
// mappings
if( fread( (LPVOID)&m_cMapping, sizeof(m_cMapping), 1, fIn ) != 1 )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( &md5Check, (LPBYTE)&m_cMapping, sizeof(m_cMapping) );
m_pMapping = (CIisMapping**)LocalAlloc( LMEM_FIXED, sizeof(CIisMapping*)*m_cMapping );
if ( m_pMapping == NULL )
{
fSt = FALSE;
goto cleanup;
}
for ( x = 0 ; x < m_cMapping ; ++x )
{
if ( !(m_pMapping[x] = CreateNewMapping()) )
{
m_cMapping = x;
fSt = FALSE;
goto cleanup;
}
if ( !m_pMapping[x]->Deserialize( fIn ,(VALID_CTX)&md5Check, (LPVOID)&storage ) )
{
m_cMapping = x;
fSt = FALSE;
goto cleanup;
}
}
// load hierarchy
if( fread( (LPVOID)&m_cHierarchy, sizeof(m_cHierarchy), 1, fIn ) != 1 )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( &md5Check, (LPBYTE)&m_cHierarchy, sizeof(m_cHierarchy) );
m_pHierarchy = (IISMDB_HEntry*)LocalAlloc( LMEM_FIXED, sizeof(IISMDB_HEntry)*m_cHierarchy );
if ( m_pHierarchy == NULL )
{
fSt = FALSE;
goto cleanup;
}
if( fread( (LPVOID)m_pHierarchy, sizeof(IISMDB_HEntry), m_cHierarchy, fIn ) != m_cHierarchy )
{
fSt = FALSE;
goto cleanup;
}
//
// insure hierarchy correct
//
for ( x = 0 ; x < m_cHierarchy; ++x )
{
if ( m_pHierarchy[x].m_dwIndex >= m_cFields )
{
fSt = FALSE;
goto cleanup;
}
}
MD5Update( &md5Check, (LPBYTE)m_pHierarchy, sizeof(IISMDB_HEntry)*m_cHierarchy );
// load private data
fSt = LoadPrivate( fIn, (VALID_CTX)&md5Check );
MD5Final( &md5Check );
#if 0
//
// Don't use signature for now - a metabase Restore operation
// may have restored another signature, so metabase and
// file won't match
//
if ( !(fSt = !memcmp( m_md5.digest,
md5Check.digest,
sizeof(md5Check.digest) )) )
{
SetLastError( ERROR_INVALID_ACCESS );
}
#endif
cleanup:
fclose( fIn );
if ( !fSt && GetLastError() != ERROR_INVALID_ACCESS )
{
Reset();
}
else
{
UpdateClasses();
}
if ( !fSt )
{
char achErr[32];
LPCTSTR pA[2];
pA[0] = m_achFileName;
pA[1] = achErr;
_itoa( GetLastError(), achErr, 10 );
ReportIisMapEvent( EVENTLOG_ERROR_TYPE,
IISMAP_EVENT_LOAD_ERROR,
2,
pA );
}
return fSt;
}
// CIisCertMapper
CIisCertMapper::CIisCertMapper(
)
/*++
Routine Description:
Constructor for CIisCertMapper
Arguments:
None
Returns:
Nothing
--*/
{
m_pIssuers = NULL;
m_cIssuers = 0;
m_pFields = IisCertMappingFields;
m_cFields = sizeof(IisCertMappingFields)/sizeof(IISMDB_Fields);
m_dwOptions = IISMDB_CERT_OPTIONS;
}
CIisCertMapper::~CIisCertMapper(
)
/*++
Routine Description:
Destructor for CIisCertMapper
Arguments:
None
Returns:
Nothing
--*/
{
}
IISMDB_HEntry*
CIisCertMapper::GetDefaultHierarchy(
LPDWORD pdwN
)
/*++
Routine Description:
return ptr to default hierarchy for certificates mapping
Arguments:
pdwN -- updated with hierarchy entries count
Returns:
ptr to hierarchy entries or NULL if error
--*/
{
*pdwN = sizeof(IisCertMappingHierarchy) / sizeof(IISMDB_HEntry);
return IisCertMappingHierarchy;
}
#if defined(DECODE_ASN1)
CIisMapping*
CIisCertMapper::CreateNewMapping(
Cert_Map *pC
)
/*++
Routine Description:
Create a new mapping from a certificate
Arguments:
pC -- ptr to certificate issuer & subject
Returns:
ptr to mapping. ownership of this object is transfered to caller.
NULL if error
--*/
{
CCertMapping *pCM = new CCertMapping( this );
if ( pCM == NULL )
{
return NULL;
}
if ( pCM->Init( pC, m_pHierarchy, m_cHierarchy ) )
{
return (CIisMapping*)pCM;
}
delete pCM;
return NULL;
}
CIisMapping*
CIisCertMapper::CreateNewMapping(
const LPBYTE pC,
DWORD cC
)
/*++
Routine Description:
Create a new mapping from a certificate
Arguments:
pC -- ptr to certificate issuer & subject
cC -- size of buffer pointed to by pC
Returns:
ptr to mapping. ownership of this object is transfered to caller.
NULL if error
--*/
{
CCertMapping *pCM = new CCertMapping( this );
if ( pCM == NULL )
{
return NULL;
}
if ( pCM->Init( pC, cC, m_pHierarchy, m_cHierarchy ) )
{
return (CIisMapping*)pCM;
}
delete pCM;
return NULL;
}
#endif
BOOL
CIisCertMapper::ResetPrivate(
)
/*++
Routine Description:
Reset CIisCertMapper issuer list
Arguments:
None
Returns:
TRUE if success, FALSE if error
--*/
{
// free issuer list
if ( m_pIssuers != NULL )
{
for ( UINT x = 0 ; x < m_cIssuers ; ++x )
{
LocalFree( m_pIssuers[x].pbIssuer );
}
LocalFree( m_pIssuers );
m_pIssuers = NULL;
}
m_cIssuers = 0;
return TRUE;
}
BOOL
CIisCertMapper::LoadPrivate(
FILE* fIn,
VALID_CTX pMD5
)
/*++
Routine Description:
Load issuer list
Arguments:
fIn -- file to read from
pMD5 -- MD5 to update with signature from input byte stream
Returns:
TRUE if success, FALSE if error
--*/
{
BOOL fSt = TRUE;
UINT x;
if( fread( (LPVOID)&m_cIssuers, sizeof(m_cIssuers), 1, fIn ) != 1 )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)&m_cIssuers, sizeof(m_cIssuers) );
m_pIssuers = (IssuerAccepted*)LocalAlloc( LMEM_FIXED, sizeof(IssuerAccepted)*m_cIssuers );
if ( m_pIssuers == NULL )
{
fSt = FALSE;
goto cleanup;
}
for ( x = 0 ; x < m_cIssuers ; ++x )
{
if ( fread( (LPVOID)&m_pIssuers[x].cbIssuerLen, sizeof(m_pIssuers[x].cbIssuerLen), 1, fIn ) != 1 )
{
m_cIssuers = x;
fSt = FALSE;
goto cleanup;
}
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)&m_pIssuers[x].cbIssuerLen, sizeof(m_pIssuers[x].cbIssuerLen) );
if ( (m_pIssuers[x].pbIssuer = (LPBYTE)LocalAlloc( LMEM_FIXED, m_pIssuers[x].cbIssuerLen )) == NULL )
{
m_cIssuers = x;
fSt = FALSE;
goto cleanup;
}
if ( fread( m_pIssuers[x].pbIssuer, m_pIssuers[x].cbIssuerLen, 1, fIn ) != 1 )
{
m_cIssuers = x;
fSt = FALSE;
goto cleanup;
}
MD5Update( (MD5_CTX*)pMD5, m_pIssuers[x].pbIssuer, m_pIssuers[x].cbIssuerLen );
}
cleanup:
return fSt;
}
BOOL
CIisCertMapper::SavePrivate(
FILE* fOut,
VALID_CTX pMD5
)
/*++
Routine Description:
Save issuer list
Arguments:
fOut -- file to write to
pMD5 -- MD5 to update with signature of output byte stream
Returns:
TRUE if success, FALSE if error
--*/
{
BOOL fSt = TRUE;
UINT x;
if( fwrite( (LPVOID)&m_cIssuers, sizeof(m_cIssuers), 1, fOut ) != 1 )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)&m_cIssuers, sizeof(m_cIssuers) );
for ( x = 0 ; x < m_cIssuers ; ++x )
{
if ( fwrite( (LPVOID)&m_pIssuers[x].cbIssuerLen, sizeof(m_pIssuers[x].cbIssuerLen), 1, fOut ) != 1 )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)&m_pIssuers[x].cbIssuerLen, sizeof(m_pIssuers[x].cbIssuerLen) );
if ( fwrite( m_pIssuers[x].pbIssuer, m_pIssuers[x].cbIssuerLen, 1, fOut ) != 1 )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( (MD5_CTX*)pMD5, m_pIssuers[x].pbIssuer, m_pIssuers[x].cbIssuerLen );
}
cleanup:
return fSt;
}
BOOL
CIisCertMapper::SetIssuerList(
IssuerAccepted*pI,
DWORD dwC
)
/*++
Routine Description:
Set the issuer list by copying supplied list
Arguments:
pI -- list of issuers
dwC -- count of issuers
Returns:
TRUE if success, FALSE if error
--*/
{
UINT x;
if ( (m_pIssuers = (IssuerAccepted*)LocalAlloc( LMEM_FIXED, sizeof(IssuerAccepted)*dwC )) == NULL )
{
return FALSE;
}
for ( x = 0 ; x < dwC ; ++x )
{
m_pIssuers[x].cbIssuerLen = pI[x].cbIssuerLen;
if ( (m_pIssuers[x].pbIssuer = (LPBYTE)LocalAlloc( LMEM_FIXED, pI[x].cbIssuerLen )) == NULL )
{
m_cIssuers = x;
return FALSE;
}
memcpy( m_pIssuers[x].pbIssuer, pI[x].pbIssuer, pI[x].cbIssuerLen );
}
m_cIssuers = dwC;
return TRUE;
}
BOOL
CIisCertMapper::GetIssuerList(
IssuerAccepted**pIssuers,
DWORD*pdwI
)
/*++
Routine Description:
Retrieve the issuer list. Ownership of list transferred to caller
Arguments:
pI -- updated with ptr to array of issuers
pdwI -- updated with count of issuers
Returns:
TRUE if success, FALSE if error
--*/
{
IssuerAccepted *pI;
Lock();
pI = (IssuerAccepted*)LocalAlloc( LMEM_FIXED, m_cIssuers * sizeof(IssuerAccepted*) );
if ( pI == NULL )
{
Unlock();
return FALSE;
}
for ( UINT x = 0 ; x < m_cIssuers ; ++x )
{
if ( (pI[x].pbIssuer = (LPBYTE)LocalAlloc( LMEM_FIXED,
m_pIssuers[x].cbIssuerLen ))
== NULL )
{
Unlock();
DeleteIssuerList( pI, x );
return FALSE;
}
memcpy( pI[x].pbIssuer,
m_pIssuers[x].pbIssuer,
m_pIssuers[x].cbIssuerLen );
}
*pIssuers = pI;
*pdwI = m_cIssuers;
Unlock();
return TRUE;
}
BOOL
CIisCertMapper::DeleteIssuerList(
IssuerAccepted* pI,
DWORD dwI
)
/*++
Routine Description:
Delete an issuer list.
Arguments:
pI -- ptr to array of issuers
dwI -- count of issuers
Returns:
TRUE if success, FALSE if error
--*/
{
for ( DWORD x = 0 ; x < dwI ; ++x )
{
LocalFree( pI[x].pbIssuer );
}
LocalFree( pI );
return TRUE;
}
BOOL
CIisCertMapper::GetIssuerBuffer(
LPBYTE pB,
DWORD* pdwI
)
/*++
Routine Description:
Retrieve the issuer list. Ownership of list transferred to caller
Arguments:
pB -- updated with ptr to issuers buffer
pdwI -- updated with size of buffer of issuers
Returns:
TRUE if success, FALSE if error
--*/
{
LPBYTE pS;
DWORD dwC = 0;
Lock();
for ( UINT x = 0 ; x < m_cIssuers ; ++x )
{
dwC += m_pIssuers[x].cbIssuerLen + sizeof(USHORT);
}
*pdwI = dwC;
if ( pB != NULL )
{
for ( pS = pB, x = 0 ; x < m_cIssuers ; ++x )
{
pS[0] = (BYTE)(m_pIssuers[x].cbIssuerLen >> 8);
pS[1] = (BYTE)(m_pIssuers[x].cbIssuerLen);
memcpy( pS + sizeof(USHORT),
m_pIssuers[x].pbIssuer,
m_pIssuers[x].cbIssuerLen );
pS += m_pIssuers[x].cbIssuerLen + sizeof(USHORT);
}
}
Unlock();
return TRUE;
}
BOOL
CIisCertMapper::FreeIssuerBuffer(
LPBYTE pI
)
/*++
Routine Description:
Delete an issuer list.
Arguments:
pI -- ptr to issuers
Returns:
TRUE if success, FALSE if error
--*/
{
LocalFree( pI );
return TRUE;
}
// CIisCert11Mapper
CIisCert11Mapper::CIisCert11Mapper(
)
/*++
Routine Description:
Constructor for CIisCert11Mapper
Arguments:
None
Returns:
Nothing
--*/
{
m_pIssuers = NULL;
m_cIssuers = 0;
m_pFields = IisCert11MappingFields;
m_cFields = sizeof(IisCert11MappingFields)/sizeof(IISMDB_Fields);
m_dwOptions = IISMDB_CERT11_OPTIONS;
m_pSubjectSource = NULL;
m_pDefaultDomain = NULL;
}
CIisCert11Mapper::~CIisCert11Mapper(
)
/*++
Routine Description:
Destructor for CIisCert11Mapper
Arguments:
None
Returns:
Nothing
--*/
{
}
BOOL
CIisCert11Mapper::Add(
CIisMapping* pM
)
/*++
Routine Description:
Add a mapping entry to mapping array
Transfer ownership of mapping object to mapper
Check is mapping to same NT account does not already exist.
Arguments:
pM -- pointer to mapping to be added to mapper
Returns:
TRUE if success, FALSE if error
--*/
{
UINT x;
LPSTR pA;
LPSTR pF;
DWORD dwA;
DWORD dwF;
// check if NT acct not already present.
// if so, return FALSE, SetLastError( ERROR_INVALID_PARAMETER );
if ( pM == NULL )
{
return FALSE;
}
#if 0
if ( !pM->MappingGetField( IISMDB_INDEX_CERT11_NT_ACCT, &pA, &dwA, FALSE )
|| pA == NULL )
{
pA = "";
}
for ( x = 0 ; x < m_cMapping ; ++x )
{
if ( !m_pMapping[x]->MappingGetField( IISMDB_INDEX_CERT11_NT_ACCT, &pF, &dwF, FALSE )
|| pF == NULL )
{
pF = "";
}
if ( dwA == dwF && !memcmp( pF, pA, dwF ) )
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
}
#endif
#if 1
#if defined(CERT11_FULL_CERT)
LPSTR pCe;
DWORD dwCe;
LPSTR pCeIter;
DWORD dwCeIter;
if ( !pM->MappingGetField( IISMDB_INDEX_CERT11_CERT, &pCe, &dwCe, FALSE )
|| pCe == NULL )
{
dwCe = 0;
}
for ( x = 0 ; x < m_cMapping ; ++x )
{
if ( !m_pMapping[x]->MappingGetField( IISMDB_INDEX_CERT11_CERT, &pCeIter, &dwCeIter, FALSE )
|| pCeIter == NULL )
{
dwCeIter = 0;
}
if ( dwCe == dwCeIter && !memcmp( pCe, pCeIter, dwCe ) )
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
}
#else
LPSTR pSu;
LPSTR pIs;
DWORD dwSu;
DWORD dwIs;
LPSTR pSuIter;
LPSTR pIsIter;
DWORD dwSuIter;
DWORD dwIsIter;
if ( !pM->MappingGetField( IISMDB_INDEX_CERT11_SUBJECT, &pSu, &dwSu, FALSE )
|| pSu == NULL )
{
dwSu = 0;
}
if ( !pM->MappingGetField( IISMDB_INDEX_CERT11_ISSUER, &pIs, &dwIs, FALSE )
|| pIs == NULL )
{
dwIs = 0;
}
for ( x = 0 ; x < m_cMapping ; ++x )
{
if ( !m_pMapping[x]->MappingGetField( IISMDB_INDEX_CERT11_SUBJECT, &pSuIter, &dwSuIter, FALSE )
|| pSuIter == NULL )
{
dwSuIter = 0;
}
if ( !m_pMapping[x]->MappingGetField( IISMDB_INDEX_CERT11_ISSUER, &pIsIter, &dwIsIter, FALSE )
|| pIsIter == NULL )
{
dwIsIter = 0;
}
if ( dwSu == dwSuIter && !memcmp( pSu, pSuIter, dwSu ) &&
dwIs == dwIsIter && !memcmp( pIs, pIsIter, dwIs ) )
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
}
#endif
#endif
return CIisAcctMapper::Add( pM );
}
IISMDB_HEntry*
CIisCert11Mapper::GetDefaultHierarchy(
LPDWORD pdwN
)
/*++
Routine Description:
return ptr to default hierarchy for certificates mapping
Arguments:
pdwN -- updated with hierarchy entries count
Returns:
ptr to hierarchy entries or NULL if error
--*/
{
*pdwN = sizeof(IisCert11MappingHierarchy) / sizeof(IISMDB_HEntry);
return IisCert11MappingHierarchy;
}
#if defined(CERT11_FULL_CERT)
CIisMapping*
CIisCert11Mapper::CreateNewMapping(
LPBYTE pC,
DWORD dwC
)
/*++
Routine Description:
Create a new mapping from a certificate
Arguments:
pC -- cert ( ASN.1 format )
dwC -- length of cert
Returns:
ptr to mapping. ownership of this object is transfered to caller.
NULL if error
--*/
{
CCert11Mapping *pCM = new CCert11Mapping( this );
if ( pCM == NULL )
{
return NULL;
}
if ( pCM->Init( pC, dwC, m_pHierarchy, m_cHierarchy ) )
{
return (CIisMapping*)pCM;
}
delete pCM;
return NULL;
}
#else
CIisMapping*
CIisCert11Mapper::CreateNewMapping(
LPBYTE pI,
DWORD dwI,
LPBYTE pS,
DWORD dwS
)
/*++
Routine Description:
Create a new mapping from a certificate
Arguments:
pI -- cert issuer ( ASN.1 format )
dwI -- length of issuer
pS -- cert subject ( ASN.1 format )
dwS -- length of subject
Returns:
ptr to mapping. ownership of this object is transfered to caller.
NULL if error
--*/
{
CCert11Mapping *pCM = new CCert11Mapping( this );
if ( pCM == NULL )
{
return NULL;
}
if ( pCM->Init( pI, dwI, pS, dwS, m_pHierarchy, m_cHierarchy ) )
{
return (CIisMapping*)pCM;
}
delete pCM;
return NULL;
}
#endif
BOOL
CIisCert11Mapper::ResetPrivate(
)
/*++
Routine Description:
Reset CIisCert11Mapper issuer list
Arguments:
None
Returns:
TRUE if success, FALSE if error
--*/
{
// free issuer list
if ( m_pIssuers != NULL )
{
for ( UINT x = 0 ; x < m_cIssuers ; ++x )
{
LocalFree( m_pIssuers[x].pbIssuer );
}
LocalFree( m_pIssuers );
m_pIssuers = NULL;
}
m_cIssuers = 0;
if ( m_pSubjectSource != NULL )
{
LocalFree( m_pSubjectSource );
}
if ( m_pDefaultDomain != NULL )
{
LocalFree( m_pDefaultDomain );
}
return TRUE;
}
BOOL
CIisCert11Mapper::LoadPrivate(
FILE* fIn,
VALID_CTX pMD5
)
/*++
Routine Description:
Load issuer list
Arguments:
fIn -- file to read from
pMD5 -- MD5 to update with signature from input byte stream
Returns:
TRUE if success, FALSE if error
--*/
{
BOOL fSt = TRUE;
UINT x;
UINT cLen;
CHAR achBuf[64];
if( fread( (LPVOID)&m_cIssuers, sizeof(m_cIssuers), 1, fIn ) != 1 )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)&m_cIssuers, sizeof(m_cIssuers) );
m_pIssuers = (IssuerAccepted*)LocalAlloc( LMEM_FIXED, sizeof(IssuerAccepted)*m_cIssuers );
if ( m_pIssuers == NULL )
{
fSt = FALSE;
goto cleanup;
}
for ( x = 0 ; x < m_cIssuers ; ++x )
{
if ( fread( (LPVOID)&m_pIssuers[x].cbIssuerLen, sizeof(m_pIssuers[x].cbIssuerLen), 1, fIn ) != 1 )
{
m_cIssuers = x;
fSt = FALSE;
goto cleanup;
}
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)&m_pIssuers[x].cbIssuerLen, sizeof(m_pIssuers[x].cbIssuerLen) );
if ( (m_pIssuers[x].pbIssuer = (LPBYTE)LocalAlloc( LMEM_FIXED, m_pIssuers[x].cbIssuerLen )) == NULL )
{
m_cIssuers = x;
fSt = FALSE;
goto cleanup;
}
if ( fread( m_pIssuers[x].pbIssuer, m_pIssuers[x].cbIssuerLen, 1, fIn ) != 1 )
{
m_cIssuers = x;
fSt = FALSE;
goto cleanup;
}
MD5Update( (MD5_CTX*)pMD5, m_pIssuers[x].pbIssuer, m_pIssuers[x].cbIssuerLen );
}
//
// Read subject source
//
if( Iisfgets( achBuf, sizeof(achBuf), fIn ) == NULL )
{
fSt = FALSE;
goto cleanup;
}
cLen = strlen(achBuf);
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)achBuf, cLen );
if ( !(m_pSubjectSource = (LPSTR)LocalAlloc( LMEM_FIXED, cLen+1 )) )
{
fSt = FALSE;
goto cleanup;
}
memcpy( m_pSubjectSource, achBuf, cLen+1 );
//
// Read default domain
//
if( Iisfgets( achBuf, sizeof(achBuf), fIn ) == NULL )
{
fSt = FALSE;
goto cleanup;
}
cLen = strlen(achBuf);
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)achBuf, cLen );
if ( !(m_pDefaultDomain = (LPSTR)LocalAlloc( LMEM_FIXED, cLen+1 )) )
{
fSt = FALSE;
goto cleanup;
}
memcpy( m_pDefaultDomain, achBuf, cLen+1 );
cleanup:
return fSt;
}
BOOL
CIisCert11Mapper::SavePrivate(
FILE* fOut,
VALID_CTX pMD5
)
/*++
Routine Description:
Save issuer list
Arguments:
fOut -- file to write to
pMD5 -- MD5 to update with signature of output byte stream
Returns:
TRUE if success, FALSE if error
--*/
{
BOOL fSt = TRUE;
UINT x;
if( fwrite( (LPVOID)&m_cIssuers, sizeof(m_cIssuers), 1, fOut ) != 1 )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)&m_cIssuers, sizeof(m_cIssuers) );
for ( x = 0 ; x < m_cIssuers ; ++x )
{
if ( fwrite( (LPVOID)&m_pIssuers[x].cbIssuerLen, sizeof(m_pIssuers[x].cbIssuerLen), 1, fOut ) != 1 )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)&m_pIssuers[x].cbIssuerLen, sizeof(m_pIssuers[x].cbIssuerLen) );
if ( fwrite( m_pIssuers[x].pbIssuer, m_pIssuers[x].cbIssuerLen, 1, fOut ) != 1 )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( (MD5_CTX*)pMD5, m_pIssuers[x].pbIssuer, m_pIssuers[x].cbIssuerLen );
}
//
// Write subject source
//
if ( m_pSubjectSource )
{
if( Iisfputs( m_pSubjectSource, fOut ) == EOF )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)m_pSubjectSource, strlen( m_pSubjectSource ) );
}
else
{
Iisfputs( "", fOut );
}
//
// Write default domain
//
if ( m_pDefaultDomain )
{
if( Iisfputs( m_pDefaultDomain, fOut ) == EOF )
{
fSt = FALSE;
goto cleanup;
}
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)m_pDefaultDomain, strlen( m_pDefaultDomain ) );
}
else
{
Iisfputs( "", fOut );
}
cleanup:
return fSt;
}
BOOL
CIisCert11Mapper::SetSubjectSource(
LPSTR psz
)
/*++
Routine Description:
Set the subject field to use as source for NT acct
Arguments:
psz - ASN.1 name of field to use
Returns:
TRUE if success, FALSE if error
--*/
{
if ( m_pSubjectSource != NULL )
{
LocalFree( m_pSubjectSource );
}
if ( m_pSubjectSource = (LPSTR)LocalAlloc( LMEM_FIXED, strlen(psz)+1) )
{
strcpy( m_pSubjectSource, psz );
return TRUE;
}
return FALSE;
}
BOOL
CIisCert11Mapper::SetDefaultDomain(
LPSTR psz
)
/*++
Routine Description:
Set the domain to use for NT acct
Arguments:
psz - domain name
Returns:
TRUE if success, FALSE if error
--*/
{
if ( m_pDefaultDomain != NULL )
{
LocalFree( m_pDefaultDomain );
}
if ( m_pDefaultDomain = (LPSTR)LocalAlloc( LMEM_FIXED, strlen(psz)+1) )
{
strcpy( m_pDefaultDomain, psz );
return TRUE;
}
return FALSE;
}
BOOL
CIisCert11Mapper::SetIssuerList(
IssuerAccepted*pI,
DWORD dwC
)
/*++
Routine Description:
Set the issuer list by copying supplied list
Arguments:
pI -- list of issuers
dwC -- count of issuers
Returns:
TRUE if success, FALSE if error
--*/
{
UINT x;
if ( (m_pIssuers = (IssuerAccepted*)LocalAlloc( LMEM_FIXED, sizeof(IssuerAccepted)*dwC )) == NULL )
{
return FALSE;
}
for ( x = 0 ; x < dwC ; ++x )
{
m_pIssuers[x].cbIssuerLen = pI[x].cbIssuerLen;
if ( (m_pIssuers[x].pbIssuer = (LPBYTE)LocalAlloc( LMEM_FIXED, pI[x].cbIssuerLen )) == NULL )
{
m_cIssuers = x;
return FALSE;
}
memcpy( m_pIssuers[x].pbIssuer, pI[x].pbIssuer, pI[x].cbIssuerLen );
}
m_cIssuers = dwC;
return TRUE;
}
BOOL
CIisCert11Mapper::GetIssuerList(
IssuerAccepted**pIssuers,
DWORD*pdwI
)
/*++
Routine Description:
Retrieve the issuer list. Ownership of list transferred to caller
Arguments:
pI -- updated with ptr to array of issuers
pdwI -- updated with count of issuers
Returns:
TRUE if success, FALSE if error
--*/
{
IssuerAccepted *pI;
Lock();
pI = (IssuerAccepted*)LocalAlloc( LMEM_FIXED, m_cIssuers * sizeof(IssuerAccepted*) );
if ( pI == NULL )
{
Unlock();
return FALSE;
}
for ( UINT x = 0 ; x < m_cIssuers ; ++x )
{
if ( (pI[x].pbIssuer = (LPBYTE)LocalAlloc( LMEM_FIXED,
m_pIssuers[x].cbIssuerLen ))
== NULL )
{
Unlock();
DeleteIssuerList( pI, x );
return FALSE;
}
memcpy( pI[x].pbIssuer,
m_pIssuers[x].pbIssuer,
m_pIssuers[x].cbIssuerLen );
}
*pIssuers = pI;
*pdwI = m_cIssuers;
Unlock();
return TRUE;
}
BOOL
CIisCert11Mapper::DeleteIssuerList(
IssuerAccepted* pI,
DWORD dwI
)
/*++
Routine Description:
Delete an issuer list.
Arguments:
pI -- ptr to array of issuers
dwI -- count of issuers
Returns:
TRUE if success, FALSE if error
--*/
{
for ( DWORD x = 0 ; x < dwI ; ++x )
{
LocalFree( pI[x].pbIssuer );
}
LocalFree( pI );
return TRUE;
}
BOOL
CIisCert11Mapper::GetIssuerBuffer(
LPBYTE pB,
DWORD* pdwI
)
/*++
Routine Description:
Retrieve the issuer list. Ownership of list transferred to caller
Arguments:
pB -- updated with ptr to issuers buffer
pdwI -- updated with size of buffer of issuers
Returns:
TRUE if success, FALSE if error
--*/
{
LPBYTE pS;
DWORD dwC = 0;
Lock();
for ( UINT x = 0 ; x < m_cIssuers ; ++x )
{
dwC += m_pIssuers[x].cbIssuerLen + sizeof(USHORT);
}
*pdwI = dwC;
if ( pB != NULL )
{
for ( pS = pB, x = 0 ; x < m_cIssuers ; ++x )
{
pS[0] = (BYTE)(m_pIssuers[x].cbIssuerLen >> 8);
pS[1] = (BYTE)(m_pIssuers[x].cbIssuerLen);
memcpy( pS + sizeof(USHORT),
m_pIssuers[x].pbIssuer,
m_pIssuers[x].cbIssuerLen );
pS += m_pIssuers[x].cbIssuerLen + sizeof(USHORT);
}
}
Unlock();
return TRUE;
}
BOOL
CIisCert11Mapper::FreeIssuerBuffer(
LPBYTE pI
)
/*++
Routine Description:
Delete an issuer list.
Arguments:
pI -- ptr to issuers
Returns:
TRUE if success, FALSE if error
--*/
{
LocalFree( pI );
return TRUE;
}
// CCertMapping
CCertMapping::CCertMapping(
CIisAcctMapper* pMap
)
/*++
Routine Description:
Constructor for CCertMapping
Arguments:
pMap -- ptr to mapper object linked to this mapping
Returns:
Nothing
--*/
{
m_pMapper = (CIisAcctMapper*)pMap;
for ( int x = 0 ; x < sizeof(m_pFields)/sizeof(LPSTR) ; ++x )
{
m_pFields[x] = NULL;
}
}
CCertMapping::~CCertMapping(
)
/*++
Routine Description:
Destructor for CCertMapping
Arguments:
None
Returns:
Nothing
--*/
{
}
#if defined(DECODE_ASN1)
BOOL
DecodeNextField(
LPBYTE* ppAscii,
DWORD* pcAscii,
int* piF,
LPBYTE* ppN
)
/*++
Routine Description:
Decode next field certificate ASCII representation
field format as
name=content
where name is zero or more non comma chars
Arguments:
ppAscii - ptr to buffer where to scan for next field
updated with ptr to field content
pcAscii - ptr to count of char in ppAscii
updated with count of remaining char after ppAscii update
piF - updated with field type ( -1: unrecognized, 0:O, 1:OU, 2:C, 3:CN )
ppN - updated with ptr to field name
Returns:
TRUE if next field exists, otherwise FALSE
--*/
{
LPBYTE pAscii = *ppAscii;
LPBYTE pN;
int iF;
LPBYTE p = (LPBYTE)memchr( pAscii, '=', *pcAscii );
if ( p == NULL )
{
return FALSE;
}
for ( pN = p ; pN > pAscii && pN[-1] != ' ' ; --pN )
{
}
if ( pN[0] == 'O' && pN[1] == '=' )
{
iF = 0;
}
else if ( pN[0] == 'O' && pN[1] == 'U' && pN[2] == '=' )
{
iF = 1;
}
else if ( pN[0] == 'C' && pN[1] == '=' )
{
iF = 2;
}
else if ( pN[0] == 'C' && pN[1] == 'U' && pN[2] == '=' )
{
iF = 3;
}
else
{
iF = -1;
}
*piF = iF;
*pcAscii -= (p + 1 - pAscii);
*ppAscii = p + 1;
*ppN = pN;
return TRUE;
}
int
IisDecodeAsciiDN(
LPSTR *pF,
LPSTR pStore,
LPBYTE pAscii,
DWORD cAscii
)
/*++
Routine Description:
Decode certificate ASCII representation to an array of well-known fields
( 0:O, 1:OU, 2:C, 3:CN )
Arguments:
pF - ptr to array of fields to be updated with ptr to field content
pStore - buffer to be used to store fields content, assumed to be big enough
pAscii - ptr to buffer where to scan for fields
cAscii - ptr to count of char in pAscii
Returns:
# of chars stored in pStore
--*/
{
int iF;
int iNF;
LPBYTE pN;
BOOL f;
int l = 0;
//O, OU, C, CN
f = DecodeNextField( &pAscii, &cAscii, &iF, &pN );
for ( ; f ; )
{
LPBYTE pC = pAscii;
if ( !(f=DecodeNextField( &pAscii, &cAscii, &iNF, &pN )) )
{
pN = pAscii + cAscii;
}
else
{
while ( pN > pC && *pN != ',' )
{
--pN;
}
}
// field content is from pC to pN-1 inclusive
if ( iF >= 0 )
{
pF[iF] = pStore;
int cL = pN - pC;
memcpy( pStore, pC, cL );
pStore[cL++] = '\0';
l += cL;
pStore += cL;
}
iF = iNF;
}
return l;
}
BOOL
CCertMapping::Init(
Cert_Map *pCert,
IISMDB_HEntry *pH,
DWORD dwH
)
/*++
Routine Description:
Constructor for CCertMapping
Arguments:
pCert -- ptr to certificate info to initialize from
pH -- ptr to hierarchy info
dwH -- number of hierarchy entries
Returns:
TRUE if success, otherwise FALSE
--*/
{
int l;
int l2;
if ( m_pBuff )
{
LocalFree( m_pBuff );
}
m_cUsedBuff = 0;
if ( !(m_pBuff = (LPBYTE)LocalAlloc( LMEM_FIXED, m_cAllocBuff = 2048 )) )
{
return FALSE;
}
for ( int x = 0 ; x < sizeof(m_pFields)/sizeof(LPSTR) ; ++x )
{
m_pFields[x] = NULL;
}
//
// Check if content ASCII ( if so, 1st byte is a field name, so >= 'A' )
//
if ( pCert->cbIssuerLen && pCert->pIssuer[0] >= 'A' )
{
if ( (l = IisDecodeAsciiDN( m_pFields,
(LPSTR)m_pBuff,
pCert->pIssuer,
pCert->cbIssuerLen
)) == -1
|| (l2 = IisDecodeAsciiDN(
m_pFields+3,
(LPSTR)m_pBuff+l,
pCert->pSubject,
pCert->cbSubjectLen
)) == -1
)
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
}
//
// otherwise decode ASN.1 format
//
else if ( (l = IisDecodeDN( m_pFields,
(LPSTR)m_pBuff,
pCert->pIssuer,
pCert->cbIssuerLen
)) == -1
|| (l2 = IisDecodeDN(
m_pFields+3,
(LPSTR)m_pBuff+l,
pCert->pSubject,
pCert->cbSubjectLen
)) == -1
)
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
m_cUsedBuff = (UINT)(l + l2);
UpdateMask( pH, dwH );
return TRUE;
}
BOOL
CCertMapping::Init(
const LPBYTE pCert,
DWORD cCert,
IISMDB_HEntry *pH,
DWORD dwH
)
/*++
Routine Description:
Constructor for CCertMapping
Arguments:
pCert -- ptr to certificate info to initialize from
cCert -- size of buffer pointed to by pCert
pH -- ptr to hierarchy info
dwH -- number of hierarchy entries
Returns:
TRUE if success, otherwise FALSE
--*/
{
UINT l;
if ( m_pBuff )
{
LocalFree( m_pBuff );
}
m_cUsedBuff = 0;
if ( !(m_pBuff = (LPBYTE)LocalAlloc( LMEM_FIXED, m_cAllocBuff = 2048 )) )
{
return FALSE;
}
for ( int x = 0 ; x < sizeof(m_pFields)/sizeof(LPSTR) ; ++x )
{
m_pFields[x] = NULL;
}
//
// decode ASN.1 format
//
// extract issuer, subject from pCert, cCert
// O, OU, C, CN ( issuer then subject )
//
if ( (l = DecodeCert(
pCert,
cCert,
m_pFields,
(LPSTR)m_pBuff
)) == 0
)
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
m_cUsedBuff = l;
UpdateMask( pH, dwH );
return TRUE;
}
#endif
// CCert11Mapping
CCert11Mapping::CCert11Mapping(
CIisAcctMapper* pMap
)
/*++
Routine Description:
Constructor for CCert11Mapping
Arguments:
pMap -- ptr to mapper object linked to this mapping
Returns:
Nothing
--*/
{
m_pMapper = (CIisAcctMapper*)pMap;
for ( int x = 0 ; x < sizeof(m_pFields)/sizeof(LPSTR) ; ++x )
{
m_pFields[x] = NULL;
}
for ( x = 0 ; x < sizeof(m_pFields)/sizeof(LPSTR) ; ++x )
{
m_cFields[x] = 0;
}
}
CCert11Mapping::~CCert11Mapping(
)
/*++
Routine Description:
Destructor for CCert11Mapping
Arguments:
None
Returns:
Nothing
--*/
{
}
#if defined(CERT11_FULL_CERT)
BOOL
CCert11Mapping::Init(
LPBYTE pC,
DWORD dwC,
IISMDB_HEntry *pH,
DWORD dwH
)
/*++
Routine Description:
Constructor for CCert11Mapping
Arguments:
pC -- cert ( ASN.1 format )
dwC -- length of cert
pH -- ptr to hierarchy info
dwH -- number of hierarchy entries
Returns:
TRUE if success, FALSE if error
--*/
{
StoreFieldRef( IISMDB_INDEX_CERT11_CERT, (LPSTR)pC, dwC );
UpdateMask( pH, dwH );
return TRUE;
}
#else
BOOL
CCert11Mapping::Init(
LPBYTE pI,
DWORD dwI,
LPBYTE pS,
DWORD dwS,
IISMDB_HEntry *pH,
DWORD dwH
)
/*++
Routine Description:
Constructor for CCert11Mapping
Arguments:
pI -- cert issuer ( ASN.1 format )
dwI -- length of issuer
pS -- cert subject ( ASN.1 format )
dwS -- length of subject
pH -- ptr to hierarchy info
dwH -- number of hierarchy entries
Returns:
TRUE if success, FALSE if error
--*/
{
StoreFieldRef( IISMDB_INDEX_CERT11_SUBJECT, (LPSTR)pS, dwS );
StoreFieldRef( IISMDB_INDEX_CERT11_ISSUER, (LPSTR)pI, dwI);
UpdateMask( pH, dwH );
return TRUE;
}
#endif
// CIisMapping
CIisMapping::CIisMapping(
)
/*++
Routine Description:
Constructor for CIisMapping
Arguments:
None
Returns:
Nothing
--*/
{
m_pBuff = NULL;
m_cUsedBuff = m_cAllocBuff = 0;
m_dwMask = 0;
}
BOOL
CIisMapping::CloneEx(
CIisMapping** ppM,
LPSTR* ppTargetS,
LPSTR* ppS,
LPDWORD pTargetC,
LPDWORD pC,
UINT cF
)
/*++
Routine Description:
Clone a mapping entry
Arguments:
Returns:
TRUE if success, otherwise FALSE
--*/
{
CIisMapping* pM = *ppM;
UINT i;
if ( ppTargetS && ppS )
{
memcpy( ppTargetS, ppS, sizeof(LPSTR*) * cF );
}
if ( pTargetC && pC )
{
memcpy( pTargetC, pC, sizeof(DWORD) * cF );
}
if ( !(pM->m_pBuff = (LPBYTE)LocalAlloc( LMEM_FIXED, m_cAllocBuff )) )
{
delete pM;
*ppM = NULL;
return FALSE;
}
memcpy( pM->m_pBuff, m_pBuff, m_cUsedBuff );
pM->m_cUsedBuff = m_cUsedBuff;
pM->m_cAllocBuff = m_cAllocBuff;
pM->m_pMapper = m_pMapper;
pM->m_dwMask = m_dwMask;
//
// Adjust ptr to point to new buffer
//
for ( i = 0 ; i < cF ; ++i )
{
if ( ppTargetS[i] )
{
ppTargetS[i] += pM->m_pBuff - m_pBuff;
}
}
return TRUE;
}
BOOL
CIisMapping::UpdateMask(
IISMDB_HEntry* pH,
DWORD dwI
)
/*++
Routine Description:
Update mask of significant fields for a mapping object
Field is significant if not containing "*"
mask if bitmask of n bits where n is # of hierarchy entries
bit of rank m == 0 means field pointed by hierarchy entry n - 1 - m
is significant. ( i.e. MSB is hierarchy entry 0, the most significant )
Arguments:
pH -- ptr to hierarchy info
dwI -- number of hierarchy entries
Returns:
TRUE if success, FALSE if error
--*/
{
LPSTR *pFields;
LPDWORD pcFields;
LPSTR pF;
DWORD dwC;
int iMax;
m_dwMask = (1u << dwI)-1;
iMax = GetNbField( &pFields, &pcFields );
if ( pcFields )
{
for ( UINT x = 0 ; x < dwI ; ++x )
{
MappingGetField( pH[x].m_dwIndex, &pF, &dwC, FALSE );
if ( !pF || dwC != 1 || *pF != '*' )
{
m_dwMask &= ~(1u << (dwI - 1 - x) );
}
}
}
else
{
for ( UINT x = 0 ; x < dwI ; ++x )
{
MappingGetField( pH[x].m_dwIndex, &pF );
if ( !pF || strcmp( pF, "*" ) )
{
m_dwMask &= ~(1u << (dwI - 1 - x) );
}
}
}
return TRUE;
}
BOOL
CIisMapping::Copy(
CIisMapping* pM
)
/*++
Routine Description:
Copy the specified mapping in this
Arguments:
pM - ptr to mapping to duplicate
Returns:
TRUE if success, FALSE if error
--*/
{
LPSTR *pFields;
LPSTR pF;
UINT iMax = GetNbField( &pFields );
for ( UINT x = 0 ; x < iMax ; ++x )
{
if ( pM->MappingGetField( x, &pF ) && *pF )
{
if ( !MappingSetField( x, pF ) )
{
return FALSE;
}
}
}
return TRUE;
}
int
CIisMapping::Cmp(
CIisMapping* pM,
BOOL fCmpForMatch
)
/*++
Routine Description:
Compare 2 mappings, return -1, 0 or 1 as suitable for qsort or bsearch
Can compare either for full sort order ( using mask & significant fields )
or for a match ( not using mask )
Arguments:
pM -- ptr to mapping to compare to. This is to be used as the 2nd
entry for purpose of lexicographical order.
fCmpForMatch -- TRUE if comparing for a match inside a given mask class
Returns:
-1 if *this < *pM, 0 if *this == *pM, 1 if *this > *pM
--*/
{
DWORD dwCmpMask = 0xffffffff;
// if not compare for match, consider mask
if ( !fCmpForMatch )
{
if ( m_dwMask < pM->GetMask() )
{
return -1;
}
else if ( m_dwMask > pM->GetMask() )
{
return 1;
}
// mask are identical, have to consider fields
}
// compute common significant fields : bit is 1 if significant
dwCmpMask = (~m_dwMask) & (~pM->GetMask());
DWORD dwH;
IISMDB_HEntry* pH = m_pMapper->GetHierarchy( &dwH );
UINT x;
LPSTR *pFL;
LPDWORD pcFL;
GetNbField( &pFL, &pcFL );
for ( x = 0 ; x < dwH ; ++x )
{
if( ! (dwCmpMask & (1u << (dwH - 1 - x) )) )
{
continue;
}
LPSTR pA;
LPSTR pB;
DWORD dwA;
DWORD dwB;
int fC;
if ( pcFL ) // check if length available
{
MappingGetField( pH[x].m_dwIndex, &pA, &dwA, FALSE );
pM->MappingGetField( pH[x].m_dwIndex, &pB, &dwB, FALSE );
if ( pA == NULL )
{
dwA = 0;
}
if ( pB == NULL )
{
dwB = 0;
}
if ( dwA != dwB )
{
return dwA < dwB ? -1 : 1;
}
fC = memcmp( pA, pB, dwA );
}
else
{
MappingGetField( pH[x].m_dwIndex, &pA );
pM->MappingGetField( pH[x].m_dwIndex, &pB );
if ( pA == NULL )
{
pA = "";
}
if ( pB == NULL )
{
pB = "";
}
fC = strcmp( pA, pB );
}
if ( fC )
{
return fC;
}
}
return 0;
}
BOOL
CIisMapping::MappingGetField(
DWORD dwIndex,
LPSTR *pF
)
/*++
Routine Description:
Get ptr to field in mapping entry
ownership of field remains with mapping entry
Arguments:
dwIndex -- index of field
pF -- updated with ptr to field entry. can be NULL if
field empty.
Returns:
TRUE if success, FALSE if error
Lock:
mapper must be locked for ptr to remain valid
--*/
{
LPSTR *pFields;
DWORD iMax = GetNbField( &pFields );
if ( dwIndex >= iMax )
{
return FALSE;
}
*pF = pFields[dwIndex];
return TRUE;
}
BOOL
CIisMapping::MappingGetField(
DWORD dwIndex,
LPSTR *pF,
LPDWORD pcF,
BOOL fUuEncode
)
/*++
Routine Description:
Get ptr to field in mapping entry
ownership of field remains with mapping entry
Arguments:
dwIndex -- index of field
pF -- updated with ptr to field entry. can be NULL if
field empty.
pcF -- updated with length of fields, 0 if empty
fUuEncode -- TRUE if result is to be uuencoded.
if TRUE, caller must LocalFree( *pF )
Returns:
TRUE if success, FALSE if error
Lock:
mapper must be locked for ptr to remain valid
--*/
{
LPSTR *pFields;
LPDWORD pcFields;
DWORD iMax = GetNbField( &pFields, &pcFields );
if ( dwIndex >= iMax )
{
return FALSE;
}
if ( fUuEncode )
{
LPSTR pU = (LPSTR)LocalAlloc( LMEM_FIXED, ((pcFields[dwIndex]+3)*4)/3+1 );
if ( pU == NULL )
{
return FALSE;
}
DWORD cO;
IISuuencode( (LPBYTE)pFields[dwIndex], pcFields[dwIndex], (LPBYTE)pU, FALSE );
*pF = pU;
*pcF = strlen(pU);
}
else
{
*pF = pFields[dwIndex];
*pcF = pcFields[dwIndex];
}
return TRUE;
}
BOOL
CIisMapping::MappingSetField(
DWORD dwIndex,
LPSTR pszNew
)
/*++
Routine Description:
Set field in mapping entry to specified content
data pointed by pszNew is copied inside mapping entry
Arguments:
dwIndex -- index of field
pszNew -- data to copy inside field
Returns:
TRUE if success, FALSE if error
Lock:
mapper must be locked for ptr to remain valid
--*/
{
LPSTR *pFields;
DWORD iMax = GetNbField( &pFields );
if ( dwIndex >= iMax )
{
return FALSE;
}
return StoreField( pFields, dwIndex, iMax, pszNew );
}
BOOL
CIisMapping::MappingSetField(
DWORD dwIndex,
LPSTR pszNew,
DWORD cNew,
BOOL fIsUuEncoded
)
/*++
Routine Description:
Set field in mapping entry to specified content
data pointed by pszNew is copied inside mapping entry
Arguments:
dwIndex -- index of field
pszNew -- data to copy inside field
cNew -- length of data
fIsUuEncoded -- TRUE if pszNew is UUEncoded
Returns:
TRUE if success, FALSE if error
Lock:
mapper must be locked for ptr to remain valid
--*/
{
LPSTR *pFields;
LPDWORD pcFields;
DWORD iMax = GetNbField( &pFields, &pcFields );
if ( dwIndex >= iMax )
{
return FALSE;
}
return StoreField( pFields, pcFields, dwIndex, iMax, pszNew, cNew, fIsUuEncoded );
}
BOOL
CIisMapping::StoreField(
LPSTR* ppszFields,
DWORD dwIndex,
DWORD dwNbIndex,
LPSTR pszNew
)
/*++
Routine Description:
Update field array in mapping entry with new field
data pointed by pszNew is copied inside mapping entry
Arguments:
ppszFields -- array of field pointers to be updated
dwIndex -- index of field
dwNbIndex -- number of fields in array
pszNew -- data to copy inside field
Returns:
TRUE if success, FALSE if error
--*/
{
UINT x;
// pszOld is assumed to point inside m_pBuff if non NULL
// is has to be removed
LPSTR pszOld = ppszFields[dwIndex];
if ( pszOld && m_pBuff && (LPBYTE)pszOld > m_pBuff && (LPBYTE)pszOld < m_pBuff+m_cUsedBuff )
{
int lO = strlen( pszOld ) + 1;
int lM = DIFF((m_pBuff + m_cUsedBuff) - (LPBYTE)pszOld) - lO;
if ( lM )
{
memmove( pszOld, pszOld + lO, lM );
for ( x = 0 ; x < dwNbIndex ; ++x )
{
if ( x != dwIndex && ppszFields[x] > pszOld )
{
ppszFields[x] -= lO;
}
}
}
ppszFields[ dwIndex ] = NULL;
m_cUsedBuff -= lO;
}
// pszNew is to appended to m_pBuff
int lN = strlen( pszNew ) + 1;
if ( m_cUsedBuff + lN > m_cAllocBuff )
{
UINT cNewBuff = (( m_cUsedBuff + lN + IIS_MAP_BUFF_GRAN ) / IIS_MAP_BUFF_GRAN) * IIS_MAP_BUFF_GRAN;
LPSTR pNewBuff = (LPSTR)LocalAlloc( LMEM_FIXED, cNewBuff );
if ( pNewBuff == NULL )
{
return FALSE;
}
if ( m_pBuff )
{
memcpy( pNewBuff, m_pBuff, m_cUsedBuff );
LocalFree( m_pBuff );
}
m_cAllocBuff = cNewBuff;
// adjust pointers
for ( UINT x = 0 ; x < dwNbIndex ; ++x )
{
if ( x != dwIndex )
{
if ( ppszFields[x] != NULL )
{
ppszFields[x] += ((LPBYTE)pNewBuff - m_pBuff);
}
}
}
m_pBuff = (LPBYTE)pNewBuff;
}
memcpy( m_pBuff + m_cUsedBuff, pszNew, lN );
ppszFields[dwIndex] = (LPSTR)(m_pBuff + m_cUsedBuff);
m_cUsedBuff += lN;
return TRUE;
}
BOOL
CIisMapping::StoreField(
LPSTR* ppszFields,
LPDWORD ppdwFields,
DWORD dwIndex,
DWORD dwNbIndex,
LPSTR pbNew,
DWORD cNew,
BOOL fIsUuEncoded
)
/*++
Routine Description:
Update field array in mapping entry with new field
data pointed by pszNew is copied inside mapping entry
Arguments:
ppszFields -- array of field pointers to be updated
ppdwFields -- array of field length to be updated
dwIndex -- index of field
dwNbIndex -- number of fields in array
pbNew -- data to copy inside field
cNew -- length of data
fIsUuEncoded -- TRUE if pbNew is UUEncoded
Returns:
TRUE if success, FALSE if error
--*/
{
UINT x;
// pszOld is assumed to point inside m_pBuff if non NULL
// it has to be removed
LPSTR pszOld = ppszFields[dwIndex];
if ( pszOld && m_pBuff && (LPBYTE)pszOld > m_pBuff && (LPBYTE)pszOld < m_pBuff+m_cUsedBuff )
{
int lO = ppdwFields[dwIndex];
int lM = DIFF((m_pBuff + m_cUsedBuff) - (LPBYTE)pszOld) - lO;
if ( lM )
{
memmove( pszOld, pszOld + lO, lM );
for ( x = 0 ; x < dwNbIndex ; ++x )
{
if ( x != dwIndex && ppszFields[x] > pszOld )
{
ppszFields[x] -= lO;
}
}
}
ppszFields[ dwIndex ] = NULL;
m_cUsedBuff -= lO;
}
// pszNew is to appended to m_pBuff
int lN = cNew;
if ( fIsUuEncoded )
{
LPSTR pU = (LPSTR)LocalAlloc( LMEM_FIXED, lN + 3);
if ( pU == NULL )
{
return FALSE;
}
DWORD cO;
IISuudecode( pbNew, (LPBYTE)pU, &cO, FALSE );
pbNew = pU;
cNew = lN = cO;
}
if ( m_cUsedBuff + lN > m_cAllocBuff )
{
UINT cNewBuff = (( m_cUsedBuff + lN + IIS_MAP_BUFF_GRAN ) / IIS_MAP_BUFF_GRAN) * IIS_MAP_BUFF_GRAN;
LPSTR pNewBuff = (LPSTR)LocalAlloc( LMEM_FIXED, cNewBuff );
if ( pNewBuff == NULL )
{
if ( fIsUuEncoded )
{
LocalFree( pbNew );
}
return FALSE;
}
if ( m_pBuff )
{
memcpy( pNewBuff, m_pBuff, m_cUsedBuff );
LocalFree( m_pBuff );
}
m_cAllocBuff = cNewBuff;
// adjust pointers
for ( UINT x = 0 ; x < dwNbIndex ; ++x )
{
if ( x != dwIndex )
{
if ( ppszFields[x] != NULL )
{
ppszFields[x] += ((LPBYTE)pNewBuff - m_pBuff);
}
}
}
m_pBuff = (LPBYTE)pNewBuff;
}
memcpy( m_pBuff + m_cUsedBuff, pbNew, lN );
ppszFields[dwIndex] = (LPSTR)(m_pBuff + m_cUsedBuff);
if ( ppdwFields )
{
ppdwFields[dwIndex] = cNew;
}
m_cUsedBuff += lN;
if ( fIsUuEncoded )
{
LocalFree( pbNew );
}
return TRUE;
}
BOOL
CIisMapping::Serialize(
FILE* pFile,
VALID_CTX pMD5,
LPVOID pStorage
)
/*++
Routine Description:
Serialize a mapping entry
Arguments:
pFile -- file to write to
pMD5 -- MD5 to update with signature of written bytes
Returns:
TRUE if success, FALSE if error
Lock:
mapper must be locked while serializing
--*/
{
LPSTR *pFields;
LPDWORD pcFields;
LPSTR pO = NULL;
DWORD dwO = 0;
UINT iMax = GetNbField( &pFields, &pcFields );
UINT x;
LPBYTE pB;
BOOL fMustFree;
for ( x = 0 ; x < iMax ; ++x )
{
LPSTR pF;
DWORD dwF;
fMustFree = FALSE;
if ( pcFields )
{
MappingGetField( x, &pF, &dwF, FALSE );
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)pF, dwF );
store_as_binary:
if ( IsCrypt( x ) && dwF )
{
if ( FAILED(((IIS_CRYPTO_STORAGE*)pStorage)->EncryptData(
(PIIS_CRYPTO_BLOB*)&pB,
pF,
dwF,
REG_BINARY )) )
{
return FALSE;
}
pF = (LPSTR)pB;
dwF = IISCryptoGetBlobLength( (PIIS_CRYPTO_BLOB)pB );
fMustFree = TRUE;
}
if ( dwF )
{
DWORD dwNeed = ((dwF+2)*4)/3 + 1;
if ( dwNeed > dwO )
{
if ( pO != NULL )
{
LocalFree( pO );
}
dwNeed += 100; // alloc more than needed
// to minimize # of allocation
if ( !(pO = (LPSTR)LocalAlloc( LMEM_FIXED, dwNeed )) )
{
return FALSE;
}
dwO = dwNeed;
}
/* INTRINSA suppress = null */
IISuuencode( (LPBYTE)pF, dwF, (LPBYTE)pO, FALSE );
fputs( pO, pFile );
}
if ( fMustFree )
{
IISCryptoFreeBlob( (PIIS_CRYPTO_BLOB)pB );
}
}
else
{
MappingGetField( x, &pF );
if ( pF != NULL )
{
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)pF, strlen(pF) );
if ( IsCrypt( x ) )
{
dwF = strlen( pF ) + 1;
goto store_as_binary;
}
fputs( pF, pFile );
}
}
fputs( "|", pFile );
}
fputs( "\r\n", pFile );
if ( pO != NULL )
{
LocalFree( pO );
}
return TRUE;
}
BOOL
CIisMapping::Deserialize(
FILE* pFile,
VALID_CTX pMD5,
LPVOID pStorage
)
/*++
Routine Description:
Deserialize a mapping entry
Arguments:
pFile -- file to read from
pMD5 -- MD5 to update with signature of read bytes
Returns:
TRUE if success, FALSE if error
Lock:
mapper must be locked while serializing
--*/
{
LPSTR *pFields;
LPDWORD pcFields;
UINT iMax;
UINT x;
int c;
CHAR achBuf[4096];
DWORD dwType;
LPBYTE pB;
iMax = GetNbField( &pFields, &pcFields );
for ( x = 0 ; x < iMax ; ++x )
{
StoreFieldRef( x, NULL );
}
for ( x = 0 ; x < sizeof(achBuf) && (c=fgetc(pFile))!= EOF ; )
{
achBuf[x++] = (CHAR)c;
if ( c == '\n' )
{
break;
}
}
if ( x == sizeof(achBuf ) )
{
return FALSE;
}
if ( x > 1 )
{
achBuf[x-2] = '\0';
m_cUsedBuff = m_cAllocBuff = x - 1;
if ( (m_pBuff = (LPBYTE)LocalAlloc( LMEM_FIXED, m_cAllocBuff )) == NULL )
{
m_cAllocBuff = m_cUsedBuff = 0;
return FALSE;
}
memcpy( m_pBuff, achBuf, m_cUsedBuff );
LPSTR pCur = (LPSTR)m_pBuff;
LPSTR pNext;
LPSTR pStore = (LPSTR)m_pBuff;
DWORD dwDec;
if ( pcFields )
{
for ( x = 0 ; x < iMax ; ++x )
{
pNext = strchr( pCur, '|' );
if ( pNext != NULL )
{
*pNext = '\0';
++pNext;
}
else
{
pNext = NULL;
}
IISuudecode( pCur, (PBYTE)pStore, &dwDec, FALSE );
if ( IsCrypt( x ) && dwDec )
{
if ( FAILED(((IIS_CRYPTO_STORAGE*)pStorage)->DecryptData(
(PVOID*)&pB,
&dwDec,
&dwType,
(PIIS_CRYPTO_BLOB)pStore )) )
{
return FALSE;
}
memmove( pStore, pB, dwDec );
}
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)pStore, dwDec );
StoreFieldRef( x, pStore, dwDec );
pCur = pNext;
pStore += dwDec;
}
}
else
{
for ( x = 0 ; x < iMax ; ++x )
{
pNext = strchr( pCur, '|' );
if ( pNext != NULL )
{
*pNext = '\0';
++pNext;
}
if ( *pCur && IsCrypt( x ) )
{
IISuudecode( pCur, (PBYTE)pCur, &dwDec, FALSE );
if ( FAILED(((IIS_CRYPTO_STORAGE*)pStorage)->DecryptData(
(PVOID*)&pB,
&dwDec,
&dwType,
(PIIS_CRYPTO_BLOB)pCur )) )
{
return FALSE;
}
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)pB, dwDec );
StoreFieldRef( x, (LPSTR)pB );
pCur = pNext;
}
else
{
MD5Update( (MD5_CTX*)pMD5, (LPBYTE)pCur, strlen(pCur) );
StoreFieldRef( x, pCur );
pCur = pNext;
}
}
}
return TRUE;
}
return FALSE;
}
//
extern "C" BOOL WINAPI
DllMain(
HANDLE hModule,
DWORD dwReason,
LPVOID pV
)
/*++
Routine Description:
DLL init/terminate notification function
Arguments:
hModule - DLL handle
dwReason - notification type
LPVOID - not used
Returns:
TRUE if success, FALSE if failure
--*/
{
//BOOL f = Crypt32DllMain( (HINSTANCE)hModule, dwReason, pV );
switch ( dwReason )
{
case DLL_PROCESS_ATTACH:
#ifdef _NO_TRACING_
CREATE_DEBUG_PRINT_OBJECT( "IISMAP" );
#endif
// record the module handle to access module info later
g_hModule = (HINSTANCE)hModule;
INITIALIZE_CRITICAL_SECTION( &g_csIisMap );
InitializeWildcardMapping( hModule );
InitializeMapping( hModule );
if ( IISCryptoInitialize() != NO_ERROR )
{
return FALSE;
}
return TRUE;
case DLL_PROCESS_DETACH:
IISCryptoTerminate();
TerminateWildcardMapping();
TerminateMapping();
DeleteCriticalSection( &g_csIisMap );
#ifdef _NO_TRACING_
DELETE_DEBUG_PRINT_OBJECT( );
#endif
break;
}
return TRUE;
}
BOOL
InitializeMapping(
HANDLE hModule
)
/*++
Routine Description:
Initialize mapping
Arguments:
hModule - module handle of this DLL
Return Value:
Nothing
--*/
{
// get install path
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
W3_PARAMS,
0,
KEY_READ|KEY_SET_VALUE,
&g_hKey ) == ERROR_SUCCESS )
{
DWORD dwLen = 0;
DWORD dwType;
if ( RegQueryValueEx( g_hKey,
INSTALL_PATH,
NULL,
&dwType,
NULL,
&dwLen ) != ERROR_SUCCESS ||
dwType != REG_SZ ||
!( g_pszInstallPath = (LPSTR)LocalAlloc( LMEM_FIXED, dwLen ) ) ||
RegQueryValueEx( g_hKey,
INSTALL_PATH,
NULL,
&dwType,
(LPBYTE)g_pszInstallPath,
&dwLen ) != ERROR_SUCCESS )
{
if ( g_pszInstallPath )
{
LocalFree( g_pszInstallPath );
g_pszInstallPath = NULL;
}
}
dwLen = sizeof( g_dwGuid );
if ( RegQueryValueEx( g_hKey,
MAPPER_GUID,
NULL,
&dwType,
(LPBYTE)&g_dwGuid,
&dwLen ) != ERROR_SUCCESS ||
dwType != REG_DWORD )
{
g_dwGuid = 0;
}
return LoadFieldNames( IisItaMappingFields,
sizeof(IisItaMappingFields)/sizeof(IISMDB_Fields) ) &&
LoadFieldNames( IisCert11MappingFields,
sizeof(IisCert11MappingFields)/sizeof(IISMDB_Fields) ) &&
LoadFieldNames( IisMd5MappingFields,
sizeof(IisMd5MappingFields)/sizeof(IISMDB_Fields) );
}
else
{
g_hKey = NULL;
}
return FALSE;
}
BOOL
LoadFieldNames(
IISMDB_Fields* pFields,
UINT cFields
)
/*++
Routine Description:
Load fields names from resource
Arguments:
pFields - ptr to array where to store reference to names
cFields - count of element in array
Return Value:
TRUE if success, otherwise FALSE
--*/
{
UINT x;
BOOL fSt = TRUE;
for ( x = 0 ;
x < cFields ;
++x )
{
char achTmp[128];
if ( LoadString( g_hModule,
pFields[x].m_dwResID,
achTmp,
sizeof( achTmp ) ) != 0 )
{
int lN = strlen( achTmp ) + sizeof(CHAR);
if ( (pFields[x].m_pszDisplayName = (LPSTR)LocalAlloc( LMEM_FIXED, lN )) == NULL )
{
fSt = FALSE;
break;
}
memcpy( pFields[x].m_pszDisplayName, achTmp, lN );
}
else
{
fSt = FALSE;
break;
}
}
return fSt;
}
VOID
FreeFieldNames(
IISMDB_Fields* pFields,
UINT cFields
)
/*++
Routine Description:
Free fields names loaded from resource
Arguments:
pFields - ptr to array where reference to names are stored
cFields - count of element in array
Return Value:
Nothing
--*/
{
UINT x;
BOOL fSt = TRUE;
for ( x = 0 ;
x < cFields ;
++x )
{
if ( pFields[x].m_pszDisplayName )
{
LocalFree( pFields[x].m_pszDisplayName );
}
}
}
VOID
TerminateMapping(
)
/*++
Routine Description:
Terminate mapping
Arguments:
None
Return Value:
Nothing
--*/
{
if ( g_hKey != NULL )
{
RegCloseKey( g_hKey );
}
if ( g_pszInstallPath )
{
LocalFree( g_pszInstallPath );
}
FreeFieldNames( IisItaMappingFields,
sizeof(IisItaMappingFields)/sizeof(IISMDB_Fields) );
FreeFieldNames( IisCert11MappingFields,
sizeof(IisCert11MappingFields)/sizeof(IISMDB_Fields) );
FreeFieldNames( IisMd5MappingFields,
sizeof(IisMd5MappingFields)/sizeof(IISMDB_Fields) );
}
//
dllexp
BOOL
ReportIisMapEvent(
WORD wType,
DWORD dwEventId,
WORD cNbStr,
LPCTSTR* pStr
)
/*++
Routine Description:
Log an event based on type, ID and insertion strings
Arguments:
wType -- event type ( error, warning, information )
dwEventId -- event ID ( as defined by the .mc file )
cNbStr -- nbr of LPSTR in the pStr array
pStr -- insertion strings
Returns:
TRUE if success, FALSE if failure
--*/
{
BOOL fSt = TRUE;
HANDLE hEventLog = NULL;
hEventLog = RegisterEventSource(NULL,"IISMAP");
if ( hEventLog != NULL )
{
if (!ReportEvent(hEventLog, // event log handle
wType, // event type
0, // category zero
(DWORD) dwEventId, // event identifier
NULL, // no user security identifier
cNbStr, // count of substitution strings (may be no strings)
// less ProgName (argv[0]) and Event ID (argv[1])
0, // no data
(LPCTSTR *) pStr, // address of string array
NULL)) // address of data
{
fSt = FALSE;
}
DeregisterEventSource( hEventLog );
}
else
{
fSt = FALSE;
}
return fSt;
}
/////////////////////////////////////////
// CIisItaMapper
CIisItaMapper::CIisItaMapper(
)
/*++
Routine Description:
Constructor for CIisItaMapper
Arguments:
None
Returns:
Nothing
--*/
{
m_pFields = IisItaMappingFields;
m_cFields = sizeof(IisItaMappingFields)/sizeof(IISMDB_Fields);
m_dwOptions = IISMDB_ITA_OPTIONS;
}
CIisItaMapper::~CIisItaMapper(
)
/*++
Routine Description:
Destructor for CIisItaMapper
Arguments:
None
Returns:
Nothing
--*/
{
}
IISMDB_HEntry*
CIisItaMapper::GetDefaultHierarchy(
LPDWORD pdwN
)
/*++
Routine Description:
return ptr to default hierarchy for ita mapping
Arguments:
pdwN -- updated with hierarchy entries count
Returns:
ptr to hierarchy entries or NULL if error
--*/
{
*pdwN = sizeof(IisItaMappingHierarchy) / sizeof(IISMDB_HEntry);
return IisItaMappingHierarchy;
}
CIisMapping*
CIisItaMapper::CreateNewMapping(
LPSTR pszType,
LPSTR pszUser,
LPSTR pszPwd
)
/*++
Routine Description:
Create a new mapping from internet credentials
Arguments:
pszType -- login type : basic, user, MD5, SSL/PCT, ...
pszUser -- user name
pszPwd -- clear text password
Returns:
ptr to mapping. ownership of this object is transfered to caller.
NULL if error
--*/
{
CItaMapping *pCM = new CItaMapping( this );
if ( pCM == NULL )
{
return NULL;
}
if ( pCM->Init( pszType, pszUser, pszPwd, m_pHierarchy, m_cHierarchy ) )
{
return (CIisMapping*)pCM;
}
delete pCM;
return NULL;
}
// CItaMapping
CItaMapping::CItaMapping(
CIisAcctMapper* pMap
)
/*++
Routine Description:
Constructor for CItaMapping
Arguments:
pMap -- ptr to mapper object linked to this mapping
Returns:
Nothing
--*/
{
m_pMapper = (CIisAcctMapper*)pMap;
for ( int x = 0 ; x < sizeof(m_pFields)/sizeof(LPSTR) ; ++x )
{
m_pFields[x] = NULL;
}
}
CItaMapping::~CItaMapping(
)
/*++
Routine Description:
Destructor for CItaMapping
Arguments:
None
Returns:
Nothing
--*/
{
}
BOOL
CItaMapping::Init(
LPSTR pszType,
LPSTR pszUser,
LPSTR pszPwd,
IISMDB_HEntry *pH,
DWORD dwH
)
/*++
Routine Description:
Constructor for CItaMapping
Arguments:
pszType -- login type : basic, user, MD5, SSL/PCT, ...
pszUser -- user name
pszPwd -- clear text password
pH -- ptr to hierarchy info
dwH -- number of hierarchy entries
Returns:
TRUE if success, FALSE if error
--*/
{
if ( !MappingSetField( IISIMDB_INDEX_IT_ACCT, pszUser ) )
{
return FALSE;
}
if ( !MappingSetField( IISIMDB_INDEX_IT_PWD, pszPwd ) )
{
return FALSE;
}
return UpdateMask( pH, dwH );
}
BOOL
CCert11Mapping::MappingSetField(
DWORD dwIndex,
LPSTR pszNew
)
/*++
Routine Description:
Set field in mapping entry to specified content
data pointed by pszNew is copied inside mapping entry
Arguments:
dwIndex -- index of field
pszNew -- data to copy inside field
Returns:
TRUE if success, FALSE if error
Lock:
mapper must be locked for ptr to remain valid
--*/
{
LPSTR *pFields;
LPDWORD pcFields;
DWORD iMax = GetNbField( &pFields, &pcFields );
if ( dwIndex >= iMax )
{
return FALSE;
}
return StoreField( pFields, pcFields, dwIndex, iMax, pszNew, strlen(pszNew)+1, FALSE );
}
BOOL
CItaMapping::MappingSetField(
DWORD dwIndex,
LPSTR pszNew
)
/*++
Routine Description:
Set field in mapping entry to specified content
data pointed by pszNew is copied inside mapping entry
Arguments:
dwIndex -- index of field
pszNew -- data to copy inside field
Returns:
TRUE if success, FALSE if error
Lock:
mapper must be locked for ptr to remain valid
--*/
{
MD5_CTX md5;
CHAR achDigest[ sizeof(md5.digest)*2 + 1];
#define TOHEX(a) ((a)>=10 ? 'a'+(a)-10 : '0'+(a))
// convert clear text pwd to MD5 digest ( as ASCII string )
if ( dwIndex == IISIMDB_INDEX_IT_PWD )
{
MD5Init( &md5 );
MD5Update( &md5, (LPBYTE)pszNew, strlen(pszNew) );
MD5Final( &md5 );
for ( UINT x = 0, y = 0 ; x < sizeof(md5.digest) ; ++x )
{
UINT v;
v = md5.digest[x]>>4;
achDigest[y++] = TOHEX( v );
v = md5.digest[x]&0x0f;
achDigest[y++] = TOHEX( v );
}
achDigest[y] = '\0';
pszNew = achDigest;
}
return CIisMapping::MappingSetField( dwIndex, pszNew );
}
// CIisMd5Mapper
CIisMd5Mapper::CIisMd5Mapper(
)
/*++
Routine Description:
Constructor for CIisMd5Mapper
Arguments:
None
Returns:
Nothing
--*/
{
m_pFields = IisMd5MappingFields;
m_cFields = sizeof(IisMd5MappingFields)/sizeof(IISMDB_Fields);
m_dwOptions = IISMDB_MD5_OPTIONS;
}
CIisMd5Mapper::~CIisMd5Mapper(
)
/*++
Routine Description:
Destructor for CIisMd5Mapper
Arguments:
None
Returns:
Nothing
--*/
{
}
IISMDB_HEntry*
CIisMd5Mapper::GetDefaultHierarchy(
LPDWORD pdwN
)
/*++
Routine Description:
return ptr to default hierarchy for ita mapping
Arguments:
pdwN -- updated with hierarchy entries count
Returns:
ptr to hierarchy entries or NULL if error
--*/
{
*pdwN = sizeof(IisMd5MappingHierarchy) / sizeof(IISMDB_HEntry);
return IisMd5MappingHierarchy;
}
CIisMapping*
CIisMd5Mapper::CreateNewMapping(
LPSTR pszRealm,
LPSTR pszUser
)
/*++
Routine Description:
Create a new mapping from internet credentials
Arguments:
pszRealm -- Realm
pszUser -- user name
Returns:
ptr to mapping. ownership of this object is transfered to caller.
NULL if error
--*/
{
CMd5Mapping *pCM = new CMd5Mapping( this );
if ( pCM == NULL )
{
return NULL;
}
if ( pCM->Init( pszRealm, pszUser, m_pHierarchy, m_cHierarchy ) )
{
return (CIisMapping*)pCM;
}
delete pCM;
return NULL;
}
// CMd5Mapping
CMd5Mapping::CMd5Mapping(
CIisAcctMapper* pMap
)
/*++
Routine Description:
Constructor for CMd5Mapping
Arguments:
pMap -- ptr to mapper object linked to this mapping
Returns:
Nothing
--*/
{
m_pMapper = (CIisAcctMapper*)pMap;
for ( int x = 0 ; x < sizeof(m_pFields)/sizeof(LPSTR) ; ++x )
{
m_pFields[x] = NULL;
}
}
CMd5Mapping::~CMd5Mapping(
)
/*++
Routine Description:
Destructor for CItaMapping
Arguments:
None
Returns:
Nothing
--*/
{
}
BOOL
CMd5Mapping::Init(
LPSTR pszRealm,
LPSTR pszUser,
IISMDB_HEntry *pH,
DWORD dwH
)
/*++
Routine Description:
Constructor for CItaMapping
Arguments:
pszRealm -- Realm
pszUser -- user name
pH -- ptr to hierarchy info
dwH -- number of hierarchy entries
Returns:
TRUE if success, FALSE if error
--*/
{
if ( !MappingSetField( IISMMDB_INDEX_IT_ACCT, pszUser ) )
{
return FALSE;
}
if ( !MappingSetField( IISMMDB_INDEX_IT_REALM, pszRealm ) )
{
return FALSE;
}
return UpdateMask( pH, dwH );
}
BOOL
CMd5Mapping::MappingSetField(
DWORD dwIndex,
LPSTR pszNew
)
/*++
Routine Description:
Set field in mapping entry to specified content
data pointed by pszNew is copied inside mapping entry
Arguments:
dwIndex -- index of field
pszNew -- data to copy inside field
Returns:
TRUE if success, FALSE if error
Lock:
mapper must be locked for ptr to remain valid
--*/
{
MD5_CTX md5;
CHAR achDigest[ sizeof(md5.digest)*2 + 1];
// convert clear text pwd to MD5 digest ( as ASCII string )
if ( dwIndex == IISMMDB_INDEX_IT_MD5PWD )
{
if ( !CIisMapping::MappingSetField( IISMMDB_INDEX_IT_CLRPWD, pszNew ) )
{
return FALSE;
}
gen_md5pwd:
LPSTR pszName = m_pFields[IISMMDB_INDEX_IT_ACCT];
LPSTR pszRealm = m_pFields[IISMMDB_INDEX_IT_REALM];
CHAR *pS;
if ( pszName == NULL )
{
pszName = "";
}
if ( pszRealm == NULL )
{
pszRealm = "";
}
pS = new CHAR[strlen(pszName)+1+strlen(pszRealm)+1+strlen(pszNew)+1];
if ( pS == NULL )
{
return FALSE;
}
strcpy( pS, pszName );
strcat( pS, ":" );
strcat( pS, pszRealm );
strcat( pS, ":" );
strcat( pS, pszNew );
MD5Init( &md5 );
MD5Update( &md5, (LPBYTE)pS, strlen(pS) );
MD5Final( &md5 );
for ( UINT x = 0, y = 0 ; x < sizeof(md5.digest) ; ++x )
{
UINT v;
v = md5.digest[x]>>4;
achDigest[y++] = TOHEX( v );
v = md5.digest[x]&0x0f;
achDigest[y++] = TOHEX( v );
}
achDigest[y] = '\0';
pszNew = achDigest;
delete [] pS;
}
else if ( (dwIndex == IISMMDB_INDEX_IT_REALM ||
dwIndex == IISMMDB_INDEX_IT_ACCT) &&
m_pFields[ IISMMDB_INDEX_IT_CLRPWD ] )
{
if ( !CIisMapping::MappingSetField( dwIndex, pszNew ) )
{
return FALSE;
}
dwIndex = IISMMDB_INDEX_IT_MD5PWD;
pszNew = m_pFields[ IISMMDB_INDEX_IT_CLRPWD ];
goto gen_md5pwd;
}
return CIisMapping::MappingSetField( dwIndex, pszNew );
}
#if 0
PRDN_VALUE_BLOB
CertGetNameField(
UINT iEncoding,
IN LPCTSTR pszObjId,
IN PNAME_INFO pInfo
)
{
DWORD cRDN, cAttr;
PRDN pRDN;
PRDN_ATTR pAttr;
// Array of RDNs
for ( cRDN = pInfo->cRDN, pRDN = pInfo->rgRDN ;
cRDN > 0 ;
cRDN--, pRDN++ )
{
for ( cAttr = pRDN->cRDNAttr, pAttr = pRDN->rgRDNAttr ;
cAttr > 0 ;
cAttr--, pAttr++ )
{
if ( !strcmp( pAttr->pszObjId, pszObjId ) )
{
return &pAttr->Value;
}
}
}
return NULL;
}
BOOL
StoreField(
LPSTR* pFields,
LPSTR* pStore,
UINT* pLen,
PRDN_VALUE_BLOB pValue
)
{
memcpy( *pStore, pValue->pbData, pValue->cbData );
(*pStore)[ pValue->cbData ] = '\0';
*pFields = *pStore;
*pStore += pValue->cbData + 1;
*pLen += pValue->cbData + 1;
return TRUE;
}
UINT DecodeNames(
IN PNAME_BLOB pNameBlob,
IN LPSTR* pFields,
IN LPSTR pStore
)
{
PNAME_INFO pNameInfo = NULL;
DWORD cbNameInfo;
PRDN_VALUE_BLOB pValue;
UINT l = 0;
if (!DecodeObject(X509_ASN_ENCODING,
(LPCSTR)X509_NAME,
pNameBlob->pbData,
pNameBlob->cbData,
NULL,
&cbNameInfo))
{
goto Ret;
}
if (NULL == (pNameInfo = (PNAME_INFO)malloc(cbNameInfo)))
{
goto Ret;
}
if (!CertDecodeName(X509_ASN_ENCODING,
//(LPCSTR)X509_NAME,
pNameBlob->pbData,
pNameBlob->cbData,
pNameInfo,
&cbNameInfo))
{
goto Ret;
}
if (NULL == (pValue = CertGetNameField(X509_ASN_ENCODING,
COUNTRY_NAME_OBJID,
pNameInfo)))
{
goto Ret;
}
StoreField( pFields+IISMDB_INDEX_ISSUER_C, &pStore, &l, pValue );
if (NULL == (pValue = CertGetNameField(X509_ASN_ENCODING,
ORGANIZATION_NAME_OBJID,
pNameInfo)))
{
goto Ret;
}
StoreField( pFields+IISMDB_INDEX_ISSUER_O, &pStore, &l, pValue );
if (NULL == (pValue = CertGetNameField(X509_ASN_ENCODING,
ORGANIZATIONAL_UNIT_NAME_OBJID,
pNameInfo)))
{
goto Ret;
}
StoreField( pFields+IISMDB_INDEX_ISSUER_OU, &pStore, &l, pValue );
if (NULL == (pValue = CertGetNameField(X509_ASN_ENCODING,
COMMON_NAME_OBJID,
pNameInfo)))
{
goto Ret;
}
StoreField( pFields+IISMDB_INDEX_ISSUER_C+1, &pStore, &l, pValue );
Ret:
free(pNameInfo);
return l;
}
UINT DecodeCert(
IN PBYTE pbEncodedCert,
IN DWORD cbEncodedCert,
LPSTR* pFields,
LPSTR pStore
)
{
PCCERT_CONTEXT pCert = NULL;
UINT l;
if (NULL == (pCert = CertCreateCertificateContext(X509_ASN_ENCODING,
pbEncodedCert,
cbEncodedCert)))
{
return 0;
}
l = DecodeNames(&pCert->pCertInfo->Issuer, pFields, pStore )
+
DecodeNames(&pCert->pCertInfo->Subject, pFields+3, pStore );
CertFreeCertificateContext( pCert );
return l;
}
#endif
///////////////////////
//
// Taken from NCSA HTTP and wwwlib.
//
// NOTE: These conform to RFC1113, which is slightly different then the Unix
// uuencode and uudecode!
//
const int _pr2six[256]={
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64
};
char _six2pr[64] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z',
'0','1','2','3','4','5','6','7','8','9','+','/'
};
const int _pr2six64[256]={
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,
40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
64,64,64,64,64,64,64,64,64,64,64,64,64
};
char _six2pr64[64] = {
'`','!','"','#','$','%','&','\'','(',')','*','+',',',
'-','.','/','0','1','2','3','4','5','6','7','8','9',
':',';','<','=','>','?','@','A','B','C','D','E','F',
'G','H','I','J','K','L','M','N','O','P','Q','R','S',
'T','U','V','W','X','Y','Z','[','\\',']','^','_'
};
BOOL IISuudecode(char * bufcoded,
BYTE * bufout,
DWORD * pcbDecoded,
BOOL fBase64
)
{
int nbytesdecoded;
char *bufin = bufcoded;
int nprbytes;
int *pr2six = (int*)(fBase64 ? _pr2six64 : _pr2six);
int chL;
/* Strip leading whitespace. */
while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
/* Figure out how many characters are in the input buffer.
* If this would decode into more bytes than would fit into
* the output buffer, adjust the number of input bytes downwards.
*/
bufin = bufcoded;
while(pr2six[*(bufin++)] <= 63);
nprbytes = DIFF(bufin - bufcoded) - 1;
nbytesdecoded = ((nprbytes+3)/4) * 3;
bufin = bufcoded;
while (nprbytes > 0) {
chL = bufin[2];
*(bufout++) =
(unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
*(bufout++) =
(unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
*(bufout++) =
(unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
bufin += 4;
nprbytes -= 4;
}
if(nprbytes & 03) {
if(pr2six[chL] > 63)
nbytesdecoded -= 2;
else
nbytesdecoded -= 1;
}
if ( pcbDecoded )
*pcbDecoded = nbytesdecoded;
return TRUE;
}
//
// NOTE NOTE NOTE
// If the buffer length isn't a multiple of 3, we encode one extra byte beyond the
// end of the buffer. This garbage byte is stripped off by the uudecode code, but
// -IT HAS TO BE THERE- for uudecode to work. This applies not only our uudecode, but
// to every uudecode() function that is based on the lib-www distribution [probably
// a fairly large percentage of the code that's floating around out there].
//
BOOL IISuuencode( BYTE * bufin,
DWORD nbytes,
BYTE * outptr,
BOOL fBase64 )
{
unsigned int i;
unsigned int iRemainder = 0;
unsigned int iClosestMultOfThree = 0;
char *six2pr = fBase64 ? _six2pr64 : _six2pr;
BOOL fOneByteDiff = FALSE;
BOOL fTwoByteDiff = FALSE;
iRemainder = nbytes % 3; //also works for nbytes == 1, 2
fOneByteDiff = (iRemainder == 1 ? TRUE : FALSE);
fTwoByteDiff = (iRemainder == 2 ? TRUE : FALSE);
iClosestMultOfThree = ((nbytes - iRemainder)/3) * 3 ;
//
// Encode bytes in buffer up to multiple of 3 that is closest to nbytes.
//
for (i=0; i< iClosestMultOfThree ; i += 3) {
*(outptr++) = six2pr[*bufin >> 2]; /* c1 */
*(outptr++) = six2pr[((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)]; /*c2*/
*(outptr++) = six2pr[((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)];/*c3*/
*(outptr++) = six2pr[bufin[2] & 077]; /* c4 */
bufin += 3;
}
//
// We deal with trailing bytes by pretending that the input buffer has been padded with
// zeros. Expressions are thus the same as above, but the second half drops off b'cos
// ( a | ( b & 0) ) = ( a | 0 ) = a
//
if (fOneByteDiff)
{
*(outptr++) = six2pr[*bufin >> 2]; /* c1 */
*(outptr++) = six2pr[((*bufin << 4) & 060)]; /* c2 */
//pad with '='
*(outptr++) = '='; /* c3 */
*(outptr++) = '='; /* c4 */
}
else if (fTwoByteDiff)
{
*(outptr++) = six2pr[*bufin >> 2]; /* c1 */
*(outptr++) = six2pr[((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)]; /*c2*/
*(outptr++) = six2pr[((bufin[1] << 2) & 074)];/*c3*/
//pad with '='
*(outptr++) = '='; /* c4 */
}
//encoded buffer must be zero-terminated
*outptr = '\0';
return TRUE;
}
#if 0
//
// Functions to create 1:1 mapping using issuer, subject to NT acct
//
static CIisCert11Mapper g_ExpCert11Mapper;
LONG g_fCert11Init = FALSE;
DWORD
MappingInit(
VOID
)
/*++
Routine Description:
Initialize cert 1:1 mapping entry points
Arguments:
None
Returns:
0 if success, otherwise NT error code
--*/
{
DWORD st = 0;
BOOL fFirst;
EnterCriticalSection( &g_csIisMap );
if ( !g_fCert11Init )
{
st = g_ExpCert11Mapper.Init( &fFirst, FALSE ) ? 0 : ERROR_OPEN_FAILED;
if ( !st )
{
st = g_ExpCert11Mapper.Load() ? 0 : GetLastError();
}
g_fCert11Init = TRUE;
}
LeaveCriticalSection( &g_csIisMap );
return st;
}
BOOL
UnicodeToAnsi(
LPWSTR pwsz,
LPSTR* ppsz,
LPDWORD pc )
/*++
Routine Description:
Create ANSI version of Unicode string
Arguments:
pwsz - ptr to Unicode string
ppsz - updated with ptr to ANSI string, or NULL if error
pc - updated with # of chars in converted string
Returns:
TRUE if success, otherwise FALSE
--*/
{
DWORD dwW = wcslen( pwsz );
#if 1 // DBCS worst case
DWORD dwS = dwW * 2;
#else
DWORD dwS = dwW;
#endif
LPSTR psz;
if ( *ppsz = psz = (LPSTR)LocalAlloc( LMEM_FIXED, dwS + 1 ) )
{
dwS = WideCharToMultiByte( CP_ACP, 0,
pwsz, dwW,
psz, dwS,
NULL, NULL );
psz[dwS] = '\0';
*pc = dwS;
}
if ( dwS == 0 && dwW != 0 )
{
if ( psz )
{
LocalFree( psz );
*ppsz = NULL;
}
return FALSE;
}
return TRUE;
}
#define UnicodeToAnsiFree( a ) {if ( (a)!=NULL ) LocalFree(a);}
DWORD WINAPI
CreateMapping(
LPWSTR pwszUuIssuer,
LPWSTR pwszUuSubject,
LPWSTR pwszNtAcct
)
/*++
Routine Description:
Create mapping for cert 1:1 mapper
Arguments:
pwszUuIssuer - uuencoded Issuer
pwszSubject - uuencoded Subject
pwszNtAcct - NT account to map to
Returns:
0 if success, otherwise NT error code
--*/
{
DWORD st = 0;
LPSTR pI;
LPSTR pS;
LPSTR pN;
DWORD cI;
DWORD cS;
DWORD cN;
if ( (st=MappingInit()) )
{
return st;
}
CIisMapping *pM = g_ExpCert11Mapper.CreateNewMapping();
if ( !pM )
{
return ERROR_NOT_ENOUGH_MEMORY;
}
UnicodeToAnsi( pwszUuIssuer, &pI, &cI );
UnicodeToAnsi( pwszUuSubject, &pS, &cS );
UnicodeToAnsi( pwszNtAcct, &pN, &cN );
if ( pI != NULL && pS != NULL && pN != NULL )
{
pM->MappingSetField( IISMDB_INDEX_CERT11_ISSUER, pI, cI, TRUE );
pM->MappingSetField( IISMDB_INDEX_CERT11_SUBJECT, pS, cS, TRUE );
pM->MappingSetField( IISMDB_INDEX_CERT11_NT_ACCT, pN, cN, FALSE );
if ( !g_ExpCert11Mapper.Add( pM ) )
{
st = GetLastError();;
}
}
else
{
st = ERROR_NOT_ENOUGH_MEMORY;
}
UnicodeToAnsiFree( pI );
UnicodeToAnsiFree( pS );
UnicodeToAnsiFree( pN );
return st;
}
DWORD WINAPI
CheckMapping(
LPWSTR pwszUuIssuer,
LPWSTR pwszUuSubject,
LPWSTR* ppwszNtAcct // Out
)
/*++
Routine Description:
Check if mapping exists for cert 1:1 mapper
Arguments:
pwszUuIssuer - uuencoded Issuer
pwszSubject - uuencoded Subject
ppwszNtAcct - receive ptr to mapped NT account if exist
or NULL if any error
Must be released by a call to LocalFree()
Returns:
0 if success, otherwise NT error code
ERROR_INVALID_PARAMETER if no such mapping
--*/
{
DWORD st = 0;
LPSTR pI;
LPSTR pS;
DWORD cI;
DWORD cS;
LPWSTR pwszNtAcct = NULL;
if ( (st=MappingInit()) )
{
return st;
}
CIisMapping *pM = g_ExpCert11Mapper.CreateNewMapping();
if ( !pM )
{
return ERROR_NOT_ENOUGH_MEMORY;
}
UnicodeToAnsi( pwszUuIssuer, &pI, &cI );
UnicodeToAnsi( pwszUuSubject, &pS, &cS );
if ( pI != NULL && pS != NULL )
{
pM->MappingSetField( IISMDB_INDEX_CERT11_ISSUER, pI, cI, TRUE );
pM->MappingSetField( IISMDB_INDEX_CERT11_SUBJECT, pS, cS, TRUE );
DWORD iCurrent = 0xffffffff;
CIisMapping* pMi;
LPSTR pAcct;
DWORD dwAcct;
if ( !g_ExpCert11Mapper.FindMatch( pM, &pMi ) ||
!pMi->MappingGetField( IISMDB_INDEX_CERT11_NT_ACCT, &pAcct, &dwAcct, FALSE )
|| pAcct == NULL )
{
st = ERROR_INVALID_PARAMETER;
}
else
{
DWORD dw;
if ( !(pwszNtAcct = (LPWSTR)LocalAlloc( LMEM_FIXED,
(dwAcct+1)*sizeof(WCHAR) )) )
{
st = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
dw = MultiByteToWideChar( CP_ACP, 0,
pAcct, dwAcct,
pwszNtAcct, dwAcct );
pwszNtAcct[dw] = L'\0';
*ppwszNtAcct = pwszNtAcct;
}
}
}
else
{
st = ERROR_NOT_ENOUGH_MEMORY;
}
g_ExpCert11Mapper.DeleteMappingObject( pM );
UnicodeToAnsiFree( pI );
UnicodeToAnsiFree( pS );
if ( st )
{
*ppwszNtAcct = NULL;
}
return st;
}
DWORD WINAPI
SaveMapping(
VOID
)
/*++
Routine Description:
Save mappings for cert 1:1 mapper
Arguments:
None
Returns:
0 if success, otherwise NT error code
ERROR_WRITE_FAULT if generic write error
--*/
{
DWORD st = 0;
if ( (st=MappingInit()) )
{
return st;
}
SetLastError( 0 );
if ( !g_ExpCert11Mapper.Save() )
{
st = GetLastError();
st = st ? st : ERROR_WRITE_FAULT;
}
return st;
}
#endif