//--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 1997 // // File: common.cxx // // Contents: Microsoft ADs IIS Common routines // // History: 28-Feb-97 SophiaC Created. // //---------------------------------------------------------------------------- #include "iis.hxx" extern SERVER_CACHE * g_pServerCache; extern WIN32_CRITSEC * g_pGlobalLock; #pragma hdrstop FILTERS Filters[] = { {L"user", IIS_USER_ID}, {L"group", IIS_GROUP_ID}, {L"queue", IIS_PRINTER_ID}, {L"domain", IIS_DOMAIN_ID}, {L"computer", IIS_COMPUTER_ID}, {L"service", IIS_SERVICE_ID}, {L"fileservice", IIS_FILESERVICE_ID}, {L"fileshare", IIS_FILESHARE_ID}, {L"class", IIS_CLASS_ID}, {L"functionalset", IIS_FUNCTIONALSET_ID}, {L"syntax", IIS_SYNTAX_ID}, {L"property", IIS_PROPERTY_ID}, {L"tree", IIS_TREE_ID}, {L"Organizational Unit", IIS_OU_ID}, {L"Organization", IIS_O_ID}, {L"Locality", IIS_LOCALITY_ID} }; #define MAX_FILTERS (sizeof(Filters)/sizeof(FILTERS)) #define DEFAULT_TIMEOUT_VALUE 30000 PFILTERS gpFilters = Filters; DWORD gdwMaxFilters = MAX_FILTERS; extern WCHAR * szProviderName; //+------------------------------------------------------------------------ // // Class: Common // // Purpose: Contains Winnt routines and properties that are common to // all Winnt objects. Winnt objects get the routines and // properties through C++ inheritance. // //------------------------------------------------------------------------- HRESULT BuildADsPath( BSTR Parent, BSTR Name, BSTR *pADsPath ) { LPWSTR lpADsPath = NULL; WCHAR ProviderName[MAX_PATH]; HRESULT hr = S_OK; DWORD dwLen = 0; // // We will assert if bad parameters are passed to us. // This is because this should never be the case. This // is an internal call // ADsAssert(Parent && Name); ADsAssert(pADsPath); // // Special case the Namespace object; if // the parent is L"ADs:", then Name = ADsPath // if (!_wcsicmp(Parent, L"ADs:")) { RRETURN(ADsAllocString( Name, pADsPath)); } // // Allocate the right side buffer // 2 for // + a buffer of MAX_PATH // dwLen = (DWORD)(wcslen(Parent) + wcslen(Name)) + 2 + MAX_PATH; lpADsPath = (LPWSTR)AllocADsMem(dwLen*sizeof(WCHAR)); if (!lpADsPath) { RRETURN(E_OUTOFMEMORY); } // // The rest of the cases we expect valid data, // Path, Parent and Name are read-only, the end-user // cannot modify this data // // // For the first object, the domain object we do not add // the first backslash; so we examine that the parent is // L"WinNT:" and skip the slash otherwise we start with // the slash // wsprintf(ProviderName, L"%s:", szProviderName); wcscpy(lpADsPath, Parent); if (_wcsicmp(lpADsPath, ProviderName)) { wcscat(lpADsPath, L"/"); }else { wcscat(lpADsPath, L"//"); } wcscat(lpADsPath, Name); hr = ADsAllocString( lpADsPath, pADsPath); if (lpADsPath) { FreeADsMem(lpADsPath); } RRETURN(hr); } HRESULT BuildSchemaPath( BSTR bstrADsPath, BSTR bstrClass, BSTR *pSchemaPath ) { WCHAR ADsSchema[MAX_PATH]; OBJECTINFO ObjectInfo; POBJECTINFO pObjectInfo = &ObjectInfo; CLexer Lexer(bstrADsPath); HRESULT hr = S_OK; memset(pObjectInfo, 0, sizeof(OBJECTINFO)); wcscpy(ADsSchema, L""); memset(pObjectInfo, 0, sizeof(OBJECTINFO)); if (bstrClass && *bstrClass) { hr = ADsObject(&Lexer, pObjectInfo); BAIL_ON_FAILURE(hr); if (pObjectInfo->TreeName) { wsprintf(ADsSchema,L"%s://",pObjectInfo->ProviderName); wcscat(ADsSchema, pObjectInfo->TreeName); wcscat(ADsSchema,L"/schema/"); wcscat(ADsSchema, bstrClass); } } hr = ADsAllocString( ADsSchema, pSchemaPath); error: if (pObjectInfo) { FreeObjectInfo( pObjectInfo ); } RRETURN(hr); } HRESULT BuildADsGuid( REFCLSID clsid, BSTR *pADsClass ) { WCHAR ADsClass[MAX_PATH]; StringFromGUID2(clsid, ADsClass, 256); RRETURN(ADsAllocString( ADsClass, pADsClass)); } HRESULT ValidateOutParameter( BSTR * retval ) { if (!retval) { RRETURN(E_ADS_BAD_PARAMETER); } RRETURN(S_OK); } HRESULT OpenAdminBaseKey( IN CCredentials& Credentials, IN LPWSTR pszServerName, IN LPWSTR pszPathName, IN DWORD dwAccessType, IN OUT IMSAdminBase **ppAdminBase, OUT METADATA_HANDLE *phHandle ) { HRESULT hr; IMSAdminBase *pAdminBase = *ppAdminBase; METADATA_HANDLE RootHandle = NULL; DWORD dwThreadId; hr = pAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE, pszPathName, dwAccessType, DEFAULT_TIMEOUT_VALUE, &RootHandle ); if (FAILED(hr)) { if ((HRESULT_CODE(hr) == RPC_S_SERVER_UNAVAILABLE) || ((HRESULT_CODE(hr) >= RPC_S_NO_CALL_ACTIVE) && (HRESULT_CODE(hr) <= RPC_S_CALL_FAILED_DNE)) || hr == RPC_E_DISCONNECTED) { SERVER_CACHE_ITEM * item = NULL; IMSAdminBase * pOldAdminBase = pAdminBase; // // RPC error, try to recover connection // hr = InitAdminBase(Credentials, pszServerName, &pAdminBase); BAIL_ON_FAILURE(hr); *ppAdminBase = pAdminBase; hr = pAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE, pszPathName, dwAccessType, DEFAULT_TIMEOUT_VALUE, &RootHandle ); // // update cache item // dwThreadId = GetCurrentThreadId(); item = g_pServerCache->Find(pszServerName, dwThreadId); ASSERT(item != NULL); if (item != NULL) { UninitAdminBase(pOldAdminBase); item->UpdateAdminBase(pAdminBase, dwThreadId); } } } error : if (FAILED(hr)) { if (pAdminBase && RootHandle) { pAdminBase->CloseKey(RootHandle); } } else { *phHandle = RootHandle; } RRETURN(hr); } VOID CloseAdminBaseKey( IN IMSAdminBase *pAdminBase, IN METADATA_HANDLE hHandle ) { HRESULT hr; if (pAdminBase) { hr = pAdminBase->CloseKey(hHandle); } return; } HRESULT MetaBaseGetAllData( IN IMSAdminBase *pAdminBase, IN METADATA_HANDLE hObjHandle, IN LPWSTR pszIISPathName, IN DWORD dwMDAttributes, IN DWORD dwMDUserType, IN DWORD dwMDDataType, OUT PDWORD pdwMDNumDataEntries, OUT PDWORD pdwMDDataSetNumber, OUT LPBYTE * ppBuffer ) { LPBYTE pBuffer = NULL; HRESULT hr = S_OK; DWORD dwBufferSize = 0; DWORD dwReqdBufferSize = 0; hr = pAdminBase->GetAllData( hObjHandle, pszIISPathName, dwMDAttributes, dwMDUserType, dwMDDataType, pdwMDNumDataEntries, pdwMDDataSetNumber, dwBufferSize, (LPBYTE)"", &dwReqdBufferSize ); pBuffer = (LPBYTE) AllocADsMem(dwReqdBufferSize); if (!pBuffer) { hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } dwBufferSize = dwReqdBufferSize; hr = pAdminBase->GetAllData( hObjHandle, pszIISPathName, dwMDAttributes, dwMDUserType, dwMDDataType, pdwMDNumDataEntries, pdwMDDataSetNumber, dwBufferSize, pBuffer, &dwReqdBufferSize ); BAIL_ON_FAILURE(hr); *ppBuffer = pBuffer; RRETURN(hr); error: if (pBuffer) { FreeADsMem(pBuffer); } RRETURN(hr); } HRESULT MetaBaseSetAllData( IN IMSAdminBase *pAdminBase, IN METADATA_HANDLE hObjHandle, IN LPWSTR pszIISPathName, IN PMETADATA_RECORD pMetaDataArray, IN DWORD dwNumEntries ) { HRESULT hr = S_OK; PMETADATA_RECORD pTemp = NULL; METADATA_RECORD mdrMDData; DWORD i; // // Set each METADATA record one at a time // for (i = 0; i < dwNumEntries; i++) { pTemp = pMetaDataArray + i; mdrMDData.dwMDIdentifier = pTemp->dwMDIdentifier; mdrMDData.dwMDAttributes = pTemp->dwMDAttributes; mdrMDData.dwMDUserType = pTemp->dwMDUserType; mdrMDData.dwMDDataType = pTemp->dwMDDataType; mdrMDData.dwMDDataLen = pTemp->dwMDDataLen; mdrMDData.dwMDDataTag = pTemp->dwMDDataTag; mdrMDData.pbMDData = pTemp->pbMDData; hr = pAdminBase->SetData( hObjHandle, pszIISPathName, &mdrMDData ); BAIL_ON_FAILURE(hr); } error: RRETURN(hr); } HRESULT MetaBaseDeleteObject( IN IMSAdminBase * pAdminBase, IN METADATA_HANDLE hObjHandle, IN LPWSTR pszIISPathName ) { HRESULT hr = S_OK; hr = pAdminBase->DeleteKey( hObjHandle, pszIISPathName ); RRETURN(hr); } HRESULT MetaBaseCreateObject( IN IMSAdminBase * pAdminBase, IN METADATA_HANDLE hObjHandle, IN LPWSTR pszIISPathName ) { HRESULT hr = S_OK; hr = pAdminBase->AddKey( hObjHandle, pszIISPathName ); RRETURN(hr); } HRESULT MetaBaseCopyObject( IN IMSAdminBase * pAdminBase, IN METADATA_HANDLE hSrcObjHandle, IN LPWSTR pszIISSrcPathName, IN METADATA_HANDLE hDestObjHandle, IN LPWSTR pszIISDestPathName ) { HRESULT hr = S_OK; hr = pAdminBase->CopyKey( hSrcObjHandle, pszIISSrcPathName, hDestObjHandle, pszIISDestPathName, TRUE, TRUE ); RRETURN(hr); } HRESULT MetaBaseMoveObject( IN IMSAdminBase * pAdminBase, IN METADATA_HANDLE hSrcObjHandle, IN LPWSTR pszIISSrcPathName, IN METADATA_HANDLE hDestObjHandle, IN LPWSTR pszIISDestPathName ) { HRESULT hr = S_OK; hr = pAdminBase->CopyKey( hSrcObjHandle, pszIISSrcPathName, hDestObjHandle, pszIISDestPathName, FALSE, FALSE ); RRETURN(hr); } HRESULT MetaBaseGetAdminACL( IN IMSAdminBase * pAdminBase, IN METADATA_HANDLE hObjHandle, IN LPWSTR pszIISPathName, OUT LPBYTE *ppBuffer ) { HRESULT hr = S_OK; DWORD dwBufferSize = 0; METADATA_RECORD mdrMDData; LPBYTE pBuffer = NULL; MD_SET_DATA_RECORD(&mdrMDData, MD_ADMIN_ACL, // admin acl METADATA_INHERIT, IIS_MD_UT_FILE, BINARY_METADATA, dwBufferSize, pBuffer); hr = pAdminBase->GetData( hObjHandle, pszIISPathName, &mdrMDData, &dwBufferSize ); pBuffer = (LPBYTE) AllocADsMem(dwBufferSize); if (!pBuffer) { hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } MD_SET_DATA_RECORD(&mdrMDData, MD_ADMIN_ACL, // admin acl METADATA_INHERIT, IIS_MD_UT_FILE, BINARY_METADATA, dwBufferSize, pBuffer); hr = pAdminBase->GetData( hObjHandle, pszIISPathName, &mdrMDData, &dwBufferSize ); BAIL_ON_FAILURE(hr); *ppBuffer = pBuffer; RRETURN(hr); error: if (pBuffer) { FreeADsMem(pBuffer); } RRETURN(hr); } HRESULT MetaBaseDetectKey( IN IMSAdminBase *pAdminBase, IN LPCWSTR pszIISPathName ) { HRESULT hr = S_OK; FILETIME ft; hr = pAdminBase->GetLastChangeTime( METADATA_MASTER_ROOT_HANDLE, pszIISPathName, &ft, FALSE ); RRETURN(hr); } HRESULT MetaBaseGetADsClass( IN IMSAdminBase *pAdminBase, IN LPWSTR pszIISPathName, IN IIsSchema *pSchema, OUT LPWSTR pszDataBuffer, IN DWORD dwBufferLen ) /*++ Routine Description: Get the ADsClass from the metabase path. Arguments: IN pAdminBase : the metabase IN pszIISPathName : the full metabase path (may be upcased) IN pSchema : schema against which to validate OUT pszDataBuffer : the class name IN dwBufferLen : number of characters allocated for class name Return Value: --*/ { // CODEWORK - There are at least two other places that do essentially // the same thing. It should be possible to replace that code with a // call to this routine HRESULT hr = S_OK; METADATA_HANDLE hObjHandle = NULL; METADATA_RECORD mdrData; DWORD dwReqdBufferLen = 0; hr = pAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE, pszIISPathName, METADATA_PERMISSION_READ, DEFAULT_TIMEOUT_VALUE, &hObjHandle ); BAIL_ON_FAILURE(hr); // // Find out Class Name // mdrData.dwMDIdentifier = MD_KEY_TYPE; mdrData.dwMDDataType = STRING_METADATA; mdrData.dwMDUserType = ALL_METADATA; mdrData.dwMDAttributes = METADATA_INHERIT; mdrData.dwMDDataLen = dwBufferLen * sizeof(WCHAR); mdrData.pbMDData = (PBYTE)pszDataBuffer; hr = pAdminBase->GetData( hObjHandle, L"", &mdrData, &dwReqdBufferLen ); if (FAILED(hr)) { if (hr == MD_ERROR_DATA_NOT_FOUND) { // // If the key does not have a KeyType we will do our best // to guess. This is pretty bogus, but there is existing code // that depends on this behavior. // _wcsupr(pszIISPathName); if (wcsstr(pszIISPathName, L"W3SVC") != NULL) { wcscpy( pszDataBuffer, WEBDIR_CLASS_W ); } else if (wcsstr(pszIISPathName, L"MSFTPSVC") != NULL) { wcscpy( pszDataBuffer, FTPVDIR_CLASS_W ); } else { wcscpy( pszDataBuffer, DEFAULT_SCHEMA_CLASS_W ); } hr = S_FALSE; } else { BAIL_ON_FAILURE(hr); } } else { hr = pSchema->ValidateClassName( pszDataBuffer ); if (hr == E_ADS_UNKNOWN_OBJECT) { wcscpy( pszDataBuffer, DEFAULT_SCHEMA_CLASS_W ); } } error: // // Close the handle now // if (hObjHandle) { CloseAdminBaseKey(pAdminBase, hObjHandle); hObjHandle = NULL; } RRETURN(hr); } static HRESULT GetSchema( CCredentials& Credentials, LPWSTR machineNameW, IIsSchema **out ) /*++ Routine Description: Creates and initializes a new IIsSchema object. Arguments: Return Value: Notes: This routine should only be used internally. If it is necessary to get a reference to the schema for the current machine, use InitServerInfo(). --*/ { IIsSchema *schema=NULL; HRESULT hr = S_OK; schema = new IIsSchema(); if (schema) { hr = schema->InitSchema(machineNameW, Credentials); if (FAILED(hr)) { delete schema; schema = 0; *out = 0; return hr; } } else { return E_OUTOFMEMORY; } *out = schema; return hr; } HRESULT FreeMetaDataRecordArray( PMETADATA_RECORD pMetaDataArray, DWORD dwNumEntries ) { DWORD i; DWORD dwIISType; PMETADATA_RECORD pMetaData; for (i = 0; i < dwNumEntries; i++ ) { pMetaData = pMetaDataArray + i; dwIISType = pMetaData->dwMDDataType; switch(dwIISType) { case DWORD_METADATA: break; case STRING_METADATA: case EXPANDSZ_METADATA: FreeADsStr((LPWSTR)pMetaData->pbMDData); break; case MULTISZ_METADATA: case BINARY_METADATA: FreeADsMem(pMetaData->pbMDData); break; default: break; } } FreeADsMem(pMetaDataArray); RRETURN(S_OK); } HRESULT InitAdminBase( IN CCredentials& Credentials, IN LPWSTR pszServerName, OUT IMSAdminBase **ppAdminBase ) { HRESULT hr = S_OK; COSERVERINFO csiName; COSERVERINFO *pcsiParam = &csiName; IClassFactory * pcsfFactory = NULL; IMSAdminBase * pAdminBase = NULL; IMSAdminBase * pAdminBaseT = NULL; LPWSTR pszUserName = NULL; LPWSTR pszPassword = NULL; hr = Credentials.GetUserName(&pszUserName); if (FAILED(hr)) { return hr; } hr = Credentials.GetPassword(&pszPassword); if (FAILED(hr)) { return hr; } CComAuthInfo localAuthInfo(pszServerName, pszUserName, pszPassword); memset(pcsiParam, 0, sizeof(COSERVERINFO)); pcsiParam = localAuthInfo.CreateServerInfoStruct(); hr = CoGetClassObject( CLSID_MSAdminBase, CLSCTX_SERVER, pcsiParam, IID_IClassFactory, (void**) &pcsfFactory ); BAIL_ON_FAILURE(hr); hr = localAuthInfo.ApplyProxyBlanket(pcsfFactory); BAIL_ON_FAILURE(hr); hr = pcsfFactory->CreateInstance( NULL, IID_IMSAdminBase, (void **) &pAdminBaseT ); BAIL_ON_FAILURE(hr); hr = localAuthInfo.ApplyProxyBlanket(pAdminBaseT); BAIL_ON_FAILURE(hr); hr = pAdminBaseT->UnmarshalInterface((IMSAdminBaseW **)&pAdminBase); pAdminBaseT->Release(); pAdminBaseT = NULL; BAIL_ON_FAILURE(hr); hr = localAuthInfo.ApplyProxyBlanket(pAdminBase); BAIL_ON_FAILURE(hr); *ppAdminBase = pAdminBase; localAuthInfo.FreeServerInfoStruct(pcsiParam); error: if (pcsfFactory) { pcsfFactory->Release(); } RRETURN(hr); } VOID UninitAdminBase( IN IMSAdminBase * pAdminBase ) { if (pAdminBase != NULL) { pAdminBase->Release(); } } HRESULT InitServerInfo( IN CCredentials& Credentials, IN LPWSTR pszServerName, OUT IMSAdminBase ** ppObject, OUT IIsSchema **ppSchema ) { HRESULT hr = S_OK; IMSAdminBase * pAdminBase = NULL; IIsSchema * pSchema = NULL; SERVER_CACHE_ITEM * item; BOOL Success; DWORD dwThreadId; ASSERT(g_pServerCache != NULL); // // We'll return the localhost machine config to the users if // pszServerName == NULL, e.g. IIS: // if (pszServerName == NULL) { pszServerName = L"Localhost"; } dwThreadId = GetCurrentThreadId(); if ((item = g_pServerCache->Find(pszServerName, dwThreadId)) == NULL) { // // get pAdminBase and pSchema // hr = InitAdminBase(Credentials, pszServerName, &pAdminBase); BAIL_ON_FAILURE(hr); hr = GetSchema(Credentials, pszServerName, &pSchema); if( ERROR_PATH_NOT_FOUND == HRESULT_CODE(hr) || MD_ERROR_DATA_NOT_FOUND == hr ) { // Return custom error. hr = MD_ERROR_IISAO_INVALID_SCHEMA; } BAIL_ON_FAILURE(hr); item = new SERVER_CACHE_ITEM(pszServerName, pAdminBase, pSchema, dwThreadId, Success); if (item == NULL || !Success) { if (item != NULL) { delete pSchema; UninitAdminBase(pAdminBase); delete item; } RRETURN(E_OUTOFMEMORY); // OUT_OF_MEMORY; } if (g_pServerCache->Insert(item) == FALSE) { delete pSchema; UninitAdminBase(pAdminBase); delete item; RRETURN(E_OUTOFMEMORY); // OUT_OF_MEMORY; } } *ppSchema = item->pSchema; *ppObject = item->pAdminBase; error : RRETURN(hr); } HRESULT MetaBaseGetDataPaths( IN IMSAdminBase *pAdminBase, IN METADATA_HANDLE hObjHandle, IN DWORD dwMDMetaID, OUT LPBYTE * ppBuffer ) { LPBYTE pBuffer = NULL; HRESULT hr = S_OK; DWORD dwBufferSize = 0; DWORD dwReqdBufferSize = 0; hr = pAdminBase->GetDataPaths( hObjHandle, (LPWSTR)L"", dwMDMetaID, ALL_METADATA, dwBufferSize, (LPWSTR)L"", &dwReqdBufferSize ); pBuffer = (LPBYTE) AllocADsMem(dwReqdBufferSize*sizeof(WCHAR)); if (!pBuffer) { hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } dwBufferSize = dwReqdBufferSize; hr = pAdminBase->GetDataPaths( hObjHandle, (LPWSTR)L"", dwMDMetaID, ALL_METADATA, dwBufferSize, (LPWSTR)pBuffer, &dwReqdBufferSize ); BAIL_ON_FAILURE(hr); *ppBuffer = pBuffer; RRETURN(hr); error: if (pBuffer) { FreeADsMem(pBuffer); } RRETURN(hr); } HRESULT MakeVariantFromStringArray( LPWSTR pszStr, LPWSTR pszList, VARIANT *pvVariant ) { HRESULT hr = S_OK; SAFEARRAY *aList = NULL; SAFEARRAYBOUND aBound; LPWSTR pszStrList; WCHAR wchPath[MAX_PATH]; if (pszList != NULL) { long nCount = 0; long i = 0; pszStrList = pszList; if (*pszStrList == L'\0') { nCount = 1; pszStrList++; } while (*pszStrList != L'\0') { while (*pszStrList != L'\0') { pszStrList++; } nCount++; pszStrList++; } aBound.lLbound = 0; aBound.cElements = nCount; aList = SafeArrayCreate( VT_VARIANT, 1, &aBound ); if ( aList == NULL ) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } pszStrList = pszList; for (i = 0; i < nCount; i++ ) { VARIANT v; VariantInit(&v); V_VT(&v) = VT_BSTR; if (pszStr) { wcscpy((LPWSTR)wchPath, pszStr); wcscat((LPWSTR)wchPath, pszStrList); hr = ADsAllocString((LPWSTR)wchPath, &(V_BSTR(&v))); } else { hr = ADsAllocString( pszStrList, &(V_BSTR(&v))); } BAIL_ON_FAILURE(hr); hr = SafeArrayPutElement( aList, &i, &v ); VariantClear(&v); BAIL_ON_FAILURE(hr); pszStrList += wcslen(pszStrList) + 1; } VariantInit( pvVariant ); V_VT(pvVariant) = VT_ARRAY | VT_VARIANT; V_ARRAY(pvVariant) = aList; } else { aBound.lLbound = 0; aBound.cElements = 0; aList = SafeArrayCreate( VT_VARIANT, 1, &aBound ); if ( aList == NULL ) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } VariantInit( pvVariant ); V_VT(pvVariant) = VT_ARRAY | VT_VARIANT; V_ARRAY(pvVariant) = aList; } return S_OK; error: if ( aList ) SafeArrayDestroy( aList ); return hr; } HRESULT MakeVariantFromPathArray( LPWSTR pszStr, LPWSTR pszList, VARIANT *pvVariant ) { HRESULT hr = S_OK; SAFEARRAY *aList = NULL; SAFEARRAYBOUND aBound; LPWSTR pszStrList; LPWSTR pszConcatBuffer = NULL; DWORD cbConcatBuffer = 0; DWORD cbRequiredConcatBuffer = 0; DWORD nStrLen = 0; DWORD nPathStrLen = 0; if (pszList != NULL) { // // Count strings in pszList // long nCount = 0; long i = 0; pszStrList = pszList; while (*pszStrList != L'\0') { while (*pszStrList != L'\0') { pszStrList++; } nCount++; pszStrList++; } // // Allocate output array // aBound.lLbound = 0; aBound.cElements = nCount; aList = SafeArrayCreate( VT_VARIANT, 1, &aBound ); if ( aList == NULL ) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } // // Prepare to copy our values from pszList to aList // if( pszStr ) { nStrLen = (DWORD)wcslen( pszStr ); } pszStrList = pszList; while ( *pszStrList != L'\0' ) { VARIANT v; VariantInit(&v); V_VT(&v) = VT_BSTR; if (pszStr) { // // Reallocate our string buffer. Since the strings are // generally increasing in size, we'll allocate more space // than we need so we don't have to reallocate every time. // nPathStrLen = (DWORD)wcslen(pszStrList); cbRequiredConcatBuffer = ( nStrLen + nPathStrLen + 1 ) * sizeof(WCHAR); if( cbRequiredConcatBuffer > cbConcatBuffer ) { pszConcatBuffer = (LPWSTR)ReallocADsMem( pszConcatBuffer, cbConcatBuffer, 2 * cbRequiredConcatBuffer ); if( pszConcatBuffer == NULL ) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } if( cbConcatBuffer == 0 ) { // This is our first time through. wcscpy(pszConcatBuffer, pszStr); } cbConcatBuffer = 2 * cbRequiredConcatBuffer; } // // Copy the returned value into the buffer. // wcscpy(pszConcatBuffer + nStrLen, pszStrList); if (pszConcatBuffer[nStrLen + nPathStrLen - 1] == L'/') { pszConcatBuffer[nStrLen + nPathStrLen - 1] = L'\0'; } hr = ADsAllocString(pszConcatBuffer, &(V_BSTR(&v))); } else { hr = ADsAllocString( pszStrList, &(V_BSTR(&v))); } BAIL_ON_FAILURE(hr); hr = SafeArrayPutElement( aList, &i, &v ); VariantClear(&v); BAIL_ON_FAILURE(hr); pszStrList += wcslen(pszStrList) + 1; i++; } VariantInit( pvVariant ); V_VT(pvVariant) = VT_ARRAY | VT_VARIANT; V_ARRAY(pvVariant) = aList; } else { aBound.lLbound = 0; aBound.cElements = 0; aList = SafeArrayCreate( VT_VARIANT, 1, &aBound ); if ( aList == NULL ) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } VariantInit( pvVariant ); V_VT(pvVariant) = VT_ARRAY | VT_VARIANT; V_ARRAY(pvVariant) = aList; } if( pszConcatBuffer ) { FreeADsMem( pszConcatBuffer ); } return S_OK; error: if( pszConcatBuffer ) { FreeADsMem( pszConcatBuffer ); } if ( aList ) SafeArrayDestroy( aList ); return hr; } HRESULT InitWamAdmin( IN LPWSTR pszServerName, OUT IWamAdmin2 **ppWamAdmin ) { HRESULT hr = S_OK; COSERVERINFO csiName; COSERVERINFO *pcsiParam = &csiName; IClassFactory * pcsfFactory = NULL; IWamAdmin2 * pWamAdmin = NULL; memset(pcsiParam, 0, sizeof(COSERVERINFO)); // // special case to handle "localhost" to work-around ole32 bug // if (pszServerName == NULL || _wcsicmp(pszServerName,L"localhost") == 0) { pcsiParam->pwszName = NULL; } else { pcsiParam->pwszName = pszServerName; } csiName.pAuthInfo = NULL; pcsiParam = &csiName; hr = CoGetClassObject( CLSID_WamAdmin, CLSCTX_SERVER, pcsiParam, IID_IClassFactory, (void**) &pcsfFactory ); BAIL_ON_FAILURE(hr); hr = pcsfFactory->CreateInstance( NULL, IID_IWamAdmin2, (void **) &pWamAdmin ); BAIL_ON_FAILURE(hr); *ppWamAdmin = pWamAdmin; error: if (pcsfFactory) { pcsfFactory->Release(); } RRETURN(hr); } VOID UninitWamAdmin( IN IWamAdmin2 *pWamAdmin ) { if (pWamAdmin != NULL) { pWamAdmin->Release(); } } HRESULT ConvertDispatchToVariantArray( VARIANT varDispatch, PVARIANT * ppVarArray, PDWORD pdwNumVariants ) { HRESULT hr = S_OK; VARIANT vVar; WCHAR* wComma = NULL; WCHAR* wHolder = NULL; DWORD dwNumVariants = 0; VARIANT * pVarArray = NULL; VariantInit(&vVar); hr = VariantCopyInd(&vVar, &varDispatch); BAIL_ON_FAILURE(hr); // Output here is VT_BSTR, of format: "str_1,str_2,str_3, ... str_n\0" hr = VariantChangeType( &vVar, &vVar, 0, VT_BSTR ); BAIL_ON_FAILURE(hr); // count the number of comma separated entries wHolder = wComma = vVar.bstrVal; while (wComma) { wComma = wcsstr(wHolder, L","); dwNumVariants++; if (wComma) { wComma++; wHolder = wComma; } } if (!dwNumVariants) { hr = E_FAIL; BAIL_ON_FAILURE(hr); } pVarArray = (PVARIANT)AllocADsMem( sizeof(VARIANT)*dwNumVariants ); if (!pVarArray) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } DWORD i = 0; wHolder = wComma = vVar.bstrVal; while (wHolder) { wComma = wcsstr(wHolder, L","); if (wComma) { *wComma = 0; // change the comma to null char wComma++; } if (*wHolder) { // use wHolder here VariantInit(pVarArray + i); V_VT(pVarArray + i) = VT_BSTR; hr = ADsAllocString(wHolder, &(V_BSTR(pVarArray + i))); BAIL_ON_FAILURE(hr); i++; } else { dwNumVariants--; } wHolder = wComma; } *ppVarArray = pVarArray; *pdwNumVariants = dwNumVariants; error: VariantClear(&vVar); RRETURN(hr); } HRESULT ConvertArrayToVariantArray( VARIANT varSafeArray, PVARIANT * ppVarArray, PDWORD pdwNumVariants ) { HRESULT hr = S_OK; DWORD dwSLBound = 0; DWORD dwSUBound = 0; DWORD dwNumVariants = 0; DWORD i = 0; VARIANT * pVarArray = NULL; SAFEARRAY * pArray = NULL; *pdwNumVariants = 0; *ppVarArray = 0; if(!(V_ISARRAY(&varSafeArray))) RRETURN(E_FAIL); // // This handles by-ref and regular SafeArrays. // if (V_VT(&varSafeArray) & VT_BYREF) pArray = *(V_ARRAYREF(&varSafeArray)); else pArray = V_ARRAY(&varSafeArray); // // Check that there is only one dimension in this array // if (pArray && pArray->cDims != 1) { hr = E_FAIL; BAIL_ON_FAILURE(hr); } // // Check that there is at least one element in this array // if (!pArray || ( pArray->rgsabound[0].cElements == 0) ) { dwNumVariants = 1; pVarArray = (PVARIANT)AllocADsMem( sizeof(VARIANT)*dwNumVariants ); if (!pVarArray) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } VariantInit(pVarArray); pVarArray->vt = VT_BSTR; pVarArray->bstrVal = NULL; } else { // // We know that this is a valid single dimension array // hr = SafeArrayGetLBound(pArray, 1, (long FAR *)&dwSLBound ); BAIL_ON_FAILURE(hr); hr = SafeArrayGetUBound(pArray, 1, (long FAR *)&dwSUBound ); BAIL_ON_FAILURE(hr); dwNumVariants = dwSUBound - dwSLBound + 1; pVarArray = (PVARIANT)AllocADsMem( sizeof(VARIANT)*dwNumVariants ); if (!pVarArray) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } for (i = dwSLBound; i <= dwSUBound; i++) { VariantInit(pVarArray + i); hr = SafeArrayGetElement(pArray, (long FAR *)&i, (pVarArray + i) ); CONTINUE_ON_FAILURE(hr); } } *ppVarArray = pVarArray; *pdwNumVariants = dwNumVariants; error: RRETURN(hr); } // // Property helper functions // // #define VALIDATE_PTR(pPtr) \ if (!pPtr) { \ hr = E_ADS_BAD_PARAMETER;\ }\ BAIL_ON_FAILURE(hr); HRESULT put_BSTR_Property( IADs * pADsObject, BSTR bstrPropertyName, BSTR pSrcStringProperty ) { HRESULT hr = S_OK; VARIANT varInputData; hr = PackStringinVariant( pSrcStringProperty, &varInputData ); BAIL_ON_FAILURE(hr); hr = pADsObject->Put( bstrPropertyName, varInputData ); BAIL_ON_FAILURE(hr); error: VariantClear( &varInputData ); RRETURN(hr); } HRESULT get_BSTR_Property( IADs * pADsObject, BSTR bstrPropertyName, BSTR *ppDestStringProperty ) { HRESULT hr = S_OK; VARIANT varOutputData; VALIDATE_PTR( ppDestStringProperty ); VariantInit( &varOutputData ); hr = pADsObject->Get( bstrPropertyName, &varOutputData ); BAIL_ON_FAILURE(hr); hr = UnpackStringfromVariant( varOutputData, ppDestStringProperty ); BAIL_ON_FAILURE(hr); error: VariantClear( &varOutputData ); RRETURN(hr); } HRESULT put_LONG_Property( IADs * pADsObject, BSTR bstrPropertyName, LONG lSrcProperty ) { HRESULT hr = S_OK; VARIANT varInputData; hr = PackLONGinVariant( lSrcProperty, &varInputData ); BAIL_ON_FAILURE(hr); hr = pADsObject->Put( bstrPropertyName, varInputData ); BAIL_ON_FAILURE(hr); error: VariantClear( &varInputData ); RRETURN(hr); } HRESULT get_LONG_Property( IADs * pADsObject, BSTR bstrPropertyName, PLONG plDestProperty ) { HRESULT hr = S_OK; VARIANT varOutputData; VALIDATE_PTR( plDestProperty ); VariantInit( &varOutputData ); hr = pADsObject->Get( bstrPropertyName, &varOutputData ); BAIL_ON_FAILURE(hr); hr = UnpackLONGfromVariant( varOutputData, plDestProperty ); BAIL_ON_FAILURE(hr); error: VariantClear( &varOutputData ); RRETURN(hr); } HRESULT put_DATE_Property( IADs * pADsObject, BSTR bstrPropertyName, DATE daSrcProperty ) { HRESULT hr = S_OK; VARIANT varInputData; hr = PackDATEinVariant( daSrcProperty, &varInputData ); BAIL_ON_FAILURE(hr); hr = pADsObject->Put( bstrPropertyName, varInputData ); BAIL_ON_FAILURE(hr); error: VariantClear( &varInputData ); RRETURN(hr); } HRESULT put_VARIANT_BOOL_Property( IADs * pADsObject, BSTR bstrPropertyName, VARIANT_BOOL fSrcProperty ) { HRESULT hr = S_OK; VARIANT varInputData; hr = PackVARIANT_BOOLinVariant( fSrcProperty, &varInputData ); BAIL_ON_FAILURE(hr); hr = pADsObject->Put( bstrPropertyName, varInputData ); BAIL_ON_FAILURE(hr); error: VariantClear( &varInputData ); RRETURN(hr); } HRESULT get_VARIANT_BOOL_Property( IADs * pADsObject, BSTR bstrPropertyName, PVARIANT_BOOL pfDestProperty ) { HRESULT hr = S_OK; VARIANT varOutputData; VALIDATE_PTR( pfDestProperty ); VariantInit( &varOutputData ); hr = pADsObject->Get( bstrPropertyName, &varOutputData ); BAIL_ON_FAILURE(hr); hr = UnpackVARIANT_BOOLfromVariant( varOutputData, pfDestProperty ); BAIL_ON_FAILURE(hr); error: VariantClear( &varOutputData ); RRETURN(hr); } HRESULT put_VARIANT_Property( IADs * pADsObject, BSTR bstrPropertyName, VARIANT vSrcProperty ) { HRESULT hr = S_OK; VARIANT varInputData; hr = PackVARIANTinVariant( vSrcProperty, &varInputData ); BAIL_ON_FAILURE(hr); hr = pADsObject->Put( bstrPropertyName, varInputData ); BAIL_ON_FAILURE(hr); error: VariantClear( &varInputData ); RRETURN(hr); } HRESULT get_VARIANT_Property( IADs * pADsObject, BSTR bstrPropertyName, PVARIANT pvDestProperty ) { HRESULT hr = S_OK; VARIANT varOutputData; VALIDATE_PTR( pvDestProperty ); VariantInit( &varOutputData ); hr = pADsObject->Get( bstrPropertyName, &varOutputData ); BAIL_ON_FAILURE(hr); hr = UnpackVARIANTfromVariant( varOutputData, pvDestProperty ); BAIL_ON_FAILURE(hr); error: VariantClear( &varOutputData ); RRETURN(hr); } HRESULT MetaBaseGetStringData( IN IMSAdminBase * pAdminBase, IN METADATA_HANDLE hObjHandle, IN LPWSTR pszIISPathName, IN DWORD dwMetaId, OUT LPBYTE *ppBuffer ) { HRESULT hr = S_OK; DWORD dwBufferSize = 0; METADATA_RECORD mdrMDData; LPBYTE pBuffer = NULL; MD_SET_DATA_RECORD(&mdrMDData, dwMetaId, METADATA_NO_ATTRIBUTES, ALL_METADATA, STRING_METADATA, dwBufferSize, pBuffer); hr = pAdminBase->GetData( hObjHandle, pszIISPathName, &mdrMDData, &dwBufferSize ); pBuffer = (LPBYTE) AllocADsMem(dwBufferSize); if (!pBuffer) { hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } MD_SET_DATA_RECORD(&mdrMDData, dwMetaId, METADATA_NO_ATTRIBUTES, ALL_METADATA, STRING_METADATA, dwBufferSize, pBuffer); hr = pAdminBase->GetData( hObjHandle, pszIISPathName, &mdrMDData, &dwBufferSize ); BAIL_ON_FAILURE(hr); *ppBuffer = pBuffer; RRETURN(hr); error: if (pBuffer) { FreeADsMem(pBuffer); } RRETURN(hr); } HRESULT MetaBaseGetDwordData( IN IMSAdminBase * pAdminBase, IN METADATA_HANDLE hObjHandle, IN LPWSTR pszIISPathName, IN DWORD dwMetaId, OUT PDWORD pdwData ) { HRESULT hr = S_OK; DWORD dwBufferSize = sizeof(DWORD); METADATA_RECORD mdrMDData; LPBYTE pBuffer = (LPBYTE)pdwData; MD_SET_DATA_RECORD(&mdrMDData, dwMetaId, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, dwBufferSize, pBuffer); hr = pAdminBase->GetData( hObjHandle, pszIISPathName, &mdrMDData, &dwBufferSize ); RRETURN(hr); } HRESULT MakeStringFromVariantArray( VARIANT *pvVariant, LPBYTE* ppBuffer ) { HRESULT hr = S_OK; DWORD i; DWORD dwLen = 0; VARIANT *pVar; LPBYTE pBuffer = NULL; DWORD dwNumVars = 0; VARIANT * pVarArray = NULL; pVar = pvVariant; if (pVar->vt == VT_EMPTY) { RRETURN(S_OK); } hr = ConvertArrayToVariantArray( *pVar, &pVarArray, &dwNumVars ); BAIL_ON_FAILURE(hr); if (dwNumVars == 0) { RRETURN(S_OK); } // // find out total length // pVar = pVarArray; for (i = 0; i < dwNumVars; i++ ) { // // add 1 for comma // if (pVar->vt == VT_BSTR || pVar->vt == VT_EMPTY) { if (pVar->bstrVal && *(pVar->bstrVal)) { // // validate parameter; check for ',' // if (wcschr(pVar->bstrVal, L',')) { hr = E_ADS_BAD_PARAMETER; BAIL_ON_FAILURE(hr); } dwLen += ((DWORD)wcslen(pVar->bstrVal) + 1); } } else { hr = E_ADS_CANT_CONVERT_DATATYPE; BAIL_ON_FAILURE(hr); } pVar++; } // // if there are non-empty entries found in the array, copy them to buffer // if (dwLen != 0) { pBuffer = (LPBYTE) AllocADsMem(dwLen*sizeof(WCHAR)); if (!pBuffer) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } *ppBuffer = pBuffer; pVar = pVarArray; for (i = 0; i < dwNumVars; i++, pVar++ ) { if (pVar->bstrVal && *(pVar->bstrVal)) { memcpy(pBuffer, pVar->bstrVal, wcslen(pVar->bstrVal)*sizeof(WCHAR)); pBuffer = pBuffer + wcslen(pVar->bstrVal)*sizeof(WCHAR); if (i != dwNumVars -1) { memcpy(pBuffer, L",", sizeof(WCHAR)); pBuffer = pBuffer + sizeof(WCHAR); } } } if (*ppBuffer == pBuffer - dwLen*sizeof(WCHAR)) { pBuffer -= sizeof(WCHAR); *pBuffer = L'\0'; } else { *pBuffer = L'\0'; } } error: if (pVarArray) { for (i = 0; i < dwNumVars; i++) { VariantClear(pVarArray + i); } FreeADsMem(pVarArray); } if (FAILED(hr) && pBuffer) { FreeADsMem(pBuffer); } RRETURN(hr); } HRESULT CheckVariantDataType( PVARIANT pVar, VARTYPE vt ) { HRESULT hr; hr = VariantChangeType(pVar, pVar, 0, vt); if (FAILED(hr)) { if (hr == E_OUTOFMEMORY) { RRETURN(hr); } RRETURN(hr = E_ADS_CANT_CONVERT_DATATYPE); } RRETURN(hr); } HRESULT MakeMultiStringFromVariantArray( VARIANT *pvVariant, LPBYTE* ppBuffer ) { HRESULT hr = S_OK; DWORD i; DWORD dwLen = 0; VARIANT *pVar; LPBYTE pBuffer = NULL; DWORD dwNumVars = 0; VARIANT * pVarArray = NULL; pVar = pvVariant; if (pVar->vt == VT_EMPTY) { RRETURN(S_OK); } hr = ConvertArrayToVariantArray( *pVar, &pVarArray, &dwNumVars ); BAIL_ON_FAILURE(hr); if (dwNumVars == 0) { RRETURN(S_OK); } // // find out total length // pVar = pVarArray; for (i = 0; i < dwNumVars; i++ ) { if (pVar->vt == VT_BSTR) { if (pVar->bstrVal && *(pVar->bstrVal)) { dwLen += ((DWORD)wcslen(pVar->bstrVal) + 1); } else { // // add 1 for \0 // dwLen++; } } else { hr = E_ADS_CANT_CONVERT_DATATYPE; BAIL_ON_FAILURE(hr); } pVar++; } // // +1 for extra \0 // dwLen++; // // copy entries to buffer // if (dwLen != 0) { pBuffer = (LPBYTE) AllocADsMem(dwLen*sizeof(WCHAR)); if (!pBuffer) { hr = E_OUTOFMEMORY; BAIL_ON_FAILURE(hr); } *ppBuffer = pBuffer; pVar = pVarArray; for (i = 0; i < dwNumVars; i++, pVar++ ) { if (pVar->bstrVal && *(pVar->bstrVal)) { memcpy(pBuffer, pVar->bstrVal, wcslen(pVar->bstrVal)*sizeof(WCHAR)); pBuffer = pBuffer + wcslen(pVar->bstrVal)*sizeof(WCHAR); } memcpy(pBuffer, L"\0", sizeof(WCHAR)); pBuffer = pBuffer + sizeof(WCHAR); } *pBuffer = L'\0'; } error: if (pVarArray) { for (i = 0; i < dwNumVars; i++) { VariantClear(pVarArray + i); } FreeADsMem(pVarArray); } if (FAILED(hr) && pBuffer) { FreeADsMem(pBuffer); } RRETURN(hr); }