/*++ Copyright (c) 2001 Microsoft Corporation Module Name: bitssrvcfgimp.h Abstract: Implementation header to define server configuration information. --*/ HRESULT PropertyIDManager::LoadPropertyInfo( const WCHAR * MachineName ) { bool ComLoaded; HRESULT Hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ); if ( RPC_E_CHANGED_MODE == Hr ) ComLoaded = false; else if ( FAILED(Hr) ) return Hr; else ComLoaded = true; BSTR MetaIDBSTR = NULL; BSTR UserTypeBSTR = NULL; WCHAR *PathBuffer = NULL; SIZE_T PathBufferSize = 0; MetaIDBSTR = SysAllocString( L"MetaId" ); UserTypeBSTR = SysAllocString( L"UserType" ); if ( !MetaIDBSTR || !UserTypeBSTR) { Hr = E_OUTOFMEMORY; goto exit; } PathBuffer = (WCHAR*)HeapAlloc( GetProcessHeap(), 0, 1024 ); if ( !PathBuffer ) { Hr = E_OUTOFMEMORY; goto exit; } PathBufferSize = 1024; for ( SIZE_T i = 0; i < g_NumberOfProperties; i++ ) { WCHAR SchemaPrefix[] = L"IIS://"; WCHAR SchemaPath[] = L"/Schema/"; SIZE_T SchemaPrefixSize = ( sizeof( SchemaPrefix ) / sizeof( WCHAR ) ) - 1; SIZE_T SchemaPathSize = ( sizeof( SchemaPath ) / sizeof( WCHAR ) ) - 1; SIZE_T MachineNameSize = wcslen( MachineName ); SIZE_T PropertyNameSize = wcslen( g_Properties[i].PropertyName ); SIZE_T PathSize = SchemaPrefixSize + SchemaPathSize + MachineNameSize + PropertyNameSize + 1; if ( PathBufferSize < ( PathSize * sizeof( WCHAR ) ) ) { WCHAR *NewBuffer = (WCHAR*)HeapReAlloc( GetProcessHeap(), 0, PathBuffer, PathSize * sizeof( WCHAR ) ); if ( !NewBuffer ) { Hr = E_OUTOFMEMORY; goto exit; } PathBuffer = NewBuffer; PathBufferSize = PathSize * sizeof( WCHAR ); } // build schema path WCHAR *ObjectPath = PathBuffer; { WCHAR *TempPointer = ObjectPath; memcpy( TempPointer, SchemaPrefix, SchemaPrefixSize * sizeof( WCHAR ) ); TempPointer += SchemaPrefixSize; memcpy( TempPointer, MachineName, MachineNameSize * sizeof( WCHAR ) ); TempPointer += MachineNameSize; memcpy( TempPointer, SchemaPath, SchemaPathSize * sizeof( WCHAR ) ); TempPointer += SchemaPathSize; memcpy( TempPointer, g_Properties[i].PropertyName, ( PropertyNameSize + 1 ) * sizeof( WCHAR ) ); } // Open the object IADs *MbObject = NULL; Hr = ADsGetObject( ObjectPath, __uuidof( *MbObject ), reinterpret_cast( &MbObject ) ); if ( FAILED( Hr ) ) { #if defined( ALLOW_OVERWRITES ) // workaround for IIS issue. IIS isn't handling schema extension property. Dream up a ID. if ( E_ADS_UNKNOWN_OBJECT == Hr && MD_BITS_ALLOW_OVERWRITES == i ) { m_PropertyIDs[i] = m_PropertyIDs[ i - 1] + 1; m_PropertyUserTypes[i] = m_PropertyUserTypes[ i - 1 ]; continue; } else #endif goto exit; } VARIANT var; VariantInit( &var ); Hr = MbObject->Get( MetaIDBSTR, &var ); if ( FAILED(Hr ) ) { MbObject->Release(); goto exit; } Hr = VariantChangeType( &var, &var, 0, VT_UI4 ); if ( FAILED(Hr ) ) { MbObject->Release(); VariantClear( &var ); goto exit; } m_PropertyIDs[i] = var.ulVal; VariantClear( &var ); Hr = MbObject->Get( UserTypeBSTR, &var ); if ( FAILED( Hr ) ) { MbObject->Release(); goto exit; } Hr = VariantChangeType( &var, &var, 0, VT_UI4 ); if ( FAILED( Hr ) ) { MbObject->Release(); VariantClear( &var ); goto exit; } m_PropertyUserTypes[i] = var.ulVal; VariantClear( &var ); MbObject->Release(); } Hr = S_OK; exit: SysFreeString( MetaIDBSTR ); SysFreeString( UserTypeBSTR ); if ( ComLoaded ) CoUninitialize(); if ( PathBuffer ) { HeapFree( GetProcessHeap(), 0, PathBuffer ); PathBuffer = 0; PathBufferSize = 0; } return Hr; } // ================================================================================================ // Auxiliary functions that access the IIS Metabase // ================================================================================================ LPWSTR CSimplePropertyReader::ConvertObjectPathToADSI( LPCWSTR szObjectPath ) { WCHAR *szReturnPath = NULL; SIZE_T ReturnPathSize = 0; if ( _wcsnicmp( L"IIS://", szObjectPath, wcslen( L"IIS://") ) == 0 ) { // already have an adsi path ReturnPathSize = wcslen( szObjectPath ) + 1; szReturnPath = new WCHAR[ ReturnPathSize ]; THROW_OUTOFMEMORY_IFNULL( szReturnPath ); memcpy( szReturnPath, szObjectPath, ReturnPathSize * sizeof( WCHAR ) ); } else if ( _wcsnicmp( L"/LM/", szObjectPath, wcslen( L"/LM/" ) ) == 0 ) { //metabase path to local machine ReturnPathSize = wcslen( szObjectPath ) + wcslen( L"IIS://LocalHost/" ) + 1; szReturnPath = new WCHAR[ ReturnPathSize ]; THROW_OUTOFMEMORY_IFNULL( szReturnPath ); StringCchCopyW( szReturnPath, ReturnPathSize, L"IIS://LocalHost/" ); StringCchCatW( szReturnPath, ReturnPathSize, szObjectPath + wcslen( L"/LM/" ) ); } else if ( _wcsnicmp( L"LM/", szObjectPath, wcslen( L"LM/" ) ) == 0 ) { //metabase path to local machine ReturnPathSize = wcslen( szObjectPath ) + wcslen( L"IIS://LocalHost/" ) + 1; szReturnPath = new WCHAR[ ReturnPathSize ]; THROW_OUTOFMEMORY_IFNULL( szReturnPath ); StringCchCopyW( szReturnPath, ReturnPathSize, L"IIS://LocalHost/" ); StringCchCatW( szReturnPath, ReturnPathSize, szObjectPath + wcslen( L"LM/" ) ); } else { //metabase path to another server ReturnPathSize = wcslen( szObjectPath ) + wcslen( L"IIS://" ) + 1; szReturnPath = new WCHAR[ ReturnPathSize ]; THROW_OUTOFMEMORY_IFNULL( szReturnPath ); if ( '/' == szObjectPath[0] ) StringCchCopyW( szReturnPath, ReturnPathSize, L"IIS:/" ); else StringCchCopyW( szReturnPath, ReturnPathSize, L"IIS://" ); StringCchCatW( szReturnPath, ReturnPathSize, (WCHAR*)szObjectPath ); } // check for a trailing \ character SIZE_T StringLength = wcslen( szReturnPath ); if ( StringLength >= 1 ) { if ( L'\\' == szReturnPath[ StringLength - 1 ] || L'/' == szReturnPath[ StringLength - 1 ] ) { szReturnPath[ StringLength - 1 ] = L'\0'; } } return szReturnPath; } BSTR CSimplePropertyReader::GetADsStringProperty( IADs *MetaObj, BSTR bstrPropName) { BSTR bstrRetval; VARIANT vt; THROW_COMERROR( MetaObj->Get( bstrPropName, &vt ) ); THROW_COMERROR( VariantChangeType( &vt, &vt, 0, VT_BSTR ) ); bstrRetval = vt.bstrVal; vt.bstrVal = NULL; VariantClear( &vt ); return bstrRetval; } LPWSTR CSimplePropertyReader::GetAdmObjStringProperty( SmartIMSAdminBasePointer IISAdminBase, METADATA_HANDLE MdVDirKey, DWORD dwMDIdentifier ) { METADATA_RECORD MdRecord; DWORD dwBytesRequired = 0; WCHAR *szBuffer = NULL; try { memset( &MdRecord, 0, sizeof( MdRecord ) ); MdRecord.dwMDIdentifier = dwMDIdentifier; MdRecord.dwMDAttributes = METADATA_INHERIT; MdRecord.dwMDUserType = IIS_MD_UT_FILE; MdRecord.dwMDDataType = STRING_METADATA; MdRecord.dwMDDataLen = 0; MdRecord.pbMDData = NULL; HRESULT hr = IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &dwBytesRequired ); if (hr != HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER )) throw ComError( hr ); szBuffer = reinterpret_cast(new BYTE[ dwBytesRequired ]); THROW_OUTOFMEMORY_IFNULL(szBuffer); memset( szBuffer, 0, dwBytesRequired ); MdRecord.dwMDDataLen = dwBytesRequired; MdRecord.pbMDData = (PBYTE)szBuffer; THROW_COMERROR( IISAdminBase->GetData( MdVDirKey, NULL, &MdRecord, &dwBytesRequired ) ); } catch( ComError Error ) { // just forward the error throw; } return szBuffer; } CAccessRemoteVDir::CAccessRemoteVDir() : m_MetaObj(NULL), m_fIsImpersonated(FALSE), m_hUserToken(INVALID_HANDLE_VALUE), m_szUNCPath(NULL), m_szUNCUsername(NULL), m_szUNCPassword(NULL) { } CAccessRemoteVDir::~CAccessRemoteVDir() { // // Free the user token obtained when/if LogonUser() was called // if (m_hUserToken != INVALID_HANDLE_VALUE) { CloseHandle( m_hUserToken ); m_hUserToken = INVALID_HANDLE_VALUE; } // // If CAccessRemoteVDir::RevertFromUNCAccount() wasn't called before // the destructor was called, then make sure we revert the impersonation. // Is advised the the code that is using this class explicity call // RevertFromUNCAccount(), however. This test is a safe guard in case // the call is not made. // if (m_fIsImpersonated) { RevertToSelf(); } // // Free variables used when using the IIS AdmObj to access the meta store. // All the m_szUNC* variables assume memory was allocated by calling // CSimplePropertyReader::GetAdmObjStringProperty(), which allocated a buffer // by calling "new BYTE[ ...]" // if (m_szUNCPath) { delete [] reinterpret_cast(m_szUNCPath); m_szUNCPath = NULL; } if (m_szUNCUsername) { delete [] reinterpret_cast(m_szUNCUsername); m_szUNCUsername = NULL; } if (m_szUNCPassword) { delete [] reinterpret_cast(m_szUNCPassword); m_szUNCPassword = NULL; } } void CAccessRemoteVDir::RevertFromUNCAccount() { // revert to previous security setting if (m_fIsImpersonated) { if (!RevertToSelf()) { throw ComError( HRESULT_FROM_WIN32( GetLastError() ) ); } m_fIsImpersonated = FALSE; } if (m_hUserToken != INVALID_HANDLE_VALUE) { // revert to previous security setting CloseHandle( m_hUserToken ); m_hUserToken = INVALID_HANDLE_VALUE; } } inline BOOL CAccessRemoteVDir::IsUNCPath(LPCWSTR szPath) { if ( szPath && szPath[0] == L'\\' && szPath[1] == L'\\' ) { return TRUE; } return FALSE; } void CAccessRemoteVDir::LoginToUNC( SmartIMSAdminBasePointer IISAdminBase, METADATA_HANDLE MdVDirKey ) { try { m_szUNCPath = CSimplePropertyReader::GetAdmObjStringProperty(IISAdminBase, MdVDirKey, MD_VR_PATH); // // Don't logon if the path isn't a UNC path // if (!IsUNCPath(m_szUNCPath)) { // this class destructor will free m_szUNCPath; return; } m_szUNCUsername = CSimplePropertyReader::GetAdmObjStringProperty(IISAdminBase, MdVDirKey, MD_VR_USERNAME); m_szUNCPassword = CSimplePropertyReader::GetAdmObjStringProperty(IISAdminBase, MdVDirKey, MD_VR_PASSWORD); ImpersonateUNCUser(m_szUNCPath, m_szUNCUsername, m_szUNCPassword, &m_hUserToken); m_fIsImpersonated = TRUE; } catch( ComError Error ) { // just forward the error throw; } } void CAccessRemoteVDir::ImpersonateUNCUser(IN LPCWSTR szUNCPath, IN LPCWSTR szUNCUsername, IN LPCWSTR szUNCPassword, OUT HANDLE *hUserToken) { *hUserToken = INVALID_HANDLE_VALUE; // make sure we are not getting unexpected data if (!szUNCUsername || !szUNCPassword || szUNCUsername[0] == L'\0') { throw ComError( HRESULT_FROM_WIN32( ERROR_INVALID_DATA ) ); } // crack the user name into a user and domain WCHAR *szUserName = (WCHAR*)szUNCUsername; WCHAR *szDomainName = NULL; WCHAR *p = szUserName; while(*p != L'\0') { if(*p == L'\\') { *p = L'\0'; p++; // // first part is domain // second is user. // szDomainName = szUserName; szUserName = p; break; } p++; } if ( !LogonUserW( szUserName, szDomainName, (WCHAR*)szUNCPassword, LOGON32_LOGON_BATCH, LOGON32_PROVIDER_DEFAULT, hUserToken ) ) { if ( GetLastError() == ERROR_LOGON_TYPE_NOT_GRANTED ) { if ( !LogonUserW( szUserName, szDomainName, (WCHAR*)szUNCPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, hUserToken ) ) { // LogonUser() may touch the handle // make sure we don't think we have a valid handle *hUserToken = INVALID_HANDLE_VALUE; throw ComError( HRESULT_FROM_WIN32( GetLastError() ) ); } } else { *hUserToken = INVALID_HANDLE_VALUE; throw ComError( HRESULT_FROM_WIN32( GetLastError() ) ); } } if ( !ImpersonateLoggedOnUser( *hUserToken ) ) throw ComError( HRESULT_FROM_WIN32( GetLastError() ) ); }