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

3402 lines
78 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
crmap.cxx
Abstract:
ADSIIS cert mapper object
Certificate mappings storage has changed for IIS6.
ADSI however has to support downlevel admin of
IIS5, IIS5.1
NSEPM support was removed from IIS6 and 1to1 client certificate
mapping information is now stored under <site>/Cert11/Mappings
node directly in the metabase
Functions with IIS6 postfix access new location
for 1to1 client certificate mappings storage
Author:
Philippe Choquier (phillich) 10-Apr-1997
--*/
#include "iisext.hxx"
#pragma hdrstop
#include <nsepname.hxx>
#include <dbgutil.h>
DEFINE_IPrivateDispatch_Implementation(CIISDsCrMap)
DEFINE_DELEGATING_IDispatch_Implementation(CIISDsCrMap)
DEFINE_CONTAINED_IADs_Implementation(CIISDsCrMap)
DEFINE_IADsExtension_Implementation(CIISDsCrMap)
#define LOCAL_MAX_SIZE METADATA_MAX_NAME_LEN + 1
const int SHA1_HASH_SIZE = 20;
//Local functions used only for IIS6
HRESULT
GetStringAFromBSTR(
BSTR bstr,
LPSTR* psz,
LPDWORD pdwLen,
BOOL fAddDelimInCount = TRUE
);
HRESULT
GetBlobFromVariant(
VARIANT* pVar,
PBYTE* ppbOut,
LPDWORD pcbOut
);
HRESULT
SetVariantAsBSTRFromStringW(
VARIANT* pvarReturn,
DWORD cbLen,
LPBYTE pbIn
);
HRESULT
SetBSTRFromStringW(
BSTR* pbstrRet,
DWORD cb,
LPBYTE sz
);
//
// Local functions used for IIS5 and IIS6
//
HRESULT
GetStringFromBSTR(
BSTR bstr,
LPSTR* psz,
LPDWORD pdwLen,
BOOL fAddDelimInCount = TRUE
);
HRESULT
GetStringFromVariant(
VARIANT* pVar,
LPSTR* psz,
LPDWORD pdwLen,
BOOL fAddDelimInCount = TRUE
);
VOID
FreeString(
LPSTR psz
);
HRESULT
SetBSTR(
BSTR* pbstrRet,
DWORD cch,
LPBYTE sz
);
HRESULT
SetVariantAsByteArray(
VARIANT* pvarReturn,
DWORD cbLen,
LPBYTE pbIn
);
HRESULT
SetVariantAsBSTR(
VARIANT* pvarReturn,
DWORD cbLen,
LPBYTE pbIn
);
HRESULT
SetVariantAsLong(
VARIANT* pvarReturn,
DWORD dwV
);
HRESULT
VariantResolveDispatch(
VARIANT * pVarOut,
VARIANT * pVarIn
);
HRESULT
GetCertificateHashString(
PBYTE pbCert,
DWORD cbCert,
WCHAR *pwszCertHash,
DWORD cchCertHashBuffer)
/*++
Routine Description:
verifies validity of cert blob by creating cert context
and retrieves SHA1 hash and converts it to WCHAR *
Used for IIS6 only
Arguments:
pbCert - X.509 certificate blob
cbCert - size of the cert blob in bytes
pwszCertHash - buffer must be big enough to fit SHA1 hash in hex string form
(40 WCHAR + terminating 0 )
cchCertHashBuffer - size of the CertHash buffer in WCHARS (includes terminating 0)
Returns:
HRESULT
--*/
{
HRESULT hr = E_FAIL;
BYTE rgbHash[ SHA1_HASH_SIZE ];
DWORD cbSize = SHA1_HASH_SIZE;
#ifndef HEX_DIGIT
#define HEX_DIGIT( nDigit ) \
(WCHAR)((nDigit) > 9 ? \
(nDigit) - 10 + L'a' \
: (nDigit) + L'0')
#endif
PCCERT_CONTEXT pCertContext = NULL;
pCertContext = CertCreateCertificateContext(
X509_ASN_ENCODING,
(const BYTE *)pbCert,
cbCert );
if ( pCertContext == NULL )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
return hr;
}
//
// get hash of the certificate to be verified
//
if ( !CertGetCertificateContextProperty( pCertContext,
CERT_SHA1_HASH_PROP_ID,
rgbHash,
&cbSize ) )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
CertFreeCertificateContext( pCertContext );
pCertContext=NULL;
return hr;
}
CertFreeCertificateContext( pCertContext );
pCertContext = NULL;
if ( cchCertHashBuffer < SHA1_HASH_SIZE * 2 + 1 )
{
// we don't have big enough buffer to store
// hex string of the SHA1 hash each byte takes 2 chars + terminating 0
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
DBG_ASSERT( FALSE );
return hr;
}
//
// convert to text
//
for (int i = 0; i < sizeof(rgbHash); i ++ )
{
*(pwszCertHash++) = HEX_DIGIT( ( rgbHash[ i ] >> 4 ) );
*(pwszCertHash++) = HEX_DIGIT( ( rgbHash[ i ] & 0x0F ) );
}
*(pwszCertHash) = L'\0';
#undef HEX_DIGIT
return S_OK;
}
//
// Mapping functins for IIS6
//
HRESULT
CIISDsCrMap::CreateMappingIIS6(
VARIANT vCert,
BSTR bstrNtAcct,
BSTR bstrNtPwd,
BSTR bstrName,
LONG lEnabled
)
/*++
Routine Description:
Create a mapping entry
Arguments:
vCert - X.509 certificate
bstrNtAcct - NT acct to map to
bstrNtPwd - NT pwd
bstrName - friendly name for mapping entry
lEnabled - 1 to enable mapping entry, 0 to disable it
Returns:
COM status
--*/
{
HRESULT hres;
LPBYTE pbCert = NULL;
DWORD cbCert;
LPBYTE pRes;
DWORD cRes;
VARIANT vOldAcct;
VARIANT vOldCert;
VARIANT vOldPwd;
VARIANT vOldName;
VARIANT vOldEnabledFlag;
PCCERT_CONTEXT pcCert = NULL;
WCHAR wszCertHash[ 2*SHA1_HASH_SIZE + 1];
BOOL fFoundExisting = FALSE;
//
// Do some sanity checks on the cert
//
if ( SUCCEEDED( hres = GetBlobFromVariant( &vCert,
&pbCert,
&cbCert ) ) )
{
//
// verify validity of certificate blob
// and retrieve certificate hash
//
if ( FAILED( hres = GetCertificateHashString(
pbCert,
cbCert,
wszCertHash,
sizeof( wszCertHash )/sizeof( WCHAR ) ) ) )
{
DBGPRINTF((DBG_CONTEXT,
"Invalid cert passed to CreateMapping() 0x%x\n", hres));
//
// If the decoding fails, GetLastError() returns an ASN1 decoding
// error that is obtained by subtracting CRYPT_E_OSS_ERROR from the returned
// error and looking in file asn1code.h for the actual error. To avoid the
// cryptic ASN1 errors, we'll just return a general "invalid arg" error
//
goto Exit;
}
}
else
{
goto Exit;
}
//
// check if we already have a mapping for this cert; if we do, we'll replace that mapping
// with the new one
//
WCHAR achIndex[METADATA_MAX_NAME_LEN + 1];
if ( SUCCEEDED( hres = OpenMd( L"Cert11/Mappings",
METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ) ) )
{
if ( SUCCEEDED(hres = Locate( IISMAPPER_LOCATE_BY_CERT,
vCert,
achIndex )) )
{
fFoundExisting = TRUE;
DBGPRINTF((DBG_CONTEXT,
"Replacing old 1-1 cert mapping with new mapping\n"));
if ( FAILED( hres = SetMdData( achIndex, MD_MAPENABLED, DWORD_METADATA,
sizeof(DWORD), (LPBYTE)&lEnabled ) ) ||
FAILED( hres = SetMdData( achIndex, MD_MAPNAME, STRING_METADATA,
sizeof(WCHAR) * (SysStringLen(bstrName) + 1 ),
(LPBYTE)bstrName ) ) ||
FAILED( hres = SetMdData( achIndex, MD_MAPNTPWD, STRING_METADATA,
sizeof(WCHAR) * (SysStringLen(bstrNtPwd) + 1 ),
(LPBYTE)bstrNtPwd ) ) ||
FAILED( hres = SetMdData( achIndex, MD_MAPNTACCT, STRING_METADATA,
sizeof(WCHAR) * (SysStringLen(bstrNtAcct) + 1 ),
(LPBYTE)bstrNtAcct ) ) ||
FAILED( hres = SetMdData( achIndex, MD_MAPCERT, BINARY_METADATA,
cbCert, (LPBYTE)pbCert ) ) )
{
//NOP - Something failed
}
}
CloseMd( SUCCEEDED( hres ) );
}
//
// New mapping
//
if ( !fFoundExisting )
{
//
// check mapping exists, create if not
//
hres = OpenMd( L"Cert11/Mappings", METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ );
if ( hres == RETURNCODETOHRESULT( ERROR_PATH_NOT_FOUND ) )
{
if ( SUCCEEDED( hres = OpenMd( L"",
METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ) ) )
{
hres = CreateMdObject( L"Cert11/Mappings" );
CloseMd( FALSE );
// Reopen to the correct node.
hres = OpenMd( L"Cert11/Mappings", METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ );
}
}
// failed to open metabase
if ( FAILED( hres ) )
{
goto Exit;
}
//
// adding the new mapping under it's CertHash node
//
if ( SUCCEEDED( hres = CreateMdObject( wszCertHash ) ) )
{
if ( FAILED( hres = SetMdData( wszCertHash, MD_MAPENABLED, DWORD_METADATA,
sizeof(DWORD), (LPBYTE)&lEnabled ) ) ||
FAILED( hres = SetMdData( wszCertHash, MD_MAPNAME, STRING_METADATA,
sizeof(WCHAR) * (SysStringLen(bstrName) + 1 ),
(LPBYTE)bstrName ) ) ||
FAILED( hres = SetMdData( wszCertHash, MD_MAPNTPWD, STRING_METADATA,
sizeof(WCHAR) * (SysStringLen(bstrNtPwd) + 1 ),
(LPBYTE)bstrNtPwd ) ) ||
FAILED( hres = SetMdData( wszCertHash, MD_MAPNTACCT, STRING_METADATA,
sizeof(WCHAR) * (SysStringLen(bstrNtAcct) + 1 ),
(LPBYTE)bstrNtAcct ) ) ||
FAILED( hres = SetMdData( wszCertHash, MD_MAPCERT, BINARY_METADATA,
cbCert, (LPBYTE)pbCert ) ) )
{
}
}
CloseMd( SUCCEEDED( hres ) );
}
Exit:
if( pbCert != NULL )
{
LocalFree( pbCert );
pbCert = NULL;
}
return hres;
}
HRESULT
CIISDsCrMap::GetMappingIIS6(
LONG lMethod,
VARIANT vKey,
VARIANT* pvCert,
VARIANT* pbstrNtAcct,
VARIANT* pbstrNtPwd,
VARIANT* pbstrName,
VARIANT* plEnabled
)
/*++
Routine Description:
Get a mapping entry using key
Arguments:
lMethod - method to use for access ( IISMAPPER_LOCATE_BY_* )
vKey - key to use to locate mapping
pvCert - X.509 certificate
pbstrNtAcct - NT acct to map to
pbstrNtPwd - NT pwd
pbstrName - friendly name for mapping entry
plEnabled - 1 to enable mapping entry, 0 to disable it
Returns:
COM status
--*/
{
WCHAR achIndex[METADATA_MAX_NAME_LEN + 1];
HRESULT hres;
DWORD dwLen;
LPBYTE pbData = NULL;
VariantInit( pvCert );
VariantInit( pbstrNtAcct );
VariantInit( pbstrNtPwd );
VariantInit( pbstrName );
VariantInit( plEnabled );
if ( SUCCEEDED( hres = OpenMd( L"Cert11/Mappings",
METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ) ) )
{
if ( SUCCEEDED(hres = Locate( lMethod, vKey, achIndex )) )
{
if ( SUCCEEDED( hres = GetMdData( achIndex, MD_MAPCERT, BINARY_METADATA, &dwLen,
&pbData ) ) )
{
if ( FAILED( hres = SetVariantAsByteArray( pvCert, dwLen, pbData ) ) )
{
goto Done;
}
LocalFree( pbData );
}
else
{
if ( hres != MD_ERROR_DATA_NOT_FOUND ||
FAILED( hres = SetVariantAsByteArray( pvCert, 0, (PBYTE)"" ) ) )
{
goto Done;
}
}
if ( SUCCEEDED( hres = GetMdData( achIndex, MD_MAPNTACCT, STRING_METADATA, &dwLen,
&pbData ) ) )
{
if ( FAILED( hres = SetVariantAsBSTRFromStringW(
pbstrNtAcct,
dwLen, pbData ) ) )
{
goto Done;
}
LocalFree( pbData );
pbData = NULL;
}
else
{
if ( hres != MD_ERROR_DATA_NOT_FOUND ||
FAILED ( hres = SetVariantAsBSTRFromStringW(
pbstrNtAcct,
sizeof(L""), (LPBYTE)L"" ) ) )
{
goto Done;
}
}
if ( SUCCEEDED( hres = GetMdData( achIndex, MD_MAPNTPWD, STRING_METADATA, &dwLen,
&pbData ) ) )
{
if ( FAILED( hres = SetVariantAsBSTRFromStringW(
pbstrNtPwd,
dwLen, pbData ) ) )
{
goto Done;
}
LocalFree( pbData );
pbData = NULL;
}
else
{
if ( hres != MD_ERROR_DATA_NOT_FOUND ||
FAILED( hres = SetVariantAsBSTRFromStringW(
pbstrNtPwd,
sizeof(L""), (LPBYTE)L"" ) ) )
{
goto Done;
}
}
if ( SUCCEEDED( hres = GetMdData( achIndex, MD_MAPNAME, STRING_METADATA, &dwLen,
&pbData ) ) )
{
if ( FAILED( hres = SetVariantAsBSTRFromStringW(
pbstrName,
dwLen, pbData ) ) )
{
goto Done;
}
LocalFree( pbData );
pbData = NULL;
}
else
{
if ( hres != MD_ERROR_DATA_NOT_FOUND ||
FAILED( hres = SetVariantAsBSTRFromStringW(
pbstrName,
sizeof(L""), (LPBYTE)L"" ) ) )
{
goto Done;
}
}
if ( SUCCEEDED( hres = GetMdData( achIndex, MD_MAPENABLED, DWORD_METADATA, &dwLen,
&pbData ) ) )
{
if ( FAILED( hres = SetVariantAsLong( plEnabled, *(LPDWORD)pbData ) ) )
{
goto Done;
}
LocalFree( pbData );
pbData = NULL;
}
else
{
if ( hres != MD_ERROR_DATA_NOT_FOUND ||
FAILED( hres = SetVariantAsLong( plEnabled, FALSE ) ) )
{
goto Done;
}
hres = S_OK;
}
}
Done:
if ( pbData != NULL )
{
LocalFree( pbData );
pbData = NULL;
}
CloseMd( FALSE );
}
return hres;
}
HRESULT
CIISDsCrMap::DeleteMappingIIS6(
LONG lMethod,
VARIANT vKey
)
/*++
Routine Description:
Delete a mapping entry using key
Arguments:
lMethod - method to use for access ( IISMAPPER_LOCATE_BY_* )
vKey - key to use to locate mapping
Returns:
COM status
--*/
{
WCHAR achIndex[METADATA_MAX_NAME_LEN + 1];
HRESULT hres;
if ( SUCCEEDED( hres = OpenMd( L"Cert11/Mappings",
METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ) ) )
{
if ( SUCCEEDED(hres = Locate( lMethod, vKey, achIndex )) )
{
hres = DeleteMdObject( achIndex );
}
CloseMd( TRUE );
}
return hres;
}
HRESULT
CIISDsCrMap::SetEnabledIIS6(
LONG lMethod,
VARIANT vKey,
LONG lEnabled
)
/*++
Routine Description:
Set the enable flag on a mapping entry using key
Arguments:
lMethod - method to use for access ( IISMAPPER_LOCATE_BY_* )
vKey - key to use to locate mapping
lEnabled - 1 to enable, 0 to disable
Returns:
COM status
--*/
{
WCHAR achIndex[METADATA_MAX_NAME_LEN + 1];
HRESULT hres;
if ( SUCCEEDED( hres = OpenMd( L"Cert11/Mappings",
METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ) ) )
{
if ( SUCCEEDED(hres = Locate( lMethod, vKey, achIndex )) )
{
hres = SetMdData( achIndex, MD_MAPENABLED, DWORD_METADATA, sizeof(DWORD), (LPBYTE)&lEnabled );
}
CloseMd( TRUE );
}
return hres;
}
HRESULT
CIISDsCrMap::SetNameIIS6(
LONG lMethod,
VARIANT vKey,
BSTR bstrName
)
/*++
Routine Description:
Set the Name on a mapping entry using key
Arguments:
lMethod - method to use for access ( IISMAPPER_LOCATE_BY_* )
vKey - key to use to locate mapping
bstrName - name to assign to mapping entry
Returns:
COM status
--*/
{
return SetStringIIS6( lMethod, vKey, bstrName, MD_MAPNAME );
}
HRESULT
CIISDsCrMap::SetStringIIS6(
LONG lMethod,
VARIANT vKey,
BSTR bstrName,
DWORD dwProp
)
/*++
Routine Description:
Set a string property on a mapping entry using key
Arguments:
lMethod - method to use for access ( IISMAPPER_LOCATE_BY_* )
vKey - key to use to locate mapping
bstrName - string content to assign to mapping entry
dwProp - property ID to assign to
Returns:
COM status
--*/
{
WCHAR achIndex[METADATA_MAX_NAME_LEN + 1];
LPSTR pszName = NULL;
HRESULT hres;
DWORD dwLen;
if ( SUCCEEDED( hres = OpenMd( L"Cert11/Mappings",
METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ) ) )
{
if ( SUCCEEDED(hres = Locate( lMethod, vKey, achIndex )) )
{
hres = SetMdData( achIndex, dwProp, STRING_METADATA,
sizeof(WCHAR) * (SysStringLen(bstrName) + 1 ),
(LPBYTE)bstrName );
}
CloseMd( TRUE );
}
return hres;
}
HRESULT
CIISDsCrMap::SetPwdIIS6(
LONG lMethod,
VARIANT vKey,
BSTR bstrPwd
)
/*++
Routine Description:
Set the Password on a mapping entry using key
Arguments:
lMethod - method to use for access ( IISMAPPER_LOCATE_BY_* )
vKey - key to use to locate mapping
bstrPwd - password to assign to mapping entry
Returns:
COM status
--*/
{
// Password must be saved with METADATA_SECURE flag
// SetMdData() is used by SetStringIIS6() and it will take care of it
//
return SetStringIIS6( lMethod, vKey, bstrPwd, MD_MAPNTPWD );
}
HRESULT
CIISDsCrMap::SetAcctIIS6(
LONG lMethod,
VARIANT vKey,
BSTR bstrAcct
)
/*++
Routine Description:
Set the NT account name on a mapping entry using key
Arguments:
lMethod - method to use for access ( IISMAPPER_LOCATE_BY_* )
vKey - key to use to locate mapping
bstrAcct - NT account name to assign to mapping entry
Returns:
COM status
--*/
{
return SetStringIIS6( lMethod, vKey, bstrAcct, MD_MAPNTACCT );
}
//////
HRESULT
CIISDsCrMap::LocateIIS6(
LONG lMethod,
VARIANT vKey,
LPWSTR pszResKey
)
/*++
Routine Description:
Locate a mapping entry based on key
OpenMd() must be called 1st
Arguments:
lMethod - method to use for access ( IISMAPPER_LOCATE_BY_* )
vKey - key to use to locate mapping
pszResKey - must be METADATA_MAX_NAME_LEN + 1 WCHARs long
Returns:
COM status
--*/
{
HRESULT hres;
PBYTE pbKeyData = NULL;
DWORD cbKeyData =0;
PBYTE pbCert = NULL;
DWORD cbCert =0;
DWORD dwProp;
LPSTR pRes;
DWORD cRes;
BOOL fAddDelim = TRUE;
VARIANT vKeyUI4;
VARIANT vKeyBSTR;
WCHAR achIndex[ METADATA_MAX_NAME_LEN + 1 ];
DWORD dwIndex = 0;
DWORD cbData = 0;
PBYTE pbData = NULL;
VariantInit( &vKeyUI4 );
VariantInit( &vKeyBSTR );
if ( lMethod == IISMAPPER_LOCATE_BY_INDEX )
{
//
// Convert index to numeric value VT_UI4 (within variant)
//
if ( FAILED( hres = VariantChangeType( &vKeyUI4, &vKey, 0, VT_UI4 ) ) )
{
goto Exit;
}
if ( V_UI4( &vKeyUI4 ) == 0 )
{
// Error PATH_NOT_FOUND chosen for backward compatibility
// with version IIS5.1 and older
//
hres = HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND );
goto Exit;
}
hres = m_pcAdmCom->EnumKeys( m_hmd,
L"",
achIndex,
V_UI4( &vKeyUI4 ) - 1
);
if ( hres == HRESULT_FROM_WIN32( ERROR_NO_MORE_ITEMS ) )
{
// Error PATH_NOT_FOUND chosen for backward compatibility
// with version IIS5.1 and older
//
hres = HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND );
}
goto Exit;
}
//
// get ptr to data
//
if ( lMethod == IISMAPPER_LOCATE_BY_CERT )
{
// Now this is really wacky. Because of the legacy of the bad
// decision in the past the CERT is not enforced to be byte array
// It can be passed as string. That causes problems with
// conversions between byte array and UNICODE and back
// but we got to stick with it for compatibility with previous versions.
//
if ( FAILED( hres = GetBlobFromVariant( &vKey, &pbCert, &cbCert ) ) )
{
goto Exit;
}
pbKeyData = pbCert;
cbKeyData = cbCert;
}
else
{
//
// the rest of the lookups (by mapping, name or by account name)
// assumes string
//
if ( FAILED( hres = VariantChangeType( &vKeyBSTR, &vKey, 0, VT_BSTR ) ) )
{
goto Exit;
}
pbKeyData = (PBYTE) V_BSTR( &vKeyBSTR );
cbKeyData = ( SysStringLen(V_BSTR( &vKeyBSTR )) + 1 ) * sizeof(WCHAR);
}
//
// enumerate all entries to find match
// Now this is really slooow if many mappings are configured
//
for(;;)
{
hres = m_pcAdmCom->EnumKeys( m_hmd,
L"",
achIndex,
dwIndex
);
if ( FAILED( hres ) )
{
if ( hres == HRESULT_FROM_WIN32( ERROR_NO_MORE_ITEMS ) )
{
// Error PATH_NOT_FOUND chosen for backward compatibility
// with version IIS5.1 and older
//
hres = HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND );
}
goto Exit;
}
switch ( lMethod )
{
case IISMAPPER_LOCATE_BY_CERT:
hres = GetMdData( achIndex, MD_MAPCERT, BINARY_METADATA, &cbData,
&pbData );
if ( hres == MD_ERROR_DATA_NOT_FOUND )
{
cbData = 0;
pbData = NULL;
}
else if ( FAILED( hres ) )
{
// goto next entry
break;
}
//
// compare if key is matching value read from metabase
//
if ( cbData == cbKeyData )
{
if ( ( cbData == 0 ) ||
memcmp( pbKeyData, pbData, cbData ) == 0 )
{
// we found match
hres = S_OK;
goto Exit;
}
}
break;
case IISMAPPER_LOCATE_BY_ACCT:
hres = GetMdData( achIndex, MD_MAPNTACCT, STRING_METADATA, &cbData,
&pbData );
if ( hres == MD_ERROR_DATA_NOT_FOUND )
{
cbData = sizeof(L"");
pbData = (PBYTE) L"";
}
else if ( FAILED( hres ) )
{
// goto next entry
break;
}
if ( cbData == cbKeyData )
{
if ( _wcsicmp( (WCHAR *) pbKeyData, (WCHAR *) pbData ) == 0 )
{
// we found match
hres = S_OK;
goto Exit;
}
}
break;
case IISMAPPER_LOCATE_BY_NAME:
hres = GetMdData( achIndex, MD_MAPNAME, STRING_METADATA, &cbData,
&pbData );
if ( hres == MD_ERROR_DATA_NOT_FOUND )
{
cbData = sizeof(L"");
pbData = (PBYTE) L"";
}
else if ( FAILED( hres ) )
{
// goto next entry
break;
}
if ( cbData == cbKeyData )
{
if ( _wcsicmp( (WCHAR *) pbKeyData, (WCHAR *) pbData ) == 0 )
{
// we found match
hres = S_OK;
goto Exit;
}
}
break;
}
if ( pbData != NULL )
{
LocalFree( pbData );
pbData = NULL;
}
dwIndex++;
}
Exit:
if ( pbData != NULL )
{
LocalFree( pbData );
pbData = NULL;
}
if ( pbCert != NULL )
{
LocalFree( pbCert );
pbCert = NULL;
}
if ( SUCCEEDED( hres ) )
{
wcsncpy( pszResKey, achIndex, METADATA_MAX_NAME_LEN + 1 );
pszResKey[ METADATA_MAX_NAME_LEN ] ='\0';
}
VariantClear( &vKeyUI4 );
VariantClear( &vKeyBSTR );
return hres;
}
//
// IIS5, IIS51 mapping functions
// They call IIS6 mapping function when connecting to IIS6 box
//
HRESULT
CIISDsCrMap::CreateMapping(
VARIANT vCert,
BSTR bstrNtAcct,
BSTR bstrNtPwd,
BSTR bstrName,
LONG lEnabled
)
/*++
Routine Description:
Create a mapping entry
Arguments:
vCert - X.509 certificate
bstrNtAcct - NT acct to map to
bstrNtPwd - NT pwd
bstrName - friendly name for mapping entry
lEnabled - 1 to enable mapping entry, 0 to disable it
Returns:
COM status
--*/
{
if ( m_fIsIIS6 )
{
return CreateMappingIIS6( vCert,
bstrNtAcct,
bstrNtPwd,
bstrName,
lEnabled );
}
HRESULT hres;
LPBYTE pbCert = NULL;
DWORD cCert;
LPSTR pszNtAcct = NULL;
LPSTR pszNtPwd = NULL;
LPSTR pszName = NULL;
LPBYTE pRes;
DWORD cRes;
DWORD cName;
DWORD cNtAcct;
DWORD cNtPwd;
WCHAR achIndex[LOCAL_MAX_SIZE];
VARIANT vOldAcct;
VARIANT vOldCert;
VARIANT vOldPwd;
VARIANT vOldName;
VARIANT vOldEnabledFlag;
PCCERT_CONTEXT pcCert = NULL;
//
// Do some sanity checks on the cert
//
if ( SUCCEEDED( hres = GetStringFromVariant( &vCert,
(LPSTR*)&pbCert,
&cCert,
FALSE ) ) )
{
//
// try to construct a cert context
//
if ( !( pcCert = CertCreateCertificateContext( X509_ASN_ENCODING,
pbCert,
cCert ) ) )
{
DBGPRINTF((DBG_CONTEXT,
"Invalid cert passed to CreateMapping()\n"));
//
// If the decoding fails, GetLastError() returns an ASN1 decoding
// error that is obtained by subtracting CRYPT_E_OSS_ERROR from the returned
// error and looking in file asn1code.h for the actual error. To avoid the
// cryptic ASN1 errors, we'll just return a general "invalid arg" error
//
hres = RETURNCODETOHRESULT( E_INVALIDARG );
FreeString( (LPSTR) pbCert );
goto Exit;
}
CertFreeCertificateContext( pcCert );
}
else
{
goto Exit;
}
//
// check if we already have a mapping for this cert; if we do, we'll replace that mapping
// with the new one
//
if ( SUCCEEDED( hres = GetMapping( IISMAPPER_LOCATE_BY_CERT,
vCert,
&vOldCert,
&vOldAcct,
&vOldPwd,
&vOldName,
&vOldEnabledFlag ) ) )
{
DBGPRINTF((DBG_CONTEXT,
"Replacing old 1-1 cert mapping with new mapping\n"));
if ( FAILED( hres = SetName( IISMAPPER_LOCATE_BY_CERT,
vCert,
bstrName ) ) ||
FAILED( hres = SetAcct( IISMAPPER_LOCATE_BY_CERT,
vCert,
bstrNtAcct ) ) ||
FAILED( hres = SetPwd( IISMAPPER_LOCATE_BY_CERT,
vCert,
bstrNtPwd ) ) ||
FAILED( hres = SetEnabled( IISMAPPER_LOCATE_BY_CERT,
vCert,
lEnabled ) ) )
{
hres; //NOP - Something failed
}
}
//
// New mapping
//
else if ( hres == RETURNCODETOHRESULT( ERROR_PATH_NOT_FOUND ) )
{
//
// check mapping exists, create if not
//
hres = OpenMd( L"Cert11", METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ );
if ( hres == RETURNCODETOHRESULT( ERROR_PATH_NOT_FOUND ) )
{
if ( SUCCEEDED( hres = OpenMd( L"",
METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ) ) )
{
hres = CreateMdObject( L"Cert11" );
CloseMd( FALSE );
// Reopen to the correct node.
hres = OpenMd( L"Cert11", METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ );
}
}
if ( FAILED( hres ) )
{
goto Exit;
}
//
// adding mapping cert "0" means add @ end of list
//
if ( SUCCEEDED( hres = CreateMdObject( L"mappings/0" ) ) )
{
if ( SUCCEEDED( hres = GetMdData( L"", MD_NSEPM_ACCESS_CERT, DWORD_METADATA, &
cRes, &pRes ) ) )
{
if ( cRes == sizeof(DWORD ) )
{
wsprintfW( achIndex, L"mappings/%u", *(LPDWORD)pRes );
if ( FAILED( hres = GetStringFromBSTR( bstrNtAcct, &pszNtAcct, &cNtAcct ) ) ||
FAILED( hres = GetStringFromBSTR( bstrNtPwd, &pszNtPwd, &cNtPwd ) ) ||
FAILED( hres = GetStringFromBSTR( bstrName, &pszName, &cName ) ) ||
FAILED( hres = SetMdData( achIndex, MD_MAPENABLED, DWORD_METADATA,
sizeof(DWORD), (LPBYTE)&lEnabled ) ) ||
FAILED( hres = SetMdData( achIndex, MD_MAPNAME, STRING_METADATA,
cName, (LPBYTE)pszName ) ) ||
FAILED( hres = SetMdData( achIndex, MD_MAPNTPWD, STRING_METADATA,
cNtPwd, (LPBYTE)pszNtPwd ) ) ||
FAILED( hres = SetMdData( achIndex, MD_MAPNTACCT, STRING_METADATA,
cNtAcct, (LPBYTE)pszNtAcct ) ) ||
FAILED( hres = SetMdData( achIndex, MD_MAPCERT, BINARY_METADATA,
cCert, (LPBYTE)pbCert ) ) )
{
}
}
else
{
hres = E_FAIL;
}
}
}
}
CloseMd( SUCCEEDED( hres ) );
FreeString( (LPSTR)pbCert );
FreeString( pszNtAcct );
FreeString( pszNtPwd );
FreeString( pszName );
Exit:
return hres;
}
HRESULT
CIISDsCrMap::GetMapping(
LONG lMethod,
VARIANT vKey,
VARIANT* pvCert,
VARIANT* pbstrNtAcct,
VARIANT* pbstrNtPwd,
VARIANT* pbstrName,
VARIANT* plEnabled
)
/*++
Routine Description:
Get a mapping entry using key
Arguments:
lMethod - method to use for access ( IISMAPPER_LOCATE_BY_* )
vKey - key to use to locate mapping
pvCert - X.509 certificate
pbstrNtAcct - NT acct to map to
pbstrNtPwd - NT pwd
pbstrName - friendly name for mapping entry
plEnabled - 1 to enable mapping entry, 0 to disable it
Returns:
COM status
--*/
{
if ( m_fIsIIS6 )
{
return GetMappingIIS6( lMethod,
vKey,
pvCert,
pbstrNtAcct,
pbstrNtPwd,
pbstrName,
plEnabled );
}
WCHAR achIndex[LOCAL_MAX_SIZE];
HRESULT hres;
DWORD dwLen;
LPBYTE pbData;
VariantInit( pvCert );
VariantInit( pbstrNtAcct );
VariantInit( pbstrNtPwd );
VariantInit( pbstrName );
VariantInit( plEnabled );
if ( SUCCEEDED( hres = OpenMd( L"Cert11",
METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ) ) )
{
if ( SUCCEEDED(hres = Locate( lMethod, vKey, achIndex )) )
{
if ( SUCCEEDED( hres = GetMdData( achIndex, MD_MAPCERT, BINARY_METADATA, &dwLen,
&pbData ) ) )
{
hres = SetVariantAsByteArray( pvCert, dwLen, pbData );
LocalFree( pbData );
}
else
{
goto Done;
}
if ( SUCCEEDED( hres = GetMdData( achIndex, MD_MAPNTACCT, STRING_METADATA, &dwLen,
&pbData ) ) )
{
hres = SetVariantAsBSTR( pbstrNtAcct, dwLen, pbData );
LocalFree( pbData );
}
else
{
goto Done;
}
if ( SUCCEEDED( hres = GetMdData( achIndex, MD_MAPNTPWD, STRING_METADATA, &dwLen,
&pbData ) ) )
{
hres = SetVariantAsBSTR( pbstrNtPwd, dwLen, pbData );
LocalFree( pbData );
}
else
{
goto Done;
}
if ( SUCCEEDED( hres = GetMdData( achIndex, MD_MAPNAME, STRING_METADATA, &dwLen,
&pbData ) ) )
{
hres = SetVariantAsBSTR( pbstrName, dwLen, pbData );
LocalFree( pbData );
}
else
{
goto Done;
}
if ( FAILED( hres = GetMdData( achIndex, MD_MAPENABLED, STRING_METADATA, &dwLen,
&pbData ) ) )
{
SetVariantAsLong( plEnabled, FALSE );
}
else
{
SetVariantAsLong( plEnabled, *(LPDWORD)pbData );
LocalFree( pbData );
}
}
Done:
CloseMd( FALSE );
}
return hres;
}
HRESULT
CIISDsCrMap::DeleteMapping(
LONG lMethod,
VARIANT vKey
)
/*++
Routine Description:
Delete a mapping entry using key
Arguments:
lMethod - method to use for access ( IISMAPPER_LOCATE_BY_* )
vKey - key to use to locate mapping
Returns:
COM status
--*/
{
if ( m_fIsIIS6 )
{
return DeleteMappingIIS6( lMethod,
vKey );
}
WCHAR achIndex[LOCAL_MAX_SIZE];
HRESULT hres;
if ( SUCCEEDED( hres = OpenMd( L"Cert11",
METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ) ) )
{
if ( SUCCEEDED(hres = Locate( lMethod, vKey, achIndex )) )
{
hres = DeleteMdObject( achIndex );
}
CloseMd( TRUE );
}
return hres;
}
HRESULT
CIISDsCrMap::SetEnabled(
LONG lMethod,
VARIANT vKey,
LONG lEnabled
)
/*++
Routine Description:
Set the enable flag on a mapping entry using key
Arguments:
lMethod - method to use for access ( IISMAPPER_LOCATE_BY_* )
vKey - key to use to locate mapping
lEnabled - 1 to enable, 0 to disable
Returns:
COM status
--*/
{
if ( m_fIsIIS6 )
{
return SetEnabledIIS6( lMethod,
vKey,
lEnabled );
}
WCHAR achIndex[LOCAL_MAX_SIZE];
HRESULT hres;
if ( SUCCEEDED( hres = OpenMd( L"Cert11",
METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ) ) )
{
if ( SUCCEEDED(hres = Locate( lMethod, vKey, achIndex )) )
{
hres = SetMdData( achIndex, MD_MAPENABLED, DWORD_METADATA, sizeof(DWORD), (LPBYTE)&lEnabled );
}
CloseMd( TRUE );
}
return hres;
}
HRESULT
CIISDsCrMap::SetName(
LONG lMethod,
VARIANT vKey,
BSTR bstrName
)
/*++
Routine Description:
Set the Name on a mapping entry using key
Arguments:
lMethod - method to use for access ( IISMAPPER_LOCATE_BY_* )
vKey - key to use to locate mapping
bstrName - name to assign to mapping entry
Returns:
COM status
--*/
{
if ( m_fIsIIS6 )
{
return SetNameIIS6( lMethod,
vKey,
bstrName );
}
return SetString( lMethod, vKey, bstrName, MD_MAPNAME );
}
HRESULT
CIISDsCrMap::SetString(
LONG lMethod,
VARIANT vKey,
BSTR bstrName,
DWORD dwProp
)
/*++
Routine Description:
Set a string property on a mapping entry using key
Arguments:
lMethod - method to use for access ( IISMAPPER_LOCATE_BY_* )
vKey - key to use to locate mapping
bstrName - string content to assign to mapping entry
dwProp - property ID to assign to
Returns:
COM status
--*/
{
WCHAR achIndex[LOCAL_MAX_SIZE];
LPSTR pszName = NULL;
HRESULT hres;
DWORD dwLen;
if ( FAILED( hres = GetStringFromBSTR( bstrName, &pszName, &dwLen, TRUE ) ) )
{
return hres;
}
if ( SUCCEEDED( hres = OpenMd( L"Cert11",
METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ) ) )
{
if ( SUCCEEDED(hres = Locate( lMethod, vKey, achIndex )) )
{
hres = SetMdData( achIndex, dwProp, STRING_METADATA, dwLen, (LPBYTE)pszName );
}
CloseMd( TRUE );
}
FreeString( pszName );
return hres;
}
HRESULT
CIISDsCrMap::SetPwd(
LONG lMethod,
VARIANT vKey,
BSTR bstrPwd
)
/*++
Routine Description:
Set the Password on a mapping entry using key
Arguments:
lMethod - method to use for access ( IISMAPPER_LOCATE_BY_* )
vKey - key to use to locate mapping
bstrPwd - password to assign to mapping entry
Returns:
COM status
--*/
{
if ( m_fIsIIS6 )
{
return SetPwdIIS6( lMethod,
vKey,
bstrPwd );
}
return SetString( lMethod, vKey, bstrPwd, MD_MAPNTPWD );
}
HRESULT
CIISDsCrMap::SetAcct(
LONG lMethod,
VARIANT vKey,
BSTR bstrAcct
)
/*++
Routine Description:
Set the NT account name on a mapping entry using key
Arguments:
lMethod - method to use for access ( IISMAPPER_LOCATE_BY_* )
vKey - key to use to locate mapping
bstrAcct - NT account name to assign to mapping entry
Returns:
COM status
--*/
{
if ( m_fIsIIS6 )
{
return SetAcctIIS6( lMethod,
vKey,
bstrAcct );
}
return SetString( lMethod, vKey, bstrAcct, MD_MAPNTACCT );
}
////
HRESULT
CIISDsCrMap::OpenMd(
LPWSTR pszOpenPath,
DWORD dwPermission
)
/*++
Routine Description:
Open metabase using path & permission
path is relative to the top of the name space extension ( i.e. /.../<nsepm> )
Arguments:
pszOpenPath - path to open inside name space extension
dwPermission - metabase permission ( read/write )
Returns:
COM status
--*/
{
HRESULT hres;
LPWSTR pszPath;
UINT cL = wcslen( m_pszMetabasePath );
pszPath = (LPWSTR)LocalAlloc( LMEM_FIXED, (wcslen(pszOpenPath) + 1 + cL + 1)*sizeof(WCHAR) );
if ( pszPath == NULL )
{
return E_OUTOFMEMORY;
}
memcpy( pszPath, m_pszMetabasePath, cL * sizeof(WCHAR) );
if ( cL && m_pszMetabasePath[cL-1] != L'/' && *pszOpenPath && *pszOpenPath != L'/' )
{
pszPath[cL++] = L'/';
}
wcscpy( pszPath + cL, pszOpenPath );
hres = OpenAdminBaseKey(
m_pszServerName,
pszPath,
dwPermission,
&m_pcAdmCom,
&m_hmd
);
LocalFree( pszPath );
if ( FAILED(hres) )
{
m_hmd = NULL;
}
return hres;
}
HRESULT
CIISDsCrMap::CloseMd(
BOOL fSave
)
/*++
Routine Description:
close metabase
Arguments:
fSave - TRUE to save data immediatly
Returns:
COM status
--*/
{
CloseAdminBaseKey( m_pcAdmCom, m_hmd );
m_hmd = NULL;
if ( m_pcAdmCom && fSave )
{
m_pcAdmCom->SaveData();
}
return S_OK;
}
HRESULT
CIISDsCrMap::DeleteMdObject(
LPWSTR pszKey
)
/*++
Routine Description:
Delete metabase object in an opened tree
OpenMd() must be called 1st
Arguments:
pszKey - key to delete in opened metabase
Returns:
COM status
--*/
{
return m_pcAdmCom->DeleteKey( m_hmd, pszKey );
}
HRESULT
CIISDsCrMap::CreateMdObject(
LPWSTR pszKey
)
/*++
Routine Description:
Create metabase object in an opened tree
OpenMd() must be called 1st
Arguments:
pszKey - key to create in opened metabase
Returns:
COM status
--*/
{
return m_pcAdmCom->AddKey( m_hmd, pszKey );
}
HRESULT
CIISDsCrMap::SetMdData(
LPWSTR achIndex,
DWORD dwProp,
DWORD dwDataType,
DWORD dwDataLen,
LPBYTE pbData
)
/*++
Routine Description:
Set a metabase property
OpenMd() must be called 1st
Property will be stored with NULL attribute, except for MD_MAPPWD
which will be stored with METADATA_SECURE
Arguments:
achIndex - key name where to store property
dwProp - property ID
dwDataType - property data type
dwDataLen - property length
pbData - property value
Returns:
COM status
--*/
{
METADATA_RECORD md;
md.dwMDDataLen = dwDataLen;
md.dwMDDataType = dwDataType;
md.dwMDIdentifier = dwProp;
md.dwMDAttributes = (dwProp == MD_MAPNTPWD) ? METADATA_SECURE : 0;
md.pbMDData = pbData;
return m_pcAdmCom->SetData( m_hmd, achIndex, &md );
}
HRESULT
CIISDsCrMap::GetMdData(
LPWSTR achIndex,
DWORD dwProp,
DWORD dwDataType,
LPDWORD pdwDataLen,
LPBYTE* ppbData
)
/*++
Routine Description:
Get a metabase property
OpenMd() must be called 1st
Arguments:
achIndex - key name where to get property
dwProp - property ID
dwDataType - property data type
pdwDataLen - property length
ppData - property value, to be freed using LocalFree() on successfull return
Returns:
COM status
--*/
{
HRESULT hres;
METADATA_RECORD md;
DWORD dwRequired;
md.dwMDDataLen = 0;
md.dwMDDataType = dwDataType;
md.dwMDIdentifier = dwProp;
md.dwMDAttributes = 0;
md.pbMDData = NULL;
if ( FAILED(hres = m_pcAdmCom->GetData( m_hmd, achIndex, &md, &dwRequired )) )
{
if ( hres == RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER) )
{
if ( (*ppbData = (LPBYTE)LocalAlloc( LMEM_FIXED, dwRequired )) == NULL )
{
return E_OUTOFMEMORY;
}
md.pbMDData = *ppbData;
md.dwMDDataLen = dwRequired;
hres = m_pcAdmCom->GetData( m_hmd, achIndex, &md, &dwRequired );
*pdwDataLen = md.dwMDDataLen;
}
}
else
{
*pdwDataLen = 0;
*ppbData = NULL;
}
return hres;
}
//////
HRESULT
CIISDsCrMap::Locate(
LONG lMethod,
VARIANT vKey,
LPWSTR pszResKey
)
/*++
Routine Description:
Locate a mapping entry based on key
OpenMd() must be called 1st
Arguments:
lMethod - method to use for access ( IISMAPPER_LOCATE_BY_* )
vKey - key to use to locate mapping
pszResKey -
Returns:
COM status
--*/
{
if ( m_fIsIIS6 )
{
return LocateIIS6( lMethod,
vKey,
pszResKey );
}
HRESULT hres;
LPSTR pV = NULL;
DWORD cV;
DWORD dwProp;
LPSTR pRes;
DWORD cRes;
BOOL fAddDelim = TRUE;
//
// determine method
//
switch ( lMethod )
{
case IISMAPPER_LOCATE_BY_CERT:
dwProp = MD_NSEPM_ACCESS_CERT;
fAddDelim = FALSE;
break;
case IISMAPPER_LOCATE_BY_NAME:
dwProp = MD_NSEPM_ACCESS_NAME;
break;
case IISMAPPER_LOCATE_BY_ACCT:
dwProp = MD_NSEPM_ACCESS_ACCOUNT;
break;
case IISMAPPER_LOCATE_BY_INDEX:
if ( SUCCEEDED( hres = GetStringFromVariant( &vKey, &pV, &cV, TRUE ) ) )
{
WCHAR pwV[LOCAL_MAX_SIZE];
int i = MultiByteToWideChar(CP_ACP, 0, pV, cV, pwV, LOCAL_MAX_SIZE);
if (i ==0)
return E_FAIL; // MultiByteToWideChar failure
if (i >= (int)(LOCAL_MAX_SIZE - wcslen(L"mappings/")))
return E_FAIL; //pwV is too big for pszResKey
wsprintfW( pszResKey, L"mappings/%s", pwV );
}
goto Exit;
default:
return E_FAIL;
}
//
// get ptr to data
//
if ( SUCCEEDED( hres = GetStringFromVariant( &vKey, &pV, &cV, fAddDelim ) ) )
{
//
// set search prop, get result
//
if ( SUCCEEDED( hres = SetMdData( L"", dwProp, BINARY_METADATA, cV, (LPBYTE)pV ) ) )
{
if ( SUCCEEDED( hres = GetMdData( L"", dwProp, DWORD_METADATA, &cRes, (LPBYTE*)&pRes ) ) )
{
if ( cRes == sizeof(DWORD ) )
{
wsprintfW( pszResKey, L"mappings/%u", *(LPDWORD)pRes );
}
else
{
hres = E_FAIL;
}
LocalFree( pRes );
}
}
}
Exit:
FreeString( pV );
return hres;
}
HRESULT
GetStringFromBSTR(
BSTR bstr,
LPSTR* psz,
LPDWORD pdwLen,
BOOL fAddDelimInCount
)
/*++
Routine Description:
Allocate string buffer from BSTR
Arguments:
bstr - bstr to convert from
psz - updated with ptr to buffer, to be freed with FreeString()
pdwLen - updated with strlen(string), incremented by 1 if fAddDelimInCount is TRUE
fAddDelimInCount - TRUE to increment *pdwLen
Returns:
COM status
--*/
{
UINT cch = SysStringLen(bstr);
UINT cchT;
// include NULL terminator
*pdwLen = cch + (fAddDelimInCount ? 1 : 0);
CHAR *szNew = (CHAR*)LocalAlloc( LMEM_FIXED, (2 * cch) + 1); // * 2 for worst case DBCS string
if (szNew == NULL)
{
return E_OUTOFMEMORY;
}
cchT = WideCharToMultiByte(CP_ACP, 0, bstr, cch + 1, szNew, (2 * cch) + 1, NULL, NULL);
*psz = szNew;
return NOERROR;
}
HRESULT
GetStringFromVariant(
VARIANT* pVar,
LPSTR* psz,
LPDWORD pdwLen,
BOOL fAddDelim
)
/*++
Routine Description:
Allocate string buffer from BSTR
Arguments:
pVar - variant to convert from. Recognizes BSTR, VT_ARRAY|VT_UI1, ByRef or ByVal
psz - updated with ptr to buffer, to be freed with FreeString()
pdwLen - updated with size of input, incremented by 1 if fAddDelimInCount is TRUE
fAddDelimInCount - TRUE to increment *pdwLen
Returns:
COM status
--*/
{
LPBYTE pbV;
UINT cV;
HRESULT hres;
WORD vt = V_VT(pVar);
BOOL fByRef = FALSE;
VARIANT vOut;
VariantInit( &vOut );
if ( vt & VT_BYREF )
{
vt &= ~VT_BYREF;
fByRef = TRUE;
}
if ( vt == VT_DISPATCH )
{
if ( FAILED(hres = VariantResolveDispatch( &vOut, pVar )) )
{
return hres;
}
pVar = &vOut;
vt = V_VT(pVar);
if ( fByRef = vt & VT_BYREF )
{
vt &= ~VT_BYREF;
}
}
// if pVar is BSTR, convert to multibytes
if ( vt == VT_VARIANT )
{
pVar = (VARIANT*)V_BSTR(pVar);
vt = V_VT(pVar);
if ( fByRef = vt & VT_BYREF )
{
vt &= ~VT_BYREF;
}
}
if ( vt == VT_BSTR )
{
hres = GetStringFromBSTR( fByRef ?
*(BSTR*)V_BSTR(pVar) :
V_BSTR(pVar),
psz,
pdwLen,
fAddDelim );
}
else if( vt == (VT_ARRAY | VT_UI1) )
{
long lBound, uBound, lItem;
BYTE bValue;
SAFEARRAY* pSafeArray;
// array of VT_UI1 (probably OctetString)
pSafeArray = fByRef ? *(SAFEARRAY**)V_BSTR(pVar) : V_ARRAY( pVar );
hres = SafeArrayGetLBound(pSafeArray, 1, &lBound);
hres = SafeArrayGetUBound(pSafeArray, 1, &uBound);
cV = uBound - lBound + 1;
if ( !(pbV = (LPBYTE)LocalAlloc( LMEM_FIXED, cV )) )
{
hres = E_OUTOFMEMORY;
goto Exit;
}
hres = S_OK;
for( lItem = lBound; lItem <= uBound ; lItem++ )
{
hres = SafeArrayGetElement( pSafeArray, &lItem, &bValue );
if( FAILED( hres ) )
{
break;
}
pbV[lItem-lBound] = bValue;
}
*psz = (LPSTR)pbV;
*pdwLen = cV;
}
else if( vt == (VT_ARRAY | VT_VARIANT) )
{
long lBound, uBound, lItem;
VARIANT vValue;
BYTE bValue;
SAFEARRAY* pSafeArray;
// array of VT_VARIANT (probably VT_I4 )
pSafeArray = fByRef ? *(SAFEARRAY**)V_BSTR(pVar) : V_ARRAY( pVar );
hres = SafeArrayGetLBound(pSafeArray, 1, &lBound);
hres = SafeArrayGetUBound(pSafeArray, 1, &uBound);
cV = uBound - lBound + 1;
if ( !(pbV = (LPBYTE)LocalAlloc( LMEM_FIXED, cV )) )
{
hres = E_OUTOFMEMORY;
goto Exit;
}
hres = S_OK;
for( lItem = lBound; lItem <= uBound ; lItem++ )
{
hres = SafeArrayGetElement( pSafeArray, &lItem, &vValue );
if( FAILED( hres ) )
{
break;
}
if ( V_VT(&vValue) == VT_UI1 )
{
bValue = V_UI1(&vValue);
}
else if ( V_VT(&vValue) == VT_I2 )
{
bValue = (BYTE)V_I2(&vValue);
}
else if ( V_VT(&vValue) == VT_I4 )
{
bValue = (BYTE)V_I4(&vValue);
}
else
{
bValue = 0;
}
pbV[lItem-lBound] = bValue;
}
*psz = (LPSTR)pbV;
*pdwLen = cV;
}
else
{
hres = E_FAIL;
}
Exit:
VariantClear( &vOut );
return hres;
}
HRESULT
GetStringAFromBSTR(
BSTR bstr,
LPSTR* psz,
LPDWORD pdwLen,
BOOL fAddDelimInCount
)
/*++
Routine Description:
Allocate string buffer from BSTR - for IIS6 only
Arguments:
bstr - bstr to convert from
psz - updated with ptr to buffer, to be freed with FreeString()
pdwLen - updated with strlen(string), incremented by 1 if fAddDelimInCount is TRUE
fAddDelimInCount - TRUE to increment *pdwLen
Returns:
COM status
--*/
{
UINT cch = SysStringLen(bstr);
UINT cchT;
// include NULL terminator
*pdwLen = cch + (fAddDelimInCount ? 1 : 0);
CHAR *szNew = (CHAR*)LocalAlloc( LMEM_FIXED, (2 * cch) + 1); // * 2 for worst case DBCS string
if (szNew == NULL)
{
return E_OUTOFMEMORY;
}
cchT = WideCharToMultiByte(CP_ACP, 0, bstr, cch + 1, szNew, (2 * cch) + 1, NULL, NULL);
*psz = szNew;
return NOERROR;
}
HRESULT
GetBlobFromVariant(
VARIANT* pVar,
PBYTE* ppbOut,
LPDWORD pcbOut
)
/*++
Routine Description:
Allocate string buffer from BSTR - for IIS6 only
Arguments:
pVar - variant to convert from. Recognizes BSTR, VT_ARRAY|VT_UI1, ByRef or ByVal
ppbOut - updated with ptr to buffer, to be freed with LocalFree()
pcbOut - updated with size of input
Returns:
COM status
--*/
{
LPBYTE pbV;
UINT cV;
HRESULT hres;
WORD vt = V_VT(pVar);
BOOL fByRef = FALSE;
VARIANT vOut;
VariantInit( &vOut );
if ( vt & VT_BYREF )
{
vt &= ~VT_BYREF;
fByRef = TRUE;
}
if ( vt == VT_DISPATCH )
{
if ( FAILED(hres = VariantResolveDispatch( &vOut, pVar )) )
{
return hres;
}
pVar = &vOut;
vt = V_VT(pVar);
if ( fByRef = vt & VT_BYREF )
{
vt &= ~VT_BYREF;
}
}
// if pVar is BSTR, convert to multibytes
if ( vt == VT_VARIANT )
{
pVar = (VARIANT*)V_BSTR(pVar);
vt = V_VT(pVar);
if ( fByRef = vt & VT_BYREF )
{
vt &= ~VT_BYREF;
}
}
if ( vt == VT_BSTR )
{
hres = GetStringAFromBSTR( fByRef ?
*(BSTR*)V_BSTR(pVar) :
V_BSTR(pVar),
(LPSTR *)ppbOut,
pcbOut,
FALSE );
}
else if( vt == (VT_ARRAY | VT_UI1) )
{
long lBound, uBound, lItem;
BYTE bValue;
SAFEARRAY* pSafeArray;
// array of VT_UI1 (probably OctetString)
pSafeArray = fByRef ? *(SAFEARRAY**)V_BSTR(pVar) : V_ARRAY( pVar );
hres = SafeArrayGetLBound(pSafeArray, 1, &lBound);
hres = SafeArrayGetUBound(pSafeArray, 1, &uBound);
cV = uBound - lBound + 1;
if ( !(pbV = (LPBYTE)LocalAlloc( LMEM_FIXED, cV )) )
{
hres = E_OUTOFMEMORY;
goto Exit;
}
hres = S_OK;
for( lItem = lBound; lItem <= uBound ; lItem++ )
{
hres = SafeArrayGetElement( pSafeArray, &lItem, &bValue );
if( FAILED( hres ) )
{
break;
}
pbV[lItem-lBound] = bValue;
}
*ppbOut = pbV;
*pcbOut = cV;
}
else if( vt == (VT_ARRAY | VT_VARIANT) )
{
long lBound, uBound, lItem;
VARIANT vValue;
BYTE bValue;
SAFEARRAY* pSafeArray;
// array of VT_VARIANT (probably VT_I4 )
pSafeArray = fByRef ? *(SAFEARRAY**)V_BSTR(pVar) : V_ARRAY( pVar );
hres = SafeArrayGetLBound(pSafeArray, 1, &lBound);
hres = SafeArrayGetUBound(pSafeArray, 1, &uBound);
cV = uBound - lBound + 1;
if ( !(pbV = (LPBYTE)LocalAlloc( LMEM_FIXED, cV )) )
{
hres = E_OUTOFMEMORY;
goto Exit;
}
hres = S_OK;
for( lItem = lBound; lItem <= uBound ; lItem++ )
{
hres = SafeArrayGetElement( pSafeArray, &lItem, &vValue );
if( FAILED( hres ) )
{
break;
}
if ( V_VT(&vValue) == VT_UI1 )
{
bValue = V_UI1(&vValue);
}
else if ( V_VT(&vValue) == VT_I2 )
{
bValue = (BYTE)V_I2(&vValue);
}
else if ( V_VT(&vValue) == VT_I4 )
{
bValue = (BYTE)V_I4(&vValue);
}
else
{
bValue = 0;
}
pbV[lItem-lBound] = bValue;
}
*ppbOut = pbV;
*pcbOut = cV;
}
else
{
hres = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
}
Exit:
VariantClear( &vOut );
return hres;
}
VOID
FreeString(
LPSTR psz
)
/*++
Routine Description:
Free a string returned by GetStringFromVariant() or GetStringFromBTR()
can be NULL
Arguments:
psz - string to free, can be NULL
Returns:
Nothing
--*/
{
if ( psz )
{
LocalFree( psz );
}
}
HRESULT
SetBSTR(
BSTR* pbstrRet,
DWORD cch,
LPBYTE sz
)
/*++
Routine Description:
Build a BSTR from byte array - for IIS5, IIS5.1 assumes ansi string on input
Arguments:
pbstrRet - updated with BSTR
cch - byte count in sz
sz - byte array
Returns:
COM status
--*/
{
BSTR bstrRet;
if (sz == NULL)
{
*pbstrRet = NULL;
return(NOERROR);
}
// Allocate a string of the desired length
// SysAllocStringLen allocates enough room for unicode characters plus a null
// Given a NULL string it will just allocate the space
bstrRet = SysAllocStringLen(NULL, cch);
if (bstrRet == NULL)
{
return(E_OUTOFMEMORY);
}
// If we were given "", we will have cch=0. return the empty bstr
// otherwise, really copy/convert the string
// NOTE we pass -1 as 4th parameter of MultiByteToWideChar for DBCS support
if (cch != 0)
{
UINT cchTemp = 0;
if (MultiByteToWideChar(CP_ACP, 0, (LPSTR)sz, -1, bstrRet, cch+1) == 0)
{
SysFreeString(bstrRet);
return(HRESULT_FROM_WIN32(GetLastError()));
}
// If there are some DBCS characters in the sz(Input), then, the character count of BSTR(DWORD) is
// already set to cch(strlen(sz)) in SysAllocStringLen(NULL, cch), we cannot change the count,
// and later call of SysStringLen(bstr) always returns the number of characters specified in the
// cch parameter at allocation time. Bad, because one DBCS character(2 bytes) will convert
// to one UNICODE character(2 bytes), not 2 UNICODE characters(4 bytes).
// Example: For input sz contains only one DBCS character, we want to see SysStringLen(bstr)
// = 1, not 2.
bstrRet[cch] = 0;
cchTemp = wcslen(bstrRet);
if (cchTemp < cch)
{
BSTR bstrTemp = SysAllocString(bstrRet);
SysFreeString(bstrRet);
bstrRet = bstrTemp;
cch = cchTemp;
}
}
if (bstrRet != NULL)
bstrRet[cch] = 0;
*pbstrRet = bstrRet;
return(NOERROR);
}
HRESULT
SetBSTRFromStringW(
BSTR* pbstrRet,
DWORD cb,
LPBYTE sz
)
/*++
Routine Description:
Build a BSTR from byte array (that is actually WCHAR string)
Arguments:
pbstrRet - updated with BSTR
cb - byte count
sz - byte array (we assume WCHAR string)
Returns:
COM status
--*/
{
BSTR bstrRet;
if (sz == NULL)
{
*pbstrRet = NULL;
return(NOERROR);
}
// Allocate a string of the desired length
// SysAllocStringLen allocates enough room for unicode characters plus a null
// Given a NULL string it will just allocate the space
bstrRet = SysAllocStringLen(NULL, cb/sizeof(WCHAR));
if (bstrRet == NULL)
{
return(E_OUTOFMEMORY);
}
wcsncpy( bstrRet, (WCHAR *) sz, cb/sizeof(WCHAR) );
*pbstrRet = bstrRet;
return(NOERROR);
}
HRESULT
CIISDsCrMap::Create(
IUnknown *pUnkOuter,
REFIID riid,
void **ppvObj
)
/*++
Routine Description:
Create a CIISDsCrMap
Arguments:
pUnkOuter - ptr to iunknown
riid - requested IID
ppvObj - updated with ptr to requested IID
Returns:
COM status
--*/
{
CCredentials Credentials;
CIISDsCrMap FAR * pMap = NULL;
HRESULT hr = S_OK;
BSTR bstrAdsPath = NULL;
OBJECTINFO ObjectInfo;
POBJECTINFO pObjectInfo = &ObjectInfo;
CLexer * pLexer = NULL;
LPWSTR pszIISPathName = NULL;
memset(pObjectInfo, 0, sizeof(OBJECTINFO));
hr = AllocateObject(pUnkOuter, Credentials, &pMap);
BAIL_ON_FAILURE(hr);
//
// get ServerName and pszPath
//
hr = pMap->_pADs->get_ADsPath(&bstrAdsPath);
BAIL_ON_FAILURE(hr);
pLexer = new CLexer();
hr = pLexer->Initialize(bstrAdsPath);
BAIL_ON_FAILURE(hr);
//
// Parse the pathname
//
hr = ADsObject(pLexer, pObjectInfo);
BAIL_ON_FAILURE(hr);
pszIISPathName = AllocADsStr(bstrAdsPath);
if (!pszIISPathName) {
hr = E_OUTOFMEMORY;
BAIL_ON_FAILURE(hr);
}
*pszIISPathName = L'\0';
hr = BuildIISPathFromADsPath(
pObjectInfo,
pszIISPathName
);
BAIL_ON_FAILURE(hr);
hr = pMap->Init( pObjectInfo->TreeName,
pszIISPathName );
BAIL_ON_FAILURE(hr);
//
// pass non-delegating IUnknown back to the aggregator
//
*ppvObj = (INonDelegatingUnknown FAR *) pMap;
if (bstrAdsPath) {
ADsFreeString(bstrAdsPath);
}
if (pLexer) {
delete pLexer;
}
if (pszIISPathName ) {
FreeADsStr( pszIISPathName );
}
FreeObjectInfo( &ObjectInfo );
RRETURN(hr);
error:
if (bstrAdsPath) {
ADsFreeString(bstrAdsPath);
}
if (pLexer) {
delete pLexer;
}
if (pszIISPathName ) {
FreeADsStr( pszIISPathName );
}
FreeObjectInfo( &ObjectInfo );
*ppvObj = NULL;
delete pMap;
RRETURN(hr);
}
STDMETHODIMP
CIISDsCrMap::QueryInterface(
REFIID iid,
LPVOID FAR* ppv
)
/*++
Routine Description:
Query interface to CIISDsCrMap
Arguments:
iid - requested IID
ppv - updated with ptr to requested IID
Returns:
COM status
--*/
{
HRESULT hr = S_OK;
hr = _pUnkOuter->QueryInterface(iid,ppv);
RRETURN(hr);
}
CIISDsCrMap::CIISDsCrMap(
)
/*++
Routine Description:
CIISDsCrMap constructor
Arguments:
pADs - ptr to contained ADs
Credentials - credential
pDispMgr - ptr to dispatch manager
Returns:
Nothing
--*/
{
m_pcAdmCom = NULL;
m_hmd = NULL;
m_pszServerName = NULL;
m_pszMetabasePath = NULL;
m_ADsPath = NULL;
_pADs = NULL;
_pDispMgr = NULL;
m_fIsIIS6 = TRUE;
ENLIST_TRACKING(CIISDsCrMap);
}
CIISDsCrMap::~CIISDsCrMap(
)
/*++
Routine Description:
CIISDsCrMap destructor
Arguments:
None
Returns:
Nothing
--*/
{
if ( m_ADsPath )
{
ADsFreeString( m_ADsPath );
}
if ( m_pszServerName )
{
LocalFree( m_pszServerName );
}
if ( m_pszMetabasePath )
{
LocalFree( m_pszMetabasePath );
}
if ( _pDispMgr )
{
delete _pDispMgr;
}
}
HRESULT
CIISDsCrMap::AllocateObject(
IUnknown *pUnkOuter,
CCredentials& Credentials,
CIISDsCrMap ** ppMap
)
/*++
Routine Description:
Allocate CIISDsCrMap
Arguments:
pUnkOuter - ptr to iunknown
Credentials - credential
ppMap - updated with ptr to IUnknown to Allocated object
Returns:
COM status
--*/
{
CIISDsCrMap FAR * pMap = NULL;
IADs FAR * pADs = NULL;
CAggregateeDispMgr FAR * pDispMgr = NULL;
HRESULT hr = S_OK;
pDispMgr = new CAggregateeDispMgr;
if (pDispMgr == NULL) {
hr = E_OUTOFMEMORY;
}
BAIL_ON_FAILURE(hr);
pMap = new CIISDsCrMap();
if (pMap == NULL) {
hr = E_OUTOFMEMORY;
}
BAIL_ON_FAILURE(hr);
hr = pDispMgr->LoadTypeInfoEntry(
LIBID_IISExt, //LIBID_ADs,
IID_IISDsCrMap,
(IISDsCrMap *)pMap,
DISPID_REGULAR
);
BAIL_ON_FAILURE(hr);
//
// Store the IADs Pointer, but again do NOT ref-count
// this pointer - we keep the pointer around, but do
// a release immediately.
//
hr = pUnkOuter->QueryInterface(IID_IADs, (void **)&pADs);
pADs->Release();
pMap->_pADs = pADs;
//
// Store the pointer to the pUnkOuter object
// AND DO NOT add ref this pointer
//
pMap->_pUnkOuter = pUnkOuter;
pMap->m_Credentials = Credentials;
pMap->_pDispMgr = pDispMgr;
*ppMap = pMap;
RRETURN(hr);
error:
delete pDispMgr;
delete pMap;
RRETURN(hr);
}
HRESULT
CIISDsCrMap::Init(
LPWSTR pszServerName,
LPWSTR pszMetabasePath
)
/*++
Routine Description:
Initialize CIISDsCrMap
Arguments:
pszServerName - target computer name for metabase access
pszParent - metabase path to IisMapper object
Returns:
COM status
--*/
{
UINT cL;
HRESULT hr = S_OK;
DWORD dwMajVer = 0;
DWORD dwLen = 0;
METADATA_RECORD mr = {
MD_SERVER_VERSION_MAJOR,
METADATA_NO_ATTRIBUTES,
IIS_MD_UT_SERVER,
DWORD_METADATA,
sizeof(DWORD),
(unsigned char*)&dwMajVer,
0
};
hr = InitServerInfo(pszServerName, &m_pcAdmCom);
BAIL_ON_FAILURE(hr);
// need to set m_fIsIIS6
METADATA_HANDLE MDataHandle;
hr = OpenAdminBaseKey(pszServerName,
L"/LM/W3SVC/Info",
METADATA_PERMISSION_READ,
&m_pcAdmCom,
&MDataHandle);
if (HRESULTTOWIN32(hr) == ERROR_PATH_NOT_FOUND)
{
m_fIsIIS6 = FALSE;
}
else
{
BAIL_ON_FAILURE(hr);
}
if (hr == S_OK)
{
hr = m_pcAdmCom->GetData(
MDataHandle,
L"",
&mr,
&dwLen);
if(hr == MD_ERROR_DATA_NOT_FOUND)
{
m_fIsIIS6 = FALSE;
}
else
{
BAIL_ON_FAILURE(hr);
}
if (hr == S_OK)
{
if (dwMajVer >= 6)
{
m_fIsIIS6 = TRUE;
}
else
{
m_fIsIIS6 = FALSE;
}
}
}
hr = S_OK;
cL = wcslen( pszServerName );
if ( m_pszServerName = (LPWSTR)LocalAlloc( LMEM_FIXED, ( cL + 1 )*sizeof(WCHAR) ) )
{
memcpy( m_pszServerName, pszServerName, ( cL + 1 )*sizeof(WCHAR) );
}
else
{
BAIL_ON_FAILURE(hr=E_OUTOFMEMORY);
}
cL = wcslen( pszMetabasePath );
while ( cL && pszMetabasePath[cL-1] != L'/' && pszMetabasePath[cL-1] != L'\\' )
{
--cL;
}
if ( m_fIsIIS6 && ( m_pszMetabasePath = (LPWSTR)LocalAlloc( LMEM_FIXED, (( cL + 1 )*sizeof(WCHAR) ) )))
{
memcpy( m_pszMetabasePath, pszMetabasePath, cL * sizeof(WCHAR) );
m_pszMetabasePath[ cL ] = L'\0';
}
else if ( !m_fIsIIS6 && ( m_pszMetabasePath = (LPWSTR)LocalAlloc( LMEM_FIXED, ( cL*sizeof(WCHAR) + sizeof(L"<nsepm>") )) ) )
{
memcpy( m_pszMetabasePath, pszMetabasePath, cL * sizeof(WCHAR) );
memcpy( m_pszMetabasePath + cL, L"<nsepm>", sizeof(L"<nsepm>") );
}
else
{
BAIL_ON_FAILURE(hr=E_OUTOFMEMORY);
}
error:
if (m_pcAdmCom)
{
CloseAdminBaseKey(m_pcAdmCom, MDataHandle);
}
return hr;
}
HRESULT
SetVariantAsByteArray(
VARIANT* pvarReturn,
DWORD cbLen,
LPBYTE pbIn
)
/*++
Routine Description:
Create variant as byte array
Arguments:
pVarReturn - ptr to created variant
cbLen - byte count
pbIn - byte array
Returns:
COM status
--*/
{
HRESULT hr;
SAFEARRAYBOUND rgsabound[1];
BYTE * pbData = NULL;
// Set the variant type of the output parameter
V_VT(pvarReturn) = VT_ARRAY|VT_UI1;
V_ARRAY(pvarReturn) = NULL;
// Allocate a SafeArray for the data
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = cbLen;
V_ARRAY(pvarReturn) = SafeArrayCreate(VT_UI1, 1, rgsabound);
if (V_ARRAY(pvarReturn) == NULL)
{
return E_OUTOFMEMORY;
}
if (FAILED(SafeArrayAccessData(V_ARRAY(pvarReturn), (void **) &pbData)))
{
return E_UNEXPECTED;
}
memcpy(pbData, pbIn, cbLen );
SafeArrayUnaccessData(V_ARRAY(pvarReturn));
return NOERROR;
}
HRESULT
SetVariantAsBSTR(
VARIANT* pvarReturn,
DWORD cbLen,
LPBYTE pbIn
)
/*++
Routine Description:
Create variant BSTR
Arguments:
pVarReturn - ptr to created variant
cbLen - byte count
pbIn - byte array
Returns:
COM status
--*/
{
HRESULT hr;
V_VT(pvarReturn) = VT_BSTR;
return SetBSTR( &V_BSTR(pvarReturn), cbLen, pbIn );
}
HRESULT
SetVariantAsBSTRFromStringW(
VARIANT* pvarReturn,
DWORD cbLen,
LPBYTE pbIn
)
/*++
Routine Description:
Create variant BSTR
Arguments:
pVarReturn - ptr to created variant
cbLen - byte count
pbIn - byte array
Returns:
COM status
--*/
{
HRESULT hr;
V_VT(pvarReturn) = VT_BSTR;
return SetBSTRFromStringW( &V_BSTR(pvarReturn), cbLen, pbIn );
}
HRESULT
SetVariantAsLong(
VARIANT* pvarReturn,
DWORD dwV
)
/*++
Routine Description:
Create variant as long
Arguments:
pVarReturn - ptr to created variant
dwV - value
Returns:
COM status
--*/
{
HRESULT hr;
V_VT(pvarReturn) = VT_I4;
V_I4(pvarReturn) = dwV;
return S_OK;
}
HRESULT
VariantResolveDispatch(
VARIANT * pVarOut,
VARIANT * pVarIn
)
/*++
Routine Description:
Extract value from IDispatch default property
Arguments:
pVarOut - ptr to created variant
pVarIn - ptr to IDispatch variant to resolve
Returns:
COM status
--*/
{
VARIANT varResolved; // value of IDispatch::Invoke
DISPPARAMS dispParamsNoArgs = {NULL, NULL, 0, 0};
EXCEPINFO ExcepInfo;
HRESULT hrCopy;
VariantInit(pVarOut);
hrCopy = VariantCopy(pVarOut, pVarIn);
if (FAILED(hrCopy))
{
return hrCopy;
}
// follow the IDispatch chain.
//
while (V_VT(pVarOut) == VT_DISPATCH)
{
HRESULT hrInvoke = S_OK;
// If the variant is equal to Nothing, then it can be argued
// with certainty that it does not have a default property!
// hence we return DISP_E_MEMBERNOTFOUND for this case.
//
if (V_DISPATCH(pVarOut) == NULL)
{
hrInvoke = DISP_E_MEMBERNOTFOUND;
}
else
{
VariantInit(&varResolved);
hrInvoke = V_DISPATCH(pVarOut)->Invoke(
DISPID_VALUE,
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_PROPERTYGET | DISPATCH_METHOD,
&dispParamsNoArgs,
&varResolved,
&ExcepInfo,
NULL);
}
if (FAILED(hrInvoke))
{
if (hrInvoke == DISP_E_EXCEPTION)
{
//
// forward the ExcepInfo from Invoke to caller's ExcepInfo
//
SysFreeString(ExcepInfo.bstrHelpFile);
}
VariantClear(pVarOut);
return hrInvoke;
}
// The correct code to restart the loop is:
//
// VariantClear(pVar)
// VariantCopy(pVar, &varResolved);
// VariantClear(&varResolved);
//
// however, the same affect can be achieved by:
//
// VariantClear(pVar)
// *pVar = varResolved;
// VariantInit(&varResolved)
//
// this avoids a copy. The equivalence rests in the fact that
// *pVar will contain the pointers of varResolved, after we
// trash varResolved (WITHOUT releasing strings or dispatch
// pointers), so the net ref count is unchanged. For strings,
// there is still only one pointer to the string.
//
// NOTE: the next interation of the loop will do the VariantInit.
//
VariantClear(pVarOut);
*pVarOut = varResolved;
}
return S_OK;
}
STDMETHODIMP
CIISDsCrMap::NonDelegatingQueryInterface(
REFIID iid,
LPVOID FAR* ppv
)
{
ASSERT(ppv);
if (IsEqualIID(iid, IID_IISDsCrMap)) {
*ppv = (IADsUser FAR *) this;
} else if (IsEqualIID(iid, IID_IADsExtension)) {
*ppv = (IADsExtension FAR *) this;
} else if (IsEqualIID(iid, IID_IUnknown)) {
//
// probably not needed since our 3rd party extension does not stand
// alone and provider does not ask for this, but to be safe
//
*ppv = (INonDelegatingUnknown FAR *) this;
} else {
*ppv = NULL;
return E_NOINTERFACE;
}
//
// Delegating AddRef to aggregator for IADsExtesnion and IISDsCrMap.
// AddRef on itself for IPrivateUnknown. (both tested.)
//
((IUnknown *) (*ppv)) -> AddRef();
return S_OK;
}
//
// IADsExtension::Operate()
//
STDMETHODIMP
CIISDsCrMap::Operate(
THIS_ DWORD dwCode,
VARIANT varUserName,
VARIANT varPassword,
VARIANT varFlags
)
{
RRETURN(E_NOTIMPL);
}
STDMETHODIMP
CIISDsCrMap::ADSIInitializeDispatchManager(
long dwExtensionId
)
{
HRESULT hr = S_OK;
if (_fDispInitialized) {
RRETURN(E_FAIL);
}
hr = _pDispMgr->InitializeDispMgr(dwExtensionId);
if (SUCCEEDED(hr)) {
_fDispInitialized = TRUE;
}
RRETURN(hr);
}
STDMETHODIMP
CIISDsCrMap::ADSIInitializeObject(
THIS_ BSTR lpszUserName,
BSTR lpszPassword,
long lnReserved
)
{
CCredentials NewCredentials(lpszUserName, lpszPassword, lnReserved);
m_Credentials = NewCredentials;
RRETURN(S_OK);
}
STDMETHODIMP
CIISDsCrMap::ADSIReleaseObject()
{
delete this;
RRETURN(S_OK);
}