windows-nt/Source/XPSP1/NT/inetsrv/iis/admin/adsi/iisext/crmap.cxx
2020-09-26 16:20:57 +08:00

1989 lines
40 KiB
C++

/*++
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);
}