//////////////////////////////////////////////////// // // Copyright (c) 1997 Microsoft Corporation // // Module Name: certmap.cpp // // Abstract: IIS privider cert mapper object methods // // Author: Philippe Choquier (phillich) 10-Apr-1997 // // History: Zeyong Xu borrowed the source code from ADSI object // (created by Philippe Choquier at 10-Apr-1997) at 20-Oct-1999 // /////////////////////////////////////////////////// #include "iisprov.h" #include "certmap.h" const ULONG MAX_CERT_KEY_LEN = 32; // // CCertMapperMethod // CCertMapperMethod::CCertMapperMethod(LPCWSTR pszMetabasePathIn) { DBG_ASSERT(pszMetabasePathIn != NULL); m_hmd = NULL; HRESULT hr = CoCreateInstance( CLSID_MSAdminBase, NULL, CLSCTX_ALL, IID_IMSAdminBase, (void**)&m_pIABase ); THROW_ON_ERROR(hr); hr = Init(pszMetabasePathIn); THROW_ON_ERROR(hr); } CCertMapperMethod::~CCertMapperMethod() { if ( m_pszMetabasePath ) { free( m_pszMetabasePath ); } if(m_pIABase) m_pIABase->Release(); } // // CreateMapping(): 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 // HRESULT CCertMapperMethod::CreateMapping( VARIANT vCert, BSTR bstrNtAcct, BSTR bstrNtPwd, BSTR bstrName, LONG lEnabled ) { HRESULT hr; 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[MAX_CERT_KEY_LEN]; VARIANT vOldAcct; VARIANT vOldCert; VARIANT vOldPwd; VARIANT vOldName; VARIANT vOldEnabledFlag; PCCERT_CONTEXT pcCert = NULL; // // Do some sanity checks on the cert // if ( SUCCEEDED( hr = GetStringFromVariant( &vCert, (LPSTR*)&pbCert, &cCert, FALSE ) ) ) { // // try to construct a cert context // if ( !( pcCert = CertCreateCertificateContext( X509_ASN_ENCODING, pbCert, cCert ) ) ) { // // 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 // hr = RETURNCODETOHRESULT( E_INVALIDARG ); FreeString( (LPSTR) pbCert ); pbCert = NULL; return hr; } CertFreeCertificateContext( pcCert ); } else { DBG_ASSERT(pbCert == NULL); return hr; } // // check if we already have a mapping for this cert; if we do, we'll replace that mapping // with the new one // if ( SUCCEEDED( hr = GetMapping( IISMAPPER_LOCATE_BY_CERT, vCert, &vOldCert, &vOldAcct, &vOldPwd, &vOldName, &vOldEnabledFlag ) ) ) { if ( FAILED( hr = SetName( IISMAPPER_LOCATE_BY_CERT, vCert, bstrName ) ) || FAILED( hr = SetAcct( IISMAPPER_LOCATE_BY_CERT, vCert, bstrNtAcct ) ) || FAILED( hr = SetPwd( IISMAPPER_LOCATE_BY_CERT, vCert, bstrNtPwd ) ) || FAILED( hr = SetEnabled( IISMAPPER_LOCATE_BY_CERT, vCert, lEnabled ) ) ) { hr; //NOP - Something failed } } // // New mapping // else if ( hr == RETURNCODETOHRESULT( ERROR_PATH_NOT_FOUND ) ) { // // check mapping exists, create if not // hr = OpenMd( L"Cert11", METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ); if ( hr == RETURNCODETOHRESULT( ERROR_PATH_NOT_FOUND ) ) { if ( SUCCEEDED( hr = OpenMd( L"", METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ) ) ) { hr = CreateMdObject( L"Cert11" ); CloseMd( FALSE ); // Reopen to the correct node. hr = OpenMd( L"Cert11", METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ); } } if ( FAILED( hr ) ) { return hr; } // // adding mapping cert "0" means add @ end of list // if ( SUCCEEDED( hr = CreateMdObject( L"mappings/0" ) ) ) { if ( SUCCEEDED( hr = GetMdData( L"", MD_NSEPM_ACCESS_CERT, DWORD_METADATA, & cRes, &pRes ) ) ) { if ( cRes == sizeof(DWORD ) ) { _snwprintf( achIndex, MAX_CERT_KEY_LEN, L"mappings/%u", *(LPDWORD)pRes ); if ( FAILED( hr = GetStringFromBSTR( bstrNtAcct, &pszNtAcct, &cNtAcct ) ) || FAILED( hr = GetStringFromBSTR( bstrNtPwd, &pszNtPwd, &cNtPwd ) ) || FAILED( hr = GetStringFromBSTR( bstrName, &pszName, &cName ) ) || FAILED( hr = SetMdData( achIndex, MD_MAPENABLED, DWORD_METADATA, sizeof(DWORD), (LPBYTE)&lEnabled ) ) || FAILED( hr = SetMdData( achIndex, MD_MAPNAME, STRING_METADATA, cName, (LPBYTE)pszName ) ) || FAILED( hr = SetMdData( achIndex, MD_MAPNTPWD, STRING_METADATA, cNtPwd, (LPBYTE)pszNtPwd ) ) || FAILED( hr = SetMdData( achIndex, MD_MAPNTACCT, STRING_METADATA, cNtAcct, (LPBYTE)pszNtAcct ) ) || FAILED( hr = SetMdData( achIndex, MD_MAPCERT, BINARY_METADATA, cCert, (LPBYTE)pbCert ) ) ) { } } else { hr = E_FAIL; } } } } CloseMd( SUCCEEDED( hr ) ); FreeString( (LPSTR)pbCert ); FreeString( pszNtAcct ); FreeString( pszNtPwd ); FreeString( pszName ); return hr; } // // GetMapping: 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 // HRESULT CCertMapperMethod::GetMapping( LONG lMethod, VARIANT vKey, VARIANT* pvCert, VARIANT* pbstrNtAcct, VARIANT* pbstrNtPwd, VARIANT* pbstrName, VARIANT* plEnabled ) { WCHAR achIndex[MAX_CERT_KEY_LEN]; HRESULT hr; DWORD dwLen; LPBYTE pbData; VariantInit( pvCert ); VariantInit( pbstrNtAcct ); VariantInit( pbstrNtPwd ); VariantInit( pbstrName ); VariantInit( plEnabled ); if ( SUCCEEDED( hr = OpenMd( L"Cert11", METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ) ) ) { if ( SUCCEEDED(hr = Locate( lMethod, vKey, achIndex )) ) { if ( SUCCEEDED( hr = GetMdData( achIndex, MD_MAPCERT, BINARY_METADATA, &dwLen, &pbData ) ) ) { hr = SetVariantAsByteArray( pvCert, dwLen, pbData ); free( pbData ); } else { CloseMd( FALSE ); return hr; } if ( SUCCEEDED( hr = GetMdData( achIndex, MD_MAPNTACCT, STRING_METADATA, &dwLen, &pbData ) ) ) { hr = SetVariantAsBSTR( pbstrNtAcct, dwLen, pbData ); free( pbData ); } else { CloseMd( FALSE ); return hr; } if ( SUCCEEDED( hr = GetMdData( achIndex, MD_MAPNTPWD, STRING_METADATA, &dwLen, &pbData ) ) ) { hr = SetVariantAsBSTR( pbstrNtPwd, dwLen, pbData ); free( pbData ); } else { CloseMd( FALSE ); return hr; } if ( SUCCEEDED( hr = GetMdData( achIndex, MD_MAPNAME, STRING_METADATA, &dwLen, &pbData ) ) ) { hr = SetVariantAsBSTR( pbstrName, dwLen, pbData ); free( pbData ); } else { CloseMd( FALSE ); return hr; } if ( FAILED( hr = GetMdData( achIndex, MD_MAPENABLED, STRING_METADATA, &dwLen, &pbData ) ) ) { SetVariantAsLong( plEnabled, FALSE ); } else { SetVariantAsLong( plEnabled, *(LPDWORD)pbData ); free( pbData ); } } CloseMd( FALSE ); } return hr; } // // Delete a mapping entry using key // HRESULT CCertMapperMethod::DeleteMapping( LONG lMethod, VARIANT vKey ) { WCHAR achIndex[MAX_CERT_KEY_LEN]; HRESULT hr; if ( SUCCEEDED( hr = OpenMd( L"Cert11", METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ) ) ) { if ( SUCCEEDED(hr = Locate( lMethod, vKey, achIndex )) ) { hr = DeleteMdObject( achIndex ); } CloseMd( TRUE ); } return hr; } // // Set the enable flag on a mapping entry using key // HRESULT CCertMapperMethod::SetEnabled( LONG lMethod, VARIANT vKey, LONG lEnabled ) { WCHAR achIndex[MAX_CERT_KEY_LEN]; HRESULT hr; if ( SUCCEEDED( hr = OpenMd( L"Cert11", METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ) ) ) { if ( SUCCEEDED(hr = Locate( lMethod, vKey, achIndex )) ) { hr = SetMdData( achIndex, MD_MAPENABLED, DWORD_METADATA, sizeof(DWORD), (LPBYTE)&lEnabled ); } CloseMd( TRUE ); } return hr; } // // Set the Name on a mapping entry using key // HRESULT CCertMapperMethod::SetName( LONG lMethod, VARIANT vKey, BSTR bstrName ) { return SetString( lMethod, vKey, bstrName, MD_MAPNAME ); } // // Set a string property on a mapping entry using key // HRESULT CCertMapperMethod::SetString( LONG lMethod, VARIANT vKey, BSTR bstrName, DWORD dwProp ) { WCHAR achIndex[MAX_CERT_KEY_LEN]; LPSTR pszName = NULL; HRESULT hr; DWORD dwLen; if ( FAILED( hr = GetStringFromBSTR( bstrName, &pszName, &dwLen, TRUE ) ) ) { return hr; } if ( SUCCEEDED( hr = OpenMd( L"Cert11", METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ ) ) ) { if ( SUCCEEDED(hr = Locate( lMethod, vKey, achIndex )) ) { hr = SetMdData( achIndex, dwProp, STRING_METADATA, dwLen, (LPBYTE)pszName ); } CloseMd( TRUE ); } FreeString( pszName ); return hr; } // // Set the Password on a mapping entry using key // HRESULT CCertMapperMethod::SetPwd( LONG lMethod, VARIANT vKey, BSTR bstrPwd ) { return SetString( lMethod, vKey, bstrPwd, MD_MAPNTPWD ); } // // Set the NT account name on a mapping entry using key // HRESULT CCertMapperMethod::SetAcct( LONG lMethod, VARIANT vKey, BSTR bstrAcct ) { return SetString( lMethod, vKey, bstrAcct, MD_MAPNTACCT ); } HRESULT CCertMapperMethod::OpenMd( LPWSTR pszOpenPath, DWORD dwPermission ) { HRESULT hr; LPWSTR pszPath; UINT cL = wcslen( m_pszMetabasePath ); pszPath = (LPWSTR)malloc( (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 ); hr = OpenAdminBaseKey( pszPath, dwPermission ); free( pszPath ); return hr; } HRESULT CCertMapperMethod::CloseMd( BOOL fSave ) { CloseAdminBaseKey(); m_hmd = NULL; if ( m_pIABase && fSave ) { m_pIABase->SaveData(); } return S_OK; } HRESULT CCertMapperMethod::DeleteMdObject( LPWSTR pszKey ) { return m_pIABase->DeleteKey( m_hmd, pszKey ); } HRESULT CCertMapperMethod::CreateMdObject( LPWSTR pszKey ) { return m_pIABase->AddKey( m_hmd, pszKey ); } HRESULT CCertMapperMethod::SetMdData( LPWSTR achIndex, DWORD dwProp, DWORD dwDataType, DWORD dwDataLen, LPBYTE pbData ) { 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_pIABase->SetData( m_hmd, achIndex, &md ); } HRESULT CCertMapperMethod::GetMdData( LPWSTR achIndex, DWORD dwProp, DWORD dwDataType, LPDWORD pdwDataLen, LPBYTE* ppbData ) { HRESULT hr; METADATA_RECORD md; DWORD dwRequired; md.dwMDDataLen = 0; md.dwMDDataType = dwDataType; md.dwMDIdentifier = dwProp; md.dwMDAttributes = 0; md.pbMDData = NULL; if ( FAILED(hr = m_pIABase->GetData( m_hmd, achIndex, &md, &dwRequired )) ) { if ( hr == RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER) ) { if ( (*ppbData = (LPBYTE)malloc(dwRequired)) == NULL ) { return E_OUTOFMEMORY; } md.pbMDData = *ppbData; md.dwMDDataLen = dwRequired; hr = m_pIABase->GetData( m_hmd, achIndex, &md, &dwRequired ); *pdwDataLen = md.dwMDDataLen; } } else { *pdwDataLen = 0; *ppbData = NULL; } return hr; } // // Locate a mapping entry based on key // OpenMd() must be called 1st // HRESULT CCertMapperMethod::Locate( LONG lMethod, VARIANT vKey, LPWSTR pszResKey ) { HRESULT hr; 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( hr = GetStringFromVariant( &vKey, &pV, &cV, TRUE ) ) ) { wsprintfW( pszResKey, L"mappings/%s", pV ); } FreeString( pV ); return hr; default: return E_FAIL; } // // get ptr to data // if ( SUCCEEDED( hr = GetStringFromVariant( &vKey, &pV, &cV, fAddDelim ) ) ) { // // set search prop, get result // if ( SUCCEEDED( hr = SetMdData( L"", dwProp, BINARY_METADATA, cV, (LPBYTE)pV ) ) ) { if ( SUCCEEDED( hr = GetMdData( L"", dwProp, DWORD_METADATA, &cRes, (LPBYTE*)&pRes ) ) ) { if ( cRes == sizeof(DWORD ) ) { wsprintfW( pszResKey, L"mappings/%u", *(LPDWORD)pRes ); } else { hr = E_FAIL; } free( pRes ); } } } FreeString( pV ); return hr; } // // GetStringFromBSTR: 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 // HRESULT CCertMapperMethod::GetStringFromBSTR( BSTR bstr, LPSTR* psz, LPDWORD pdwLen, BOOL fAddDelimInCount ) { UINT cch = SysStringLen(bstr); UINT cchT; // include NULL terminator *pdwLen = cch + (fAddDelimInCount ? 1 : 0); CHAR *szNew = (CHAR*)malloc((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; } // // GetStringFromVariant: 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 // HRESULT CCertMapperMethod::GetStringFromVariant( VARIANT* pVar, LPSTR* psz, LPDWORD pdwLen, BOOL fAddDelim ) { LPBYTE pbV = NULL; UINT cV; HRESULT hr; WORD vt = V_VT(pVar); BOOL fByRef = FALSE; VARIANT vOut; // Set out params to 0 *psz = NULL; *pdwLen = 0; VariantInit( &vOut ); if ( vt & VT_BYREF ) { vt &= ~VT_BYREF; fByRef = TRUE; } // 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 ) { hr = 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 ); hr = SafeArrayGetLBound(pSafeArray, 1, &lBound); hr = SafeArrayGetUBound(pSafeArray, 1, &uBound); cV = uBound - lBound + 1; if ( !(pbV = (LPBYTE)malloc(cV)) ) { hr = E_OUTOFMEMORY; VariantClear( &vOut ); return hr; } hr = S_OK; for( lItem = lBound; lItem <= uBound ; lItem++ ) { hr = SafeArrayGetElement( pSafeArray, &lItem, &bValue ); if( FAILED( hr ) ) { 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 ); hr = SafeArrayGetLBound(pSafeArray, 1, &lBound); hr = SafeArrayGetUBound(pSafeArray, 1, &uBound); cV = uBound - lBound + 1; if ( !(pbV = (LPBYTE)malloc(cV)) ) { hr = E_OUTOFMEMORY; VariantClear( &vOut ); return hr; } hr = S_OK; for( lItem = lBound; lItem <= uBound ; lItem++ ) { hr = SafeArrayGetElement( pSafeArray, &lItem, &vValue ); if( FAILED( hr ) ) { 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 { hr = E_FAIL; } VariantClear( &vOut ); if(FAILED(hr)) { *psz = NULL; *pdwLen = 0; free(pbV); pbV = NULL; } return hr; } VOID CCertMapperMethod::FreeString( LPSTR psz ) { if ( psz ) { free( psz ); } } HRESULT CCertMapperMethod::SetBSTR( BSTR* pbstrRet, DWORD cch, LPBYTE sz ) { 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; } } bstrRet[cch] = 0; *pbstrRet = bstrRet; return(NOERROR); } HRESULT CCertMapperMethod::Init( LPCWSTR pszMetabasePath ) { DBG_ASSERT(pszMetabasePath != NULL); UINT cL; cL = wcslen( pszMetabasePath ); while ( cL && pszMetabasePath[cL-1] != L'/' && pszMetabasePath[cL-1] != L'\\' ) { --cL; } if ( m_pszMetabasePath = (LPWSTR)malloc( cL*sizeof(WCHAR) + sizeof(L"") ) ) { memcpy( m_pszMetabasePath, pszMetabasePath, cL * sizeof(WCHAR) ); memcpy( m_pszMetabasePath + cL, L"", sizeof(L"") ); } else { return E_OUTOFMEMORY; } return S_OK; } HRESULT CCertMapperMethod::SetVariantAsByteArray( VARIANT* pvarReturn, DWORD cbLen, LPBYTE pbIn ) { 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 CCertMapperMethod::SetVariantAsBSTR( VARIANT* pvarReturn, DWORD cbLen, LPBYTE pbIn ) { V_VT(pvarReturn) = VT_BSTR; return SetBSTR( &V_BSTR(pvarReturn), cbLen, pbIn ); } HRESULT CCertMapperMethod::SetVariantAsLong( VARIANT* pvarReturn, DWORD dwV ) { V_VT(pvarReturn) = VT_I4; V_I4(pvarReturn) = dwV; return S_OK; } HRESULT CCertMapperMethod::OpenAdminBaseKey( LPWSTR pszPathName, DWORD dwAccessType ) { if(m_hmd) CloseAdminBaseKey(); HRESULT t_hr = m_pIABase->OpenKey( METADATA_MASTER_ROOT_HANDLE, pszPathName, dwAccessType, DEFAULT_TIMEOUT_VALUE, // 30 seconds &m_hmd ); if(FAILED(t_hr)) m_hmd = NULL; return t_hr; } VOID CCertMapperMethod::CloseAdminBaseKey() { if(m_hmd && m_pIABase) { m_pIABase->CloseKey(m_hmd); m_hmd = NULL; } }