|
|
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
crmap.cxx
Abstract:
ADSIIS cert mapper object
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 32
//
// Local functions
//
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 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
--*/ { 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
--*/ { 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
--*/ { 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
--*/ { 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
--*/ { 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
--*/ { 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
--*/ { 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_MAPPWD) ? 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
--*/ { 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; }
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
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) { 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 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;
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
//
memset(pObjectInfo, 0, sizeof(OBJECTINFO)); 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; 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;
cL = wcslen( pszServerName ); if ( m_pszServerName = (LPWSTR)LocalAlloc( LMEM_FIXED, ( cL + 1 )*sizeof(WCHAR) ) ) { memcpy( m_pszServerName, pszServerName, ( cL + 1 )*sizeof(WCHAR) ); } else { return E_OUTOFMEMORY; }
cL = wcslen( pszMetabasePath ); while ( cL && pszMetabasePath[cL-1] != L'/' && pszMetabasePath[cL-1] != L'\\' ) { --cL; } if ( 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 { return E_OUTOFMEMORY; }
return InitServerInfo(pszServerName, &m_pcAdmCom); }
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 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); }
|